MCP client: spawn external tool servers, dispatch via JSON-RPC

New mcp_client.rs: McpRegistry manages MCP server connections.
Spawns child processes, speaks JSON-RPC 2.0 over stdio. Discovers
tools via tools/list, dispatches calls via tools/call.

dispatch_with_agent falls through to MCP after checking internal
tools. McpRegistry lives on Agent (shared across forks).

Still needs: config-driven server startup, system prompt integration.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-09 11:45:39 -04:00
parent ec7e11db56
commit 8b5614ba99
4 changed files with 241 additions and 3 deletions

View file

@ -6,6 +6,7 @@
// Core tools
mod ast_grep;
pub mod mcp_client;
mod bash;
pub mod channels;
mod edit;
@ -152,7 +153,22 @@ pub async fn dispatch_with_agent(
match tool {
Some(t) => (t.handler)(agent, args.clone()).await
.unwrap_or_else(|e| format!("Error: {}", e)),
None => format!("Error: Unknown tool: {}", name),
None => {
let allowed = match &agent {
Some(a) => match &a.state.lock().await.mcp_tools {
super::McpToolAccess::All => true,
super::McpToolAccess::Some(list) => list.iter().any(|t| t == name),
super::McpToolAccess::None => false,
},
None => true,
};
if allowed {
if let Ok(result) = mcp_client::call_tool(name, args).await {
return result;
}
}
format!("Error: Unknown tool: {}", name)
}
}
}
@ -171,6 +187,12 @@ pub fn tools() -> Vec<Tool> {
all
}
pub async fn all_tool_definitions() -> Vec<String> {
let mut defs: Vec<String> = tools().iter().map(|t| t.to_json()).collect();
defs.extend(mcp_client::tool_definitions_json().await);
defs
}
/// Memory + journal tools only — for subconscious agents.
pub fn memory_and_journal_tools() -> Vec<Tool> {
let mut all = memory::memory_tools().to_vec();