SkillAgentSearch skills...

rust-sdk

The official Rust SDK for the Model Context Protocol

Install / Use

claude mcp add modelcontextprotocol -- npx -y github:modelcontextprotocol/rust-sdk

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

80/100

Supported Platforms

Claude Code
Claude Desktop

Our assessment of rust-sdk

rust-sdk scores 80/100 on our quality scale, 3572nd of 4,617 Development & Engineering skills we index.

Its MCP Server is 66 KB long, well organised into 79 sections with 62 code examples: long enough that it reads more like full documentation than a focused instruction file, which agents can find harder to follow.

With 4,092 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
21/30
Structure
20/20
Description
8/15
Adoption
15/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated today, so rust-sdk is actively maintained.
  • Our last check on 2026-10-21 found the source still online.
  • No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
  • Its trust signals score 83/100, with 2 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.

AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.

rust-sdk compared with similar skills

All 4 of these similar skills score higher than rust-sdk; compare them before choosing.

SkillScoreStarsUpdatedFormat
rust-sdk (this skill)by modelcontextprotocol804.1ktodayMCP Server
taste-skillby Leonxlnx100110.6ktodayCLAUDE.md
Agent-Reachby Panniantong100109.2ktodayCLAUDE.md
headroomby headroomlabs-ai10078.9ktodayCLAUDE.md
ai-job-searchby ai-job-search-dev10069.8ktodayCLAUDE.md

Frequently asked questions

How do I install rust-sdk?
Run claude mcp add modelcontextprotocol -- npx -y github:modelcontextprotocol/rust-sdk. The install tabs above show the steps for each supported agent.
Which AI agents does rust-sdk work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is rust-sdk safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 83/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is rust-sdk still maintained?
The repository was last updated today, so rust-sdk is actively maintained.

RMCP

Crates.io Version docs.rs CI License

An official Rust Model Context Protocol SDK implementation with tokio async runtime.

Migrating to 3.x? See the migration guide for breaking changes and upgrade instructions.

This repository contains the following crates:

  • rmcp: The core crate providing the RMCP protocol implementation - see rmcp
  • rmcp-macros: A procedural macro crate for generating RMCP tool implementations - see rmcp-macros

This SDK implements the stable MCP 2026-07-28 specification while remaining fully compatible with the 2025-11-25 release and earlier versions. Features introduced in 2026-07-28 — server discovery & negotiation, transport-neutral subscriptions, long-running tasks, response caching, multi-round-trip requests, and standard HTTP routing headers — are documented below. For the full MCP specification, see modelcontextprotocol.io.

Table of Contents

Usage

Import the crate

Add the latest published version with cargo:

cargo add rmcp --features server

Or use the dev channel:

cargo add rmcp --features server --git https://github.com/modelcontextprotocol/rust-sdk --branch main

Third Dependencies

Basic dependencies:

Build a Client

<details> <summary>Start a client</summary>
use rmcp::{ServiceExt, transport::{TokioChildProcess, ConfigureCommandExt}};
use tokio::process::Command;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = ().serve(TokioChildProcess::new(Command::new("npx").configure(|cmd| {
        cmd.arg("-y").arg("@modelcontextprotocol/server-everything");
    }))?).await?;
    Ok(())
}
</details>

Client lifecycle modes

serve() uses the legacy MCP lifecycle: the client sends initialize, receives the negotiated server information, and then sends notifications/initialized. Use ClientServiceExt::serve_with_lifecycle to select another lifecycle explicitly:

use rmcp::{ClientLifecycleMode, ClientServiceExt, ProtocolVersion, model::ClientConfig};

// Start directly with server/discover and include client metadata on every request.
let client = ClientConfig::default()
    .serve_with_lifecycle(
        transport,
        ClientLifecycleMode::Discover {
            preferred_versions: vec![ProtocolVersion::V_2026_07_28],
        },
    )
    .await?;

// Or probe the discover lifecycle and fall back when a legacy server reports
// that server/discover is not implemented or does not respond within 10 seconds.
let client = ClientConfig::default()
    .serve_with_lifecycle(
        transport,
        ClientLifecycleMode::Auto {
            preferred_versions: vec![ProtocolVersion::V_2026_07_28],
            legacy_version: Some(ProtocolVersion::V_2025_11_25),
        },
    )
    .await?;

ClientLifecycleMode::Initialize is equivalent to the existing serve() behavior. Discover startup does not send notifications/initialized; discovery completes startup, and each subsequent request carries its protocol version, client information, and capabilities in _meta.

Build a Server

<details> <summary>Build a transport</summary>
use tokio::io::{stdin, stdout};
let transport = (stdin(), stdout());
</details> <details> <summary>Build a service</summary>

You can easily build a service by using ServerHandler or ClientHandler.

let service = common::counter::Counter::new();
</details> <details> <summary>Start the server</summary>
// this call will finish the initialization process
let server = service.serve(transport).await?;
</details> <details> <summary>Interact with the server</summary>

Once the server is initialized, you can send requests or notifications:

// request
let roots = server.list_roots().await?;

// or send notification
server.notify_cancelled(...).await?;
</details> <details> <summary>Waiting for service shutdown</summary>
let quit_reason = server.waiting().await?;
// or cancel it
let quit_reason = server.cancel().await?;
</details>

Tools

Tools 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.

MCP Spec: Tools

Server-side

The #[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:

use rmcp::{handler::server::wrapper::Parameters, schemars, tool, tool_router, ServiceExt, transport::stdio};

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct AddParams {
    a: i32,
    b: i32,
}

#[derive(Clone)]
struct Calculator;

#[tool_router(server_handler)]
impl Calculator {
    #[tool(description = "Add two numbers")]
    fn add(&self, Parameters(AddParams { a, b }): Parameters<AddParams>) -> String {
        (a + b).to_string()
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let service = Calculator.serve(stdio()).await?;
    service.waiting().await?;
    Ok(())
}

The generated tool inputSchema and outputSchema are derived from the fields of T. The type name and documentation on T are ignored; only field names, field types, and field documentation are used.

2026-07-28 (SEP-2106): outputSchema may now be any JSON Schema type (not just object), and a tool result's structuredContent may be any JSON value (string, array, number, …) rather than only an object. Existing object-typed tools are unaffected.

When you need custom server metadata or multiple capabilities (tools + prompts), use explicit #[tool_handler]:

use rmcp::{handler::server::wrapper::Parameters, schemars, tool, tool_router, tool_handler, ServerHandler, ServiceExt};

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct AddParams {
    a: i32,
    b: i32,
}

#[derive(Clone)]
struct Calculator;

#[tool_router]
impl Calculator {
    #[tool(description = "Add two numbers")]
    fn add(&self, Parameters(AddParams { a, b }): Parameters<AddParams>) -> String {
        (a + b).to_string()
    }
}

#[tool_handler(name = "calculator", version = "1.0.0", instructions = "A simple calculator")]
impl ServerHandler for Calculator {}

See crates/rmcp-macros for full macro documentation.

Tool result content types

Beyond a plain String, tools can return images, audio, embedded resources, and mixed content. Build a CallToolResult from a Vec<ContentBlock>:

use rmcp::model::{CallToolResult, ContentBlock, ResourceContents};

#[tool(description = "Render a chart")]
async fn chart(&self) -> Result<CallToolResult, McpError> {
    let png_base64 = render_png(); // base64-encoded image bytes
    let wav_base64 = render_wav(); // base64-encoded audio bytes

    Ok(CallToolResult::success(vec![
        // Text
        ContentBlock::text("Here is your chart:"),
        // Image — base64 data + MIME type
        ContentBlock::image(png_base64, "image/png"),
        // Audio — base64 data + MIME type
        ContentBlock::audio(wav_base64, "audio/wav"),
        // Embedded resource — inline text (or ResourceContents::blob for binary)
        ContentBlock::resource(ResourceContents::text(
            "chart source data",
            "chart://last/data.csv",
        )),
    ]))
}
# fn render_png() -> String { String::new() }
# fn render_wav() -> String { String::new() }

Image and audio data are base64 strings with a MIME type. For embedded resources, ResourceContents::text(..) inlines text and ResourceContents::blob(base64, uri) inlines binary.

Error handling

Two failure modes, chosen by whose problem it is:

  • Tool-level error — Ok(CallToolResult::error(vec![...])). The tool ran but failed in a way the caller should see (no rows matched, upstream 500). The client renders your content, so the message reaches the user. Use this for almost every "the tool ran and didn't work" case.
  • Protocol error — Err(McpError) with a JSON-RPC code (e.g. McpError::invalid_params(..)). Use this when the server can't route or process the request at all; clients render these opaquely, so the caller does not see your message.
use rmcp::model::{CallToolResult, ContentBlock};
use rmcp::ErrorData as McpError;

#[tool(description = "Look up a record")]
async fn lookup(&self, Parameters(args): Parameters<LookupArgs>) -> Result<CallToolResult, McpError> {
    // Malformed request — the server can't run anything → protocol error.
    if args.query.is_empty() {
        return Err(McpError::invalid_params("query must be non-empty", None));
    }

    // Tool ran, no result → tool-level error the user should see.
    let rows = self.run_query(&args.query).await;
    if rows.is_empty() {
        return Ok(CallToolResult::error(vec![ContentBlock::text(
            format!("no rows matched '{}'", args.query),
        )]));
    }

    Ok(CallToolResult::success(vec![ContentBlock::text(format_rows(&rows))]))
}

Client-side

use rmcp::model::CallToolRequestParams;

// List all tools
let tools = client.list_all_tools().await?;

// Call a tool by name
let result = client.call_tool(CallToolRequestParams::new("add")).await?;

Example: examples/servers/src/common/calculator.rs (server), examples/servers/src/calculator_stdio.rs (stdio runner)


Resources

Resources 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.

MCP Spec: Resources

Server-side

Implement list_resources(), read_resource(), and optionally `list_resource_t

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars4.1k
CategoryDevelopment
Updated8h ago
Forks696

Languages

Rust

Trust signals

83/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 medium1 low