rmcp_macros/
lib.rs

1#[allow(unused_imports)]
2use proc_macro::TokenStream;
3
4mod common;
5mod prompt;
6mod prompt_handler;
7mod prompt_router;
8mod tool;
9mod tool_handler;
10mod tool_router;
11/// # tool
12///
13/// This macro is used to mark a function as a tool handler.
14///
15/// This will generate a function that return the attribute of this tool, with type `rmcp::model::Tool`.
16///
17/// ## Usage
18///
19/// | field             | type                       | usage |
20/// | :-                | :-                         | :-    |
21/// | `name`            | `String`                   | The name of the tool. If not provided, it defaults to the function name. |
22/// | `description`     | `String`                   | A description of the tool. The document of this function will be used. |
23/// | `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>` |
24/// | `annotations`     | `ToolAnnotationsAttribute` | Additional tool information. Defaults to `None`. |
25///
26/// ## Example
27///
28/// ```rust,ignore
29/// #[tool(name = "my_tool", description = "This is my tool", annotations(title = "我的工具", read_only_hint = true))]
30/// pub async fn my_tool(param: Parameters<MyToolParam>) {
31///     // handling tool request
32/// }
33/// ```
34#[proc_macro_attribute]
35pub fn tool(attr: TokenStream, input: TokenStream) -> TokenStream {
36    tool::tool(attr.into(), input.into())
37        .unwrap_or_else(|err| err.to_compile_error())
38        .into()
39}
40
41/// # tool_router
42///
43/// This macro is used to generate a tool router based on functions marked with `#[rmcp::tool]` in an implementation block.
44///
45/// It creates a function that returns a `ToolRouter` instance.
46///
47/// 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.
48/// ## Usage
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/// ## Example
56///
57/// ```rust,ignore
58/// #[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///         }
70///     }
71/// }
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,ignore
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#[proc_macro_attribute]
106pub fn tool_router(attr: TokenStream, input: TokenStream) -> TokenStream {
107    tool_router::tool_router(attr.into(), input.into())
108        .unwrap_or_else(|err| err.to_compile_error())
109        .into()
110}
111
112/// # tool_handler
113///
114/// This macro will generate the handler for `tool_call` and `list_tools` methods in the implementation block, by using an existing `ToolRouter` instance.
115///
116/// ## Usage
117///
118/// | field     | type          | usage |
119/// | :-        | :-            | :-    |
120/// | `router`  | `Expr`        | The expression to access the `ToolRouter` instance. Defaults to `self.tool_router`. |
121/// ## Example
122/// ```rust,ignore
123/// #[tool_handler]
124/// impl ServerHandler for MyToolHandler {
125///     // ...implement other handler
126/// }
127/// ```
128///
129/// or using a custom router expression:
130/// ```rust,ignore
131/// #[tool_handler(router = self.get_router().await)]
132/// impl ServerHandler for MyToolHandler {
133///    // ...implement other handler
134/// }
135/// ```
136///
137/// ## Explain
138///
139/// This macro will be expended to something like this:
140/// ```rust,ignore
141/// impl ServerHandler for MyToolHandler {
142///        async fn call_tool(
143///         &self,
144///         request: CallToolRequestParam,
145///         context: RequestContext<RoleServer>,
146///     ) -> Result<CallToolResult, rmcp::ErrorData> {
147///         let tcc = ToolCallContext::new(self, request, context);
148///         self.tool_router.call(tcc).await
149///     }
150///
151///     async fn list_tools(
152///         &self,
153///         _request: Option<PaginatedRequestParam>,
154///         _context: RequestContext<RoleServer>,
155///     ) -> Result<ListToolsResult, rmcp::ErrorData> {
156///         let items = self.tool_router.list_all();
157///         Ok(ListToolsResult::with_all_items(items))
158///     }
159/// }
160/// ```
161#[proc_macro_attribute]
162pub fn tool_handler(attr: TokenStream, input: TokenStream) -> TokenStream {
163    tool_handler::tool_handler(attr.into(), input.into())
164        .unwrap_or_else(|err| err.to_compile_error())
165        .into()
166}
167
168/// # prompt
169///
170/// This macro is used to mark a function as a prompt handler.
171///
172/// This will generate a function that returns the attribute of this prompt, with type `rmcp::model::Prompt`.
173///
174/// ## Usage
175///
176/// | field             | type     | usage |
177/// | :-                | :-       | :-    |
178/// | `name`            | `String` | The name of the prompt. If not provided, it defaults to the function name. |
179/// | `description`     | `String` | A description of the prompt. The document of this function will be used if not provided. |
180/// | `arguments`       | `Expr`   | An expression that evaluates to `Option<Vec<PromptArgument>>` defining the prompt's arguments. If not provided, it will automatically generate arguments from the `Parameters<T>` type found in the function signature. |
181///
182/// ## Example
183///
184/// ```rust,ignore
185/// #[prompt(name = "code_review", description = "Reviews code for best practices")]
186/// pub async fn code_review_prompt(&self, Parameters(args): Parameters<CodeReviewArgs>) -> Result<Vec<PromptMessage>> {
187///     // Generate prompt messages based on arguments
188/// }
189/// ```
190#[proc_macro_attribute]
191pub fn prompt(attr: TokenStream, input: TokenStream) -> TokenStream {
192    prompt::prompt(attr.into(), input.into())
193        .unwrap_or_else(|err| err.to_compile_error())
194        .into()
195}
196
197/// # prompt_router
198///
199/// This macro generates a prompt router based on functions marked with `#[rmcp::prompt]` in an implementation block.
200///
201/// It creates a function that returns a `PromptRouter` instance.
202///
203/// ## Usage
204///
205/// | field     | type          | usage |
206/// | :-        | :-            | :-    |
207/// | `router`  | `Ident`       | The name of the router function to be generated. Defaults to `prompt_router`. |
208/// | `vis`     | `Visibility`  | The visibility of the generated router function. Defaults to empty. |
209///
210/// ## Example
211///
212/// ```rust,ignore
213/// #[prompt_router]
214/// impl MyPromptHandler {
215///     #[prompt]
216///     pub async fn greeting_prompt(&self, Parameters(args): Parameters<GreetingArgs>) -> Result<Vec<PromptMessage>, Error> {
217///         // Generate greeting prompt using args
218///     }
219///
220///     pub fn new() -> Self {
221///         Self {
222///             // the default name of prompt router will be `prompt_router`
223///             prompt_router: Self::prompt_router(),
224///         }
225///     }
226/// }
227/// ```
228#[proc_macro_attribute]
229pub fn prompt_router(attr: TokenStream, input: TokenStream) -> TokenStream {
230    prompt_router::prompt_router(attr.into(), input.into())
231        .unwrap_or_else(|err| err.to_compile_error())
232        .into()
233}
234
235/// # prompt_handler
236///
237/// This macro generates handler methods for `get_prompt` and `list_prompts` in the implementation block, using an existing `PromptRouter` instance.
238///
239/// ## Usage
240///
241/// | field     | type   | usage |
242/// | :-        | :-     | :-    |
243/// | `router`  | `Expr` | The expression to access the `PromptRouter` instance. Defaults to `self.prompt_router`. |
244///
245/// ## Example
246/// ```rust,ignore
247/// #[prompt_handler]
248/// impl ServerHandler for MyPromptHandler {
249///     // ...implement other handler methods
250/// }
251/// ```
252///
253/// or using a custom router expression:
254/// ```rust,ignore
255/// #[prompt_handler(router = self.get_prompt_router())]
256/// impl ServerHandler for MyPromptHandler {
257///    // ...implement other handler methods
258/// }
259/// ```
260#[proc_macro_attribute]
261pub fn prompt_handler(attr: TokenStream, input: TokenStream) -> TokenStream {
262    prompt_handler::prompt_handler(attr.into(), input.into())
263        .unwrap_or_else(|err| err.to_compile_error())
264        .into()
265}