Elicitation
Conversational elicitation of strongly-typed Rust values via MCP
elicitation is a Rust library that transforms conversational LLM interactions into strongly-typed Rust values through the Model Context Protocol (MCP). It provides a trait-based system for eliciting primitive types, enums, structs, and nested data structures through natural language interaction.
Features
- Comprehensive Type Coverage - Elicit virtually any Rust standard library type
- Trait-Based Design - Simple
Elicitationtrait for all types - Derive Macros - Zero-boilerplate implementation for custom types
- Type-Safe - Compile-time guarantees with full type inference
- Composable - Nest types arbitrarily deep without limitations
- Async-First - Built on tokio with proper Send bounds
- Four Interaction Paradigms:
- Select - Choose from finite options (enum pattern)
- Affirm - Yes/no confirmation (bool pattern)
- Survey - Multi-field elicitation (struct pattern)
- Authorize - Permission policies (planned for v0.2.0)
- MCP Integration - Uses official rmcp (Rust MCP SDK) for communication
Supported Types
Primitives
- Numeric:
i8,i16,i32,i64,i128,isize,u8,u16,u32,u64,u128,usize,f32,f64 - Text:
String,bool - Time:
std::time::Duration - Filesystem:
std::path::PathBuf - Network:
IpAddr,Ipv4Addr,Ipv6Addr,SocketAddr,SocketAddrV4,SocketAddrV6
Containers
- Option:
Option<T>- Optional values - Result:
Result<T, E>- Success/failure outcomes - Vec:
Vec<T>- Dynamic arrays - Arrays:
[T; N]- Fixed-size arrays (any size N) - Tuples:
(T1, T2, ...)- Heterogeneous tuples (up to arity 12)
Smart Pointers
- Box:
Box<T>- Heap allocation - Rc:
Rc<T>- Reference counting - Arc:
Arc<T>- Atomic reference counting
Collections
- HashMap:
HashMap<K, V>- Hash-based key-value map with duplicate key handling - BTreeMap:
BTreeMap<K, V>- Ordered key-value map - HashSet:
HashSet<T>- Hash-based unique set with automatic deduplication - BTreeSet:
BTreeSet<T>- Ordered unique set - VecDeque:
VecDeque<T>- Double-ended queue - LinkedList:
LinkedList<T>- Doubly-linked list
Custom Types
- Enums: Automatic
Selectparadigm via#[derive(Elicit)] - Structs: Automatic
Surveyparadigm via#[derive(Elicit)] - Nested: Unlimited nesting depth (e.g.,
Vec<Option<Result<HashMap<String, Arc<T>>, E>>>)
Installation
Add this to your Cargo.toml:
[]
= "0.2"
= "0.12"
= { = "1", = ["macros", "rt-multi-thread"] }
MCP Setup
This library requires an MCP client (like Claude Desktop or Claude CLI) to provide the elicitation tools. Your application runs as an MCP server that the client invokes.
Running with Claude CLI
To run the examples or your own code:
# Install Claude CLI if you haven't already
# (see https://docs.anthropic.com/en/docs/agents-and-tools)
# Run an example through Claude CLI
# Or ask Claude to run it
Integration with Claude Desktop
Add your MCP server to Claude Desktop's configuration:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Linux: ~/.config/claude/claude_desktop_config.json
How It Works
- Your application creates an MCP client with
rmcp::transport::stdio() - Claude (the MCP client) provides elicitation tools via stdin/stdout
- When you call
.elicit(), it sends tool requests to Claude - Claude prompts the user and validates responses
- Your code receives strongly-typed Rust values
Note: Examples won't work standalone - they must be invoked by an MCP client.
Quick Start
use ;
use ServiceExt;
// Derive for enums (Select pattern)
// Derive for structs (Survey pattern)
async
Examples
All examples require an MCP client (Claude Desktop or Claude CLI) to run. See MCP Setup above.
Primitive Types
// Elicit basic Rust types
let age: i32 = i32elicit.await?;
let name: String = Stringelicit.await?;
let confirmed: bool = boolelicit.await?;
let nickname: = Option::elicit.await?;
let scores: = Vec::elicit.await?;
// Result types for success/failure outcomes
let operation: = Resultelicit.await?;
Try it: claude "Run the simple_types example" or claude "Run the result example"
Filesystem Paths
use PathBuf;
// Elicit a filesystem path
let file_path: PathBuf = elicit.await?;
// Optional paths work too
let config_path: = Option::elicit.await?;
Try it: claude "Run the pathbuf example"
Network Addresses
use ;
// Elicit IP addresses with automatic validation
let ip: IpAddr = elicit.await?; // IPv4 or IPv6
let ipv4: Ipv4Addr = elicit.await?; // IPv4 only
let ipv6: Ipv6Addr = elicit.await?; // IPv6 only
// Socket addresses (IP + port)
let socket: SocketAddr = elicit.await?;
Try it: claude "Run the network example"
Time Durations
use Duration;
// Elicit duration in seconds (supports decimals)
let timeout: Duration = elicit.await?;
// Works with optional durations
let cache_ttl: = Option::elicit.await?;
// Collections of durations
let intervals: = Vec::elicit.await?;
Try it: claude "Run the duration example"
Enums (Select Pattern)
Unit Variants (Simple Selection)
let status = elicit.await?;
Tuple Variants (Select + Field Elicitation)
// User first selects variant (Url/Base64/Binary), then provides the field value
let source = elicit.await?;
Struct Variants (Select + Multi-Field Survey)
// User selects variant, then provides each field
let input = elicit.await?;
Mixed Variants
All three variant types can coexist in the same enum:
let status = elicit.await?;
Try it: claude "Run the enums example"
Structs (Survey Pattern)
let person = elicit.await?;
Try it: claude "Run the structs example"
Complex Nested Types
let project = elicit.await?;
Try it: claude "Run the complex_survey example"
Collections
use ;
// Elicit a HashMap with duplicate key handling
let scores: = elicit.await?;
// Elicit a HashSet with automatic deduplication
let tags: = elicit.await?;
// BTreeMap and BTreeSet also supported for ordered collections
use ;
let config: = elicit.await?;
let priorities: = elicit.await?;
// VecDeque and LinkedList for sequential access patterns
use ;
let queue: = elicit.await?;
let linked: = elicit.await?;
Try it: claude "Run the collections example"
Interaction Paradigms
Select
For choosing from a finite set of options (enums):
Affirm
For yes/no questions (booleans):
let confirmed: bool = boolelicit.await?;
Survey
For multi-field data collection (structs):
Authorize
Permission-based elicitation (planned for v0.2.0).
Attributes
#[prompt("...")]
Customize prompts for types or fields:
// Struct-level prompt
#[skip]
Skip fields during elicitation (uses Default::default()):
Error Handling
The library provides rich error handling with location tracking:
use ;
match elicit.await
Error types:
InvalidFormat- Parsing failedOutOfRange- Value outside valid rangeInvalidOption- Invalid enum selectionMissingField- Required field missingCancelled- User cancelled operationMcp- MCP protocol errorJson- JSON parsing error
Architecture
Traits
Prompt- Provides prompt text for a typeElicit- Implements elicitation logicSelect- For enum types (finite choices)Affirm- For boolean types (yes/no)Survey- For struct types (multi-field)
Type Composition
All elicitation types compose freely:
// Nested structures
let data: = Vecelicit.await?;
// Complex hierarchies
MCP Integration
The library uses the official rmcp (Rust MCP SDK) for MCP communication:
use ServiceExt;
// Create client via stdio transport (for Claude Desktop/CLI)
let client =
.serve
.await?;
// Use with elicitation
let value = elicit.await?;
Documentation
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development
# Run all checks
# Run tests
# Check examples
# Build documentation
Versioning
This project follows Semantic Versioning.
Current version: 0.2.0
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.