# cortex-mcp
Model Context Protocol (MCP) support for cortex.
## Overview
This crate provides both **client** and **server** implementations of the [Model Context Protocol](https://modelcontextprotocol.io/), enabling:
- **Client**: Connect to MCP servers and use their tools in your agents
- **Server**: Expose your tools and agents as MCP servers for use with Claude Desktop, VS Code, etc.
## Features
- Full MCP protocol implementation (JSON-RPC 2.0)
- STDIO and SSE transports
- Tool, Resource, and Prompt support
- Easy tool bridging between MCP and cortex
## Quick Start
### Client: Connect to an MCP Server
```rust
use cortex_mcp::{McpClient, StdioTransport};
// Connect to an MCP filesystem server
let transport = StdioTransport::spawn(
"npx",
&["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
).await?;
let mut client = McpClient::new(transport).await?;
// List available tools
let tools = client.list_tools().await?;
// Call a tool
let result = client.call_tool("read_file", json!({"path": "/tmp/test.txt"})).await?;
```
### Server: Create an MCP Server
```rust
use cortex_mcp::{McpServer, ToolHandler, McpTool, CallToolResult, ToolContent};
struct MyTool;
#[async_trait]
impl ToolHandler for MyTool {
fn definition(&self) -> McpTool {
McpTool {
name: "my_tool".to_string(),
description: Some("Does something useful".to_string()),
input_schema: json!({
"type": "object",
"properties": {
"input": {"type": "string"}
}
}),
}
}
async fn execute(&self, args: serde_json::Value) -> Result<CallToolResult, McpError> {
Ok(CallToolResult {
content: vec![ToolContent::text("Result!")],
is_error: false,
})
}
}
// Build and run the server
let server = McpServer::builder()
.name("my-server")
.version("1.0.0")
.add_tool(MyTool)
.build();
server.run_stdio().await?;
```
### Server: HTTP/SSE Transport
For web-based clients, use the SSE transport:
```rust
use cortex_mcp::{McpServer, SseServerConfig};
let server = McpServer::builder()
.name("my-sse-server")
.version("1.0.0")
.add_tool(MyTool)
.build();
// Configure SSE server
let config = SseServerConfig {
host: "127.0.0.1".to_string(),
port: 3000,
sse_path: "/sse".to_string(),
message_path: "/message".to_string(),
enable_cors: true,
keep_alive_secs: 30,
};
// Run HTTP server (blocks until shutdown)
server.run_sse(config).await?;
```
Endpoints:
- `GET /sse` - SSE stream for server-to-client messages
- `POST /message?sessionId=xxx` - JSON-RPC requests from client
## Using with Claude Desktop
1. Build your MCP server:
```bash
cargo build --release --example mcp_server
```
2. Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
```json
{
"mcpServers": {
"cortex": {
"command": "/path/to/target/release/examples/mcp_server"
}
}
}
```
3. Restart Claude Desktop - your tools will be available!
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ MCP Crate │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ McpClient │ │ McpServer │ │
│ │ │ │ │ │
│ │ - list_tools() │ │ - add_tool() │ │
│ │ - call_tool() │ │ - run_stdio() │ │
│ │ - list_resources│ │ - handle_*() │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ┌────────┴────────────────────────────┴────────┐ │
│ │ McpTransport Trait │ │
│ ├──────────────────┬───────────────────────────┤ │
│ │ StdioTransport │ SseTransport │ │
│ │ (subprocess) │ (HTTP/SSE) │ │
│ └──────────────────┴───────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ McpToolBridge │ │
│ │ (Convert MCP tools to cortex Tool) │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
## Modules
### `client`
MCP client for connecting to external servers.
### `server`
MCP server for exposing tools to clients.
### `transport`
Transport implementations (STDIO, SSE).
### `bridge`
Bridge MCP tools to cortex Tool trait.
### `protocol`
MCP protocol types (JSON-RPC, capabilities, tool definitions).
## Tool Handler Trait
Implement `ToolHandler` to create MCP tools:
```rust
#[async_trait]
pub trait ToolHandler: Send + Sync {
/// Get the tool definition (name, description, schema)
fn definition(&self) -> McpTool;
/// Execute the tool with the given arguments
async fn execute(&self, arguments: serde_json::Value) -> Result<CallToolResult, McpError>;
}
```
## Function-Based Tools
For simple tools, use `FnTool` or `AsyncFnTool`:
```rust
use cortex_mcp::FnTool;
let add_tool = FnTool::new(
"add",
"Adds two numbers",
json!({
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
}
}),
|args| {
let a = args["a"].as_f64().unwrap_or(0.0);
let b = args["b"].as_f64().unwrap_or(0.0);
Ok(json!(a + b))
},
);
```
## Resource and Prompt Handlers
For resources and prompts, implement the respective traits:
```rust
#[async_trait]
pub trait ResourceHandler: Send + Sync {
fn list(&self) -> Vec<McpResource>;
async fn read(&self, uri: &str) -> Result<ResourceContent, McpError>;
}
#[async_trait]
pub trait PromptHandler: Send + Sync {
fn list(&self) -> Vec<McpPrompt>;
async fn get(&self, name: &str, arguments: HashMap<String, String>)
-> Result<Vec<PromptMessage>, McpError>;
}
```
## Examples
See the examples directory:
- `examples/mcp_server.rs` - MCP server with STDIO transport (for Claude Desktop)
- `examples/mcp_sse_server.rs` - MCP server with HTTP/SSE transport (for web clients)
- `examples/mcp_integration.rs` - Client connecting to external MCP servers
Run examples:
```bash
# STDIO server example (for Claude Desktop)
cargo run --example mcp_server
# SSE server example (HTTP on port 3000)
cargo run --example mcp_sse_server
# Client example (requires Node.js/npx)
cargo run --example mcp_integration
```
## Protocol Version
This implementation supports MCP protocol version `2024-11-05`.
## License
Apache-2.0