use anyhow::{Context, Result, bail};
use serde_json::{Value, json};
use std::io::{self, BufRead, Read, Write};
pub(crate) fn serve_inventory(path: &std::path::Path) -> Result<()> {
let source = std::fs::read(path).context("reading Claude tool inventory")?;
if source.len() > 1024 * 1024 {
bail!("Claude tool inventory too large");
}
let tools: Value = serde_json::from_slice(&source)?;
let tools = tools
.as_array()
.context("Claude tool inventory must be a list")?;
let stdin = io::stdin();
let mut input = stdin.lock();
let mut output = io::stdout().lock();
let mut line = Vec::new();
loop {
line.clear();
let count = (&mut input)
.take(1024 * 1024 + 1)
.read_until(b'\n', &mut line)?;
if count == 0 {
return Ok(());
}
if count > 1024 * 1024 || line.last() != Some(&b'\n') {
bail!("Claude MCP request too large");
}
let request: Value = serde_json::from_slice(&line).context("invalid Claude MCP request")?;
if let Some(id) = request.get("id") {
let result = match request.get("method").and_then(Value::as_str) {
Some("initialize") => {
json!({"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"magi-inert-inventory","version":"1"}})
}
Some("tools/list") => json!({"tools":tools}),
Some("tools/call") => {
json!({"isError":true,"content":[{"type":"text","text":"Denied: only magi-code executes tools."}]})
}
_ => json!({}),
};
serde_json::to_writer(
&mut output,
&json!({"jsonrpc":"2.0","id":id,"result":result}),
)?;
output.write_all(b"\n")?;
output.flush()?;
}
}
}