kibi-mcp 0.17.5 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bin/kibi-mcp +1 -1
  2. package/dist/diagnostics-helpers.js +22 -0
  3. package/dist/diagnostics.js +113 -4
  4. package/dist/runtime/mcp-runtime.js +43 -0
  5. package/dist/server/docs.js +11 -10
  6. package/dist/server/json-schema-to-zod.js +73 -2
  7. package/dist/server/session.js +33 -15
  8. package/dist/server/tool-registration.js +35 -59
  9. package/dist/server/tools-runtime.js +52 -2
  10. package/dist/server/tools.js +19 -5
  11. package/dist/server/transport.js +9 -5
  12. package/dist/tools/autopilot-generate.js +37 -646
  13. package/dist/tools/autopilot-test-compat.js +88 -0
  14. package/dist/tools/autopilot-test-parsers.js +120 -0
  15. package/dist/tools/check-config.js +67 -0
  16. package/dist/tools/check-format.js +92 -0
  17. package/dist/tools/check-impact.js +45 -0
  18. package/dist/tools/check-prolog.js +51 -0
  19. package/dist/tools/check.js +13 -190
  20. package/dist/tools/coverage.js +11 -25
  21. package/dist/tools/delete.js +5 -112
  22. package/dist/tools/discovery-adapter.js +23 -0
  23. package/dist/tools/entity-query.js +1 -111
  24. package/dist/tools/find-gaps.js +11 -26
  25. package/dist/tools/graph.js +11 -24
  26. package/dist/tools/model-requirement.js +8 -347
  27. package/dist/tools/mutation-context.js +28 -0
  28. package/dist/tools/query-plan-safety.js +58 -0
  29. package/dist/tools/query.js +5 -50
  30. package/dist/tools/relationship-validation.js +11 -0
  31. package/dist/tools/search.js +4 -37
  32. package/dist/tools/semantic-advisor.js +2 -40
  33. package/dist/tools/skills.js +25 -47
  34. package/dist/tools/sparql.js +12 -93
  35. package/dist/tools/status.js +5 -19
  36. package/dist/tools/suggest-predicates.js +11 -2448
  37. package/dist/tools/upsert.js +21 -794
  38. package/dist/tools/validate-upsert.js +16 -40
  39. package/dist/tools-config.js +75 -764
  40. package/package.json +4 -3
  41. package/dist/semantic-advisor/analyze-prose.js +0 -1367
  42. package/dist/semantic-advisor/prose-coverage-evaluator.js +0 -66
  43. /package/dist/{semantic-advisor/types.js → tools/check-types.js} +0 -0
@@ -1,3 +1,4 @@
1
+ import { getSpec } from "kibi-cli/operations";
1
2
  // implements REQ-002, REQ-013
2
3
  export function registerConfiguredTools(server, runtime, registerTool) {
3
4
  const toolDef = (name) => {
@@ -6,9 +7,23 @@ export function registerConfiguredTools(server, runtime, registerTool) {
6
7
  throw new Error(`Unknown tool: ${name}`);
7
8
  return t;
8
9
  };
9
- const register = ({ name, handler }) => {
10
+ const prologFor = (context) => {
11
+ const prolog = runtime.operationRuntime.sessionProlog(context);
12
+ if (!prolog) {
13
+ throw new Error("Operation requires a session Prolog process");
14
+ }
15
+ return prolog;
16
+ };
17
+ const register = ({ name, execute }) => {
10
18
  const definition = toolDef(name);
11
- registerTool(server, name, definition.description, definition.inputSchema, handler, runtime);
19
+ const publicSpec = getSpec(name);
20
+ const spec = {
21
+ name,
22
+ effects: publicSpec.effects,
23
+ requiresProlog: publicSpec.requiresProlog,
24
+ execute: (args, context) => execute(context, args),
25
+ };
26
+ registerTool(server, name, definition.description, definition.inputSchema, async () => undefined, runtime, spec, definition.annotations);
12
27
  };
13
28
  // INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
14
29
  // bridge the generic ToolHandler (which receives Record<string, unknown>) to the
@@ -16,113 +31,74 @@ export function registerConfiguredTools(server, runtime, registerTool) {
16
31
  // (via jsonSchemaToZod) before the handler is invoked, so the casts are safe at runtime.
17
32
  register({
18
33
  name: "kb_query",
19
- handler: async (args) => {
20
- const prolog = await runtime.ensureProlog();
21
- return runtime.handleKbQuery(prolog, args);
22
- },
34
+ execute: async (context, args) => runtime.handleKbQuery(prologFor(context), args),
23
35
  });
24
36
  register({
25
37
  name: "kb_search",
26
- handler: async (args) => {
27
- const prolog = await runtime.ensureProlog();
28
- return runtime.handleKbSearch(prolog, args);
29
- },
38
+ execute: async (context, args) => runtime.handleKbSearch(prologFor(context), args),
30
39
  });
31
40
  register({
32
41
  name: "kb_status",
33
- handler: async (args) => {
34
- const prolog = await runtime.ensureProlog();
35
- return runtime.handleKbStatus(prolog, args);
36
- },
42
+ execute: async (context, args) => runtime.handleKbStatus(prologFor(context), args),
37
43
  });
38
44
  register({
39
45
  name: "kb_skills_list",
40
- handler: async (args) => runtime.handleKbSkillsList(args),
46
+ execute: async (_context, args) => runtime.handleKbSkillsList(args),
41
47
  });
42
48
  register({
43
49
  name: "kb_skills_load",
44
- handler: async (args) => runtime.handleKbSkillsLoad(args),
50
+ execute: async (_context, args) => runtime.handleKbSkillsLoad(args),
45
51
  });
46
52
  register({
47
53
  name: "kb_skills_read",
48
- handler: async (args) => runtime.handleKbSkillsRead(args),
54
+ execute: async (_context, args) => runtime.handleKbSkillsRead(args),
49
55
  });
50
56
  register({
51
57
  name: "kb_find_gaps",
52
- handler: async (args) => {
53
- const prolog = await runtime.ensureProlog();
54
- return runtime.handleKbFindGaps(prolog, args);
55
- },
58
+ execute: async (context, args) => runtime.handleKbFindGaps(prologFor(context), args),
56
59
  });
57
60
  register({
58
61
  name: "kb_coverage",
59
- handler: async (args) => {
60
- const prolog = await runtime.ensureProlog();
61
- return runtime.handleKbCoverage(prolog, args);
62
- },
62
+ execute: async (context, args) => runtime.handleKbCoverage(prologFor(context), args),
63
63
  });
64
64
  register({
65
65
  name: "kb_graph",
66
- handler: async (args) => {
67
- const prolog = await runtime.ensureProlog();
68
- return runtime.handleKbGraph(prolog, args);
69
- },
66
+ execute: async (context, args) => runtime.handleKbGraph(prologFor(context), args),
70
67
  });
71
68
  register({
72
69
  name: "kb_sparql_remote",
73
- handler: async (args) => {
74
- const prolog = await runtime.ensureProlog();
75
- return runtime.handleSparql(prolog, args);
76
- },
70
+ execute: async (context, args) => runtime.handleSparql(args, context),
77
71
  });
78
72
  register({
79
73
  name: "kb_semantic_advisor",
80
- handler: async (args) => runtime.handleKbSemanticAdvisor(args),
74
+ execute: async (_context, args) => runtime.handleKbSemanticAdvisor(args),
81
75
  });
82
76
  register({
83
77
  name: "kb_upsert",
84
- handler: async (args) => {
85
- const prolog = await runtime.ensureProlog();
86
- return runtime.handleKbUpsert(prolog, args);
87
- },
78
+ execute: async (context, args) => runtime.handleKbUpsert(prologFor(context), args),
88
79
  });
89
80
  register({
90
81
  name: "kb_validate_upsert",
91
- handler: async (args) => runtime.handleKbValidateUpsert(args),
82
+ execute: async (context, args) => runtime.handleKbValidateUpsert(prologFor(context), args),
92
83
  });
93
84
  register({
94
85
  name: "kb_delete",
95
- handler: async (args) => {
96
- const prolog = await runtime.ensureProlog();
97
- return runtime.handleKbDelete(prolog, args);
98
- },
86
+ execute: async (context, args) => runtime.handleKbDelete(prologFor(context), args),
99
87
  });
100
88
  register({
101
89
  name: "kb_check",
102
- handler: async (args) => {
103
- const prolog = await runtime.ensureProlog();
104
- return runtime.handleKbCheck(prolog, args);
105
- },
90
+ execute: async (context, args) => runtime.handleKbCheck(prologFor(context), args),
106
91
  });
107
92
  register({
108
93
  name: "kb_model_requirement",
109
- handler: async (args) => {
110
- const prolog = await runtime.ensureProlog();
111
- return runtime.handleKbModelRequirement(prolog, args);
112
- },
94
+ execute: async (context, args) => runtime.handleKbModelRequirement(prologFor(context), args),
113
95
  });
114
96
  register({
115
97
  name: "kb_suggest_predicates",
116
- handler: async (args) => {
117
- const prolog = await runtime.ensureProlog();
118
- return runtime.handleKbSuggestPredicates(prolog, args);
119
- },
98
+ execute: async (context, args) => runtime.handleKbSuggestPredicates(prologFor(context), args),
120
99
  });
121
100
  register({
122
101
  name: "kb_autopilot_generate",
123
- handler: async (args) => {
124
- const prolog = await runtime.ensureProlog();
125
- return runtime.handleKbAutopilotGenerate(prolog, args);
126
- },
102
+ execute: async (context, args) => runtime.handleKbAutopilotGenerate(args, context),
127
103
  });
128
104
  }
@@ -1,4 +1,7 @@
1
+ import { getSpec } from "kibi-cli/operations";
1
2
  import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
3
+ import { isMcpDebugEnabled } from "../env.js";
4
+ import { createMcpRuntime } from "../runtime/mcp-runtime.js";
2
5
  import { TOOLS } from "../tools-config.js";
3
6
  import { handleKbAutopilotGenerate } from "../tools/autopilot-generate.js";
4
7
  import { handleKbCheck } from "../tools/check.js";
@@ -11,15 +14,17 @@ import { handleKbQuery } from "../tools/query.js";
11
14
  import { handleKbSearch } from "../tools/search.js";
12
15
  import { handleKbSemanticAdvisor } from "../tools/semantic-advisor.js";
13
16
  import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
14
- import { handleSparql } from "../tools/sparql.js";
15
17
  import { handleKbStatus } from "../tools/status.js";
16
18
  import { handleKbSuggestPredicates } from "../tools/suggest-predicates.js";
17
19
  import { handleKbUpsert } from "../tools/upsert.js";
18
20
  import { handleKbValidateUpsert } from "../tools/validate-upsert.js";
21
+ import { resolveWorkspaceRoot } from "../workspace.js";
22
+ import { readBranchKbStamp } from "./kb-freshness.js";
19
23
  const defaultToolsServerDeps = {
20
24
  getSessionModule: () => import("./session.js"),
21
25
  };
22
26
  let sessionModulePromise = null;
27
+ const prologPorts = new WeakMap();
23
28
  // implements REQ-008
24
29
  export function _setToolsServerDepsForTests(deps, resetPromise = false) {
25
30
  defaultToolsServerDeps.getSessionModule =
@@ -39,6 +44,50 @@ async function getSessionModule() {
39
44
  sessionModulePromise ??= defaultToolsServerDeps.getSessionModule();
40
45
  return sessionModulePromise;
41
46
  }
47
+ function adaptProlog(prolog) {
48
+ const existing = prologPorts.get(prolog);
49
+ if (existing) {
50
+ return existing;
51
+ }
52
+ let lastResult = null;
53
+ const port = {
54
+ query: async (goal) => {
55
+ lastResult = await prolog.query(goal);
56
+ return lastResult;
57
+ },
58
+ nextSolution: async () => {
59
+ const result = lastResult;
60
+ lastResult = null;
61
+ return result;
62
+ },
63
+ save: () => prolog.query("kb_save"),
64
+ };
65
+ prologPorts.set(prolog, port);
66
+ return port;
67
+ }
68
+ const operationRuntime = createMcpRuntime({
69
+ workspaceRoot: resolveWorkspaceRoot(),
70
+ activeBranchName: async () => (await getSessionModule()).activeBranchName,
71
+ attachedBranchKbPath: async () => (await getSessionModule()).attachedBranchKbPath,
72
+ ensureProlog: async () => (await getSessionModule()).ensureProlog(),
73
+ adaptProlog,
74
+ net: { fetch: (input, init) => globalThis.fetch(input, init) },
75
+ refreshAttachedBranchStamp: async () => {
76
+ const session = await getSessionModule();
77
+ const kbPath = session.attachedBranchKbPath;
78
+ if (kbPath) {
79
+ try {
80
+ session.updateAttachedBranchStamp(await readBranchKbStamp(kbPath));
81
+ }
82
+ catch (error) {
83
+ const message = error instanceof Error ? error.message : String(error);
84
+ if (isMcpDebugEnabled()) {
85
+ console.warn("[KIBI-MCP] Attached branch stamp refresh failed:", message);
86
+ }
87
+ }
88
+ }
89
+ },
90
+ });
42
91
  export const DEFAULT_TOOLS_RUNTIME = {
43
92
  diagnosticModeEnabled: () => DIAGNOSTIC_MODE_ENABLED,
44
93
  appendUsageLogLine,
@@ -55,12 +104,13 @@ export const DEFAULT_TOOLS_RUNTIME = {
55
104
  inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
56
105
  isShuttingDown: async () => (await getSessionModule()).isShuttingDown,
57
106
  prologProcess: async () => (await getSessionModule()).prologProcess,
107
+ operationRuntime,
58
108
  handleKbCheck,
59
109
  handleKbCoverage,
60
110
  handleKbDelete,
61
111
  handleKbFindGaps,
62
112
  handleKbGraph,
63
- handleSparql,
113
+ handleSparql: (args, context) => getSpec("kb_sparql_remote").execute(args, context),
64
114
  handleKbQuery,
65
115
  handleKbSearch,
66
116
  handleKbStatus,
@@ -16,6 +16,7 @@
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
18
  import process from "node:process";
19
+ import { executeOperation, } from "kibi-cli/operations/runtime-types";
19
20
  import { isMcpDebugEnabled } from "../env.js";
20
21
  import { appendDiagnosticErrorUsage, appendDiagnosticSuccessUsage, } from "./diagnostic-usage.js";
21
22
  import { jsonSchemaToZod } from "./json-schema-to-zod.js";
@@ -73,7 +74,7 @@ export function addTool(server, name, description, inputSchema, handler,
73
74
  // INTENTIONAL: DEFAULT_TOOLS_RUNTIME is typed as ToolsRuntime<PrologProcess>; the
74
75
  // generic TProlog parameter exists so tests can inject a mock type. The cast is safe
75
76
  // because the runtime object satisfies the full ToolsRuntime contract at runtime.
76
- runtime = DEFAULT_TOOLS_RUNTIME) {
77
+ runtime = DEFAULT_TOOLS_RUNTIME, spec, annotations) {
77
78
  const wrappedHandler = async (args) => {
78
79
  const startedAt = new Date();
79
80
  const diagnosticModeEnabled = runtime.diagnosticModeEnabled();
@@ -100,21 +101,30 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
100
101
  }
101
102
  // Track the handler promise in inFlightRequests Map
102
103
  const trackedRequests = await runtime.inFlightRequests();
103
- const handlerPromise = handler(businessArgs);
104
+ const controller = new AbortController();
105
+ const operationSpec = spec ?? {
106
+ name,
107
+ effects: ["local-read"],
108
+ requiresProlog: false,
109
+ execute: async (input, _context) => handler(input),
110
+ };
111
+ const handlerPromise = executeOperation(runtime.operationRuntime, operationSpec, businessArgs, { signal: controller.signal });
104
112
  trackedRequests.set(requestId, handlerPromise);
105
113
  let resetAttempted = false;
106
114
  let resetSucceeded = false;
107
115
  let resetError = null;
108
116
  try {
109
117
  // Execute handler
110
- const result = await withToolTimeout(name, handlerPromise, async () => {
118
+ const result = await withToolTimeout(name, handlerPromise, async (error) => {
111
119
  resetAttempted = true;
120
+ controller.abort(error);
112
121
  try {
113
122
  await runtime.resetProlog(`tool timeout: ${name}`);
114
123
  resetSucceeded = true;
115
124
  }
116
125
  catch (error) {
117
- resetError = error instanceof Error ? error.message : String(error);
126
+ resetError =
127
+ error instanceof Error ? error.message : String(error);
118
128
  }
119
129
  });
120
130
  // Log usage in diagnostic mode
@@ -163,7 +173,11 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
163
173
  throw new Error(`Tool ${name} failed: ${err.message}`, { cause: err });
164
174
  }
165
175
  };
166
- server.registerTool(name, { description, inputSchema: jsonSchemaToZod(inputSchema) }, wrappedHandler);
176
+ server.registerTool(name, {
177
+ description,
178
+ inputSchema: jsonSchemaToZod(inputSchema),
179
+ ...(annotations ? { annotations } : {}),
180
+ }, wrappedHandler);
167
181
  }
168
182
  // implements REQ-002, REQ-013
169
183
  export function registerAllTools(server,
@@ -23,7 +23,7 @@ function debugLog(...args) {
23
23
  console.error(...args);
24
24
  }
25
25
  }
26
- export function setupTransportHandlers(server, transport) {
26
+ export function setupTransportHandlers(_server, transport) {
27
27
  transport.onerror = (error) => {
28
28
  // Stdio transport surfaces JSON parse / schema validation failures via onerror.
29
29
  // Those errors should not crash the server: emit a JSON-RPC error (id omitted)
@@ -62,11 +62,15 @@ export function setupTransportHandlers(server, transport) {
62
62
  debugLog("[KIBI-MCP] Transport closed");
63
63
  initiateGracefulShutdown(0);
64
64
  };
65
- process.on("SIGTERM", () => {
66
- debugLog("[KIBI-MCP] Received SIGTERM, initiating graceful shutdown");
67
- void initiateGracefulShutdown(0);
68
- });
65
+ for (const signal of ["SIGINT", "SIGTERM"]) {
66
+ process.on(signal, () => {
67
+ debugLog(`[KIBI-MCP] Received ${signal}, initiating graceful shutdown`);
68
+ void initiateGracefulShutdown(0);
69
+ });
70
+ }
69
71
  }
72
+ // implements REQ-002
73
+ // covered_by TEST-mcp-kb-freshness
70
74
  export async function connectTransport(server, transport) {
71
75
  await server.connect(transport);
72
76
  }