kibi-mcp 0.1.6 → 0.2.0
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.
- package/dist/server.js +82 -106
- package/dist/tools/check.js +17 -1
- package/dist/tools/context.js +2 -12
- package/dist/tools-config.js +10 -206
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
import fs from "node:fs";
|
|
18
19
|
import { createRequire } from "node:module";
|
|
19
20
|
/*
|
|
20
21
|
How to apply this header to source files (examples)
|
|
@@ -47,22 +48,14 @@ import process from "node:process";
|
|
|
47
48
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
48
49
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
49
50
|
import { PrologProcess } from "kibi-cli/prolog";
|
|
51
|
+
import { copyCleanSnapshot, getBranchDiagnostic, isValidBranchName, resolveActiveBranch, } from "kibi-cli/public/branch-resolver";
|
|
50
52
|
import { z } from "zod";
|
|
51
53
|
import { loadDefaultEnvFile } from "./env.js";
|
|
52
54
|
import { attachMcpcat } from "./mcpcat.js";
|
|
53
55
|
import { TOOLS } from "./tools-config.js";
|
|
54
|
-
import { handleKbBranchEnsure, handleKbBranchGc, } from "./tools/branch.js";
|
|
55
56
|
import { handleKbCheck } from "./tools/check.js";
|
|
56
|
-
import { handleKbContext } from "./tools/context.js";
|
|
57
|
-
import { handleKbCoverageReport, } from "./tools/coverage-report.js";
|
|
58
57
|
import { handleKbDelete } from "./tools/delete.js";
|
|
59
|
-
import { handleKbDerive } from "./tools/derive.js";
|
|
60
|
-
import { handleKbImpact } from "./tools/impact.js";
|
|
61
|
-
import { handleKbListEntityTypes, handleKbListRelationshipTypes, } from "./tools/list-types.js";
|
|
62
|
-
import { handleKbQueryRelationships, } from "./tools/query-relationships.js";
|
|
63
58
|
import { handleKbQuery } from "./tools/query.js";
|
|
64
|
-
import { handleSuggestSharedFacts, } from "./tools/suggest-shared-facts.js";
|
|
65
|
-
import { handleKbSymbolsRefresh, } from "./tools/symbols.js";
|
|
66
59
|
import { handleKbUpsert } from "./tools/upsert.js";
|
|
67
60
|
import { resolveKbPath, resolveWorkspaceRoot } from "./workspace.js";
|
|
68
61
|
function renderToolsDoc() {
|
|
@@ -93,9 +86,9 @@ const PROMPTS = [
|
|
|
93
86
|
"",
|
|
94
87
|
"- Encode requirements as linked facts: `req --constrains--> fact` plus `req --requires_property--> fact`.",
|
|
95
88
|
"- Reuse canonical fact IDs across requirements; shared constrained facts make contradictions detectable.",
|
|
96
|
-
"- Use
|
|
97
|
-
"- Use
|
|
98
|
-
"-
|
|
89
|
+
"- Use `kb_query` first to confirm current state before any mutation.",
|
|
90
|
+
"- Use `kb_upsert` and `kb_delete` only for intentional, traceable KB changes.",
|
|
91
|
+
"- Run `kb_check` after meaningful mutations to catch integrity issues early.",
|
|
99
92
|
"- Prefer explicit IDs and enum values to avoid invalid parameters.",
|
|
100
93
|
"- Assume every write can affect downstream traceability queries.",
|
|
101
94
|
].join("\n"),
|
|
@@ -108,15 +101,13 @@ const PROMPTS = [
|
|
|
108
101
|
"",
|
|
109
102
|
"Follow this sequence for reliable operation:",
|
|
110
103
|
"",
|
|
111
|
-
"1. **
|
|
112
|
-
"2. **
|
|
113
|
-
"3. **
|
|
114
|
-
"4. **
|
|
115
|
-
"5. **
|
|
116
|
-
"6. **Verify integrity**: Call `kb_check` after mutations.",
|
|
117
|
-
"7. **Assess impact**: Call `kb_impact`, `kb_derive`, or `kb_coverage_report` as needed.",
|
|
104
|
+
"1. **Inspect**: Call `kb_query` to confirm current state before any mutation.",
|
|
105
|
+
"2. **Model requirements as facts**: For new/updated reqs, create/reuse fact entities first, then express req semantics with `constrains` + `requires_property`.",
|
|
106
|
+
"3. **Validate intent**: If creating links, call `kb_query` for both endpoint IDs first.",
|
|
107
|
+
"4. **Mutate**: Call `kb_upsert` for create/update, or `kb_delete` for explicit removals.",
|
|
108
|
+
"5. **Verify integrity**: Call `kb_check` after mutations.",
|
|
118
109
|
"",
|
|
119
|
-
"If a tool returns empty results, do not assume failure. Re-check filters (type, id, tags, sourceFile, or
|
|
110
|
+
"If a tool returns empty results, do not assume failure. Re-check filters (type, id, tags, sourceFile, limit, or offset).",
|
|
120
111
|
].join("\n"),
|
|
121
112
|
},
|
|
122
113
|
{
|
|
@@ -129,10 +120,8 @@ const PROMPTS = [
|
|
|
129
120
|
"",
|
|
130
121
|
"- `kb_upsert` validates entity and relationship payloads against JSON Schema.",
|
|
131
122
|
"- `kb_delete` blocks deletion when dependents still reference the entity.",
|
|
132
|
-
"- `kb_branch_gc` may permanently remove stale branch KB directories when `dry_run` is `false`.",
|
|
133
123
|
"- Relationship and rule names are strict enums; unknown values fail validation.",
|
|
134
|
-
"- Branch
|
|
135
|
-
"- `kb_symbols_refresh` can rewrite the symbols manifest unless `dryRun` is enabled.",
|
|
124
|
+
"- Branch KB setup is automatic at server startup; lifecycle maintenance stays outside the public MCP tool surface.",
|
|
136
125
|
].join("\n"),
|
|
137
126
|
},
|
|
138
127
|
];
|
|
@@ -144,9 +133,8 @@ function registerDocResources() {
|
|
|
144
133
|
"",
|
|
145
134
|
"Scope:",
|
|
146
135
|
"- Entity CRUD-like operations for KB records",
|
|
147
|
-
"-
|
|
148
|
-
"-
|
|
149
|
-
"- Deterministic inference for traceability and impact analysis",
|
|
136
|
+
"- Validation of KB integrity after changes",
|
|
137
|
+
"- Automatic branch-local attachment for the active workspace",
|
|
150
138
|
"",
|
|
151
139
|
"Use this server when you need branch-local, machine-readable project memory.",
|
|
152
140
|
].join("\n");
|
|
@@ -157,7 +145,7 @@ function registerDocResources() {
|
|
|
157
145
|
"",
|
|
158
146
|
"- `-32602 INVALID_PARAMS`: Tool arguments are missing/invalid. Recover by checking enum values and required fields.",
|
|
159
147
|
"- `-32601 METHOD_NOT_FOUND`: Unknown MCP method. Recover by using supported methods (`tools/*`, `prompts/*`, `resources/*`).",
|
|
160
|
-
"- `-32000 PROLOG_QUERY_FAILED`: Prolog query failed. Recover by validating IDs, rule names, and
|
|
148
|
+
"- `-32000 PROLOG_QUERY_FAILED`: Prolog query failed. Recover by validating IDs, rule names, and branch KB availability.",
|
|
161
149
|
"- `VALIDATION_ERROR` message: `kb_upsert` payload failed schema checks. Recover by fixing required fields and enum values.",
|
|
162
150
|
"- Delete blocked by dependents: `kb_delete` detected incoming references. Recover by removing/rewiring relationships first.",
|
|
163
151
|
"- Empty results: filters may be too strict. Recover by loosening type/id/tags/source filters and retrying.",
|
|
@@ -171,20 +159,10 @@ function registerDocResources() {
|
|
|
171
159
|
"3. Reuse the same constrained fact ID across related requirements; vary property facts only when semantics differ",
|
|
172
160
|
'4. `kb_check` with `{ "rules": ["required-fields","no-dangling-refs"] }`',
|
|
173
161
|
"",
|
|
174
|
-
"## Discover requirement coverage gaps",
|
|
175
|
-
'1. `kb_query` with `{ "type": "req", "limit": 20 }`',
|
|
176
|
-
'2. `kb_coverage_report` with `{ "type": "req" }`',
|
|
177
|
-
'3. `kb_derive` with `{ "rule": "coverage_gap" }`',
|
|
178
|
-
"",
|
|
179
162
|
"## Add a requirement and link it to a test",
|
|
180
163
|
"1. `kb_query` for existing IDs to avoid collisions",
|
|
181
164
|
"2. `kb_upsert` with entity payload and `relationships` containing `verified_by`",
|
|
182
165
|
'3. `kb_check` with `{ "rules": ["required-fields","no-dangling-refs"] }`',
|
|
183
|
-
"",
|
|
184
|
-
"## Safe cleanup of stale branch KBs",
|
|
185
|
-
'1. `kb_branch_gc` with `{ "dry_run": true }`',
|
|
186
|
-
"2. Review `structuredContent.stale`",
|
|
187
|
-
'3. `kb_branch_gc` with `{ "dry_run": false }` only when deletion is intended',
|
|
188
166
|
].join("\n");
|
|
189
167
|
return [
|
|
190
168
|
{
|
|
@@ -265,6 +243,22 @@ let activeBranchName = "develop";
|
|
|
265
243
|
let isShuttingDown = false;
|
|
266
244
|
let shutdownTimeout = null;
|
|
267
245
|
const inFlightRequests = new Map();
|
|
246
|
+
function ensureBranchKbExists(workspaceRoot, branch) {
|
|
247
|
+
if (!isValidBranchName(branch)) {
|
|
248
|
+
throw new Error(`Invalid branch name: ${branch}`);
|
|
249
|
+
}
|
|
250
|
+
const branchPath = resolveKbPath(workspaceRoot, branch);
|
|
251
|
+
if (fs.existsSync(branchPath)) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const templateBranch = ["develop", "main"].find((candidate) => candidate !== branch &&
|
|
255
|
+
fs.existsSync(resolveKbPath(workspaceRoot, candidate)));
|
|
256
|
+
if (!templateBranch) {
|
|
257
|
+
throw new Error(`No template branch KB found for '${branch}'. Expected '.kb/branches/develop' or '.kb/branches/main'.`);
|
|
258
|
+
}
|
|
259
|
+
// Use clean snapshot copy that excludes volatile artifacts
|
|
260
|
+
copyCleanSnapshot(resolveKbPath(workspaceRoot, templateBranch), branchPath);
|
|
261
|
+
}
|
|
268
262
|
function debugLog(...args) {
|
|
269
263
|
if (process.env.KIBI_MCP_DEBUG) {
|
|
270
264
|
console.error(...args);
|
|
@@ -316,9 +310,55 @@ async function initiateGracefulShutdown(exitCode = 0) {
|
|
|
316
310
|
process.exit(exitCode);
|
|
317
311
|
}
|
|
318
312
|
async function ensureProlog() {
|
|
313
|
+
const workspaceRoot = resolveWorkspaceRoot();
|
|
314
|
+
// Determine target branch: respect KIBI_BRANCH override or resolve from git
|
|
315
|
+
const envBranch = process.env.KIBI_BRANCH?.trim();
|
|
316
|
+
let targetBranch;
|
|
317
|
+
if (envBranch) {
|
|
318
|
+
// KIBI_BRANCH override is set - use it without re-resolving from git
|
|
319
|
+
if (!isValidBranchName(envBranch)) {
|
|
320
|
+
throw new Error(`Invalid branch name from KIBI_BRANCH: '${envBranch}'`);
|
|
321
|
+
}
|
|
322
|
+
targetBranch = envBranch;
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
// No override - resolve active branch from git (may change between requests)
|
|
326
|
+
const branchResult = resolveActiveBranch(workspaceRoot);
|
|
327
|
+
if ("error" in branchResult) {
|
|
328
|
+
const diagnostic = getBranchDiagnostic(undefined, branchResult.error);
|
|
329
|
+
console.error(`[KIBI-MCP] ${diagnostic}`);
|
|
330
|
+
throw new Error(`Failed to resolve active branch: ${branchResult.error}`);
|
|
331
|
+
}
|
|
332
|
+
targetBranch = branchResult.branch;
|
|
333
|
+
}
|
|
334
|
+
// Check if we need to switch branches
|
|
319
335
|
if (isInitialized && prologProcess?.isRunning()) {
|
|
336
|
+
if (targetBranch === activeBranchName) {
|
|
337
|
+
// Still on the same branch - return existing connection
|
|
338
|
+
return prologProcess;
|
|
339
|
+
}
|
|
340
|
+
// Branch changed - need to detach and re-attach
|
|
341
|
+
debugLog(`[KIBI-MCP] Branch changed: ${activeBranchName} -> ${targetBranch}`);
|
|
342
|
+
// Detach from old KB
|
|
343
|
+
const detachResult = await prologProcess.query("kb_detach");
|
|
344
|
+
if (!detachResult.success) {
|
|
345
|
+
debugLog(`[KIBI-MCP] Warning: failed to detach from old KB: ${detachResult.error || "Unknown error"}`);
|
|
346
|
+
// Continue anyway - we'll try to attach to the new KB
|
|
347
|
+
}
|
|
348
|
+
// Ensure new branch KB exists
|
|
349
|
+
ensureBranchKbExists(workspaceRoot, targetBranch);
|
|
350
|
+
const newKbPath = resolveKbPath(workspaceRoot, targetBranch);
|
|
351
|
+
// Attach to new branch KB
|
|
352
|
+
const attachResult = await prologProcess.query(`kb_attach('${newKbPath}')`);
|
|
353
|
+
if (!attachResult.success) {
|
|
354
|
+
throw new Error(`Failed to attach to new branch KB: ${attachResult.error || "Unknown error"}`);
|
|
355
|
+
}
|
|
356
|
+
activeBranchName = targetBranch;
|
|
357
|
+
debugLog(`[KIBI-MCP] Re-attached to branch: ${targetBranch}`);
|
|
358
|
+
debugLog(`[KIBI-MCP] KB path: ${newKbPath}`);
|
|
320
359
|
return prologProcess;
|
|
321
360
|
}
|
|
361
|
+
// First initialization
|
|
322
362
|
debugLog("[KIBI-MCP] Initializing Prolog process...");
|
|
323
363
|
prologProcess = new PrologProcess({ timeout: 120000 });
|
|
324
364
|
await prologProcess.start();
|
|
@@ -355,33 +395,12 @@ async function ensureProlog() {
|
|
|
355
395
|
debugLog("[KIBI-MCP] Failed to create require() for debug lookup:", err.message);
|
|
356
396
|
}
|
|
357
397
|
}
|
|
358
|
-
const workspaceRoot = resolveWorkspaceRoot();
|
|
359
|
-
let branch = process.env.KIBI_BRANCH || "develop";
|
|
360
|
-
let gitBranch;
|
|
361
|
-
if (!process.env.KIBI_BRANCH) {
|
|
362
|
-
try {
|
|
363
|
-
const { execSync } = await import("node:child_process");
|
|
364
|
-
const detected = execSync("git branch --show-current", {
|
|
365
|
-
cwd: workspaceRoot,
|
|
366
|
-
encoding: "utf8",
|
|
367
|
-
timeout: 3000,
|
|
368
|
-
}).trim();
|
|
369
|
-
if (detected) {
|
|
370
|
-
gitBranch = detected === "master" ? "develop" : detected;
|
|
371
|
-
branch = gitBranch;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
catch {
|
|
375
|
-
// fall back to develop
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
398
|
debugLog("[KIBI-MCP] Branch selection:");
|
|
379
399
|
debugLog(`[KIBI-MCP] KIBI_BRANCH env: ${process.env.KIBI_BRANCH || "not set"}`);
|
|
380
|
-
debugLog(`[KIBI-MCP]
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const kbPath = resolveKbPath(workspaceRoot, branch);
|
|
400
|
+
debugLog(`[KIBI-MCP] Resolved branch: ${targetBranch}`);
|
|
401
|
+
activeBranchName = targetBranch;
|
|
402
|
+
ensureBranchKbExists(workspaceRoot, targetBranch);
|
|
403
|
+
const kbPath = resolveKbPath(workspaceRoot, targetBranch);
|
|
385
404
|
const attachResult = await prologProcess.query(`kb_attach('${kbPath}')`);
|
|
386
405
|
if (!attachResult.success) {
|
|
387
406
|
throw new Error(`Failed to attach KB: ${attachResult.error || "Unknown error"}`);
|
|
@@ -537,7 +556,7 @@ function addTool(server, name, description, inputSchema, handler) {
|
|
|
537
556
|
}
|
|
538
557
|
export async function startServer() {
|
|
539
558
|
loadDefaultEnvFile();
|
|
540
|
-
const server = new McpServer({ name: "kibi-mcp", version: "0.
|
|
559
|
+
const server = new McpServer({ name: "kibi-mcp", version: "0.2.0" });
|
|
541
560
|
attachMcpcat(server);
|
|
542
561
|
for (const prompt of PROMPTS) {
|
|
543
562
|
server.prompt(prompt.name, prompt.description, async () => ({
|
|
@@ -582,49 +601,6 @@ export async function startServer() {
|
|
|
582
601
|
const prolog = await ensureProlog();
|
|
583
602
|
return handleKbCheck(prolog, args);
|
|
584
603
|
});
|
|
585
|
-
addTool(server, "kb_branch_ensure", toolDef("kb_branch_ensure").description, toolDef("kb_branch_ensure").inputSchema, async (args) => {
|
|
586
|
-
const prolog = await ensureProlog();
|
|
587
|
-
return handleKbBranchEnsure(prolog, args);
|
|
588
|
-
});
|
|
589
|
-
addTool(server, "kb_branch_gc", toolDef("kb_branch_gc").description, toolDef("kb_branch_gc").inputSchema, async (args) => {
|
|
590
|
-
const prolog = await ensureProlog();
|
|
591
|
-
return handleKbBranchGc(prolog, args);
|
|
592
|
-
});
|
|
593
|
-
addTool(server, "kb_query_relationships", toolDef("kb_query_relationships").description, toolDef("kb_query_relationships").inputSchema, async (args) => {
|
|
594
|
-
const prolog = await ensureProlog();
|
|
595
|
-
return handleKbQueryRelationships(prolog, args);
|
|
596
|
-
});
|
|
597
|
-
addTool(server, "kb_derive", toolDef("kb_derive").description, toolDef("kb_derive").inputSchema, async (args) => {
|
|
598
|
-
const prolog = await ensureProlog();
|
|
599
|
-
return handleKbDerive(prolog, args);
|
|
600
|
-
});
|
|
601
|
-
addTool(server, "kb_impact", toolDef("kb_impact").description, toolDef("kb_impact").inputSchema, async (args) => {
|
|
602
|
-
const prolog = await ensureProlog();
|
|
603
|
-
return handleKbImpact(prolog, args);
|
|
604
|
-
});
|
|
605
|
-
addTool(server, "kb_coverage_report", toolDef("kb_coverage_report").description, toolDef("kb_coverage_report").inputSchema, async (args) => {
|
|
606
|
-
const prolog = await ensureProlog();
|
|
607
|
-
return handleKbCoverageReport(prolog, args);
|
|
608
|
-
});
|
|
609
|
-
addTool(server, "kb_symbols_refresh", toolDef("kb_symbols_refresh").description, toolDef("kb_symbols_refresh").inputSchema, async (args) => handleKbSymbolsRefresh(args));
|
|
610
|
-
addTool(server, "kb_list_entity_types", toolDef("kb_list_entity_types").description, toolDef("kb_list_entity_types").inputSchema, handleKbListEntityTypes);
|
|
611
|
-
addTool(server, "kb_list_relationship_types", toolDef("kb_list_relationship_types").description, toolDef("kb_list_relationship_types").inputSchema, handleKbListRelationshipTypes);
|
|
612
|
-
addTool(server, "kbcontext", toolDef("kbcontext").description, toolDef("kbcontext").inputSchema, async (args) => {
|
|
613
|
-
const prolog = await ensureProlog();
|
|
614
|
-
return handleKbContext(prolog, args, activeBranchName);
|
|
615
|
-
});
|
|
616
|
-
addTool(server, "get_help", toolDef("get_help").description, toolDef("get_help").inputSchema, async (args) => {
|
|
617
|
-
const topic = typeof args?.topic === "string" ? args.topic : undefined;
|
|
618
|
-
const text = getHelpText(topic);
|
|
619
|
-
return {
|
|
620
|
-
content: [{ type: "text", text }],
|
|
621
|
-
structuredContent: { topic: topic ?? "overview" },
|
|
622
|
-
};
|
|
623
|
-
});
|
|
624
|
-
addTool(server, "analyze_shared_facts", toolDef("analyze_shared_facts").description, toolDef("analyze_shared_facts").inputSchema, async (args) => {
|
|
625
|
-
const prolog = await ensureProlog();
|
|
626
|
-
return handleSuggestSharedFacts(prolog, args);
|
|
627
|
-
});
|
|
628
604
|
const transport = new StdioServerTransport();
|
|
629
605
|
transport.onerror = (error) => {
|
|
630
606
|
// Stdio transport surfaces JSON parse / schema validation failures via onerror.
|
package/dist/tools/check.js
CHANGED
|
@@ -44,6 +44,15 @@
|
|
|
44
44
|
*/
|
|
45
45
|
import * as path from "node:path";
|
|
46
46
|
import { parsePairList } from "./prolog-list.js";
|
|
47
|
+
function formatDiagnosticsForMcp(diagnostics) {
|
|
48
|
+
return diagnostics.map((d) => ({
|
|
49
|
+
category: d.category,
|
|
50
|
+
severity: d.severity,
|
|
51
|
+
message: d.message,
|
|
52
|
+
file: d.file,
|
|
53
|
+
suggestion: d.suggestion,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
47
56
|
/**
|
|
48
57
|
* Handle kb_check tool calls - run validation rules on the KB
|
|
49
58
|
* Reuses validation logic from CLI check command
|
|
@@ -77,7 +86,13 @@ export async function handleKbCheck(prolog, args) {
|
|
|
77
86
|
if (rulesToRun.includes("symbol-coverage")) {
|
|
78
87
|
violations.push(...(await checkSymbolCoverage(prolog)));
|
|
79
88
|
}
|
|
80
|
-
|
|
89
|
+
const diagnostics = violations.map((v) => ({
|
|
90
|
+
category: "SYNC_ERROR",
|
|
91
|
+
severity: "error",
|
|
92
|
+
message: v.description,
|
|
93
|
+
file: v.source,
|
|
94
|
+
suggestion: v.suggestion,
|
|
95
|
+
}));
|
|
81
96
|
const summary = violations.length === 0
|
|
82
97
|
? "No violations found"
|
|
83
98
|
: `${violations.length} violations found`;
|
|
@@ -91,6 +106,7 @@ export async function handleKbCheck(prolog, args) {
|
|
|
91
106
|
structuredContent: {
|
|
92
107
|
violations,
|
|
93
108
|
count: violations.length,
|
|
109
|
+
diagnostics: formatDiagnosticsForMcp(diagnostics),
|
|
94
110
|
},
|
|
95
111
|
};
|
|
96
112
|
}
|
package/dist/tools/context.js
CHANGED
|
@@ -15,18 +15,8 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
-
export async function handleKbContext(prolog, args
|
|
19
|
-
const { sourceFile
|
|
20
|
-
if (branch && activeBranch && branch !== activeBranch) {
|
|
21
|
-
return {
|
|
22
|
-
content: [
|
|
23
|
-
{
|
|
24
|
-
type: "text",
|
|
25
|
-
text: `Error: branch parameter is not supported server-side; set KIBI_BRANCH at startup or restart server on the desired branch. (Requested: ${branch}, Active: ${activeBranch})`,
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
};
|
|
29
|
-
}
|
|
18
|
+
export async function handleKbContext(prolog, args) {
|
|
19
|
+
const { sourceFile } = args;
|
|
30
20
|
try {
|
|
31
21
|
const safeSource = sourceFile.replace(/'/g, "\\'");
|
|
32
22
|
const entityGoal = `findall([Id,Type,Props], (kb_entities_by_source('${safeSource}', SourceIds), member(Id, SourceIds), kb_entity(Id, Type, Props)), Results)`;
|
package/dist/tools-config.js
CHANGED
|
@@ -234,215 +234,19 @@ export const TOOLS = [
|
|
|
234
234
|
properties: {
|
|
235
235
|
rules: {
|
|
236
236
|
type: "array",
|
|
237
|
-
items: {
|
|
237
|
+
items: {
|
|
238
|
+
type: "string",
|
|
239
|
+
enum: [
|
|
240
|
+
"must-priority-coverage",
|
|
241
|
+
"no-dangling-refs",
|
|
242
|
+
"no-cycles",
|
|
243
|
+
"required-fields",
|
|
244
|
+
"symbol-coverage",
|
|
245
|
+
],
|
|
246
|
+
},
|
|
238
247
|
description: "Optional rule subset. Allowed: must-priority-coverage, no-dangling-refs, no-cycles, required-fields, symbol-coverage. If omitted, server runs all.",
|
|
239
248
|
},
|
|
240
249
|
},
|
|
241
250
|
},
|
|
242
251
|
},
|
|
243
|
-
{
|
|
244
|
-
name: "kb_branch_ensure",
|
|
245
|
-
description: "Ensure a branch KB exists, creating it from develop when missing. Use when targeting non-develop branches. Do not use to switch git branches. Side effects: creates .kb/branches/<branch>.",
|
|
246
|
-
inputSchema: {
|
|
247
|
-
type: "object",
|
|
248
|
-
required: ["branch"],
|
|
249
|
-
properties: {
|
|
250
|
-
branch: {
|
|
251
|
-
type: "string",
|
|
252
|
-
description: "Required git branch name. Example: 'feature/auth-hardening'. Path traversal patterns are rejected.",
|
|
253
|
-
},
|
|
254
|
-
},
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
name: "kb_branch_gc",
|
|
259
|
-
description: "Find or delete stale branch KB directories not present in git. Use for repository hygiene. Do not use if you need historical branch KBs. Side effects: can delete branch KB folders when dry_run is false.",
|
|
260
|
-
inputSchema: {
|
|
261
|
-
type: "object",
|
|
262
|
-
properties: {
|
|
263
|
-
dry_run: {
|
|
264
|
-
type: "boolean",
|
|
265
|
-
default: true,
|
|
266
|
-
description: "Optional safety flag. true = report only; false = delete stale branch KBs. Default: true.",
|
|
267
|
-
},
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
name: "kb_query_relationships",
|
|
273
|
-
description: "Read relationship edges with optional from/to/type filters. Use for traceability traversal. Do not use to create links. No mutation side effects.",
|
|
274
|
-
inputSchema: {
|
|
275
|
-
type: "object",
|
|
276
|
-
properties: {
|
|
277
|
-
from: {
|
|
278
|
-
type: "string",
|
|
279
|
-
description: "Optional source entity ID filter. Example: 'REQ-001'.",
|
|
280
|
-
},
|
|
281
|
-
to: {
|
|
282
|
-
type: "string",
|
|
283
|
-
description: "Optional target entity ID filter. Example: 'TEST-010'.",
|
|
284
|
-
},
|
|
285
|
-
type: {
|
|
286
|
-
type: "string",
|
|
287
|
-
enum: [
|
|
288
|
-
"depends_on",
|
|
289
|
-
"specified_by",
|
|
290
|
-
"verified_by",
|
|
291
|
-
"validates",
|
|
292
|
-
"implements",
|
|
293
|
-
"covered_by",
|
|
294
|
-
"constrained_by",
|
|
295
|
-
"constrains",
|
|
296
|
-
"requires_property",
|
|
297
|
-
"guards",
|
|
298
|
-
"publishes",
|
|
299
|
-
"consumes",
|
|
300
|
-
"supersedes",
|
|
301
|
-
"relates_to",
|
|
302
|
-
],
|
|
303
|
-
description: "Optional relationship type filter. Allowed enum values only. Example: 'implements'.",
|
|
304
|
-
},
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
name: "kb_derive",
|
|
310
|
-
description: "Run deterministic inference predicates and return rows. Use for impact, coverage, and consistency analysis. Do not use for entity CRUD. No mutation side effects.",
|
|
311
|
-
inputSchema: {
|
|
312
|
-
type: "object",
|
|
313
|
-
required: ["rule"],
|
|
314
|
-
properties: {
|
|
315
|
-
rule: {
|
|
316
|
-
type: "string",
|
|
317
|
-
enum: [
|
|
318
|
-
"transitively_implements",
|
|
319
|
-
"transitively_depends",
|
|
320
|
-
"impacted_by_change",
|
|
321
|
-
"affected_symbols",
|
|
322
|
-
"coverage_gap",
|
|
323
|
-
"untested_symbols",
|
|
324
|
-
"stale",
|
|
325
|
-
"orphaned",
|
|
326
|
-
"conflicting",
|
|
327
|
-
"deprecated_still_used",
|
|
328
|
-
"current_adr",
|
|
329
|
-
"adr_chain",
|
|
330
|
-
"superseded_by",
|
|
331
|
-
"domain_contradictions",
|
|
332
|
-
],
|
|
333
|
-
description: "Required inference rule name. Allowed values are the enum options. Example: 'coverage_gap'.",
|
|
334
|
-
},
|
|
335
|
-
params: {
|
|
336
|
-
type: "object",
|
|
337
|
-
description: "Optional rule-specific parameters. Example: { changed: 'REQ-001' } for impacted_by_change.",
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
{
|
|
343
|
-
name: "kb_impact",
|
|
344
|
-
description: "Return entities impacted by a changed entity ID. Use for quick change blast radius checks. Do not use for general querying. No mutation side effects.",
|
|
345
|
-
inputSchema: {
|
|
346
|
-
type: "object",
|
|
347
|
-
required: ["entity"],
|
|
348
|
-
properties: {
|
|
349
|
-
entity: {
|
|
350
|
-
type: "string",
|
|
351
|
-
description: "Required changed entity ID. Example: 'REQ-001'.",
|
|
352
|
-
},
|
|
353
|
-
},
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
name: "kb_coverage_report",
|
|
358
|
-
description: "Compute aggregate traceability coverage for requirements and/or symbols. Use for health snapshots. Do not use for raw entity dumps. No mutation side effects.",
|
|
359
|
-
inputSchema: {
|
|
360
|
-
type: "object",
|
|
361
|
-
properties: {
|
|
362
|
-
type: {
|
|
363
|
-
type: "string",
|
|
364
|
-
enum: ["req", "symbol"],
|
|
365
|
-
description: "Optional focus scope: 'req' or 'symbol'. Omit to include both.",
|
|
366
|
-
},
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
{
|
|
371
|
-
name: "kb_symbols_refresh",
|
|
372
|
-
description: "Refresh generated symbol coordinates in the symbols manifest. Use after refactors that move symbols. Do not use for semantic edits. Side effects: may rewrite symbols.yaml unless dryRun is true.",
|
|
373
|
-
inputSchema: {
|
|
374
|
-
type: "object",
|
|
375
|
-
properties: {
|
|
376
|
-
dryRun: {
|
|
377
|
-
type: "boolean",
|
|
378
|
-
default: false,
|
|
379
|
-
description: "Optional preview mode. true = report only, false = apply file updates. Default: false.",
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
},
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
name: "kb_list_entity_types",
|
|
386
|
-
description: "List supported entity type names. Use when building valid tool arguments. Do not use for entity data retrieval. No mutation side effects.",
|
|
387
|
-
inputSchema: { type: "object", properties: {} },
|
|
388
|
-
},
|
|
389
|
-
{
|
|
390
|
-
name: "kb_list_relationship_types",
|
|
391
|
-
description: "List supported relationship type names. Use before asserting or filtering relationships. Do not use for graph traversal. No mutation side effects.",
|
|
392
|
-
inputSchema: { type: "object", properties: {} },
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
name: "kbcontext",
|
|
396
|
-
description: "Return KB entities linked to a source file plus first-hop relationships. Use for file-centric traceability. Do not use for cross-repo search. No mutation side effects.",
|
|
397
|
-
inputSchema: {
|
|
398
|
-
type: "object",
|
|
399
|
-
required: ["sourceFile"],
|
|
400
|
-
properties: {
|
|
401
|
-
sourceFile: {
|
|
402
|
-
type: "string",
|
|
403
|
-
description: "Required source path substring. Example: 'src/auth/login.ts'.",
|
|
404
|
-
},
|
|
405
|
-
branch: {
|
|
406
|
-
type: "string",
|
|
407
|
-
description: "Optional branch hint for clients. Must match the server's active branch or will return an error.",
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
name: "get_help",
|
|
414
|
-
description: "Returns documentation for this MCP server. Call this first if you are unsure how to proceed or which tool to use. Available topics: overview, tools, workflow, constraints, examples, errors.",
|
|
415
|
-
inputSchema: {
|
|
416
|
-
type: "object",
|
|
417
|
-
properties: {
|
|
418
|
-
topic: {
|
|
419
|
-
type: "string",
|
|
420
|
-
enum: [
|
|
421
|
-
"overview",
|
|
422
|
-
"tools",
|
|
423
|
-
"workflow",
|
|
424
|
-
"constraints",
|
|
425
|
-
"examples",
|
|
426
|
-
"errors",
|
|
427
|
-
"branching",
|
|
428
|
-
],
|
|
429
|
-
description: "Optional documentation section. Omit to return overview. Example: 'workflow'.",
|
|
430
|
-
},
|
|
431
|
-
},
|
|
432
|
-
},
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
name: "analyze_shared_facts",
|
|
436
|
-
description: "Analyze requirements and suggest shared domain facts for extraction. LLMs call this to identify missed semantic opportunities before upserting. Lightweight heuristic: finds overlapping capitalized terms and repeated phrases across requirements.",
|
|
437
|
-
inputSchema: {
|
|
438
|
-
type: "object",
|
|
439
|
-
properties: {
|
|
440
|
-
min_frequency: {
|
|
441
|
-
type: "number",
|
|
442
|
-
default: 2,
|
|
443
|
-
description: "Minimum frequency threshold for shared concepts. Default: 2. Example: 3 to only show concepts mentioned in 3+ requirements.",
|
|
444
|
-
},
|
|
445
|
-
},
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
252
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
6
6
|
"ajv": "^8.18.0",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"fast-glob": "^3.2.12",
|
|
10
10
|
"gray-matter": "^4.0.3",
|
|
11
11
|
"js-yaml": "^4.1.0",
|
|
12
|
-
"kibi-cli": "^0.
|
|
12
|
+
"kibi-cli": "^0.2.0",
|
|
13
13
|
"kibi-core": "^0.1.6",
|
|
14
14
|
"mcpcat": "^0.1.12",
|
|
15
15
|
"ts-morph": "^23.0.0",
|