mcp: add mcp-schema command for generic MCP bridge

Add `poc-memory mcp-schema` command that outputs tool definitions with
CLI routing info (name, description, inputSchema, cli args, stdin_param).

The companion memory-mcp.py (in ~/bin/) is a generic bridge that loads
definitions from mcp-schema at startup and dynamically generates typed
Python functions for FastMCP registration. No tool-specific Python code
— adding a new tool only requires changes in Rust.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-03-31 18:20:52 -04:00
parent d6b85d204a
commit c5b5051772
2 changed files with 60 additions and 0 deletions

View file

@ -264,6 +264,52 @@ pub fn get_group_content(group: &crate::config::ContextGroup, store: &crate::sto
}
}
/// MCP tool schema with CLI routing info.
///
/// Each tool definition includes:
/// - name, description, inputSchema (standard MCP)
/// - cli: the CLI args prefix to invoke this tool
/// - stdin_param: which parameter (if any) should be sent via stdin
///
/// Tools with cli=null are agent-internal (not exposed via MCP CLI bridge).
pub fn cmd_mcp_schema() -> Result<(), String> {
use serde_json::json;
// Map tool names to CLI args + stdin param.
// Tools not listed here are skipped (agent-internal).
let cli_map: std::collections::HashMap<&str, (Vec<&str>, Option<&str>)> = [
("memory_render", (vec!["render"], None)),
("memory_write", (vec!["write"], Some("content"))),
("memory_search", (vec!["search"], None)),
("memory_search_content", (vec!["search", "--content"], None)),
("memory_spread", (vec!["graph", "spread"], None)),
("memory_links", (vec!["graph", "link"], None)),
("memory_link_set", (vec!["graph", "link-set"], None)),
("memory_link_add", (vec!["graph", "link-add"], None)),
("memory_used", (vec!["used"], None)),
("memory_weight_set", (vec!["weight-set"], None)),
("memory_rename", (vec!["node", "rename"], None)),
("memory_query", (vec!["query"], None)),
].into_iter().collect();
let defs = crate::thought::memory::definitions();
let json_out: Vec<_> = defs.iter().filter_map(|d| {
let name = &d.function.name;
let (cli, stdin_param) = cli_map.get(name.as_str())?;
Some(json!({
"name": name,
"description": d.function.description,
"inputSchema": d.function.parameters,
"cli": cli,
"stdin_param": stdin_param,
}))
}).collect();
println!("{}", serde_json::to_string_pretty(&json_out)
.map_err(|e| e.to_string())?);
Ok(())
}
pub fn cmd_load_context(stats: bool) -> Result<(), String> {
let cfg = crate::config::get();
let store = crate::store::Store::load()?;