* feat!: implement SEP-2663 Tasks extension, removing the experimental 2025-11-25 tasks design
Reshape tasks from the experimental SEP-1319/1686 core-protocol feature into
the official io.modelcontextprotocol/tasks extension (SEP-2663):
Model:
- Re-model Task (statusMessage, ttlMs nullable, pollIntervalMs) and add
DetailedTask with status-discriminated payloads (inputRequests/result/error
inlined per spec)
- CreateTaskResult now flattens Task with resultType: "task";
add ResultType::TASK and CallToolResponse::Task
- Add tasks/update (UpdateTaskParams with MRTR InputResponses); tasks/get and
tasks/cancel reworked; remove tasks/list, tasks/result
- notifications/tasks now carries a full DetailedTask; removed from client
notifications (SEP-2260)
Capabilities:
- Remove core TasksCapability et al; tasks are declared via the extensions
map (enable_tasks() builders, supports_tasks() accessors)
- Remove tool-level execution.taskSupport and the _meta.task /
TaskMetadata / with_task() opt-in: task creation is server-directed and
gated on the per-request client capability
Runtime:
- Replace OperationProcessor with TaskManager: durable-before-response task
creation, input_required round-trips via tasks/update, cooperative
cancellation, TTL expiry
- Client peer helpers get_task/update_task/cancel_task
- Emit Mcp-Name routing header from params.taskId for tasks/* methods
(SEP-2243/2663)
Macros:
- Remove #[task_handler] and the tool execution() attribute
Tests/examples/docs updated; schema snapshots regenerated.
BREAKING CHANGE: the 2025-11-25 experimental tasks API is removed without a
compatibility shim. Clients that do not declare the tasks extension always
receive synchronous results.
* feat: gate tasks/* methods on the client tasks-extension capability (SEP-2663)
When the server advertises io.modelcontextprotocol/tasks but the client did
not declare it (per-request _meta clientCapabilities, or initialize-time
capabilities in session mode), tasks/get, tasks/update, and tasks/cancel now
return -32021 Missing Required Client Capability with the required extension
in the error data, instead of falling through to the handler's -32601
default. Servers that do not advertise the extension keep returning -32601.
Also add regression tests confirming that unknown taskIds yield -32602 and
that a legacy 2025-11-25 'task' param on tools/call is silently ignored.
* feat: pass SEP-2663 Tasks extension conformance suite
Conformance fixtures (conformance/src/bin/server.rs):
- Add the required fixture tools: greet (sync-only), slow_compute,
failing_job (task support: required), protocol_error_job, confirm_delete,
multi_input, and test_tool_with_task (MRTR -> task escalation), all backed
by TaskManager with server-directed task creation gated on the client's
tasks-extension capability
- Advertise io.modelcontextprotocol/tasks in server capabilities and wire
get_task/update_task/cancel_task handlers
- Task-required tools reject with -32021 when the client did not declare the
extension
SDK wire-shape fixes surfaced by the suite:
- Add resultType: "complete" to GetTaskResult and introduce TaskAckResult
so tasks/update and tasks/cancel acks carry the SEP-2322 discriminator
(spec: every non-CreateTaskResult response on the tasks surface is
resultType complete); dispatch now returns ServerResult::task_ack
- CreateTaskResult gets a strict deserializer requiring resultType: "task"
so it does not shadow task-shaped results in untagged unions
- Client update_task/cancel_task accept both TaskAckResult and EmptyResult
All 9 runnable Tasks extension server scenarios now pass (35/35 checks;
tasks-status-notifications remains upstream-skipped), so the corresponding
entries are removed from conformance/expected-failures-extensions.yaml.
2025-11-25 server suite (40/40), 2026-07-28 server suite (114/114), draft
client suite, and extensions client suite all pass their baselines.
* fix: address PR 1020 review feedback on DetailedTask schema and cooperative cancel
- DetailedTask's JsonSchema now derives from the actual flattened wire shape
(DetailedTaskWire: base Task + optional inputRequests/result/error) instead
of approximating with the base Task schema, so generated schemas for
GetTaskResult and notifications/tasks document the status-specific payload
fields. Golden message schemas regenerated.
- TaskManager::cancel_task no longer aborts the underlying future. It records
the observable cancelled state and acks immediately (spec's eventually
consistent semantics), but lets the operation keep running so it can observe
is_cancel_requested() or the error from a woken request_input() and perform
cleanup; any late result is discarded. New unit tests cover both the
cooperative-cleanup path and waking parked input requests.
* fix: make tasks/cancel truly cooperative per SEP-2663 (FEEDBACK_2)
- TaskManager::cancel_task no longer forces terminal 'cancelled'. It records
the cancellation intent, acks immediately, and wakes parked request_input
awaits, but the operation decides its own terminal state: a post-cancel
error settles as 'cancelled', while an operation that finishes its work
settles as 'completed' — per the spec, 'the task may still reach a
non-cancelled terminal status'.
- Add TaskContext::cancelled(), a watch-based await for use with
tokio::select! as the cooperative cancellation exit path.
- Correct the unsupported-notification method string from
'notifications/tasks/status' to 'notifications/tasks' and document that
task status notifications are not yet routable through subscriptions/listen
(SubscriptionFilter has no taskIds field; upstream check still skipped).
- Update conformance slow_compute fixture, task_demo example, and tests to
honor cancellation via ctx.cancelled(); lifecycle conformance still 8/8
(all 9 scenarios remain green, 35/35 checks).
* fix: sweep and evict expired tasks from TaskManager (FEEDBACK_3)
TTL handling previously only ran from get_task and only flipped overdue
non-terminal tasks to 'failed', never removing entries — an unbounded leak
for long-lived servers, and it made ttl_ms: None = 'unlimited retention'
meaningless since everything was retained forever.
- Rename expire_overdue to sweep_expired and run it from every entry point
(spawn, get_task, update_task, cancel_task).
- Track terminal_at on each entry; terminal tasks are evicted after being
retained for one further ttl_ms window past their terminal transition, so
well-behaved pollers can observe the final state before late tasks/get
calls return -32602 (spec: servers may delete expired tasks at any time,
and returning task-not-found for purged tasks is compliant behavior).
- ttl_ms: None entries are never evicted (spec: unlimited retention);
document the retention model on TaskManager, including that there is no
background sweeper.
- New tests: retention-window eviction, sweep of abandoned tasks via other
entry points, unlimited-TTL retention, and error-code assertions
(-32602) for unknown ids across get/update/cancel.
Reviewed the second feedback item (dedicated task-not-found error code)
against SEP-2663 §Protocol Errors and it is incorrect: the SEP explicitly
specifies -32602 (Invalid params) for invalid or nonexistent taskIds, which
is what unknown_task already returns. Kept -32602; strengthened tests to
assert the code.
* fix: address Copilot review feedback on PR #1020
- TaskManager: drop the JoinHandle as soon as the operation settles instead
of retaining it for the whole retention window, and only store it at spawn
time if the task is still non-terminal (avoids keeping a completed handle
that the completion path could never clear).
- Use RequestContext::client_capabilities() (which applies the initialize-time
fallback for session peers) instead of raw context.meta.client_capabilities()
in the task_demo example, the README snippet, and the test server — the
meta-only form would wrongly treat session-declared tasks clients as
unsupported.
All 9 Tasks extension conformance scenarios remain green (35/35 checks).
* fix: enforce SEP-2663 task-result gating in tools/call dispatch
A handler could return CallToolResponse::Task without checking whether the
request declared the io.modelcontextprotocol/tasks extension, sending a
CreateTaskResult to a client that cannot parse it. The SDK dispatch now
rejects that case with -32021 Missing Required Client Capability before the
response leaves the server, using RequestContext::client_capabilities()
(per-request _meta with initialize-time fallback).
Adds a regression test with a deliberately misbehaving handler that always
materializes a task; all Tasks extension conformance scenarios remain green
(35/35 checks).
* fix: align TTL boundary comparisons in sweep_expired
Copilot review: ttlMs: 0 never expired immediately because phase 1 used a
strict 'elapsed > ttl_ms' comparison, and phase 2 retained terminal tasks
at exactly the TTL boundary ('elapsed <= ttl_ms'). Treat elapsed >= ttl_ms
as expired in phase 1 and evict when elapsed >= ttl_ms in phase 2, so both
phases agree at the boundary and ttlMs: 0 expires/evicts on the first sweep.
* fix: strict TaskAckResult deserializer and TASK_REQUIRED_TOOLS consistency
- TaskAckResult carried only resultType (+ optional _meta) with a derived
Deserialize, so inside the untagged ServerResult union it greedily matched
any result object containing a resultType key, shadowing CustomResult and
losing data (verified with a probe). Replace with a strict deserializer:
deny_unknown_fields and require resultType == "complete". Regression
tests cover both the non-matching shapes and the genuine ack shape.
- Conformance fixtures: confirm_delete and multi_input rejected non-tasks
clients inline, contradicting the TASK_REQUIRED_TOOLS doc/constant. Move
them into TASK_REQUIRED_TOOLS (they park on in-task elicitation and have
no synchronous fallback) so the upfront -32021 gate is the single source
of truth, and drop the now-unreachable inline checks.
All 9 Tasks extension conformance scenarios remain green (35/35 checks).
* fix: let the operation decide its terminal state via TaskExit
After tasks/cancel, any operation error was coerced to terminal
'cancelled', masking real failures (e.g. an unrelated error landing just
after a late cancel request) and contradicting the documented 'operation
decides its own terminal state' contract.
Change TaskFuture's error type from McpError to a new TaskExit enum:
- TaskExit::Cancelled — an explicit cooperative-cancellation exit;
settles as terminal 'cancelled'.
- TaskExit::Error(McpError) — a real failure; settles as terminal
'failed' with the error inlined, even after tasks/cancel was received.
From<McpError> for TaskExit keeps '?' ergonomic in task bodies, and
request_input() now returns TaskExit directly (its wake-on-cancel path
yields TaskExit::Cancelled), so parked operations that propagate it with
'?' settle as 'cancelled' automatically.
Update the conformance fixtures, task_demo example, and tests; add a
regression test asserting a post-cancel unrelated error settles as
'failed' with its error payload preserved.
All 9 Tasks extension conformance scenarios remain green (35/35 checks).
* fix: allow TaskExit enum to be exhaustive
* fix: close spawn/shutdown race, sweep in running_task_count, clarify TTL retention docs
Addresses branch-review findings:
- spawn() raced with shutdown(): if shutdown drained the task map between
the entry insert and the JoinHandle store, the handle was dropped and the
operation kept running detached. If the entry is gone at store time, the
handle is now aborted instead.
- running_task_count() now runs the TTL sweep like every other entry point,
so it no longer reports overdue tasks as running (matching the documented
sweep-on-every-entry-point behavior). Regression test added.
- Document that terminal-task retention intentionally extends one ttl_ms
window past the terminal transition (observation grace period) beyond the
creation-based lifetime ttlMs advertises on the wire — compliant since
SEP-2663 allows deleting expired tasks at any time after the TTL.
Re-applies #919 (reverted by #932): ToolResultContent.structured_content
becomes Option<Value> so non-object structured content is accepted,
matching CallToolResult and SEP-2106.
BREAKING CHANGE: ToolResultContent.structured_content changes from
Option<JsonObject> to Option<Value>.
The spec's prompt-message ContentBlock union is
`text | image | audio | resource_link | resource`, but
PromptMessageContent omitted `Audio`. Because the enum is
`#[serde(tag = "type")]` with no catch-all, a spec-conformant
`{"type":"audio",...}` content block failed to deserialize with
"unknown variant `audio`", breaking prompts/get for any server that
returns audio prompt content (the audio analogue of #842 / #843).
The supporting AudioContent type already existed, and Audio was
already a variant of the general RawContent enum (tool results,
sampling) -- only PromptMessageContent lacked it.
Add the flattened Audio variant (mirroring Image), a
PromptMessage::new_audio constructor (mirroring new_image), and
serialization + deserialization regression tests.
Fixes#864.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(elicitation): preserve enumNames through ElicitationSchema serde round-trip
UntitledSingleSelectEnumSchema lacked deny_unknown_fields, so a legacy
enum payload containing enumNames was silently matched by that variant
(ignoring the field) rather than falling through to LegacyEnumSchema.
The enumNames array was lost on re-serialization.
Add deny_unknown_fields to UntitledSingleSelectEnumSchema so that any
unknown field (including enumNames) causes serde to try the next
untagged variant, reaching LegacyEnumSchema correctly.
Also add skip_serializing_if = "Option::is_none" to
LegacyEnumSchema::enum_names so that an untitled legacy enum without
enumNames does not serialize "enumNames": null.
Fixes#903
* test(elicitation): regenerate server schema snapshot for deny_unknown_fields
deny_unknown_fields on UntitledSingleSelectEnumSchema makes schemars
emit additionalProperties: false for that definition. Regenerate the
golden schema fixtures to match (UPDATE_SCHEMA=1 cargo test -p rmcp
--test test_message_schema --all-features).
SEP-2577 deprecates the Roots, Sampling, and Logging features. The
deprecation is advisory: the features stay fully functional and there is
no wire-level change. Mark the corresponding Rust APIs as deprecated so
downstream users get compiler warnings and migration guidance.
- Forward attributes through the service `method!` macros and deprecate
`Peer::create_message`, `Peer::list_roots`, `Peer::set_level`, and
`Peer::notify_logging_message`.
- Forward per-field attributes through the capability `builder!` macro and
deprecate the generated `enable_roots`, `enable_sampling`, and
`enable_logging` builders, plus the hand-written
`enable_roots_list_changed`, `enable_sampling_tools`, and
`enable_sampling_context`.
- Document the deprecation on the capability types and fields, and in the
README feature sections.
- Allow `deprecated` at the crate's own call sites so the build stays
warning-clean, and refresh the message schema snapshots.
The Resource variant of PromptMessageContent was missing #[serde(flatten)],
causing the embedded resource content block to serialize as a double-nested
shape `{ "type": "resource", "resource": { "resource": {...} } }` instead of
the spec-compliant flat shape `{ "type": "resource", "resource": {uri, mimeType, text} }`.
This caused Zod-based MCP clients (e.g. Claude Code) to reject prompts/get
responses containing embedded resource messages with InvalidUnion errors.
The Image and ResourceLink variants already use #[serde(flatten)] correctly;
only Resource was missing it.
Fix: add #[serde(flatten)] so EmbeddedResource (=Annotated<RawEmbeddedResource>)
fields _meta / annotations / resource are flattened to the content-block level,
matching the MCP spec for prompts embedded resources.
Regression test: test_prompt_message_resource_serialization_is_flat verifies
content.resource.uri is reachable and content.resource.resource is absent.
Schema snapshots regenerated via UPDATE_SCHEMA=1.
* feat: add theme field to Icon
* fix: update IconThem crates/rmcp/src/model.rs (non_exhaustive)
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
* fix: update IconThem crates/rmcp/src/model.rs (eq, hash)
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
* fix: update docs with full descriptions of theme from mcp spec
---------
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
Add support for MCP extension capabilities in both ClientCapabilities
and ServerCapabilities structs, as specified in SEP-1724.
Changes:
- Add ExtensionCapabilities type alias (BTreeMap<String, JsonObject>)
- Add 'extensions' field to ClientCapabilities struct
- Add 'extensions' field to ServerCapabilities struct
- Update builder macros and impl blocks for both structs
- Add comprehensive tests for extension capabilities
- Update JSON schema test fixtures
This enables clients to advertise extension support during initialize,
such as:
{
"capabilities": {
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": ["text/html;profile=mcp-app"]
}
}
}
}
Closes#530
Move CustomRequest and CustomResult to end of their respective untagged
enums to ensure specific task variants match before catch-all custom types.
Add deny_unknown_fields to GetTaskInfoResult to prevent matching arbitrary
JSON objects.
Fixes issue where tasks/get, tasks/list, tasks/result, and tasks/cancel
incorrectly deserialized as CustomRequest instead of their typed variants.
* feat: implement SEP-1319 Decouple Request Payload from RPC Methods
* test: update tests
* fix: update handler trait methods to use new types
* fix: update examples
* fix: correct deprecation version
* fix: update wrapper macros to use new *Params type names
#580 and #556 introduced support for custom notifications,
so this PR takes the next logical step and adds support for custom requests:
- Introduces `CustomRequest` and `CustomResult` model types, wires them into the client/server
request and result unions, and allows `ClientRequest::method()` to return the dynamic method
name.
- Implements serde and meta handling for `CustomRequest` so `_meta` is carried through
extensions; adds default `on_custom_request` handlers that return `METHOD_NOT_FOUND` unless
overridden.
- Updates JSON schema fixtures to include the new request/result shapes and `EmptyObject`
strictness.
- Adds tests for custom request roundtrips and end-to-end client↔server handling.
- Focused integration test in `crates/rmcp/tests/test_custom_request.rs`.
For additional testing, I used this locally to update Codex to use a custom
request instead of a custom notification so that it gets an "ack" from the MCP
server to ensure it has processed the update before sending more messages:
https://github.com/openai/codex/pull/8142.
https://github.com/modelcontextprotocol/rust-sdk/pull/556 introduced support for
custom client notifications, so this PR makes the complementary change, adding
support for custom server notifications.
MCP clients, particularly ones that offer "experimental" capabilities,
may wish to handle custom server notifications that are not part of the
standard MCP specification. This change introduces a new
`CustomServerNotification` type that allows a client to process
such custom notifications.
- introduces `CustomServerNotification` to carry arbitrary methods/params while
still preserving meta/extensions; wires it into the `ServerNotification` union
and `serde` so `params` can be decoded with `params_as`
- allows client handlers to receive custom notifications via a new
`on_custom_notification` hook
- adds integration coverage that sends a custom server notification end-to-end
and asserts the client sees the method and payload
Test:
```shell
cargo test -p rmcp --features client test_custom_server_notification_reaches_client
```
MCP servers, particularly ones that offer "experimental" capabilities,
may wish to handle custom client notifications that are not part of the
standard MCP specification. This change introduces a new
`CustomClientNotification` type that allows a server to process
such custom notifications.
- introduces `CustomClientNotification` to carry arbitrary methods/params while
still preserving meta/extensions; wires it into the `ClientNotification` union
and `serde` so `params` can be decoded with `params_as`
- allows server handlers to receive custom notifications via a new
`on_custom_notification` hook
- adds integration coverage that sends a custom client notification end-to-end
and asserts the server sees the method and payload
Test:
```shell
cargo test -p rmcp --features client test_custom_client_notification_reaches_server
```
* feat: add type-safe elicitation schema support (#465)
Implement type-safe schema definitions for MCP elicitation requests,
replacing generic `JsonObject` with strongly-typed primitive schemas
per the [MCP 2025-06-18 specification](https://spec.modelcontextprotocol.io/specification/2025-06-18/server/elicitation/).
Features:
- Type-safe schema hierarchy (`StringSchema`, `NumberSchema`, `IntegerSchema`, `BooleanSchema`)
- Builder pattern with fluent API and 20+ convenience methods
- Build-time validation ensuring required fields exist in properties
- Private fields enforcing invariants through validated constructors
- Comprehensive validation support (range, length, format, enums)
- Typed property methods for cleaner schema construction
Benefits:
- Compile-time type safety prevents invalid schema construction
- 60-70% reduction in boilerplate through convenience methods
- Enforces MCP specification requirement for primitive-only properties
- Better IDE autocomplete and type inference
- Runtime validation catches schema errors early
Breaking changes:
- `CreateElicitationRequestParam.requested_schema` changed from `JsonObject` to `ElicitationSchema`
- `ElicitationSchemaBuilder::build()` now returns `Result` instead of direct value
Fixes#465
* fix: fix RMCP compliance
* feat: add conversion methods to ElicitationSchema
Add from_json_schema() and from_type() methods to ElicitationSchema
for easier type-to-schema conversion. This addresses feedback about
improving ergonomics when working with generated schemas.
Also make all struct fields public for better flexibility.
* chore: change `StringFormat` to enum
* feat: implement MCP completion specification 2025-06-18
Complete implementation of MCP completion specification with performance optimizations:
Core Features:
- Add CompletionContext for context-aware completion with previously resolved arguments
- Implement CompletionProvider trait with async support and dyn compatibility
- Create DefaultCompletionProvider with optimized fuzzy matching algorithm
- Add comprehensive validation and helper methods to CompletionInfo
- Update ServerHandler to handle completion/complete requests
- Add client convenience methods for prompt and resource completion
Performance Optimizations:
- Zero-allocation fuzzy matching using index-based scoring
- Top-k selection with select_nth_unstable instead of full sorting
- Pre-allocated vectors to avoid reallocations during matching
- Char-based case-insensitive matching to minimize string operations
- 5-8x performance improvement for large candidate sets
API Design:
- Context-aware completion supporting multi-argument scenarios
- Type-safe validation with MAX_VALUES limit (100 per MCP spec)
- Helper methods: with_all_values, with_pagination, validate
- Reference convenience methods: for_prompt, for_resource
- Client methods: complete_prompt_argument, complete_resource_argument
Testing:
- 17 comprehensive tests covering all functionality
- Schema compliance tests for MCP 2025-06-18 specification
- Performance tests with <100ms target for 1000 candidates
- Edge case and validation tests
Schema Updates:
- Add CompletionContext to JSON schema
- Update CompleteRequestParam with optional context field
- Maintain backward compatibility with existing API
* test: add comprehensive fuzzy matching tests for completion
Add three new test cases to enhance coverage of fuzzy matching algorithm:
- test_fuzzy_matching_with_typos_and_missing_chars: Tests subsequence matching
with real-world scenarios including abbreviated patterns, case-insensitive
matching, and complex file/package name completion
- test_fuzzy_matching_scoring_priority: Validates scoring system prioritizes
exact matches > prefix matches > substring matches > subsequence matches
- test_fuzzy_matching_edge_cases: Covers boundary conditions including
single character queries, oversized queries, and repeated characters
These tests ensure robust fuzzy search functionality for MCP completion
specification implementation with proper handling of user typos and
incomplete input patterns.
* feat: improve completion algorithms, add comprehensive tests and example
- Enhance fuzzy matching algorithm with acronym support for multi-word entries
- Add comprehensive scoring system for better relevance ranking
- Implement multi-level matching: exact, prefix, word prefix, acronym, substring
- Add context-aware completion scoring with proper priority ordering
- Optimize performance through efficient character-by-character matching
- Support case-insensitive acronym matching
- Improve code quality with clippy fixes and async fn syntax
- Add comprehensive test suite covering edge cases and acronym matching
- Create completion example server demonstrating weather-related prompts
* fix(test): typos
* refactor: improve completion API and replace example with SQL query builder
- Remove DefaultCompletionProvider from library core
- Move completion logic to examples following review feedback
- Update CompletionContext.argument_names() to return Iterator for better performance
- Replace tech search example with SQL query builder demonstrating progressive completion
- Add context-aware completion that adapts based on filled arguments
- Use proper Option types for optional SQL fields (columns, where_clause, values)
- Demonstrate real-world value of argument_names() method for dynamic completion flow
The SQL query builder showcases:
• Progressive field availability based on operation type
• Context validation using argument_names()
• Proper Optional field handling
• Smart completion that guides user through multi-step form
* fix: fmt
* feat: add _meta to content blocks and embedded resources; update schemas
* feat: set default protocol version; add _meta to content blocks/resources; update schemas
* chore: format content.rs via rustfmt
* chore(protocol): keep LATEST at 2025-03-26 per review until full 2025-06-18 compliance
* feat(prompt): add constructors with optional meta for image and resource
- Keep text helper; meta is currently ignored for text until schema supports it.
* refactor(prompt): simplify constructors so meta is optional; remove duplicate non-meta variants
* fix: modify code comment about version
* refactor(prompt): rename meta parameters in new_resource function for clarity
* feat(rmcp): support optional _meta on EmbeddedResource and ResourceContents
- Add optional _meta to RawEmbeddedResource and ResourceContents (text/blob)
- Update constructors/usages to set meta: None by default
- Add tests to lock behavior (embedded text/blob + CallToolResult)
- Update JSON Schemas to include optional _meta fields
* style(rmcp): rustfmt after _meta changes and tests
* feat: add resource_link support to tools and prompts
* chore: remove unused serde_json import from test_resource_link_integration.rs
* chore: remove unused serde_json import from test_resource_link.rs
* feat: implement MCP elicitation support for interactive user input
Adds comprehensive elicitation functionality according to MCP 2025-06-18 specification:
Core Features:
- ElicitationAction enum (Accept, Decline, Cancel)
- CreateElicitationRequestParam and CreateElicitationResult structures
- Protocol version V_2025_06_18 with elicitation methods
- Full JSON-RPC integration with method constants
Capabilities Integration:
- ElicitationCapability with schema validation support
- ClientCapabilities builder pattern integration
- enable_elicitation() and enable_elicitation_schema_validation() methods
Handler Support:
- create_elicitation method in ClientHandler and ServerHandler traits
- Integration with existing request/response union types
- Async/await compatible implementation
Service Layer:
- Basic create_elicitation method via macro expansion
- Four convenience methods for common scenarios:
* elicit_confirmation() - yes/no questions
* elicit_text_input() - string input with optional requirements
* elicit_choice() - selection from multiple options
* elicit_structured_input() - complex data via JSON Schema
Comprehensive Testing:
- 11 test cases covering all functionality aspects
- JSON serialization/deserialization validation
- MCP specification compliance verification
- Error handling and edge cases
- Performance benchmarks
- Capabilities integration tests
All tests pass and code follows project standards.
* feat: add typed elicitation API with enhanced error handling
- Add new 'elicitation' feature that depends on 'client' and 'schemars'
- Implement elicit<T>() method for type-safe elicitation with automatic schema generation
- Remove convenience methods (elicit_confirmation, elicit_text_input, elicit_choice)
- Add ElicitationError enum with detailed error variants:
- Service: underlying service errors
- UserDeclined: user cancelled or declined request
- ParseError: response parsing failed with context
- NoContent: no response content provided
- Update documentation with comprehensive examples and error handling
- Add comprehensive tests for typed elicitation and error handling
* fix: correct elicitation direction to comply with MCP 2025-06-18
- Remove CreateElicitationRequest from ClientRequest - clients cannot initiate elicitation
- Move elicit methods from client to server - servers now request user input
- Add comprehensive direction tests verifying Server→Client→Server flow
- Maintain CreateElicitationResult in ClientResult for proper responses
- Update handlers to reflect correct message routing
- Add elicitation feature flag for typed schema generation
Fixes elicitation direction to match specification where servers request
interactive user input from clients, not the reverse.
* feat: add elicitation capability checking for server methods
- Add supports_elicitation() method to check client capabilities
- Add CapabilityNotSupported error variant to ElicitationError
- Update elicit_structured_input() to check capabilities before execution
- Update elicit<T>() method to check capabilities before execution
- Add comprehensive tests for capability checking functionality
- Tests verify that servers check client capabilities before sending elicitation requests
- Ensures compliance with MCP 2025-06-18 specification requirement
* fix: json rpc message schema
* fix: doc tests
* fix: cargo nightly fmt checks
* fix: clippy
* refactor: separate elicitation methods into dedicated impl block for RoleServer
- Move (supports_elicitation, elicit_structured_input, elicit) to separate impl block
- Move ElicitationError definition to elicitation methods section
- Keep base methods (create_message, list_roots, notify_*) in main impl block with macro
- Add section comments to distinguish general and elicitation-specific methods
* revert: rollback LATEST protocol version to V_2025_03_26
* fix: remove protocol version assertions
- Remove assertions for V_2025_06_18 protocol version
* fix: fmt checks
* feat: add timeout support for elicitation methods
- Add peer_req_with_timeout macro variants for timeout-enabled methods
- Implement create_elicitation_with_timeout() method
- Implement elicit_with_timeout() for typed elicitation with timeout
- Refactor elicit() to use elicit_with_timeout() internally
- Add 8 comprehensive timeout tests covering validation, error handling, and realistic scenarios
- Fix elicitation feature dependencies in Cargo.toml
- Add proper feature gates for elicitation-specific code
* feat: add timeout validation to prevent DoS attacks
- Add InvalidTimeout error variant for comprehensive validation
- Implement validate_timeout function with security limits (1ms-300s)
- Integrate validation into peer_req_with_timeout macros
- Add comprehensive security tests for timeout validation
- Prevent DoS attacks through unreasonable timeout values
* feat: separate UserDeclined and UserCancelled elicitation errors
According to MCP specification and PR feedback, decline and cancel
actions should be handled differently:
- UserDeclined: explicit user rejection (clicked "Decline", "No", etc.)
- UserCancelled: dismissal without explicit choice (closed dialog, Escape, etc.)
Changes:
- Split ElicitationError::UserDeclined into two distinct error types
- Update error handling logic to map each ElicitationAction correctly
- Improve documentation with proper action semantics
- Add comprehensive tests for new error types and action mapping
- Update examples to demonstrate proper error handling
This provides better error granularity allowing servers to handle
explicit declines vs cancellations appropriately as per MCP spec.
* feat: add compile-time type safety for elicitation methods
Add ElicitationSafe trait and elicit_safe\! macro to ensure elicit<T>()
methods are only used with types that generate appropriate JSON object
schemas, addressing type safety concerns from PR feedback.
Features:
- ElicitationSafe marker trait for compile-time constraints
- elicit_safe\! macro for opt-in type safety declaration
- Updated elicit<T> and elicit_with_timeout<T> to require ElicitationSafe bound
- Comprehensive documentation with examples and rationale
- Full test coverage for new type safety features
This prevents common mistakes like:
- elicit::<String>() - primitives not suitable for object schemas
- elicit::<Vec<i32>>() - arrays don't match client expectations
Breaking change: Existing code must add elicit_safe\!(TypeName) declarations
for types used with elicit methods. This is an intentional safety improvement.
* Revert "feat: add timeout validation to prevent DoS attacks"
This reverts commit 829624212b4fb55ec32566329af7ec195c987ef5.
* fix: correct doctest example in elicit_safe macro documentation
- Remove invalid async/await usage in doctest example
- Comment out the actual usage line to show intent without compilation errors
- Maintain clear documentation of the macro's purpose and usage
* refactor: remove redundant elicitation direction tests
- Remove test_elicitation_not_in_client_request (duplicated functionality)
- Remove redundant ServerRequest match in test_elicitation_direction_server_to_client
- Direction compliance is already verified by the remaining comprehensive test
- Reduces test fragility and maintenance burden
* feat: add elicitation example with user name collection
- Add elicitation server example demonstrating real MCP usage
- Implement greet_user tool with context.peer.elicit::<T>() API
- Show type-safe elicitation with elicit_safe! macro
- Include reset_name tool and MCP Inspector instructions
- Update examples documentation and dependencies
* fix: add Default impl to ElicitationServer for clippy
Resolves clippy::new_without_default warning by implementing
Default trait for ElicitationServer struct.