// pi-codebase-memory: bridge codebase-memory-mcp into pi as native tools. // // pi has no built-in MCP support (docs/usage.md: "It intentionally does not // include built-in MCP..."). So instead of an MCP client, we fetch the server's // tool list once over stdio at session start, then register one pi tool per // codebase-memory-mcp tool. Each call shells out to `codebase-memory-mcp cli`, // which returns JSON synchronously — no persistent connection to manage. import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Type } from "typebox"; import { fetchTools, injectProject, normalizeSchema, resolveBin, runTool } from "./helpers"; type ToolResult = { content: { type: "text"; text: string }[]; details: Record }; export default function (pi: ExtensionAPI) { pi.on("session_start", async (_event: unknown, ctx: any) => { const bin = resolveBin(); let tools; try { tools = await fetchTools(bin); } catch (e) { ctx.ui.notify( `codebase-memory: could not load tools from ${bin} (${(e as Error).message}). ` + `Install codebase-memory-mcp or set CODEBASE_MEMORY_MCP_BIN.`, "error", ); return; } if (tools.length === 0) { ctx.ui.notify("codebase-memory: server returned no tools", "warning"); return; } const cwd = process.cwd(); for (const tool of tools) { pi.registerTool({ name: tool.name, label: tool.name, description: tool.description ?? `codebase-memory tool: ${tool.name}`, // Type.Unsafe wraps the server's raw JSON schema as a TypeBox schema so the // LLM sees the real parameter contract without re-transcribing 14 schemas. parameters: Type.Unsafe(normalizeSchema(tool.inputSchema)), async execute(_id: string, params: Record): Promise { const args = injectProject(params ?? {}, tool.inputSchema, cwd); try { const out = await runTool(bin, tool.name, args); return { content: [{ type: "text", text: out || "(empty result)" }], details: { tool: tool.name, project: args.project }, }; } catch (e: any) { const msg = (e?.stderr || e?.stdout || e?.message || String(e)).toString().trim(); return { content: [{ type: "text", text: `codebase-memory ${tool.name} failed:\n${msg}` }], details: { tool: tool.name, error: true }, }; } }, }); } ctx.ui.notify(`codebase-memory: registered ${tools.length} graph tools`, "info"); }); }