Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl fmt::Display for McpError {
McpError::Custom { code, message } => write!(f, "Error {}: {}", code, message),
McpError::ConnectionFailed => write!(f, "Connection failed"),
McpError::ConnectionTimeout => write!(f, "Connection timed out"),
McpError::ServerError(msg) => write!(f, "Server error: {}", msg),
McpError::ServerError(msg) => write!(f, "Server error: {msg}"),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/logging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ struct JsonVisitor(serde_json::Value);

impl tracing::field::Visit for JsonVisitor {
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
let value = format!("{:?}", value);
let value = format!("{value:?}");
if let serde_json::Value::Object(ref mut map) = self.0 {
map.insert(field.name().to_string(), serde_json::Value::String(value));
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/prompts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl PromptManager {
let prompts = self.prompts.read().await;
let prompt = prompts
.get(name)
.ok_or_else(|| McpError::InvalidRequest(format!("Unknown prompt: {}", name)))?;
.ok_or_else(|| McpError::InvalidRequest(format!("Unknown prompt: {name}")))?;

// Validate required arguments
if let Some(args) = &arguments {
Expand Down Expand Up @@ -174,7 +174,7 @@ impl PromptManager {
.tx
.send(notification)
.await
.map_err(|e| McpError::InternalError(format!("Notification error: {}", e)))?;
.map_err(|e| McpError::InternalError(format!("Notification error: {e}")))?;
}
Ok(())
}
Expand Down
6 changes: 5 additions & 1 deletion src/tools/calculator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use serde_json::{json, Value};
use std::{collections::HashMap, sync::Arc};
use uuid::Uuid;

use crate::{
error::McpError,
Expand Down Expand Up @@ -309,6 +310,7 @@ mod tests {
CallToolArgs::builder()
.session_id(Some("session-1234".to_string()))
.tool_id(Some("calculator-1234".to_string()))
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -327,12 +329,13 @@ mod tests {
"calculator",
json!({
"operation": "ln",
"a": 2.718281828459045
"a": std::f64::consts::E
}),
Some(
CallToolArgs::builder()
.session_id(Some("session-5678".to_string()))
.tool_id(Some("calculator-5678".to_string()))
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -370,6 +373,7 @@ mod tests {
CallToolArgs::builder()
.session_id(Some("session-9999".to_string()))
.tool_id(Some("calculator-9999".to_string()))
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down
4 changes: 2 additions & 2 deletions src/tools/file_system/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl ToolProvider for DirectoryTool {

Ok(ToolResult {
content: vec![ToolContent::Text {
text: format!("Created directory: {}", path),
text: format!("Created directory: {path}"),
}],
is_error: false,
_meta: None,
Expand Down Expand Up @@ -118,7 +118,7 @@ impl ToolProvider for DirectoryTool {

Ok(ToolResult {
content: vec![ToolContent::Text {
text: format!("Moved {} to {}", source, destination),
text: format!("Moved {source} to {destination}"),
}],
is_error: false,
_meta: None,
Expand Down
16 changes: 14 additions & 2 deletions src/tools/file_system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use async_trait::async_trait;
use serde_json::Value;
use std::path::PathBuf;
use std::sync::Arc;
use uuid::Uuid;

use super::CallToolArgs;

Expand Down Expand Up @@ -165,6 +166,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("write-to-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -183,6 +185,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("read-from-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -211,6 +214,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("create-directory-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -229,6 +233,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("list-directory-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -260,6 +265,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("write-to-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -279,6 +285,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("search-files-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -313,6 +320,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("write-to-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -331,6 +339,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("move-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -360,6 +369,7 @@ mod tests {
CallToolArgs::builder()
.tool_id("write-to-file-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -381,12 +391,13 @@ mod tests {
json!({
"operation": "write_file",
"path": path.to_str().unwrap(),
"content": format!("content {}", i),
"content": format!("content {i}"),
}),
Some(
CallToolArgs::builder()
.tool_id(format!("write-to-file-{}", i).to_string())
.tool_id(format!("write-to-file-{i}").to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -403,6 +414,7 @@ mod tests {
Some(CallToolArgs::builder()
.tool_id("read-multiple-files-1234".to_string())
.session_id("session-1234".to_string())
.agent_id(Uuid::new_v4())
.build()),
)
.await
Expand Down
4 changes: 2 additions & 2 deletions src/tools/file_system/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ impl ToolProvider for ReadFileTool {
for (path, result) in results {
match result {
Ok(content) => contents.push(ToolContent::Text {
text: format!("File: {}\n{}", path, content),
text: format!("File: {path}\n{content}"),
}),
Err(e) => contents.push(ToolContent::Text {
text: format!("Error reading {}: {}", path, e),
text: format!("Error reading {path}: {e}"),
}),
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/tools/file_system/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ impl SearchTool {
.as_secs();

Ok(format!(
"Type: {}\nSize: {} bytes\nLast Modified: {} seconds since epoch",
file_type, size, modified
"Type: {file_type}\nSize: {size} bytes\nLast Modified: {modified} seconds since epoch"
))
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,14 @@ impl ToolManager {
self.send_tool_update_notification(
name,
ToolUpdateType::Removed,
Some(format!("Tool '{}' unregistered", name)),
Some(format!("Tool '{name}' unregistered")),
)
.await;
}
Ok(())
} else {
Err(McpError::InvalidRequest(format!(
"Tool '{}' not found",
name
"Tool '{name}' not found"
)))
}
}
Expand Down Expand Up @@ -295,7 +294,7 @@ impl ToolManager {
let tools = self.tools.read().await;
let provider = tools
.get(name)
.ok_or_else(|| McpError::InvalidRequest(format!("Unknown tool: {}", name)))?;
.ok_or_else(|| McpError::InvalidRequest(format!("Unknown tool: {name}")))?;

provider.execute(arguments, metadata).await
}
Expand Down
2 changes: 1 addition & 1 deletion src/tools/test_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl ToolProvider for PingTool {
.get("server")
.and_then(|s| s.as_str())
.unwrap_or("localhost");
let res = reqwest::get(format!("http://{}", server))
let res = reqwest::get(format!("http://{server}"))
.await
.map_err(|e| McpError::ToolExecutionError(e.to_string()))?;
let body = res
Expand Down
2 changes: 1 addition & 1 deletion src/transport/sse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl SseTransport {
event_tx: mpsc::Sender<TransportEvent>,
) {
let client = reqwest::Client::new();
let sse_url = format!("http://{}:{}/sse", host, port);
let sse_url = format!("http://{host}:{port}/sse");

tracing::debug!("Connecting to SSE endpoint: {}", sse_url);

Expand Down
4 changes: 2 additions & 2 deletions src/transport/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl WebSocketTransport {
pub fn new_client(host: String, port: u16, buffer_size: usize) -> Self {
Self {
config: WsTransportConfig::Client {
url: format!("ws://{}:{}/ws", host, port),
url: format!("ws://{host}:{port}/ws"),
},
buffer_size,
auth_header: None,
Expand All @@ -57,7 +57,7 @@ impl WebSocketTransport {
pub fn new_wss_client(host: String, port: u16, buffer_size: usize) -> Self {
Self {
config: WsTransportConfig::Client {
url: format!("wss://{}:{}/ws", host, port),
url: format!("wss://{host}:{port}/ws"),
},
buffer_size,
auth_header: None,
Expand Down
73 changes: 73 additions & 0 deletions summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# mcp.rs Summary

**mcp.rs** is a high-performance, type-safe Rust implementation of the Model Context Protocol (MCP) for enabling seamless communication between AI applications and their integrations.

## Key Features

- **Multiple Transport Types**: stdio, HTTP with SSE, extensible transport system
- **Resource Management**: File system resources, templating, real-time updates, subscriptions
- **Security**: Access controls, path traversal protection, rate limiting, CORS support
- **Flexible Configuration**: YAML/JSON files, environment variables, CLI arguments

## Quick Commands

### Client Usage
```bash
# List resources
cargo run --bin client list-resources

# Read file
cargo run --bin client read-resource -u "file:///path/to/file"

# Use prompt
cargo run --bin client get-prompt -n "code_review" -a '{"code": "fn main() {}", "language": "rust"}'

# Call tool
cargo run --bin client call-tool --name "file_system" --args '{"operation": "read_file", "path": "Config.toml"}'
```

### Server Usage
```bash
# Run server with config
cargo run --bin server -- --config "../servers/test.json"

# Run with stdio transport
mcp-server -t stdio

# Run with SSE on port 3000
mcp-server -t sse -p 3000
```

## Architecture

- **Transport Layer**: Handles client-server communication
- **Protocol Layer**: Implements MCP message format and routing
- **Resource Layer**: Manages external resource access
- **Configuration**: Server settings and capabilities

## Installation

Add to `Cargo.toml`:
```toml
[dependencies]
mcp = "0.1.0"
```

## Development

- **Requirements**: Rust 1.70+, Cargo
- **Testing**: `cargo test`
- **Documentation**: `cargo doc --open`

## Core Components

- **McpServer**: Main server handling MCP protocol
- **ServerConfig**: Configuration management
- **RequestHandler**: Custom protocol handling
- **ResourceManager**: Resource access and management
- **ToolManager**: Tool execution
- **PromptManager**: Prompt templating

## License

MIT License
4 changes: 4 additions & 0 deletions tests/tools.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use async_trait::async_trait;
use serde_json::{json, Value};
use std::{collections::HashMap, sync::Arc};
use uuid::Uuid;

use mcp_rs::{
error::McpError,
Expand Down Expand Up @@ -137,6 +138,7 @@ async fn test_tool_execution() {
CallToolArgs::builder()
.session_id("calculator-id-1234".to_string())
.tool_id("calculator-tool-id-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand All @@ -163,6 +165,7 @@ async fn test_tool_execution() {
CallToolArgs::builder()
.session_id("calculator-id-1234".to_string())
.tool_id("calculator-tool-id-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down Expand Up @@ -223,6 +226,7 @@ async fn test_invalid_arguments() {
CallToolArgs::builder()
.session_id("calculator-id-1234".to_string())
.tool_id("calculator-tool-id-1234".to_string())
.agent_id(Uuid::new_v4())
.build(),
),
)
Expand Down
Loading