Skip to content

Commit e623f2a

Browse files
docs: show README content on docs.rs (#583)
Use `#![doc = include_str!("../README.md")]` to display README as crate documentation on docs.rs for both `rmcp` and `rmcp-macros`. Changes to support this: - Fix code examples to compile as doc tests (`rust,no_run`) - Fix broken rustdoc links with explicit `crate::` paths - Add "Structured Output" section and examples link to rmcp README - Simplify rmcp-macros README to a summary table with doc links - Fix grammar throughout - Add CSS to hide GitHub badges when rendered as rustdoc 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent acc1f8b commit e623f2a

4 files changed

Lines changed: 138 additions & 362 deletions

File tree

crates/rmcp-macros/README.md

Lines changed: 40 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,65 @@
1-
# rmcp-macros
2-
3-
`rmcp-macros` is a procedural macro library for the Rust Model Context Protocol (RMCP) SDK, providing macros that facilitate the development of RMCP applications.
1+
<style>
2+
.rustdoc-hidden { display: none; }
3+
</style>
44

5-
## Features
5+
<div class="rustdoc-hidden">
66

7-
This library primarily provides the following macros:
7+
# rmcp-macros
88

9-
- `#[tool]`: Mark an async/sync function as an RMCP tool and generate metadata + schema glue
10-
- `#[tool_router]`: Collect all `#[tool]` functions in an impl block into a router value
11-
- `#[tool_handler]`: Implement the `call_tool` and `list_tools` entry points by delegating to a router expression
12-
- `#[task_handler]`: Wire up the task lifecycle (list/enqueue/get/cancel) on top of an `OperationProcessor`
9+
[![Crates.io](https://img.shields.io/crates/v/rmcp-macros.svg)](https://crates.io/crates/rmcp-macros)
10+
[![Documentation](https://docs.rs/rmcp-macros/badge.svg)](https://docs.rs/rmcp-macros)
1311

14-
## Usage
12+
</div>
1513

16-
### tool
14+
`rmcp-macros` is a procedural macro library for the Rust Model Context Protocol (RMCP) SDK, providing macros that facilitate the development of RMCP applications.
1715

18-
This macro is used to mark a function as a tool handler.
16+
## Available Macros
1917

20-
This will generate a function that return the attribute of this tool, with type `rmcp::model::Tool`.
18+
| Macro | Description |
19+
|-------|-------------|
20+
| [`#[tool]`][tool] | Mark a function as an MCP tool handler |
21+
| [`#[tool_router]`][tool_router] | Generate a tool router from an impl block |
22+
| [`#[tool_handler]`][tool_handler] | Generate `call_tool` and `list_tools` handler methods |
23+
| [`#[prompt]`][prompt] | Mark a function as an MCP prompt handler |
24+
| [`#[prompt_router]`][prompt_router] | Generate a prompt router from an impl block |
25+
| [`#[prompt_handler]`][prompt_handler] | Generate `get_prompt` and `list_prompts` handler methods |
26+
| [`#[task_handler]`][task_handler] | Wire up the task lifecycle on top of an `OperationProcessor` |
2127

22-
#### Tool attributes
28+
[tool]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.tool.html
29+
[tool_router]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.tool_router.html
30+
[tool_handler]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.tool_handler.html
31+
[prompt]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.prompt.html
32+
[prompt_router]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.prompt_router.html
33+
[prompt_handler]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.prompt_handler.html
34+
[task_handler]: https://docs.rs/rmcp-macros/latest/rmcp_macros/attr.task_handler.html
2335

24-
| field | type | usage |
25-
| :- | :- | :- |
26-
| `name` | `String` | The name of the tool. If not provided, it defaults to the function name. |
27-
| `description` | `String` | A description of the tool. The document of this function will be used. |
28-
| `input_schema` | `Expr` | A JSON Schema object defining the expected parameters for the tool. If not provide, if will use the json schema of its argument with type `Parameters<T>` |
29-
| `annotations` | `ToolAnnotationsAttribute` | Additional tool information. Defaults to `None`. |
36+
## Quick Example
3037

31-
#### Tool example
38+
```rust,ignore
39+
use rmcp::{tool, tool_router, tool_handler, ServerHandler, model::*};
3240
33-
```rust
34-
#[tool(name = "my_tool", description = "This is my tool", annotations(title = "我的工具", read_only_hint = true))]
35-
pub async fn my_tool(param: Parameters<MyToolParam>) {
36-
// handling tool request
41+
#[derive(Clone)]
42+
struct MyServer {
43+
tool_router: rmcp::handler::server::tool::ToolRouter<Self>,
3744
}
38-
```
39-
40-
### tool_router
41-
42-
This macro is used to generate a tool router based on functions marked with `#[rmcp::tool]` in an implementation block.
4345
44-
It creates a function that returns a `ToolRouter` instance.
45-
46-
In most case, you need to add a field for handler to store the router information and initialize it when creating handler, or store it with a static variable.
47-
48-
#### Router attributes
49-
50-
| field | type | usage |
51-
| :- | :- | :- |
52-
| `router` | `Ident` | The name of the router function to be generated. Defaults to `tool_router`. |
53-
| `vis` | `Visibility` | The visibility of the generated router function. Defaults to empty. |
54-
55-
#### Router example
56-
57-
```rust
5846
#[tool_router]
59-
impl MyToolHandler {
60-
#[tool]
61-
pub fn my_tool() {
62-
63-
}
64-
65-
pub fn new() -> Self {
66-
Self {
67-
// the default name of tool router will be `tool_router`
68-
tool_router: Self::tool_router(),
69-
}
47+
impl MyServer {
48+
#[tool(description = "Say hello")]
49+
async fn hello(&self) -> String {
50+
"Hello, world!".into()
7051
}
7152
}
72-
```
73-
74-
Or specify the visibility and router name, which would be helpful when you want to combine multiple routers into one:
75-
76-
```rust
77-
mod a {
78-
#[tool_router(router = tool_router_a, vis = "pub")]
79-
impl MyToolHandler {
80-
#[tool]
81-
fn my_tool_a() {
82-
83-
}
84-
}
85-
}
86-
87-
mod b {
88-
#[tool_router(router = tool_router_b, vis = "pub")]
89-
impl MyToolHandler {
90-
#[tool]
91-
fn my_tool_b() {
92-
93-
}
94-
}
95-
}
96-
97-
impl MyToolHandler {
98-
fn new() -> Self {
99-
Self {
100-
tool_router: self::tool_router_a() + self::tool_router_b(),
101-
}
102-
}
103-
}
104-
```
105-
106-
### tool_handler
107-
108-
This macro will generate the handler for `tool_call` and `list_tools` methods in the implementation block, by using an existing `ToolRouter` instance.
109-
110-
#### Handler attributes
111-
112-
| field | type | usage |
113-
| :- | :- | :- |
114-
| `router` | `Expr` | The expression to access the `ToolRouter` instance. Defaults to `self.tool_router`. |
115-
116-
#### Handler example
11753
118-
```rust
11954
#[tool_handler]
120-
impl ServerHandler for MyToolHandler {
121-
// ...implement other handler
122-
}
123-
```
124-
125-
or using a custom router expression:
126-
127-
```rust
128-
#[tool_handler(router = self.get_router().await)]
129-
impl ServerHandler for MyToolHandler {
130-
// ...implement other handler
131-
}
132-
```
133-
134-
#### Handler expansion
135-
136-
This macro will be expended to something like this:
137-
138-
```rust
139-
impl ServerHandler for MyToolHandler {
140-
async fn call_tool(
141-
&self,
142-
request: CallToolRequestParam,
143-
context: RequestContext<RoleServer>,
144-
) -> Result<CallToolResult, rmcp::ErrorData> {
145-
let tcc = ToolCallContext::new(self, request, context);
146-
self.tool_router.call(tcc).await
147-
}
148-
149-
async fn list_tools(
150-
&self,
151-
_request: Option<PaginatedRequestParam>,
152-
_context: RequestContext<RoleServer>,
153-
) -> Result<ListToolsResult, rmcp::ErrorData> {
154-
let items = self.tool_router.list_all();
155-
Ok(ListToolsResult::with_all_items(items))
156-
}
157-
}
158-
```
159-
160-
### task_handler
161-
162-
This macro wires the task lifecycle endpoints (`list_tasks`, `enqueue_task`, `get_task`, `cancel_task`) to an implementation of `OperationProcessor`. It keeps the handler lean by delegating scheduling, status tracking, and cancellation semantics to the processor.
163-
164-
#### Task handler attributes
165-
166-
| field | type | usage |
167-
| :- | :- | :- |
168-
| `processor` | `Expr` | Expression that yields an `Arc<dyn OperationProcessor>` (or compatible trait object). Defaults to `self.processor.clone()`. |
169-
170-
#### Task handler example
171-
172-
```rust
173-
#[derive(Clone)]
174-
pub struct TaskHandler {
175-
processor: Arc<dyn OperationProcessor<RoleServer> + Send + Sync>,
176-
}
177-
178-
#[task_handler(processor = self.processor.clone())]
179-
impl ServerHandler for TaskHandler {}
180-
```
181-
182-
#### Task handler expansion
183-
184-
At expansion time the macro implements the task-specific handler methods by forwarding to the processor expression, roughly equivalent to:
185-
186-
```rust
187-
impl ServerHandler for TaskHandler {
188-
async fn list_tasks(&self, request: TaskListRequest, ctx: RequestContext<RoleServer>) -> Result<TaskListResult, rmcp::ErrorData> {
189-
self.processor.list_tasks(request, ctx).await
190-
}
191-
192-
async fn enqueue_task(&self, request: TaskEnqueueRequest, ctx: RequestContext<RoleServer>) -> Result<TaskEnqueueResult, rmcp::ErrorData> {
193-
self.processor.enqueue_task(request, ctx).await
55+
impl ServerHandler for MyServer {
56+
fn get_info(&self) -> ServerInfo {
57+
ServerInfo::default()
19458
}
195-
196-
// get_task and cancel_task are generated in the same manner.
19759
}
19860
```
19961

200-
201-
## Advanced Features
202-
203-
- Support for custom tool names and descriptions
204-
- Automatic generation of tool descriptions from documentation comments
205-
- JSON Schema generation for tool parameters
62+
See the [full documentation](https://docs.rs/rmcp-macros) for detailed usage of each macro.
20663

20764
## License
20865

crates/rmcp-macros/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![doc = include_str!("../README.md")]
2+
13
#[allow(unused_imports)]
24
use proc_macro::TokenStream;
35

0 commit comments

Comments
 (0)