Skip to main content

elicitation/
lib.rs

1//! Conversational elicitation of strongly-typed Rust values via MCP.
2//!
3//! The `elicitation` library provides a trait-based system for eliciting
4//! strongly-typed values from users through conversational interaction via
5//! the Model Context Protocol (MCP). It transforms LLM conversations into
6//! type-safe Rust values with compile-time guarantees.
7//!
8//! # MCP Setup Required
9//!
10//! This library runs as an **MCP server** and requires an **MCP client**
11//! (like Claude Desktop or Claude CLI) to provide the elicitation tools.
12//! Your application won't work standalone - it must be invoked by an MCP client.
13//!
14//! See the [README](https://github.com/crumplecup/elicitation) for setup instructions.
15//!
16//! # Core Concepts
17//!
18//! ## Traits
19//!
20//! - [`Prompt`] - Provides prompt metadata for a type
21//! - [`Elicit`] - Main trait for eliciting values
22//!
23//! ## Interaction Paradigms
24//!
25//! - [`Select`] - Choose from finite options (enum pattern)
26//! - [`Affirm`] - Yes/no confirmation (bool pattern)
27//! - [`Survey`] - Multi-field elicitation (struct pattern)
28//! - [`Authorize`] - Permission policies (planned for v0.2.0)
29//!
30//! # Example
31//!
32//! ```rust,ignore
33//! use elicitation::{Elicitation, ElicitResult};
34//! use rmcp::service::{Peer, RoleClient};
35//!
36//! async fn example(client: &Peer<RoleClient>) -> ElicitResult<()> {
37//!     // Elicit a simple integer
38//!     let age: i32 = i32::elicit(client).await?;
39//!
40//!     // Elicit an optional value
41//!     let nickname: Option<String> = Option::<String>::elicit(client).await?;
42//!
43//!     // Elicit a collection
44//!     let scores: Vec<i32> = Vec::<i32>::elicit(client).await?;
45//!     Ok(())
46//! }
47//! ```
48//!
49//! # Derive Macros
50//!
51//! The library provides derive macros for automatic implementation:
52//!
53//! ```rust,ignore
54//! use elicitation::Elicit;
55//!
56//! // Enums automatically use the Select paradigm
57//! #[derive(Elicit)]
58//! enum Color {
59//!     Red,
60//!     Green,
61//!     Blue,
62//! }
63//!
64//! // Structs automatically use the Survey paradigm
65//! #[derive(Elicit)]
66//! struct Person {
67//!     #[prompt("What is your name?")]
68//!     name: String,
69//!     #[prompt("What is your age?")]
70//!     age: u8,
71//! }
72//! ```
73//!
74//! # MCP Integration
75//!
76//! The library uses the [rmcp](https://crates.io/crates/rmcp) crate - the
77//! official Rust MCP SDK - for MCP client integration. All elicitation
78//! happens through asynchronous MCP tool calls.
79
80#![forbid(unsafe_code)]
81#![warn(missing_docs)]
82
83mod client;
84// Verification framework imports
85
86mod collections;
87mod containers;
88mod default_style;
89mod error;
90pub mod verification;
91
92#[cfg(kani)]
93mod kani_tests;
94
95#[cfg(feature = "cli")]
96pub mod cli;
97
98pub mod contracts;
99pub mod mcp;
100mod paradigm;
101mod primitives;
102pub mod style;
103pub mod tool;
104mod traits;
105
106#[cfg(feature = "serde_json")]
107mod value_impl;
108
109#[cfg(any(feature = "chrono", feature = "time", feature = "jiff"))]
110mod datetime_common;
111
112#[cfg(feature = "chrono")]
113pub mod datetime_chrono;
114
115#[cfg(feature = "time")]
116pub mod datetime_time;
117
118#[cfg(feature = "jiff")]
119pub mod datetime_jiff;
120
121mod elicitation_style;
122
123// Error types
124pub use error::{ElicitError, ElicitErrorKind, ElicitResult, JsonError, RmcpError, ServiceError};
125
126// Core client
127pub use client::ElicitClient;
128
129// Core traits
130pub use elicitation_style::ElicitationStyle;
131pub use traits::{ElicitBuilder, Elicitation, Generator, Prompt};
132
133// Contracts (proof-carrying composition)
134pub use contracts::{
135    And, Established, Implies, InVariant, Is, Prop, Refines, both, downcast, fst, snd,
136};
137
138// Tools (contract-based MCP tools)
139pub use tool::{Tool, True, both_tools, then};
140
141// Interaction paradigm traits
142pub use paradigm::{Affirm, Authorize, FieldInfo, Select, Survey};
143
144// Re-export rmcp for user convenience
145pub use rmcp;
146
147// Re-export derive macro with user-friendly name
148pub use elicitation_derive::Elicit;
149
150// Re-export verification contract types at crate level (for kani_proofs imports)
151// EXPLICIT exports - no globs (helps compiler show what's missing)
152#[cfg(any(feature = "verification", kani))]
153pub use verification::types::{
154    ArcNonNull,
155    ArcSatisfies,
156    ArrayAllSatisfy,
157    BTreeMapNonEmpty,
158    BTreeSetNonEmpty,
159    BoolFalse,
160    // Bools
161    BoolTrue,
162    BoxNonNull,
163    BoxSatisfies,
164    // Chars
165    CharAlphabetic,
166    CharAlphanumeric,
167    CharNumeric,
168    DurationNonZero,
169    // Durations
170    DurationPositive,
171    F32Finite,
172    F32NonNegative,
173    // Floats
174    F32Positive,
175    F64Finite,
176    F64NonNegative,
177    F64Positive,
178    HashMapNonEmpty,
179    HashSetNonEmpty,
180    I8NonNegative,
181    I8NonZero,
182    I8NonZeroStyle,
183    // Integers - i8 family
184    I8Positive,
185    I8Range,
186    I8RangeStyle,
187    I16NonNegative,
188    I16NonZero,
189    I16NonZeroStyle,
190    // i16 family
191    I16Positive,
192    I16Range,
193    I16RangeStyle,
194    I32NonNegative,
195    I32NonZero,
196    // i32 family
197    I32Positive,
198    I32Range,
199    I32RangeStyle,
200    I64NonNegative,
201    I64NonZero,
202    // i64 family
203    I64Positive,
204    I64Range,
205    I64RangeStyle,
206    I128NonNegative,
207    I128NonZero,
208    // i128 family
209    I128Positive,
210    I128Range,
211    I128RangeStyle,
212    // Networks
213    IpPrivate,
214    IpPublic,
215    IpV4,
216    IpV6,
217    Ipv4Loopback,
218    Ipv6Loopback,
219    IsizeNonNegative,
220    IsizeNonZero,
221    // isize family
222    IsizePositive,
223    IsizeRange,
224    IsizeRangeStyle,
225    LinkedListNonEmpty,
226    OptionSome,
227    // Paths
228    PathBufExists,
229    PathBufIsDir,
230    PathBufIsFile,
231    PathBufReadable,
232    RcNonNull,
233    RcSatisfies,
234    ResultOk,
235    // Strings
236    StringNonEmpty,
237    // Tuples
238    Tuple2,
239    Tuple3,
240    Tuple4,
241    U8NonZero,
242    // u8 family
243    U8Positive,
244    U8Range,
245    U8RangeStyle,
246    U16NonZero,
247    // u16 family
248    U16Positive,
249    U16Range,
250    U16RangeStyle,
251    U32NonZero,
252    // u32 family
253    U32Positive,
254    U32Range,
255    U32RangeStyle,
256    U64NonZero,
257    // u64 family
258    U64Positive,
259    U64Range,
260    U64RangeStyle,
261    U128NonZero,
262    // u128 family
263    U128Positive,
264    U128Range,
265    U128RangeStyle,
266    UsizeNonZero,
267    // usize family
268    UsizePositive,
269    UsizeRange,
270    UsizeRangeStyle,
271    // ValidationError
272    ValidationError,
273    VecAllSatisfy,
274    VecDequeNonEmpty,
275    // Collections
276    VecNonEmpty,
277};
278
279// UUIDs (feature-gated on uuid)
280#[cfg(all(any(feature = "verification", kani), feature = "uuid"))]
281pub use verification::types::{UuidNonNil, UuidV4};
282
283#[cfg(feature = "uuid")]
284pub use primitives::uuid::{UuidGenerationMode, UuidGenerator};
285
286// SystemTime (standard library)
287pub use primitives::systemtime::{SystemTimeGenerationMode, SystemTimeGenerator};
288
289// Duration (standard library)
290pub use primitives::duration::{DurationGenerationMode, DurationGenerator};
291
292// Unit structs (standard library)
293pub use primitives::unit_structs::{Formatter, Parser, Validator};
294
295// Error generators (for testing)
296pub use primitives::errors::{IoErrorGenerationMode, IoErrorGenerator};
297
298#[cfg(feature = "serde_json")]
299pub use primitives::errors::{JsonErrorGenerationMode, JsonErrorGenerator};
300
301// DateTime generators (feature-gated)
302#[cfg(feature = "chrono")]
303pub use datetime_chrono::{
304    DateTimeUtcGenerationMode, DateTimeUtcGenerator, NaiveDateTimeGenerationMode,
305    NaiveDateTimeGenerator,
306};
307
308#[cfg(feature = "time")]
309pub use datetime_time::{
310    InstantGenerationMode, InstantGenerator, OffsetDateTimeGenerationMode, OffsetDateTimeGenerator,
311};
312
313#[cfg(feature = "jiff")]
314pub use datetime_jiff::{TimestampGenerationMode, TimestampGenerator};
315
316// DateTimes (feature-gated on chrono/time/jiff)
317#[cfg(all(any(feature = "verification", kani), feature = "chrono"))]
318pub use verification::types::{DateTimeUtcAfter, DateTimeUtcBefore, NaiveDateTimeAfter};
319
320#[cfg(all(any(feature = "verification", kani), feature = "time"))]
321pub use verification::types::{OffsetDateTimeAfter, OffsetDateTimeBefore};
322
323#[cfg(all(any(feature = "verification", kani), feature = "jiff"))]
324pub use verification::types::{TimestampAfter, TimestampBefore};
325
326// Values (JSON - feature-gated)
327#[cfg(all(any(feature = "verification", kani), feature = "serde_json"))]
328pub use verification::types::{ValueArray, ValueNonNull, ValueObject};
329
330// URLs (feature-gated)
331#[cfg(all(any(feature = "verification", kani), feature = "url"))]
332pub use verification::types::{UrlCanBeBase, UrlHttp, UrlHttps, UrlValid, UrlWithHost};
333
334// Regexes (feature-gated)
335#[cfg(all(any(feature = "verification", kani), feature = "regex"))]
336pub use verification::types::{
337    RegexCaseInsensitive, RegexMultiline, RegexSetNonEmpty, RegexSetValid, RegexValid,
338};
339
340// Mechanisms
341#[cfg(any(feature = "verification", kani))]
342pub use verification::mechanisms::{
343    AffirmReturnsBoolean, InputNonEmpty, MechanismWithType, NumericReturnsValid,
344    SurveyReturnsValidVariant, TextReturnsNonEmpty, TextReturnsString,
345};