Rust MCP Server Development Guide
Overview
Create MCP (Model Context Protocol) servers in Rust that enable LLMs to interact with external services through well-designed tools. Rust provides type safety, memory safety, and high performance for production-grade MCP servers.
Process
π High-Level Workflow
Creating a high-quality Rust MCP server involves four main phases:
Phase 1: Deep Research and Planning
1.1 Understand Modern MCP Design
API Coverage vs. Workflow Tools: Balance comprehensive API endpoint coverage with specialized workflow tools. Workflow tools can be more convenient for specific tasks, while comprehensive coverage gives agents flexibility to compose operations. When uncertain, prioritize comprehensive API coverage.
Tool Naming and Discoverability:
Clear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., github_create_issue, github_list_repos) and action-oriented naming.
Context Management: Agents benefit from concise tool descriptions and the ability to filter/paginate results. Design tools that return focused, relevant data.
Actionable Error Messages: Error messages should guide agents toward solutions with specific suggestions and next steps. Use Rust's type system and Result types to ensure comprehensive error handling.
1.2 Study MCP Protocol Documentation
Navigate the MCP specification:
Start with the sitemap to find relevant pages: https://modelcontextprotocol.io/sitemap.xml
Then fetch specific pages with .md suffix for markdown format (e.g., https://modelcontextprotocol.io/specification/draft.md).
Key pages to review:
- Specification overview and architecture
- Transport mechanisms (streamable HTTP, stdio)
- Tool, resource, and prompt definitions
1.3 Study Framework Documentation
Recommended stack:
- Language: Rust (type safety, memory safety, high performance, async/await support)
- SDK: rmcp (official Rust MCP SDK with tokio async runtime)
- Transport: stdio (standard input/output) - DEFAULT
- Use stdio for local development, testing, and simple integrations
- Only use HTTP (Streamable HTTP) when remote access or multi-client support is required
- See Transport Options for detailed comparison
Load framework documentation:
- MCP Best Practices: π View Best Practices - Core guidelines
- rmcp SDK: Use WebFetch to load
https://raw.githubusercontent.com/modelcontextprotocol/rust-sdk/main/README.md - β‘ Rust Implementation Guide - Rust patterns and examples
1.4 Plan Your Implementation
Understand the API: Review the service's API documentation to identify key endpoints, authentication requirements, and data models. Use web search and WebFetch as needed.
Tool Selection: Prioritize comprehensive API coverage. List endpoints to implement, starting with the most common operations.
Phase 2: Implementation
Important: Unless specifically required, implement your server with stdio transport (standard input/output). This is the default and recommended approach for:
- Local development and testing
- IDE integrations
- Desktop application integrations
- Command-line tools
Only use HTTP transport when you need remote access or multi-client support. See Advanced Features - HTTP Transport if needed.
2.1 Set Up Project Structure
See Rust-specific guide for project setup:
- β‘ Rust Implementation Guide - Project structure, Cargo.toml, dependencies
Basic project structure:
my-mcp-server/
βββ Cargo.toml
βββ src/
β βββ main.rs # Server entry point
β βββ lib.rs # Library root
β βββ server.rs # Server implementation
β βββ tools/ # Tool implementations
β β βββ mod.rs
β βββ error.rs # Error handling
βββ README.md
2.2 Implement Core Infrastructure
Create shared utilities:
- API client with authentication (using
reqwestorhyper) - Error handling with
thiserrororanyhow - Response formatting (JSON/Markdown)
- Pagination support
- Async/await with tokio runtime
2.3 Implement Tools
For each tool:
Input Schema:
- Use
serdefor serialization/deserialization - Use
schemarsfor JSON Schema generation - Include constraints and clear descriptions in doc comments
- Add examples in field documentation
Output Schema:
- Define output types with
serde::Serialize - Use structured data types for tool results
- Leverage Rust's type system for compile-time guarantees
Tool Description:
- Concise summary of functionality (use Rust doc comments)
- Parameter descriptions with doc attributes
- Return type schema
Implementation:
- Use
async fnfor I/O operations - Proper error handling with
Result<T, E> - Support pagination where applicable
- Return structured data with type safety
Tool Macros:
Use rmcp's #[tool] macro for automatic tool registration:
#[tool(description = "Create a new issue")]
async fn create_issue(
&self,
Parameters(params): Parameters<CreateIssueParams>
) -> Result<CallToolResult, McpError> {
// Implementation
}
Annotations:
readOnlyHint: true/false (for read-only operations)destructiveHint: true/false (for destructive operations)idempotentHint: true/false (for idempotent operations)openWorldHint: true/false (for open-world assumptions)
Phase 3: Review and Test
3.1 Code Quality
Review for:
- No duplicated code (DRY principle)
- Consistent error handling with Result types
- Full type coverage (no
anyequivalent) - Clear tool descriptions with doc comments
- Proper async/await usage
- Memory safety (leverage Rust's ownership system)
3.2 Build and Test
Rust:
- Run
cargo buildto verify compilation - Run
cargo testfor unit tests - Run
cargo clippyfor lints - Run
cargo fmtfor formatting - Test with MCP Inspector:
npx @modelcontextprotocol/inspector
See Rust-specific guide for detailed testing approaches and quality checklists.
Phase 4: Create Evaluations
After implementing your MCP server, create comprehensive evaluations to test its effectiveness.
Evaluation guidelines apply the same way as for other MCP implementations.
4.1 Understand Evaluation Purpose
Use evaluations to test whether LLMs can effectively use your MCP server to answer realistic, complex questions.
4.2 Create 10 Evaluation Questions
Follow the same evaluation process as documented in the main MCP builder guide.
Reference Files
π Documentation Library
Load these resources as needed during development:
Core MCP Documentation (Load First)
- MCP Protocol: Start with sitemap at
https://modelcontextprotocol.io/sitemap.xml, then fetch specific pages with.mdsuffix - π MCP Best Practices - Universal MCP guidelines
SDK Documentation (Load During Phase 1/2)
- rmcp SDK: Fetch from
https://raw.githubusercontent.com/modelcontextprotocol/rust-sdk/main/README.md - rmcp crates documentation: https://docs.rs/rmcp/latest/rmcp/
Language-Specific Implementation Guide (Load During Phase 2)
-
β‘ Rust Implementation Guide - Complete Rust/rmcp guide with:
- Server initialization patterns
- Serde model examples
- Tool registration with
#[tool]macro - Complete working examples
- Quality checklist
- Async/await patterns
- Error handling strategies
-
π§ rmcp-macros Guide - Comprehensive macro reference:
- Tool macros (#[tool], #[tool_router], #[tool_handler])
- Prompt macros (#[prompt], #[prompt_router], #[prompt_handler])
- Advanced patterns (combining routers, state management)
- Complete macro examples
- Best practices for macro usage
-
π Rust MCP Client Guide - Complete MCP client implementation:
- Client architecture and basic structure
- Transport options (stdio and HTTP)
- Basic operations (listing tools, calling tools, reading resources, getting prompts)
- Advanced features (sampling handlers, progress notifications, multiple client management)
- Error handling patterns
- Complete working examples
Example Code (Load as Reference)
- Server examples: examples/basic_server/, examples/macros_demo_server/, etc.
- Client examples: examples/client_demo/
- Reference:
reference/rust-sdk/examples/in your workspace
Key Differences from TypeScript/Python
Type Safety
- Rust's type system catches errors at compile time
- No runtime type errors for properly typed code
- Use
Result<T, E>for error handling (no exceptions)
Memory Safety
- Ownership and borrowing prevent memory bugs
- No garbage collection overhead
- Zero-cost abstractions
Performance
- Native compilation for optimal performance
- Async/await with tokio for high concurrency
- Minimal runtime overhead
Tooling
cargofor dependency management and buildsrustfmtfor automatic code formattingclippyfor lints and best practices- Strong LSP support in editors
Getting Started
- Load the Rust Implementation Guide
- Review the server examples:
- Basic Server (stdio) - Start here! Default stdio transport
- Macros Demo Server - Complete rmcp-macros showcase (tools + prompts)
- HTTP Server - For production/remote access (advanced)
- Elicitation Server - Interactive user input collection (advanced)
- Progress Server - Real-time progress updates (advanced)
- Sampling Server - LLM sampling capabilities (advanced)
- Review the client examples in Client Demo:
- Tool Client - Connecting to servers and calling tools
- Resource Reader - Reading server resources via HTTP
- Prompt Consumer - Retrieving and using prompts
- Study rmcp SDK documentation, rmcp-macros Guide, and Rust MCP Client Guide
- Follow the four-phase workflow above
- Test your server with MCP Inspector
Remember: Start with stdio transport unless you have a specific need for HTTP (remote access, multi-client support).
Additional Resources
- rmcp GitHub: https://github.com/modelcontextprotocol/rust-sdk
- rmcp crates.io: https://crates.io/crates/rmcp
- MCP Specification: https://modelcontextprotocol.io/
- Rust Book: https://doc.rust-lang.org/book/
- Tokio Guide: https://tokio.rs/tokio/tutorial