rust-sdk/examples/servers
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Andrei G 81ff3159f9
feat: Add MCP Elicitation support (#332)
* 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.
2025-08-19 11:48:26 +08:00
..
src feat: Add MCP Elicitation support (#332) 2025-08-19 11:48:26 +08:00
templates chore: add oauth2 support (#130) 2025-04-29 17:52:59 +08:00
Cargo.toml feat: Add MCP Elicitation support (#332) 2025-08-19 11:48:26 +08:00
README.md feat: Add MCP Elicitation support (#332) 2025-08-19 11:48:26 +08:00

MCP Server Examples

This directory contains Model Context Protocol (MCP) server examples implemented in Rust. These examples demonstrate how to create MCP servers using different transport methods and how to implement various server capabilities including tools, resources, prompts, and authentication.

Example List

Counter Standard I/O Server (counter_stdio.rs)

A basic MCP server that communicates using standard input/output transport.

  • Provides a simple counter tool with increment, decrement, and get_value operations
  • Demonstrates basic tool implementation and stdio transport

Counter SSE Server (counter_sse.rs)

A server that provides counter functionality using Server-Sent Events (SSE) transport.

  • Runs on http://127.0.0.1:8000/sse by default
  • Provides the same counter tools as the stdio version
  • Demonstrates SSE transport setup with graceful shutdown
  • Can be accessed via web browsers or SSE-compatible clients

Counter SSE Direct Server (counter_sse_directly.rs)

A minimal SSE server implementation showing direct SSE server usage.

  • Simplified version of the SSE server
  • Demonstrates basic SSE server configuration
  • Provides counter functionality with minimal setup

Memory Standard I/O Server (memory_stdio.rs)

A minimal server example using stdio transport.

  • Lightweight server implementation
  • Demonstrates basic server setup patterns
  • Good starting point for custom server development

Counter Streamable HTTP Server (counter_streamhttp.rs)

A server using streamable HTTP transport for MCP communication, with axum.

  • Runs on HTTP with streaming capabilities
  • Provides counter tools via HTTP streaming
  • Demonstrates streamable HTTP transport configuration

Counter Streamable HTTP Server with Hyper (counter_hyper_streamable_http.rs)

A server using streamable HTTP transport for MCP communication, with hyper.

  • Runs on HTTP with streaming capabilities
  • Provides counter tools via HTTP streaming
  • Demonstrates streamable HTTP transport configuration

Complex OAuth SSE Server (complex_auth_sse.rs)

A comprehensive example demonstrating OAuth 2.0 integration with MCP servers.

  • Full OAuth 2.0 authorization server implementation
  • Client registration and token management
  • User authorization flow with web interface
  • Token validation middleware
  • Integrated with MCP SSE transport
  • Demonstrates enterprise-grade authentication patterns

Simple OAuth SSE Server (simple_auth_sse.rs)

A simplified OAuth example showing basic token-based authentication.

  • Basic token store and validation
  • Authorization middleware for SSE endpoints
  • Token generation API
  • Simplified authentication flow
  • Good starting point for adding authentication to MCP servers

Elicitation Demo (elicitation_stdio.rs)

A working MCP server demonstrating elicitation for user name collection.

  • Real MCP server using rmcp library
  • context.peer.elicit::<T>() API usage
  • Type-safe elicitation with elicit_safe! macro
  • JSON Schema validation with schemars
  • Tools: greet_user (collects name), reset_name (clears stored name)

How to Run

Each example can be run using Cargo:

# Run the counter standard I/O server
cargo run --example servers_counter_stdio

# Run the counter SSE server
cargo run --example servers_counter_sse

# Run the counter SSE direct server
cargo run --example servers_counter_sse_directly

# Run the memory standard I/O server
cargo run --example servers_memory_stdio

# Run the counter streamable HTTP server
cargo run --example servers_counter_streamhttp

# Run the complex OAuth SSE server
cargo run --example servers_complex_auth_sse

# Run the simple OAuth SSE server
cargo run --example servers_simple_auth_sse

# Run the elicitation standard I/O server
cargo run --example servers_elicitation_stdio

Testing with MCP Inspector

Many of these servers can be tested using the MCP Inspector tool: See inspector

Dependencies

These examples use the following main dependencies:

  • rmcp: Rust implementation of the MCP server library
  • tokio: Asynchronous runtime
  • serde and serde_json: For JSON serialization and deserialization
  • tracing and tracing-subscriber: For logging
  • anyhow: Error handling
  • axum: Web framework for HTTP-based transports
  • tokio-util: Utilities for async programming
  • askama: Template engine (used in OAuth examples)
  • tower-http: HTTP middleware (used for CORS in OAuth examples)
  • uuid: UUID generation (used in OAuth examples)
  • chrono: Date and time handling (used in OAuth examples)
  • rand: Random number generation (used in OAuth examples)
  • schemars: JSON Schema generation (used in elicitation examples)

Common Module

The common/ directory contains shared code used across examples:

  • counter.rs: Counter tool implementation with MCP server traits
  • calculator.rs: Calculator tool examples
  • generic_service.rs: Generic service implementations

This modular approach allows for code reuse and demonstrates how to structure larger MCP server applications.