feat(macros): auto-generate get_info and default router (#785)

* feat(macros): auto-generate get_info and default router

* docs: simplify examples and docs with new defaults

* feat(macros): add tool_router(server_handler) to elide separate #[tool_handler] impl

* docs: add Tools section to README and simplify calculator examples with server_handler
This commit is contained in:
Dale Seo 2026-04-08 15:06:26 -04:00 • committed by GitHub
commit be321a4abe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -22,6 +22,7 @@ For the full MCP specification, see [modelcontextprotocol.io](https://modelconte
## Table of Contents
- [Usage](#usage)
- [Tools](#tools)
- [Resources](#resources)
- [Prompts](#prompts)
- [Sampling](#sampling)
@ -129,6 +130,76 @@ let quit_reason = server.cancel().await?;
---
## Tools
Tools let servers expose callable functions to clients. Each tool has a name, description, and a JSON Schema for its parameters. Clients discover tools via `list_tools` and invoke them via `call_tool`.
**MCP Spec:** [Tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)
### Server-side
The `#[tool]`, `#[tool_router]`, and `#[tool_handler]` macros handle all the wiring. For a tools-only server you can use `#[tool_router(server_handler)]` to skip the separate `ServerHandler` impl:
```rust,ignore
use rmcp::{tool, tool_router, ServiceExt, transport::stdio};
#[derive(Clone)]
struct Calculator;
#[tool_router(server_handler)]
impl Calculator {
#[tool(description = "Add two numbers")]
fn add(&self, #[tool(param)] a: i32, #[tool(param)] b: i32) -> String {
(a + b).to_string()
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let service = Calculator.serve(stdio()).await?;
service.waiting().await?;
Ok(())
}
```
When you need custom server metadata or multiple capabilities (tools + prompts), use explicit `#[tool_handler]`:
```rust,ignore
use rmcp::{tool, tool_router, tool_handler, ServerHandler, ServiceExt};
#[derive(Clone)]
struct Calculator;
#[tool_router]
impl Calculator {
#[tool(description = "Add two numbers")]
fn add(&self, #[tool(param)] a: i32, #[tool(param)] b: i32) -> String {
(a + b).to_string()
}
}
#[tool_handler(name = "calculator", version = "1.0.0", instructions = "A simple calculator")]
impl ServerHandler for Calculator {}
```
See [`crates/rmcp-macros`](crates/rmcp-macros/README.md) for full macro documentation.
### Client-side
```rust,ignore
use rmcp::model::CallToolRequestParams;
// List all tools
let tools = client.list_all_tools().await?;
// Call a tool by name
let result = client.call_tool(CallToolRequestParams::new("add")).await?;
```
**Example:** [`examples/servers/src/common/calculator.rs`](examples/servers/src/common/calculator.rs) (server), [`examples/servers/src/calculator_stdio.rs`](examples/servers/src/calculator_stdio.rs) (stdio runner)
---
## Resources
Resources let servers expose data (files, database records, API responses) that clients can read. Each resource is identified by a URI and returns content as text or binary (base64-encoded) data. Resource templates allow servers to declare URI patterns with dynamic parameters.