✅ Complete API Structure
McpClient- Client for connecting to MCP serversMcpTool- Wrapper implementing ourTooltraitMcpToolInfo- Metadata about discovered tools- Full integration with existing
ToolRegistrysystem
✅ Compiles Successfully
- All types and methods defined
- Proper error handling signatures
- Async/await patterns in place
✅ Well Documented
- Comprehensive doc comments
- Usage examples in code
- Clear TODO comments marking what needs implementation
🚧 rust-mcp-sdk Integration
The rust-mcp-sdk crate is added as a dependency, but we need to:
-
Understand the SDK API Structure
- Study the documentation at https://docs.rs/rust-mcp-sdk
- Find examples or look at source code
- Identify the main types (Client, Transport, Request/Response)
-
Implement McpClient::new_stdio()
// Pseudo-code of what needs to happen: async fn new_stdio(command: &str, args: &[&str]) -> Result<Arc<Self>, String> { // Spawn process let child = tokio::process::Command::new(command) .args(args) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; // Create transport from stdin/stdout let transport = StdioTransport::new(child); // Create MCP client let client = rust_mcp_sdk::Client::new(transport); // Perform handshake client.initialize().await?; // Return wrapped client Ok(Arc::new(Self { inner: client })) }
-
Implement list_tools()
async fn list_tools(&self) -> Result<Vec<MCPToolInfo>, String> { // Send tools/list request let response = self.inner.request("tools/list", EmptyParams).await?; // Parse response let tools: Vec<Tool> = response.tools; // Convert to our format tools.into_iter().map(|t| MCPToolInfo { name: t.name, description: t.description, input_schema: t.input_schema, }).collect() }
-
Implement call_tool()
async fn call_tool(name: &str, args: HashMap<String, JsonValue>) -> Result<JsonValue, String> { // Build request let request = ToolCallRequest { name: name.to_string(), arguments: args, }; // Send to server let response = self.inner.request("tools/call", request).await?; // Return result Ok(response.result) }
use agent_runtime::{McpClient, McpTool, ToolRegistry};
use std::sync::Arc;
// Connect to filesystem MCP server
let mcp_client = McpClient::new_stdio(
"npx",
&["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
).await?;
// Discover tools
let mcp_tools = mcp_client.list_tools().await?;
println!("Found {} MCP tools", mcp_tools.len());
// Create tool registry with both native and MCP tools
let mut registry = ToolRegistry::new();
// Add native tools
registry.register(NativeTool::new("add", ...));
// Add MCP tools
for info in mcp_tools {
let tool = McpTool::from_info(info, Arc::clone(&mcp_client));
registry.register(Arc::new(tool));
}
// Use in agent
let agent = Agent::new(
AgentConfig::builder("assistant")
.tools(Arc::new(registry))
.build()
).with_llm_client(llm);- Open https://docs.rs/rust-mcp-sdk and study the API
- Look for examples in the SDK repository
- Implement the three TODO methods
- Create
mcp_tools_demo.rsto test it - Update documentation with working example
If rust-mcp-sdk proves difficult to use, we could:
- Implement the MCP protocol directly (it's JSON-RPC over stdio/HTTP)
- Use a simpler transport library
- Create our own MCP client from scratch
The MCP spec is at: https://modelcontextprotocol.io/docs/specification