[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73307":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":24,"topics":25,"createdAt":9,"pushedAt":9,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":15,"starSnapshotCount":15,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},73307,"rust-sdk","modelcontextprotocol\u002Frust-sdk","modelcontextprotocol","The official Rust SDK for the Model Context Protocol",null,"Rust",3509,537,32,36,0,16,34,98,48,30.19,"Other",false,"main",true,[],"2026-06-12 02:03:11","\u003Cdiv align = \"right\">\n\u003Ca href=\"docs\u002Freadme\u002FREADME.zh-cn.md\">简体中文\u003C\u002Fa>\n\u003C\u002Fdiv>\n\n# RMCP\n[![Crates.io Version](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fv\u002Frmcp)](https:\u002F\u002Fcrates.io\u002Fcrates\u002Frmcp)\n[![docs.rs](https:\u002F\u002Fimg.shields.io\u002Fdocsrs\u002Frmcp)](https:\u002F\u002Fdocs.rs\u002Frmcp\u002Flatest\u002Frmcp)\n[![CI](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Frust-sdk\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Frust-sdk\u002Factions\u002Fworkflows\u002Fci.yml)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fl\u002Frmcp)](LICENSE)\n\nAn official Rust Model Context Protocol SDK implementation with tokio async runtime.\n\n> **Migrating to 1.x?** See the [migration guide](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Frust-sdk\u002Fdiscussions\u002F716) for breaking changes and upgrade instructions.\n\nThis repository contains the following crates:\n\n- [rmcp](crates\u002Frmcp): The core crate providing the RMCP protocol implementation - see [rmcp](crates\u002Frmcp\u002FREADME.md)\n- [rmcp-macros](crates\u002Frmcp-macros): A procedural macro crate for generating RMCP tool implementations - see [rmcp-macros](crates\u002Frmcp-macros\u002FREADME.md)\n\nFor the full MCP specification, see [modelcontextprotocol.io](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25).\n\n## Table of Contents\n\n- [Usage](#usage)\n- [Tools](#tools)\n- [Resources](#resources)\n- [Prompts](#prompts)\n- [Sampling](#sampling)\n- [Roots](#roots)\n- [Logging](#logging)\n- [Completions](#completions)\n- [Notifications](#notifications)\n- [Subscriptions](#subscriptions)\n- [Tasks](#tasks-long-running-tool-invocations)\n- [Examples](#examples)\n- [OAuth Support](#oauth-support)\n- [Related Resources](#related-resources)\n- [Related Projects](#related-projects)\n- [Development](#development)\n\n## Usage\n\n### Import the crate\n\n```toml\nrmcp = { version = \"0.16.0\", features = [\"server\"] }\n## or dev channel\nrmcp = { git = \"https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Frust-sdk\", branch = \"main\" }\n```\n### Third Dependencies\n\nBasic dependencies:\n- [tokio](https:\u002F\u002Fgithub.com\u002Ftokio-rs\u002Ftokio)\n- [serde](https:\u002F\u002Fgithub.com\u002Fserde-rs\u002Fserde)\nJson Schema generation (version 2020-12):\n- [schemars](https:\u002F\u002Fgithub.com\u002FGREsau\u002Fschemars)\n\n### Build a Client\n\n\u003Cdetails>\n\u003Csummary>Start a client\u003C\u002Fsummary>\n\n```rust, ignore\nuse rmcp::{ServiceExt, transport::{TokioChildProcess, ConfigureCommandExt}};\nuse tokio::process::Command;\n\n#[tokio::main]\nasync fn main() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n    let client = ().serve(TokioChildProcess::new(Command::new(\"npx\").configure(|cmd| {\n        cmd.arg(\"-y\").arg(\"@modelcontextprotocol\u002Fserver-everything\");\n    }))?).await?;\n    Ok(())\n}\n```\n\u003C\u002Fdetails>\n\n### Build a Server\n\n\u003Cdetails>\n\u003Csummary>Build a transport\u003C\u002Fsummary>\n\n```rust, ignore\nuse tokio::io::{stdin, stdout};\nlet transport = (stdin(), stdout());\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Build a service\u003C\u002Fsummary>\n\nYou can easily build a service by using [`ServerHandler`](crates\u002Frmcp\u002Fsrc\u002Fhandler\u002Fserver.rs) or [`ClientHandler`](crates\u002Frmcp\u002Fsrc\u002Fhandler\u002Fclient.rs).\n\n```rust, ignore\nlet service = common::counter::Counter::new();\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Start the server\u003C\u002Fsummary>\n\n```rust, ignore\n\u002F\u002F this call will finish the initialization process\nlet server = service.serve(transport).await?;\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Interact with the server\u003C\u002Fsummary>\n\nOnce the server is initialized, you can send requests or notifications:\n\n```rust, ignore\n\u002F\u002F request\nlet roots = server.list_roots().await?;\n\n\u002F\u002F or send notification\nserver.notify_cancelled(...).await?;\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Waiting for service shutdown\u003C\u002Fsummary>\n\n```rust, ignore\nlet quit_reason = server.waiting().await?;\n\u002F\u002F or cancel it\nlet quit_reason = server.cancel().await?;\n```\n\u003C\u002Fdetails>\n\n---\n\n## Tools\n\nTools let servers expose callable functions to clients. Each tool has a name, description, and a JSON Schema for its parameters. Clients discover tools via `list_tools` and invoke them via `call_tool`.\n\n**MCP Spec:** [Tools](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Ftools)\n\n### Server-side\n\nThe `#[tool]`, `#[tool_router]`, and `#[tool_handler]` macros handle all the wiring. For a tools-only server you can use `#[tool_router(server_handler)]` to skip the separate `ServerHandler` impl:\n\n```rust,ignore\nuse rmcp::{handler::server::wrapper::Parameters, schemars, tool, tool_router, ServiceExt, transport::stdio};\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct AddParams {\n    a: i32,\n    b: i32,\n}\n\n#[derive(Clone)]\nstruct Calculator;\n\n#[tool_router(server_handler)]\nimpl Calculator {\n    #[tool(description = \"Add two numbers\")]\n    fn add(&self, Parameters(AddParams { a, b }): Parameters\u003CAddParams>) -> String {\n        (a + b).to_string()\n    }\n}\n\n#[tokio::main]\nasync fn main() -> anyhow::Result\u003C()> {\n    let service = Calculator.serve(stdio()).await?;\n    service.waiting().await?;\n    Ok(())\n}\n```\n\nWhen you need custom server metadata or multiple capabilities (tools + prompts), use explicit `#[tool_handler]`:\n\n```rust,ignore\nuse rmcp::{handler::server::wrapper::Parameters, schemars, tool, tool_router, tool_handler, ServerHandler, ServiceExt};\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct AddParams {\n    a: i32,\n    b: i32,\n}\n\n#[derive(Clone)]\nstruct Calculator;\n\n#[tool_router]\nimpl Calculator {\n    #[tool(description = \"Add two numbers\")]\n    fn add(&self, Parameters(AddParams { a, b }): Parameters\u003CAddParams>) -> String {\n        (a + b).to_string()\n    }\n}\n\n#[tool_handler(name = \"calculator\", version = \"1.0.0\", instructions = \"A simple calculator\")]\nimpl ServerHandler for Calculator {}\n```\n\nSee [`crates\u002Frmcp-macros`](crates\u002Frmcp-macros\u002FREADME.md) for full macro documentation.\n\n### Client-side\n\n```rust,ignore\nuse rmcp::model::CallToolRequestParams;\n\n\u002F\u002F List all tools\nlet tools = client.list_all_tools().await?;\n\n\u002F\u002F Call a tool by name\nlet result = client.call_tool(CallToolRequestParams::new(\"add\")).await?;\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fcalculator.rs`](examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fcalculator.rs) (server), [`examples\u002Fservers\u002Fsrc\u002Fcalculator_stdio.rs`](examples\u002Fservers\u002Fsrc\u002Fcalculator_stdio.rs) (stdio runner)\n\n---\n\n## Resources\n\nResources let servers expose data (files, database records, API responses) that clients can read. Each resource is identified by a URI and returns content as text or binary (base64-encoded) data. Resource templates allow servers to declare URI patterns with dynamic parameters.\n\n**MCP Spec:** [Resources](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Fresources)\n\n### Server-side\n\nImplement `list_resources()`, `read_resource()`, and optionally `list_resource_templates()` on the `ServerHandler` trait. Enable the resources capability in `get_info()`.\n\n```rust\nuse rmcp::{\n    ErrorData as McpError, RoleServer, ServerHandler, ServiceExt,\n    model::*,\n    service::RequestContext,\n    transport::stdio,\n};\nuse serde_json::json;\n\n#[derive(Clone)]\nstruct MyServer;\n\nimpl ServerHandler for MyServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            capabilities: ServerCapabilities::builder()\n                .enable_resources()\n                .build(),\n            ..Default::default()\n        }\n    }\n\n    async fn list_resources(\n        &self,\n        _request: Option\u003CPaginatedRequestParams>,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003CListResourcesResult, McpError> {\n        Ok(ListResourcesResult {\n            resources: vec![\n                RawResource::new(\"file:\u002F\u002F\u002Fconfig.json\", \"config\").no_annotation(),\n                RawResource::new(\"memo:\u002F\u002Finsights\", \"insights\").no_annotation(),\n            ],\n            next_cursor: None,\n            meta: None,\n        })\n    }\n\n    async fn read_resource(\n        &self,\n        request: ReadResourceRequestParams,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003CReadResourceResult, McpError> {\n        match request.uri.as_str() {\n            \"file:\u002F\u002F\u002Fconfig.json\" => Ok(ReadResourceResult {\n                contents: vec![ResourceContents::text(r#\"{\"key\": \"value\"}\"#, &request.uri)],\n            }),\n            \"memo:\u002F\u002Finsights\" => Ok(ReadResourceResult {\n                contents: vec![ResourceContents::text(\"Analysis results...\", &request.uri)],\n            }),\n            _ => Err(McpError::resource_not_found(\n                \"resource_not_found\",\n                Some(json!({ \"uri\": request.uri })),\n            )),\n        }\n    }\n\n    async fn list_resource_templates(\n        &self,\n        _request: Option\u003CPaginatedRequestParams>,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003CListResourceTemplatesResult, McpError> {\n        Ok(ListResourceTemplatesResult {\n            resource_templates: vec![],\n            next_cursor: None,\n            meta: None,\n        })\n    }\n}\n```\n\n### Client-side\n\n```rust\nuse rmcp::model::{ReadResourceRequestParams};\n\n\u002F\u002F List all resources (handles pagination automatically)\nlet resources = client.list_all_resources().await?;\n\n\u002F\u002F Read a specific resource by URI\nlet result = client.read_resource(ReadResourceRequestParams {\n    meta: None,\n    uri: \"file:\u002F\u002F\u002Fconfig.json\".into(),\n}).await?;\n\n\u002F\u002F List resource templates\nlet templates = client.list_all_resource_templates().await?;\n```\n\n### Notifications\n\nServers can notify clients when the resource list changes or when a specific resource is updated:\n\n```rust\n\u002F\u002F Notify that the resource list has changed (clients should re-fetch)\ncontext.peer.notify_resource_list_changed().await?;\n\n\u002F\u002F Notify that a specific resource was updated\ncontext.peer.notify_resource_updated(ResourceUpdatedNotificationParam {\n    uri: \"file:\u002F\u002F\u002Fconfig.json\".into(),\n}).await?;\n```\n\nClients handle these via `ClientHandler`:\n\n```rust\nimpl ClientHandler for MyClient {\n    async fn on_resource_list_changed(\n        &self,\n        _context: NotificationContext\u003CRoleClient>,\n    ) {\n        \u002F\u002F Re-fetch the resource list\n    }\n\n    async fn on_resource_updated(\n        &self,\n        params: ResourceUpdatedNotificationParam,\n        _context: NotificationContext\u003CRoleClient>,\n    ) {\n        \u002F\u002F Re-read the updated resource at params.uri\n    }\n}\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fcounter.rs`](examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fcounter.rs) (server), [`examples\u002Fclients\u002Fsrc\u002Feverything_stdio.rs`](examples\u002Fclients\u002Fsrc\u002Feverything_stdio.rs) (client)\n\n---\n\n## Prompts\n\nPrompts are reusable message templates that servers expose to clients. They accept typed arguments and return conversation messages. The `#[prompt]` macro handles argument validation and routing automatically.\n\n**MCP Spec:** [Prompts](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Fprompts)\n\n### Server-side\n\nUse the `#[prompt_router]`, `#[prompt]`, and `#[prompt_handler]` macros to define prompts declaratively. Arguments are defined as structs deriving `JsonSchema`.\n\n```rust\nuse rmcp::{\n    ErrorData as McpError, RoleServer, ServerHandler, ServiceExt,\n    handler::server::{router::prompt::PromptRouter, wrapper::Parameters},\n    model::*,\n    prompt, prompt_handler, prompt_router,\n    schemars::JsonSchema,\n    service::RequestContext,\n    transport::stdio,\n};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Serialize, Deserialize, JsonSchema)]\npub struct CodeReviewArgs {\n    #[schemars(description = \"Programming language of the code\")]\n    pub language: String,\n    #[schemars(description = \"Focus areas for the review\")]\n    pub focus_areas: Option\u003CVec\u003CString>>,\n}\n\n#[derive(Clone)]\npub struct MyServer {\n    prompt_router: PromptRouter\u003CSelf>,\n}\n\n#[prompt_router]\nimpl MyServer {\n    fn new() -> Self {\n        Self { prompt_router: Self::prompt_router() }\n    }\n\n    \u002F\u002F\u002F Simple prompt without parameters\n    #[prompt(name = \"greeting\", description = \"A simple greeting\")]\n    async fn greeting(&self) -> Vec\u003CPromptMessage> {\n        vec![PromptMessage::new_text(\n            PromptMessageRole::User,\n            \"Hello! How can you help me today?\",\n        )]\n    }\n\n    \u002F\u002F\u002F Prompt with typed arguments\n    #[prompt(name = \"code_review\", description = \"Review code in a given language\")]\n    async fn code_review(\n        &self,\n        Parameters(args): Parameters\u003CCodeReviewArgs>,\n    ) -> Result\u003CGetPromptResult, McpError> {\n        let focus = args.focus_areas\n            .unwrap_or_else(|| vec![\"correctness\".into()]);\n\n        Ok(GetPromptResult {\n            description: Some(format!(\"Code review for {}\", args.language)),\n            messages: vec![\n                PromptMessage::new_text(\n                    PromptMessageRole::User,\n                    format!(\"Review my {} code. Focus on: {}\", args.language, focus.join(\", \")),\n                ),\n            ],\n        })\n    }\n}\n\n#[prompt_handler]\nimpl ServerHandler for MyServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            capabilities: ServerCapabilities::builder().enable_prompts().build(),\n            ..Default::default()\n        }\n    }\n}\n```\n\nPrompt functions support several return types:\n- `Vec\u003CPromptMessage>` -- simple message list\n- `GetPromptResult` -- messages with an optional description\n- `Result\u003CT, McpError>` -- either of the above, with error handling\n\n### Client-side\n\n```rust\nuse rmcp::model::GetPromptRequestParams;\n\n\u002F\u002F List all prompts\nlet prompts = client.list_all_prompts().await?;\n\n\u002F\u002F Get a prompt with arguments\nlet result = client.get_prompt(GetPromptRequestParams {\n    meta: None,\n    name: \"code_review\".into(),\n    arguments: Some(rmcp::object!({\n        \"language\": \"Rust\",\n        \"focus_areas\": [\"performance\", \"safety\"]\n    })),\n}).await?;\n```\n\n### Notifications\n\n```rust\n\u002F\u002F Server: notify that available prompts have changed\ncontext.peer.notify_prompt_list_changed().await?;\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fprompt_stdio.rs`](examples\u002Fservers\u002Fsrc\u002Fprompt_stdio.rs) (server), [`examples\u002Fclients\u002Fsrc\u002Feverything_stdio.rs`](examples\u002Fclients\u002Fsrc\u002Feverything_stdio.rs) (client)\n\n---\n\n## Sampling\n\nSampling flips the usual direction: the server asks the client to run an LLM completion. The server sends a `create_message` request, the client processes it through its LLM, and returns the result.\n\n**MCP Spec:** [Sampling](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fclient\u002Fsampling)\n\n### Server-side (requesting sampling)\n\nAccess the client's sampling capability through `context.peer.create_message()`:\n\n```rust\nuse rmcp::model::*;\n\n\u002F\u002F Inside a ServerHandler method (e.g., call_tool):\nlet response = context.peer.create_message(CreateMessageRequestParams {\n    meta: None,\n    task: None,\n    messages: vec![SamplingMessage::user_text(\"Explain this error: connection refused\")],\n    model_preferences: Some(ModelPreferences {\n        hints: Some(vec![ModelHint { name: Some(\"claude\".into()) }]),\n        cost_priority: Some(0.3),\n        speed_priority: Some(0.8),\n        intelligence_priority: Some(0.7),\n    }),\n    system_prompt: Some(\"You are a helpful assistant.\".into()),\n    include_context: Some(ContextInclusion::None),\n    temperature: Some(0.7),\n    max_tokens: 150,\n    stop_sequences: None,\n    metadata: None,\n    tools: None,\n    tool_choice: None,\n}).await?;\n\n\u002F\u002F Extract the response text\nlet text = response.message.content\n    .first()\n    .and_then(|c| c.as_text())\n    .map(|t| &t.text);\n```\n\n### Client-side (handling sampling)\n\nOn the client side, implement `ClientHandler::create_message()`. This is where you'd call your actual LLM:\n\n```rust\nuse rmcp::{ClientHandler, model::*, service::{RequestContext, RoleClient}};\n\n#[derive(Clone, Default)]\nstruct MyClient;\n\nimpl ClientHandler for MyClient {\n    async fn create_message(\n        &self,\n        params: CreateMessageRequestParams,\n        _context: RequestContext\u003CRoleClient>,\n    ) -> Result\u003CCreateMessageResult, ErrorData> {\n        \u002F\u002F Forward to your LLM, or return a mock response:\n        let response_text = call_your_llm(&params.messages).await;\n\n        Ok(CreateMessageResult {\n            message: SamplingMessage::assistant_text(response_text),\n            model: \"my-model\".into(),\n            stop_reason: Some(CreateMessageResult::STOP_REASON_END_TURN.into()),\n        })\n    }\n}\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fsampling_stdio.rs`](examples\u002Fservers\u002Fsrc\u002Fsampling_stdio.rs) (server), [`examples\u002Fclients\u002Fsrc\u002Fsampling_stdio.rs`](examples\u002Fclients\u002Fsrc\u002Fsampling_stdio.rs) (client)\n\n---\n\n## Roots\n\nRoots tell servers which directories or projects the client is working in. A root is a URI (typically `file:\u002F\u002F`) pointing to a workspace or repository. Servers can query roots to know where to look for files and how to scope their work.\n\n**MCP Spec:** [Roots](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fclient\u002Froots)\n\n### Server-side\n\nAsk the client for its root list, and handle change notifications:\n\n```rust\nuse rmcp::{ServerHandler, model::*, service::{NotificationContext, RoleServer}};\n\nimpl ServerHandler for MyServer {\n    \u002F\u002F Query the client for its roots\n    async fn call_tool(\n        &self,\n        request: CallToolRequestParams,\n        context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003CCallToolResult, ErrorData> {\n        let roots = context.peer.list_roots().await?;\n        \u002F\u002F Use roots.roots to understand workspace boundaries\n        \u002F\u002F ...\n    }\n\n    \u002F\u002F Called when the client's root list changes\n    async fn on_roots_list_changed(\n        &self,\n        _context: NotificationContext\u003CRoleServer>,\n    ) {\n        \u002F\u002F Re-fetch roots to stay current\n    }\n}\n```\n\n### Client-side\n\nClients declare roots capability and implement `list_roots()`:\n\n```rust\nuse rmcp::{ClientHandler, model::*};\n\nimpl ClientHandler for MyClient {\n    async fn list_roots(\n        &self,\n        _context: RequestContext\u003CRoleClient>,\n    ) -> Result\u003CListRootsResult, ErrorData> {\n        Ok(ListRootsResult {\n            roots: vec![\n                Root {\n                    uri: \"file:\u002F\u002F\u002Fhome\u002Fuser\u002Fproject\".into(),\n                    name: Some(\"My Project\".into()),\n                },\n            ],\n        })\n    }\n}\n```\n\nClients notify the server when roots change:\n\n```rust\n\u002F\u002F After adding or removing a workspace root:\nclient.notify_roots_list_changed().await?;\n```\n\n---\n\n## Logging\n\nServers can send structured log messages to clients. The client sets a minimum severity level, and the server sends messages through the peer notification interface.\n\n**MCP Spec:** [Logging](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Futilities\u002Flogging)\n\n### Server-side\n\nEnable the logging capability, handle level changes from the client, and send log messages via the peer:\n\n```rust\nuse rmcp::{ServerHandler, model::*, service::RequestContext};\n\nimpl ServerHandler for MyServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            capabilities: ServerCapabilities::builder()\n                .enable_logging()\n                .build(),\n            ..Default::default()\n        }\n    }\n\n    \u002F\u002F Client sets the minimum log level\n    async fn set_level(\n        &self,\n        request: SetLevelRequestParams,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003C(), ErrorData> {\n        \u002F\u002F Store request.level and filter future log messages accordingly\n        Ok(())\n    }\n}\n\n\u002F\u002F Send a log message from any handler with access to the peer:\ncontext.peer.notify_logging_message(LoggingMessageNotificationParam {\n    level: LoggingLevel::Info,\n    logger: Some(\"my-server\".into()),\n    data: serde_json::json!({\n        \"message\": \"Processing completed\",\n        \"items_processed\": 42\n    }),\n}).await?;\n```\n\nAvailable log levels (from least to most severe): `Debug`, `Info`, `Notice`, `Warning`, `Error`, `Critical`, `Alert`, `Emergency`.\n\n### Client-side\n\nClients handle incoming log messages via `ClientHandler`:\n\n```rust\nimpl ClientHandler for MyClient {\n    async fn on_logging_message(\n        &self,\n        params: LoggingMessageNotificationParam,\n        _context: NotificationContext\u003CRoleClient>,\n    ) {\n        println!(\"[{}] {}: {}\", params.level,\n            params.logger.unwrap_or_default(), params.data);\n    }\n}\n```\n\nClients can also set the server's log level:\n\n```rust\nclient.set_level(SetLevelRequestParams {\n    level: LoggingLevel::Warning,\n    meta: None,\n}).await?;\n```\n\n---\n\n## Completions\n\nCompletions give auto-completion suggestions for prompt or resource template arguments. As a user fills in arguments, the client can ask the server for suggestions based on what's already been entered.\n\n**MCP Spec:** [Completions](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Futilities\u002Fcompletion)\n\n### Server-side\n\nEnable the completions capability and implement the `complete()` handler. Use `request.context` to inspect previously filled arguments:\n\n```rust\nuse rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestContext, RoleServer};\n\nimpl ServerHandler for MyServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            capabilities: ServerCapabilities::builder()\n                .enable_completions()\n                .enable_prompts()\n                .build(),\n            ..Default::default()\n        }\n    }\n\n    async fn complete(\n        &self,\n        request: CompleteRequestParams,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003CCompleteResult, McpError> {\n        let values = match &request.r#ref {\n            Reference::Prompt(prompt_ref) if prompt_ref.name == \"sql_query\" => {\n                match request.argument.name.as_str() {\n                    \"operation\" => vec![\"SELECT\", \"INSERT\", \"UPDATE\", \"DELETE\"],\n                    \"table\" => vec![\"users\", \"orders\", \"products\"],\n                    \"columns\" => {\n                        \u002F\u002F Adapt suggestions based on previously filled arguments\n                        if let Some(ctx) = &request.context {\n                            if let Some(op) = ctx.get_argument(\"operation\") {\n                                match op.to_uppercase().as_str() {\n                                    \"SELECT\" | \"UPDATE\" => {\n                                        vec![\"id\", \"name\", \"email\", \"created_at\"]\n                                    }\n                                    _ => vec![],\n                                }\n                            } else { vec![] }\n                        } else { vec![] }\n                    }\n                    _ => vec![],\n                }\n            }\n            _ => vec![],\n        };\n\n        \u002F\u002F Filter by the user's partial input\n        let filtered: Vec\u003CString> = values.into_iter()\n            .map(String::from)\n            .filter(|v| v.to_lowercase().contains(&request.argument.value.to_lowercase()))\n            .collect();\n\n        Ok(CompleteResult {\n            completion: CompletionInfo {\n                values: filtered,\n                total: None,\n                has_more: Some(false),\n            },\n        })\n    }\n}\n```\n\n### Client-side\n\n```rust\nuse rmcp::model::*;\n\nlet result = client.complete(CompleteRequestParams {\n    meta: None,\n    r#ref: Reference::Prompt(PromptReference {\n        name: \"sql_query\".into(),\n    }),\n    argument: ArgumentInfo {\n        name: \"operation\".into(),\n        value: \"SEL\".into(),\n    },\n    context: None,\n}).await?;\n\n\u002F\u002F result.completion.values contains suggestions like [\"SELECT\"]\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fcompletion_stdio.rs`](examples\u002Fservers\u002Fsrc\u002Fcompletion_stdio.rs)\n\n---\n\n## Notifications\n\nNotifications are fire-and-forget messages -- no response is expected. They cover progress updates, cancellation, and lifecycle events. Both sides can send and receive them.\n\n**MCP Spec:** [Notifications](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fbasic\u002Fnotifications)\n\n### Progress notifications\n\nServers can report progress during long-running operations:\n\n```rust\nuse rmcp::model::*;\n\n\u002F\u002F Inside a tool handler:\nfor i in 0..total_items {\n    process_item(i).await;\n\n    context.peer.notify_progress(ProgressNotificationParam {\n        progress_token: ProgressToken(NumberOrString::Number(i as i64)),\n        progress: i as f64,\n        total: Some(total_items as f64),\n        message: Some(format!(\"Processing item {}\u002F{}\", i + 1, total_items)),\n    }).await?;\n}\n```\n\n### Cancellation\n\nEither side can cancel an in-progress request:\n\n```rust\n\u002F\u002F Send a cancellation\ncontext.peer.notify_cancelled(CancelledNotificationParam {\n    request_id: the_request_id,\n    reason: Some(\"User requested cancellation\".into()),\n}).await?;\n```\n\nHandle cancellation in `ServerHandler` or `ClientHandler`:\n\n```rust\nimpl ServerHandler for MyServer {\n    async fn on_cancelled(\n        &self,\n        params: CancelledNotificationParam,\n        _context: NotificationContext\u003CRoleServer>,\n    ) {\n        \u002F\u002F Abort work for params.request_id\n    }\n}\n```\n\n### Initialized notification\n\nClients send `initialized` after the handshake completes:\n\n```rust\n\u002F\u002F Sent automatically by rmcp during the serve() handshake.\n\u002F\u002F Servers handle it via:\nimpl ServerHandler for MyServer {\n    async fn on_initialized(\n        &self,\n        _context: NotificationContext\u003CRoleServer>,\n    ) {\n        \u002F\u002F Server is ready to receive requests\n    }\n}\n```\n\n### List-changed notifications\n\nWhen available tools, prompts, or resources change, tell the client:\n\n```rust\ncontext.peer.notify_tool_list_changed().await?;\ncontext.peer.notify_prompt_list_changed().await?;\ncontext.peer.notify_resource_list_changed().await?;\n```\n\n**Example:** [`examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fprogress_demo.rs`](examples\u002Fservers\u002Fsrc\u002Fcommon\u002Fprogress_demo.rs)\n\n---\n\n## Subscriptions\n\nClients can subscribe to specific resources. When a subscribed resource changes, the server sends a notification and the client can re-read it.\n\n**MCP Spec:** [Resources - Subscriptions](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fserver\u002Fresources#subscriptions)\n\n### Server-side\n\nEnable subscriptions in the resources capability and implement the `subscribe()` \u002F `unsubscribe()` handlers:\n\n```rust\nuse rmcp::{ErrorData as McpError, ServerHandler, model::*, service::RequestContext, RoleServer};\nuse std::sync::Arc;\nuse tokio::sync::Mutex;\nuse std::collections::HashSet;\n\n#[derive(Clone)]\nstruct MyServer {\n    subscriptions: Arc\u003CMutex\u003CHashSet\u003CString>>>,\n}\n\nimpl ServerHandler for MyServer {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            capabilities: ServerCapabilities::builder()\n                .enable_resources()\n                .enable_resources_subscribe()\n                .build(),\n            ..Default::default()\n        }\n    }\n\n    async fn subscribe(\n        &self,\n        request: SubscribeRequestParams,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003C(), McpError> {\n        self.subscriptions.lock().await.insert(request.uri);\n        Ok(())\n    }\n\n    async fn unsubscribe(\n        &self,\n        request: UnsubscribeRequestParams,\n        _context: RequestContext\u003CRoleServer>,\n    ) -> Result\u003C(), McpError> {\n        self.subscriptions.lock().await.remove(&request.uri);\n        Ok(())\n    }\n}\n```\n\nWhen a subscribed resource changes, notify the client:\n\n```rust\n\u002F\u002F Check if the resource has subscribers, then notify\ncontext.peer.notify_resource_updated(ResourceUpdatedNotificationParam {\n    uri: \"file:\u002F\u002F\u002Fconfig.json\".into(),\n}).await?;\n```\n\n### Client-side\n\n```rust\nuse rmcp::model::*;\n\n\u002F\u002F Subscribe to updates for a resource\nclient.subscribe(SubscribeRequestParams {\n    meta: None,\n    uri: \"file:\u002F\u002F\u002Fconfig.json\".into(),\n}).await?;\n\n\u002F\u002F Unsubscribe when no longer needed\nclient.unsubscribe(UnsubscribeRequestParams {\n    meta: None,\n    uri: \"file:\u002F\u002F\u002Fconfig.json\".into(),\n}).await?;\n```\n\nHandle update notifications in `ClientHandler`:\n\n```rust\nimpl ClientHandler for MyClient {\n    async fn on_resource_updated(\n        &self,\n        params: ResourceUpdatedNotificationParam,\n        _context: NotificationContext\u003CRoleClient>,\n    ) {\n        \u002F\u002F Re-read the resource at params.uri\n    }\n}\n```\n\n---\n\n## Tasks (long-running tool invocations)\n\n`rmcp` supports the [task-based tool invocation](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25\u002Fbasic\u002Futilities\u002Ftasks)\nflow defined in SEP-1319. Annotate a tool with `execution(task_support = \"required\" | \"optional\")`\nand add `#[task_handler]` to your `ServerHandler` impl — `enqueue_task`, `tasks\u002Flist`, `tasks\u002Fget`,\n`tasks\u002Fresult`, and `tasks\u002Fcancel` are generated for you on top of an `OperationProcessor`.\n\n```rust, ignore\n#[tool(\n    description = \"Sum two numbers after a 2-second delay\",\n    execution(task_support = \"required\")\n)]\nasync fn slow_sum(\u002F* ... *\u002F) -> Result\u003CCallToolResult, McpError> { \u002F* ... *\u002F }\n\n#[tool_handler]\n#[task_handler]\nimpl ServerHandler for TaskDemo {}\n```\n\nSee [`servers_task_stdio`](examples\u002Fservers\u002Fsrc\u002Ftask_stdio.rs) and the matching\n[`clients_task_stdio`](examples\u002Fclients\u002Fsrc\u002Ftask_stdio.rs) for a runnable end-to-end example.\n\n## Examples\n\nSee [examples](examples\u002FREADME.md).\n\n## OAuth Support\n\nSee [Oauth_support](docs\u002FOAUTH_SUPPORT.md) for details.\n\n## Related Resources\n\n- [MCP Specification](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-11-25)\n- [Schema](https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Fspecification\u002Fblob\u002Fmain\u002Fschema\u002F2025-11-25\u002Fschema.ts)\n\n## Related Projects\n\n### Extending `rmcp`\n\n- [rmcp-actix-web](https:\u002F\u002Fgitlab.com\u002Flx-industries\u002Frmcp-actix-web) - An `actix_web` backend for `rmcp`\n- [rmcp-openapi](https:\u002F\u002Fgitlab.com\u002Flx-industries\u002Frmcp-openapi) - Transform OpenAPI definition endpoints into MCP tools\n\n### Built with `rmcp`\n\n- [goose](https:\u002F\u002Fgithub.com\u002Fblock\u002Fgoose) - An open-source, extensible AI agent that goes beyond code suggestions\n- [apollo-mcp-server](https:\u002F\u002Fgithub.com\u002Fapollographql\u002Fapollo-mcp-server) - MCP server that connects AI agents to GraphQL APIs via Apollo GraphOS\n- [rustfs-mcp](https:\u002F\u002Fgithub.com\u002Frustfs\u002Frustfs\u002Ftree\u002Fmain\u002Fcrates\u002Fmcp) - High-performance MCP server providing S3-compatible object storage operations for AI\u002FLLM integration\n- [containerd-mcp-server](https:\u002F\u002Fgithub.com\u002Fjokemanfire\u002Fmcp-containerd) - A containerd-based MCP server implementation\n- [rmcp-openapi-server](https:\u002F\u002Fgitlab.com\u002Flx-industries\u002Frmcp-openapi\u002F-\u002Ftree\u002Fmain\u002Fcrates\u002Frmcp-openapi-server) - High-performance MCP server that exposes OpenAPI definition endpoints as MCP tools\n- [nvim-mcp](https:\u002F\u002Fgithub.com\u002Flinw1995\u002Fnvim-mcp) - A MCP server to interact with Neovim\n- [terminator](https:\u002F\u002Fgithub.com\u002Fmediar-ai\u002Fterminator) - AI-powered desktop automation MCP server with cross-platform support and >95% success rate\n- [stakpak-agent](https:\u002F\u002Fgithub.com\u002Fstakpak\u002Fagent) - Security-hardened terminal agent for DevOps with MCP over mTLS, streaming, secret tokenization, and async task management\n- [video-transcriber-mcp-rs](https:\u002F\u002Fgithub.com\u002Fnhatvu148\u002Fvideo-transcriber-mcp-rs) - High-performance MCP server for transcribing videos from 1000+ platforms using whisper.cpp\n- [NexusCore MCP](https:\u002F\u002Fgithub.com\u002Fsjkim1127\u002FNexuscore_MCP) - Advanced malware analysis & dynamic instrumentation MCP server with Frida integration and stealth unpacking capabilities\n- [spreadsheet-mcp](https:\u002F\u002Fgithub.com\u002FPSU3D0\u002Fspreadsheet-mcp) - Token-efficient MCP server for spreadsheet analysis with automatic region detection, recalculation, screenshot, and editing support for LLM agents\n- [hyper-mcp](https:\u002F\u002Fgithub.com\u002Fhyper-mcp-rs\u002Fhyper-mcp) - A fast, secure MCP server that extends its capabilities through WebAssembly (WASM) plugins\n- [rudof-mcp](https:\u002F\u002Fgithub.com\u002Frudof-project\u002Frudof\u002Ftree\u002Fmaster\u002Frudof_mcp) - RDF validation and data processing MCP server with ShEx\u002FSHACL validation, SPARQL queries, and format conversion. Supports stdio and streamable HTTP transports with full MCP capabilities (tools, prompts, resources, logging, completions, tasks)\n- [McpMux](https:\u002F\u002Fgithub.com\u002Fmcpmux\u002Fmcp-mux) - Desktop app to configure MCP servers once at McpMux, connect every AI client (Cursor, Claude Desktop, VS Code, Windsurf) through a single encrypted local gateway with Spaces for project organization, FeatureSets to switch toolsets per client, and a built-in server registry\n- [systemprompt-template](https:\u002F\u002Fgithub.com\u002Fsystempromptio\u002Fsystemprompt-template) - Single-binary Rust runtime providing MCP governance — authentication, authorisation, rate-limiting, audit trails, and cost tracking for AI agents. Self-hosted, air-gap capable, 3,300+ req\u002Fs with sub-5ms governance overhead\n\n\n## Development\n\n### Tips for Contributors\n\nSee [docs\u002FCONTRIBUTE.MD](docs\u002FCONTRIBUTE.MD) to get some tips for contributing.\n\n### Using Dev Container\n\nIf you want to use dev container, see [docs\u002FDEVCONTAINER.md](docs\u002FDEVCONTAINER.md) for instructions on using Dev Container for development.\n","RMCP 是一个官方的 Rust SDK，用于实现 Model Context Protocol。该项目利用 tokio 异步运行时提供了一套完整的协议实现工具，包括核心 crate `rmcp` 和用于生成 RMCP 工具实现的宏 crate `rmcp-macros`。它支持客户端和服务端的构建，并且具备如任务、通知、订阅等高级功能。适用于需要通过异步方式处理模型上下文数据交换的应用场景，特别是在机器学习或数据密集型应用中，能够有效提升系统的响应速度和资源利用率。",2,"2026-06-11 03:44:56","high_star"]