|
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> |
4 | 4 |
|
5 | | -## Features |
| 5 | +<div class="rustdoc-hidden"> |
6 | 6 |
|
7 | | -This library primarily provides the following macros: |
| 7 | +# rmcp-macros |
8 | 8 |
|
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 | +[](https://crates.io/crates/rmcp-macros) |
| 10 | +[](https://docs.rs/rmcp-macros) |
13 | 11 |
|
14 | | -## Usage |
| 12 | +</div> |
15 | 13 |
|
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. |
17 | 15 |
|
18 | | -This macro is used to mark a function as a tool handler. |
| 16 | +## Available Macros |
19 | 17 |
|
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` | |
21 | 27 |
|
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 |
23 | 35 |
|
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 |
30 | 37 |
|
31 | | -#### Tool example |
| 38 | +```rust,ignore |
| 39 | +use rmcp::{tool, tool_router, tool_handler, ServerHandler, model::*}; |
32 | 40 |
|
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>, |
37 | 44 | } |
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. |
43 | 45 |
|
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 |
58 | 46 | #[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() |
70 | 51 | } |
71 | 52 | } |
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 |
117 | 53 |
|
118 | | -```rust |
119 | 54 | #[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() |
194 | 58 | } |
195 | | - |
196 | | - // get_task and cancel_task are generated in the same manner. |
197 | 59 | } |
198 | 60 | ``` |
199 | 61 |
|
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. |
206 | 63 |
|
207 | 64 | ## License |
208 | 65 |
|
|
0 commit comments