mcp-protocol-server 0.2.0

โ›” DEPRECATED: Use mcp-protocol-sdk v0.4.0+ instead. This crate is consolidated into the main SDK.
Documentation

MCP Protocol Server

Crates.io Documentation License: MIT

Lightweight server library for the Model Context Protocol (MCP)

This crate provides a high-level, ergonomic API for building MCP servers in Rust. It handles the JSON-RPC protocol details, capability negotiation, and transport management, allowing you to focus on implementing your tools, resources, and prompts.

โœจ Features

  • ๐Ÿฆ€ Pure Rust - Zero-cost abstractions with memory safety
  • ๐ŸŽฏ Type-Safe - Compile-time guarantees using mcp-protocol-types
  • ๐Ÿš€ Async/Await - Built on Tokio for high performance
  • ๐Ÿ”Œ Multiple Transports - STDIO transport with extensible design
  • ๐Ÿ› ๏ธ Complete MCP Support - Tools, resources, prompts, logging
  • ๐Ÿ“ฆ Lightweight - Minimal dependencies for fast builds
  • ๐Ÿงช Well Tested - Comprehensive test suite
  • ๐Ÿ“– Great Documentation - Examples and guides

๐Ÿš€ Quick Start

Add to your Cargo.toml:

[dependencies]
mcp-protocol-server = "0.1.0"
mcp-protocol-types = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
serde_json = "1.0"

Basic Server Example

use mcp_protocol_server::{Server, ServerBuilder};
use mcp_protocol_types::*;
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create server
    let server = ServerBuilder::new("my-server", "1.0.0")
        .with_tool(
            Tool::new("echo", "Echo back the input")
                .with_parameter("message", "Message to echo", true)
        )
        .build();

    // Set up tool handler
    server.set_tool_handler("echo", |request| async move {
        let message = request.arguments
            .as_ref()
            .and_then(|args| args.get("message"))
            .and_then(|v| v.as_str())
            .unwrap_or("Hello, World!");

        Ok(CallToolResult {
            content: vec![ToolResultContent::text(message)],
            is_error: None,
        })
    });

    // Run server with STDIO transport
    server.run_stdio().await?;
    Ok(())
}

Resource Server Example

use mcp_protocol_server::{Server, ServerBuilder};
use mcp_protocol_types::*;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut files = HashMap::new();
    files.insert("config.json".to_string(), r#"{"debug": true}"#.to_string());
    files.insert("README.md".to_string(), "# My Project\n\nDocumentation here.".to_string());

    let server = ServerBuilder::new("file-server", "1.0.0")
        .with_resource(Resource {
            uri: "file://config.json".to_string(),
            name: Some("Configuration".to_string()),
            description: Some("Application configuration file".to_string()),
            mime_type: Some("application/json".to_string()),
        })
        .with_resource(Resource {
            uri: "file://README.md".to_string(),
            name: Some("Documentation".to_string()),
            description: Some("Project documentation".to_string()),
            mime_type: Some("text/markdown".to_string()),
        })
        .build();

    // Set up resource handler
    server.set_resource_handler(move |request| {
        let files = files.clone();
        async move {
            let file_name = request.uri.strip_prefix("file://").unwrap_or(&request.uri);
            
            if let Some(content) = files.get(file_name) {
                Ok(ReadResourceResult {
                    contents: vec![ResourceContents::text(request.uri.clone(), content)],
                })
            } else {
                Err(McpError::invalid_params("File not found"))
            }
        }
    });

    server.run_stdio().await?;
    Ok(())
}

๐Ÿ—๏ธ Architecture

The server library provides a layered architecture:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Your Application Logic             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         MCP Protocol Server                 โ”‚ โ† This crate
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚         MCP Protocol Types                  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚           Transport Layer                   โ”‚ (STDIO, HTTP, WebSocket)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“‹ Core Concepts

Server Builder

The ServerBuilder provides a fluent API for configuring your server:

use mcp_protocol_server::ServerBuilder;
use mcp_protocol_types::*;

let server = ServerBuilder::new("my-server", "1.0.0")
    .with_description("An awesome MCP server")
    .with_instructions("Use this server to perform amazing tasks")
    .with_tool(Tool::new("calculate", "Perform calculations"))
    .with_resource(Resource {
        uri: "data://numbers".to_string(),
        name: Some("Numbers Dataset".to_string()),
        description: Some("Collection of interesting numbers".to_string()),
        mime_type: Some("application/json".to_string()),
    })
    .build();

Handler Functions

Register async handlers for different MCP operations:

// Tool handler
server.set_tool_handler("my-tool", |request| async move {
    // Process the tool request
    Ok(CallToolResult {
        content: vec![ToolResultContent::text("Result")],
        is_error: None,
    })
});

// Resource handler
server.set_resource_handler(|request| async move {
    // Read and return resource content
    Ok(ReadResourceResult {
        contents: vec![ResourceContents::text(request.uri, "content")],
    })
});

// Prompt handler
server.set_prompt_handler("my-prompt", |request| async move {
    // Generate prompt messages
    Ok(GetPromptResult {
        description: Some("Generated prompt".to_string()),
        messages: vec![PromptMessage {
            role: PromptRole::User,
            content: PromptContent::Text {
                text: "Hello!".to_string(),
            },
        }],
    })
});

Transport Support

Currently supports STDIO transport (perfect for Claude Desktop):

// Run with STDIO (for Claude Desktop integration)
server.run_stdio().await?;

// Or use custom transport implementation
let transport = MyCustomTransport::new();
server.run(transport).await?;

๐Ÿ”ง Feature Flags

Feature Description Default
stdio STDIO transport support โœ…

๐Ÿ“Š Usage Patterns

Claude Desktop Integration

Perfect for extending Claude Desktop with custom capabilities:

use mcp_protocol_server::{Server, ServerBuilder};
use mcp_protocol_types::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = ServerBuilder::new("claude-tools", "1.0.0")
        .with_instructions("I provide helpful tools for development tasks")
        .with_tool(
            Tool::new("git-status", "Check git repository status")
                .with_parameter("path", "Repository path", false)
        )
        .with_tool(
            Tool::new("run-tests", "Execute project tests")
                .with_parameter("test_name", "Specific test to run", false)
        )
        .build();

    // Implement handlers...
    server.run_stdio().await?;
    Ok(())
}

File System Tools

use mcp_protocol_server::ServerBuilder;
use mcp_protocol_types::*;
use std::fs;

let server = ServerBuilder::new("file-tools", "1.0.0")
    .with_tool(
        Tool::new("read-file", "Read file contents")
            .with_parameter("path", "File path to read", true)
    )
    .with_tool(
        Tool::new("list-dir", "List directory contents")
            .with_parameter("path", "Directory path", true)
    )
    .build();

server.set_tool_handler("read-file", |request| async move {
    let path = request.arguments
        .as_ref()
        .and_then(|args| args.get("path"))
        .and_then(|v| v.as_str())
        .ok_or_else(|| McpError::invalid_params("Missing path parameter"))?;

    match fs::read_to_string(path) {
        Ok(content) => Ok(CallToolResult {
            content: vec![ToolResultContent::text(content)],
            is_error: None,
        }),
        Err(e) => Ok(CallToolResult {
            content: vec![ToolResultContent::text(format!("Error: {}", e))],
            is_error: Some(true),
        }),
    }
});

Database Integration

// Example with a hypothetical database
server.set_tool_handler("query-db", |request| async move {
    let sql = request.arguments
        .as_ref()
        .and_then(|args| args.get("sql"))
        .and_then(|v| v.as_str())
        .ok_or_else(|| McpError::invalid_params("Missing sql parameter"))?;

    // Execute query (implement your database logic)
    let results = execute_query(sql).await?;
    
    Ok(CallToolResult {
        content: vec![ToolResultContent::text(format!("Results: {:?}", results))],
        is_error: None,
    })
});

๐Ÿงช Testing

use mcp_protocol_server::testing::MockTransport;

#[tokio::test]
async fn test_tool_handler() {
    let server = ServerBuilder::new("test-server", "1.0.0")
        .with_tool(Tool::new("test-tool", "Test tool"))
        .build();

    server.set_tool_handler("test-tool", |_| async move {
        Ok(CallToolResult {
            content: vec![ToolResultContent::text("test result")],
            is_error: None,
        })
    });

    let mut transport = MockTransport::new();
    
    // Send test request
    transport.send_request("tools/call", json!({
        "name": "test-tool",
        "arguments": {}
    })).await;

    // Verify response
    let response = transport.receive_response().await;
    // Assert response content...
}

๐Ÿ› ๏ธ Development

# Build the crate
cargo build

# Run tests
cargo test

# Run with all features
cargo check --all-features

# Generate documentation
cargo doc --open

๐Ÿ”— Related Crates

๐Ÿค Contributing

This crate is part of the MCP Rust ecosystem. Contributions are welcome!

Guidelines

  • API Design - Keep the API simple and ergonomic
  • Performance - Optimize for low latency and memory usage
  • Documentation - All public APIs need examples
  • Testing - Comprehensive test coverage required

๐Ÿ“‹ Protocol Compliance

โœ… MCP 2024-11-05 Specification

This library implements the complete MCP server specification:

  • JSON-RPC 2.0 protocol handling
  • Capability negotiation and initialization
  • Tool calling and parameter validation
  • Resource access and content delivery
  • Prompt template processing
  • Logging and debugging support
  • Error handling and recovery

๐Ÿ“„ License

Licensed under the MIT License.

๐Ÿ™ Acknowledgments

  • Anthropic - For creating the MCP specification
  • Tokio Team - For the excellent async runtime
  • Rust Community - For the amazing ecosystem

Lightweight MCP server library for Rust ๐Ÿฆ€