rust-sdk/examples/servers
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jean-Marc Le Roux fbc7ab70ca
feat: Add support for Tool.outputSchema and CallToolResult.structuredContent (#316)
* feat: add output_schema field to Tool struct

- Add optional output_schema field to Tool struct for defining tool
output structure
- Update Tool::new() to initialize output_schema as None

* feat: add structured_content field to CallToolResult

- Add optional structured_content field for JSON object results
- Make content field optional to support either structured or
unstructured results
- Add CallToolResult::structured() and structured_error() constructor
methods

* feat: implement validation for mutually exclusive content/structuredContent

- Add validate() method to ensure content and structured_content are
mutually exclusive
- Implement custom Deserialize to enforce validation during
deserialization
- Update documentation to clarify the mutual exclusivity requirement

* feat: add output_schema support to #[tool] macro

- Add output_schema field to ToolAttribute and ResolvedToolAttribute
structs
- Implement automatic output schema generation from return types
- Support explicit output_schema attribute for manual specification
- Generate schemas for Result<T, E> where T is not CallToolResult
- Update tool generation to include output_schema in Tool struct

* feat: implement IntoCallToolResult for structured content

- Add Structured<T> wrapper type for explicit structured content
- Implement IntoCallToolResult for Structured<T> with JSON serialization
- Add support for Result<Structured<T>, E> conversions
- Enable tools to return structured content through the trait system

* fix: update simple-chat-client example for optional content field

- Handle Option<Vec<Content>> in CallToolResult.content
- Add proper unwrapping for the optional content field
- Fix compilation error in chat.rs

* fix: update examples and tests for optional content field

- Add output_schema field to Tool initialization in sampling_stdio
example
- Update test_tool_macros tests to handle Option<Vec<Content>>
- Use as_ref() before calling first() on optional content field

* feat: implement basic schema validation in conversion logic

- Add validate_against_schema function for basic type validation
- Add note that full JSON Schema validation requires dedicated library
- Document that actual validation should happen in tool handler

* feat: add structured output support for tools

- Add output_schema field to Tool struct for defining output JSON schemas
- Add structured_content field to CallToolResult (mutually exclusive with content)
- Implement Structured<T> wrapper for type-safe structured outputs
- Update #[tool] macro to automatically generate output schemas from return types
- Add validation of structured outputs against their schemas
- Update all examples and tests for breaking change (CallToolResult.content now Option)
- Add comprehensive documentation and rustdoc
- Add structured_output example demonstrating the feature

BREAKING CHANGE: CallToolResult.content is now Option<Vec<Content>> instead of Vec<Content>

Closes #312

* fix: correct structured output doctest to use Parameters wrapper

The #[tool] macro requires Parameters<T> wrapper for tool inputs.
This fixes the pre-existing broken doctest in the structured output
documentation example.

* feat: replace Structured<T> with Json<T> for structured output

- Remove Structured<T> type definition and implementations
- Reuse existing Json<T> wrapper for structured content
- Update IntoCallToolResult implementations to use Json<T>
- Add JsonSchema implementation for Json<T> delegating to T
- Update all examples and tests to use Json<T> instead of Structured<T>
- Update documentation and exports

BREAKING CHANGE: Structured<T> has been replaced with Json<T>. Users must update their code to use Json<T> for structured tool outputs.

* feat: add output_schema() method to IntoCallToolResult trait

- Add output_schema() method with default None implementation
- Implement output_schema() for Json<T> to return cached schema
- Implement output_schema() for Result<Json<T>, E> delegating to Json<T>
- Enable trait-based schema generation for structured outputs

* feat: update macro to detect Json<T> wrapper for output schemas

- Add extract_json_inner_type() helper to detect Json<T> types
- Update schema generation to only occur for Json<T> wrapped types
- Remove generic Result<T, E> detection in favor of specific Json<T> detection
- Add comprehensive tests to verify schema generation behavior

* feat: add builder methods to Tool struct for setting schemas

- Add with_output_schema<T>() method to set output schema from type
- Add with_input_schema<T>() method to set input schema from type
- Both methods use cached_schema_for_type internally
- Add comprehensive tests for builder methods

* fix: address clippy warnings

- Add Default implementation for StructuredOutputServer
- Fix collapsible else-if in simple-chat-client
- No functional changes

* style: apply cargo fmt

Apply automatic formatting changes to:
- examples/simple-chat-client/src/chat.rs - fix line wrapping
- crates/rmcp-macros/src/tool.rs - format method chaining
- examples/servers/src/structured_output.rs - reorder imports and format function signatures

* chore: fix formatting

* chore: fix rustdoc redundant link warning

* refactor: validate_against_schema

* feat: enforce structured_content usage when output_schema is defined

This commit implements strict validation to ensure tools with output_schema
consistently use structured_content for both success and error responses.

Changes:
- Enhanced ToolRouter::call() validation to require structured_content when output_schema is present
- Added validation that tools with output_schema cannot use regular content field
- Added comprehensive tests covering the new strict validation behavior
- Created example demonstrating proper structured output usage
- Updated TODO.md to track validation improvements

This ensures consistent response format and better type safety for MCP clients.

* chore: remove TODO.md

* refactor: simplify output schema extraction logic in tool macro

- Extract complex nested logic into dedicated helper function
- Replace deeply nested if-else chains with functional approach
- Use early returns and ? operator for cleaner code flow
- Reduce 46 lines to 7 lines in main logic while improving readability

* chore: run cargo fmt

* fix: enforce structured_content usage when output_schema is defined

Structured content is returned as a JSON object in the structuredContent
field of a result.For backwards compatibility, a tool that returns
structured content SHOULD also return the serialized JSON in a
TextContent block.

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content

Tools may also provide an output schema for validation of structured
results. If an output schema is provided:

- Servers MUST provide structured results that conform to this schema.
- Clients SHOULD validate structured results against this schema.

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema

* chore: cargo fmt
2025-07-31 16:32:24 +08:00
..
src feat: Add support for Tool.outputSchema and CallToolResult.structuredContent (#316) 2025-07-31 16:32:24 +08:00
templates chore: add oauth2 support (#130) 2025-04-29 17:52:59 +08:00
Cargo.toml feat: Add support for Tool.outputSchema and CallToolResult.structuredContent (#316) 2025-07-31 16:32:24 +08:00
README.md refactor: provide http server as tower service (#228) 2025-05-28 19:21:40 +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

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

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)

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.