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:
parent
d6b85d204a
commit
c5b5051772
2 changed files with 60 additions and 0 deletions
|
|
@ -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> {
|
pub fn cmd_load_context(stats: bool) -> Result<(), String> {
|
||||||
let cfg = crate::config::get();
|
let cfg = crate::config::get();
|
||||||
let store = crate::store::Store::load()?;
|
let store = crate::store::Store::load()?;
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -220,6 +220,10 @@ EXAMPLES:
|
||||||
/// Admin operations (fsck, health, import, export)
|
/// Admin operations (fsck, health, import, export)
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
Admin(AdminCmd),
|
Admin(AdminCmd),
|
||||||
|
|
||||||
|
/// Output MCP tool definitions as JSON (for generic MCP bridge)
|
||||||
|
#[command(name = "mcp-schema")]
|
||||||
|
McpSchema,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
|
@ -310,6 +314,14 @@ enum GraphCmd {
|
||||||
/// Node key
|
/// Node key
|
||||||
key: Vec<String>,
|
key: Vec<String>,
|
||||||
},
|
},
|
||||||
|
/// Find related nodes via spreading activation from seed nodes
|
||||||
|
Spread {
|
||||||
|
/// Seed node keys
|
||||||
|
keys: Vec<String>,
|
||||||
|
/// Maximum results (default: 20)
|
||||||
|
#[arg(short = 'n', default_value_t = 20)]
|
||||||
|
max_results: usize,
|
||||||
|
},
|
||||||
/// Add a link between two nodes
|
/// Add a link between two nodes
|
||||||
#[command(name = "link-add")]
|
#[command(name = "link-add")]
|
||||||
LinkAdd {
|
LinkAdd {
|
||||||
|
|
@ -806,6 +818,7 @@ impl Run for Command {
|
||||||
Self::Cursor(sub) => sub.run(),
|
Self::Cursor(sub) => sub.run(),
|
||||||
Self::Agent(sub) => sub.run(),
|
Self::Agent(sub) => sub.run(),
|
||||||
Self::Admin(sub) => sub.run(),
|
Self::Admin(sub) => sub.run(),
|
||||||
|
Self::McpSchema => cli::misc::cmd_mcp_schema(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -837,6 +850,7 @@ impl Run for GraphCmd {
|
||||||
fn run(self) -> Result<(), String> {
|
fn run(self) -> Result<(), String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Link { key } => cli::graph::cmd_link(&key),
|
Self::Link { key } => cli::graph::cmd_link(&key),
|
||||||
|
Self::Spread { keys, max_results } => cli::graph::cmd_spread(&keys, max_results),
|
||||||
Self::LinkAdd { source, target, reason }
|
Self::LinkAdd { source, target, reason }
|
||||||
=> cli::graph::cmd_link_add(&source, &target, &reason),
|
=> cli::graph::cmd_link_add(&source, &target, &reason),
|
||||||
Self::LinkSet { source, target, strength }
|
Self::LinkSet { source, target, strength }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue