1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Crate-level rustdoc is sourced from pmcp-macros/README.md via include_str! so
// that docs.rs and GitHub render from a single authoritative source. Every
// `rust,no_run` code block inside the README is compiled as a doctest under
// `cargo test --doc -p pmcp-macros`, which catches API drift automatically
// (no more silent staleness in the README).
use TokenStream;
use ;
// Note on the missing `ReadmeDoctests` struct.
//
// The rustdoc book recommends this pattern for making README doctests
// executable under `cargo test --doc`:
//
// #[cfg(doctest)]
// #[doc = include_str!("../README.md")]
// pub struct ReadmeDoctests;
//
// That pattern does NOT compile in a `proc-macro = true` crate. rustc 1.94
// rejects it with:
// error: `proc-macro` crate types currently cannot export any items
// other than functions tagged with `#[proc_macro]`,
// `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
//
// Discovered during the Phase 66 POC gate. The crate-level
// `#![doc = include_str!("../README.md")]` attribute at the top of this file
// is sufficient on its own: the included file's `rust,no_run` code blocks
// are picked up as doctests attached to the crate root.
//
// This comment is intentionally preserved as a breadcrumb so future
// contributors do not re-introduce the struct expecting it to "make doctests
// work on proc-macro crates". It does not. The crate-level attribute does.
/// Defines an MCP tool with automatic schema generation and state injection.
///
/// Generates a struct implementing `ToolHandler` from an annotated standalone
/// async or sync function. Eliminates `Box::pin` boilerplate and provides
/// automatic input/output schema generation, `State<T>` injection, and MCP
/// annotation support.
///
/// # Attributes
///
/// - `description = "..."` — required. Human-readable description enforced at
/// compile time.
/// - `name = "..."` — optional. Overrides the tool name (defaults to the
/// function name).
/// - `annotations(...)` — optional. MCP standard annotations: `read_only`,
/// `destructive`, `idempotent`, `open_world`.
/// - `ui = "..."` — optional. Widget resource URI for MCP Apps integrations.
///
/// # Example
///
/// ```rust,no_run
/// use pmcp::mcp_tool;
/// use schemars::JsonSchema;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Debug, Deserialize, JsonSchema)]
/// struct AddArgs { a: f64, b: f64 }
///
/// #[derive(Debug, Serialize, JsonSchema)]
/// struct AddResult { sum: f64 }
///
/// #[mcp_tool(description = "Add two numbers")]
/// async fn add(args: AddArgs) -> pmcp::Result<AddResult> {
/// Ok(AddResult { sum: args.a + args.b })
/// }
///
/// // Register with: ServerBuilder::new().tool("add", add())
/// ```
///
/// See `examples/s23_mcp_tool_macro.rs` for a complete runnable demo covering
/// `State<T>` injection, sync tools, annotations, and impl-block registration.
/// Collects `#[mcp_tool]` and `#[mcp_prompt]` methods from an impl block and
/// generates handlers plus bulk registration.
///
/// Processes an impl block to find all methods annotated with `#[mcp_tool(...)]`
/// or `#[mcp_prompt(...)]`, generates per-method handler structs sharing an
/// `Arc<ServerType>` for `&self` access, and emits `impl McpServer for ServerType`
/// so `ServerBuilder::mcp_server(...)` can register everything at once.
///
/// # Example
///
/// ```rust,no_run
/// use pmcp::{mcp_server, mcp_tool};
/// use schemars::JsonSchema;
/// use serde::{Deserialize, Serialize};
///
/// struct Calculator;
///
/// #[derive(Debug, Deserialize, JsonSchema)]
/// struct AddArgs { a: f64, b: f64 }
///
/// #[derive(Debug, Serialize, JsonSchema)]
/// struct AddResult { sum: f64 }
///
/// #[mcp_server]
/// impl Calculator {
/// #[mcp_tool(description = "Add two numbers")]
/// async fn add(&self, args: AddArgs) -> pmcp::Result<AddResult> {
/// Ok(AddResult { sum: args.a + args.b })
/// }
/// }
///
/// // Register with: ServerBuilder::new().mcp_server(Calculator)
/// ```
///
/// See `examples/s23_mcp_tool_macro.rs` for a complete runnable demo.
/// Defines a prompt handler with automatic argument schema generation.
///
/// Generates a struct implementing `PromptHandler` from an annotated standalone
/// async or sync function. Eliminates the
/// `HashMap::get("x").ok_or()?.parse()?` boilerplate of hand-rolled prompt
/// handlers, derives argument schemas from `JsonSchema`, and supports
/// `State<T>` injection.
///
/// # Attributes
///
/// - `description = "..."` — required. Human-readable description enforced at
/// compile time.
/// - `name = "..."` — optional. Overrides the prompt name (defaults to the
/// function name).
///
/// # Example
///
/// ```rust,no_run
/// use pmcp::mcp_prompt;
/// use pmcp::types::{Content, GetPromptResult, PromptMessage};
/// use schemars::JsonSchema;
/// use serde::Deserialize;
///
/// #[derive(Debug, Deserialize, JsonSchema)]
/// struct ReviewArgs {
/// /// The programming language to review
/// language: String,
/// }
///
/// #[mcp_prompt(description = "Review code for quality issues")]
/// async fn code_review(args: ReviewArgs) -> pmcp::Result<GetPromptResult> {
/// Ok(GetPromptResult::new(
/// vec![PromptMessage::user(Content::text(format!(
/// "Review this {} code", args.language,
/// )))],
/// None,
/// ))
/// }
///
/// // Register with: ServerBuilder::new().prompt("code_review", code_review())
/// ```
///
/// See `examples/s24_mcp_prompt_macro.rs` for a complete runnable demo
/// covering `State<T>` injection and impl-block registration.
/// Defines a resource provider with automatic URI template matching.
///
/// Generates a struct implementing `DynamicResourceProvider` from an annotated
/// standalone async or sync function. Every `{variable_name}` placeholder inside
/// the `uri` template is extracted at request time and passed to the function as
/// a `String` parameter of the same name — no hand-rolled URI parsing required.
///
/// # Attributes
///
/// - `uri = "..."` — required. URI or URI template (for example
/// `"docs://{topic}"`).
/// - `description = "..."` — required. Human-readable description.
/// - `name = "..."` — optional. Overrides the resource name (defaults to the
/// function name).
/// - `mime_type = "..."` — optional. Defaults to `"text/plain"`.
///
/// # Example
///
/// ```rust,no_run
/// // Note: direct import until the `mcp_resource` re-export gap is closed.
/// use pmcp_macros::mcp_resource;
///
/// #[mcp_resource(uri = "docs://{topic}", description = "Documentation pages")]
/// async fn read_doc(topic: String) -> pmcp::Result<String> {
/// Ok(format!("# {topic}\n\nDocumentation content for `{topic}`."))
/// }
///
/// // Register with:
/// // ResourceCollection::new().add_dynamic_provider(Arc::new(read_doc()))
/// ```
///
/// See `examples/s23_mcp_tool_macro.rs` and `examples/s24_mcp_prompt_macro.rs`
/// for the related `#[mcp_tool]` / `#[mcp_prompt]` patterns; a complete runnable
/// resource demo is tracked for a future phase.