Skip to main content

component_shape_mcp_macros/
lib.rs

1use proc_macro::TokenStream;
2#[cfg(not(test))]
3use proc_macro_crate::{FoundCrate, crate_name};
4use quote::quote;
5use std::collections::BTreeMap;
6use syn::{
7    Attribute, Data, DeriveInput, Expr, Fields, GenericArgument, Ident, LitBool, LitStr, Path,
8    PathArguments, Type, ext::IdentExt as _, parse_macro_input, parse_quote, spanned::Spanned as _,
9};
10
11mod crate_paths;
12mod json_schema;
13mod options;
14mod tool_input;
15
16use crate_paths::*;
17use json_schema::*;
18use options::*;
19use tool_input::*;
20
21/// Derive JSON Schema metadata for structs, transparent newtypes, and
22/// fieldless enums used in MCP tool schemas.
23///
24/// Serde names follow its deserialize-facing field and variant rules. Explicit
25/// MCP names take precedence and are translated back during typed decoding.
26#[proc_macro_derive(McpJsonSchema, attributes(mcp, serde))]
27pub fn derive_mcp_json_schema(input: TokenStream) -> TokenStream {
28    let input = parse_macro_input!(input as DeriveInput);
29    match expand_mcp_json_schema(input) {
30        Ok(tokens) => tokens.into(),
31        Err(error) => error.to_compile_error().into(),
32    }
33}
34
35/// Derive a top-level MCP input schema and strict MCP argument decoding for a
36/// named tool input struct.
37///
38/// Serde names follow its deserialize-facing field rules. Explicit MCP names
39/// take precedence without changing Serde's field names.
40#[proc_macro_derive(McpToolInput, attributes(mcp, serde))]
41pub fn derive_mcp_tool_input(input: TokenStream) -> TokenStream {
42    let input = parse_macro_input!(input as DeriveInput);
43    match expand_mcp_tool_input(input) {
44        Ok(tokens) => tokens.into(),
45        Err(error) => error.to_compile_error().into(),
46    }
47}
48
49#[cfg(test)]
50mod tests;