turbomcp-wasm-macros

Crates.ioturbomcp-wasm-macros
lib.rsturbomcp-wasm-macros
version3.0.0-beta.3
created_at2026-01-13 19:36:04.784079+00
updated_at2026-01-22 16:45:33.17585+00
descriptionProcedural macros for TurboMCP WASM servers - zero-boilerplate MCP server development
homepagehttps://turbomcp.org
repositoryhttps://github.com/anthropics/turbomcp
max_upload_size
id2041014
size28,919
Nick Paterno (nicholasjpaterno)

documentation

https://docs.rs/turbomcp-wasm-macros

README

turbomcp-wasm-macros

Zero-boilerplate procedural macros for building MCP servers in WASM environments like Cloudflare Workers, Deno Deploy, and other edge platforms.

Features

  • #[server] - Transform impl blocks into MCP servers
  • #[tool] - Mark methods as MCP tool handlers
  • #[resource] - Mark methods as MCP resource handlers
  • #[prompt] - Mark methods as MCP prompt handlers

Usage

Add turbomcp-wasm with the macros feature to your Cargo.toml:

[dependencies]
turbomcp-wasm = { version = "3.0", default-features = false, features = ["macros"] }
worker = "0.7"
serde = { version = "1.0", features = ["derive"] }
schemars = "1.0"

Then define your server:

use turbomcp_wasm::prelude::*;
use serde::Deserialize;

#[derive(Clone)]
struct MyServer {
    greeting: String,
}

#[derive(Deserialize, schemars::JsonSchema)]
struct GreetArgs {
    name: String,
}

#[server(name = "my-server", version = "1.0.0", description = "My MCP server")]
impl MyServer {
    #[tool("Greet someone by name")]
    async fn greet(&self, args: GreetArgs) -> String {
        format!("{}, {}!", self.greeting, args.name)
    }

    #[tool("Get server status")]
    async fn status(&self) -> String {
        "Server is running".to_string()
    }

    #[resource("config://app")]
    async fn config(&self, uri: String) -> ResourceResult {
        ResourceResult::text(&uri, r#"{"theme": "dark"}"#)
    }

    #[prompt("Default greeting")]
    async fn greeting_prompt(&self) -> PromptResult {
        PromptResult::user("Hello! How can I help?")
    }
}

// In your Cloudflare Worker handler:
#[event(fetch)]
async fn fetch(req: Request, _env: Env, _ctx: Context) -> Result<Response> {
    let server = MyServer { greeting: "Hello".into() };
    server.into_mcp_server().handle(req).await
}

Generated Methods

The #[server] macro generates the following methods on your struct:

  • into_mcp_server(self) -> McpServer - Convert to a fully-configured MCP server
  • server_info() -> (&'static str, &'static str) - Get (name, version) tuple
  • get_tools_metadata() -> Vec<(&'static str, &'static str)> - Get tool metadata
  • get_resources_metadata() -> Vec<(&'static str, &'static str)> - Get resource metadata
  • get_prompts_metadata() -> Vec<(&'static str, &'static str)> - Get prompt metadata

Attribute Syntax

#[server]

#[server(name = "my-server", version = "1.0.0", description = "Optional description")]
impl MyServer { ... }

#[tool]

#[tool("Description of the tool")]
async fn my_tool(&self, args: MyArgs) -> String { ... }

// Or without arguments
#[tool("Description")]
async fn no_args_tool(&self) -> String { ... }

#[resource]

#[resource("config://app")]
async fn config(&self, uri: String) -> ResourceResult { ... }

// With URI template
#[resource("file://{path}")]
async fn file(&self, uri: String) -> ResourceResult { ... }

#[prompt]

#[prompt("Description of the prompt")]
async fn my_prompt(&self) -> PromptResult { ... }

// With optional arguments
#[prompt("Prompt with args")]
async fn prompt_with_args(&self, args: Option<MyArgs>) -> PromptResult { ... }

Requirements

Your struct must implement Clone for the generated code to work, as handlers need to clone the server instance.

License

MIT

Commit count: 0

cargo fmt