KeiSeiKit-1.0/_ts_packages/packages/mcp-server/src/tool-registry.ts
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

88 lines
3.8 KiB
TypeScript

// Tool registry: auto-register each Rust primitive CLI as one MCP tool.
// Plus the meta-tool kei(query) that routes natural language via kei-router.
import { z } from "zod";
import { jsonArgsToCli, RustBridge } from "./rust-bridge.js";
import { ToolNotFoundError } from "./errors.js";
export interface ToolDefinition {
name: string;
description: string;
inputSchema: z.ZodObject<Record<string, z.ZodTypeAny>>;
handler: (args: Record<string, unknown>) => Promise<string>;
}
// Primitive CLIs exposed 1:1 as tools. Each Rust binary accepts flags as
// --kebab-case; tool names stay snake_case for MCP convention.
export const RUST_PRIMITIVE_TOOLS: ReadonlyArray<{ binary: string; desc: string }> = [
{ binary: "kei-ledger", desc: "Append-only event ledger; sign, verify, append, list." },
{ binary: "kei-memory", desc: "Local key-value memory store with SQLite backend." },
{ binary: "kei-store", desc: "Content-addressed blob store." },
{ binary: "kei-graph-check", desc: "Validate graph invariants in a project." },
{ binary: "kei-refactor-engine", desc: "Apply structural refactors from a plan file." },
{ binary: "kei-conflict-scan", desc: "Scan a tree for merge/rebase conflict markers." },
{ binary: "kei-migrate", desc: "Run schema or directory migrations." },
{ binary: "kei-changelog", desc: "Generate changelog from commit/tag history." },
{ binary: "ssh-check", desc: "Validate SSH config + known_hosts consistency." },
{ binary: "firewall-diff", desc: "Diff two firewall rule dumps." },
{ binary: "tokens-sync", desc: "Sync design tokens from Figma export to code." },
{ binary: "visual-diff", desc: "Compare rendered screenshots pixel-wise." },
{ binary: "mock-render", desc: "Render HTML mock templates for preview." },
{ binary: "kei-gdrive-import", desc: "Classify a Google Drive folder as PROJECT/AMBIGUOUS/NOT-A-PROJECT/ALREADY-REPO via 8-marker scoring (Cargo.toml, package.json, pyproject.toml, go.mod, pom.xml, build.gradle, Gemfile, composer.json). Subcommands: classify <path> [--remote], scan-tree <root> [--remote]. Remote mode shells to rclone lsf — no download." },
];
export function buildRegistry(bridge: RustBridge): Map<string, ToolDefinition> {
const map = new Map<string, ToolDefinition>();
for (const t of RUST_PRIMITIVE_TOOLS) map.set(t.binary, wrapPrimitive(bridge, t));
map.set("kei", buildKeiMetaTool(bridge));
return map;
}
function wrapPrimitive(
bridge: RustBridge,
entry: { binary: string; desc: string },
): ToolDefinition {
return {
name: entry.binary,
description: entry.desc,
inputSchema: z.object({ args: z.record(z.unknown()).optional() }),
handler: async (rawArgs) => {
const parsed = (rawArgs["args"] as Record<string, unknown> | undefined) ?? {};
const cli = jsonArgsToCli(parsed);
const result = await bridge.call({ binary: entry.binary, args: cli });
if (result.exitCode !== 0) {
return `exit=${result.exitCode}\nstderr=${result.stderr}\nstdout=${result.stdout}`;
}
return result.stdout;
},
};
}
function buildKeiMetaTool(bridge: RustBridge): ToolDefinition {
return {
name: "kei",
description:
"Meta-tool: routes a natural-language query to the right primitive via kei-router.",
inputSchema: z.object({ query: z.string().min(1) }),
handler: async (rawArgs) => {
const query = String(rawArgs["query"] ?? "");
const result = await bridge.call({
binary: "kei-router",
args: ["--query", query],
});
if (result.exitCode !== 0) {
return `router failed exit=${result.exitCode}\nstderr=${result.stderr}`;
}
return result.stdout;
},
};
}
export function lookupTool(
registry: ReadonlyMap<string, ToolDefinition>,
name: string,
): ToolDefinition {
const t = registry.get(name);
if (!t) throw new ToolNotFoundError(name);
return t;
}