kibi-mcp 0.17.4 → 0.19.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/diagnostics-helpers.js +159 -0
- package/dist/diagnostics.js +117 -100
- package/dist/semantic-advisor/analyze-prose.js +25 -0
- package/dist/server/diagnostic-usage.js +74 -0
- package/dist/server/docs.js +7 -6
- package/dist/server/json-schema-to-zod.js +104 -0
- package/dist/server/tool-registration.js +131 -0
- package/dist/server/tool-types.js +1 -0
- package/dist/server/tools-runtime.js +76 -0
- package/dist/server/tools.js +24 -287
- package/dist/tools/check-config.js +67 -0
- package/dist/tools/check-format.js +92 -0
- package/dist/tools/check-impact.js +45 -0
- package/dist/tools/check-prolog.js +51 -0
- package/dist/tools/check-types.js +1 -0
- package/dist/tools/check.js +64 -148
- package/dist/tools/query-plan-safety.js +58 -0
- package/dist/tools/relationship-validation.js +118 -0
- package/dist/tools/skills.js +20 -2
- package/dist/tools/upsert.js +23 -1
- package/dist/tools/validate-upsert.js +13 -1
- package/dist/tools-config.js +40 -2
- package/package.json +3 -3
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// implements REQ-002
|
|
3
|
+
export function jsonSchemaToZod(schema) {
|
|
4
|
+
if (!schema || typeof schema !== "object") {
|
|
5
|
+
return z.any();
|
|
6
|
+
}
|
|
7
|
+
const obj = schema;
|
|
8
|
+
if (Array.isArray(obj.enum) && obj.enum.length > 0) {
|
|
9
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
10
|
+
const literals = obj.enum.filter((value) => typeof value === "string" ||
|
|
11
|
+
typeof value === "number" ||
|
|
12
|
+
typeof value === "boolean" ||
|
|
13
|
+
value === null);
|
|
14
|
+
if (literals.length === 0) {
|
|
15
|
+
return description ? z.any().describe(description) : z.any();
|
|
16
|
+
}
|
|
17
|
+
const literalSchemas = literals.map((value) => z.literal(value));
|
|
18
|
+
if (literalSchemas.length === 1) {
|
|
19
|
+
const single = literalSchemas[0];
|
|
20
|
+
if (!single) {
|
|
21
|
+
return description ? z.any().describe(description) : z.any();
|
|
22
|
+
}
|
|
23
|
+
return description ? single.describe(description) : single;
|
|
24
|
+
}
|
|
25
|
+
const union = z.union(literalSchemas);
|
|
26
|
+
return description ? union.describe(description) : union;
|
|
27
|
+
}
|
|
28
|
+
const schemaType = typeof obj.type === "string" ? obj.type : undefined;
|
|
29
|
+
switch (schemaType) {
|
|
30
|
+
case "object": {
|
|
31
|
+
const properties = obj.properties && typeof obj.properties === "object"
|
|
32
|
+
? obj.properties
|
|
33
|
+
: {};
|
|
34
|
+
const required = new Set(Array.isArray(obj.required)
|
|
35
|
+
? obj.required.filter((k) => typeof k === "string" && k.length > 0)
|
|
36
|
+
: []);
|
|
37
|
+
const shape = {};
|
|
38
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
39
|
+
const propSchema = jsonSchemaToZod(value);
|
|
40
|
+
shape[key] = required.has(key) ? propSchema : propSchema.optional();
|
|
41
|
+
}
|
|
42
|
+
const objectSchema = obj.additionalProperties === false
|
|
43
|
+
? z.object(shape)
|
|
44
|
+
: z.looseObject(shape);
|
|
45
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
46
|
+
return description ? objectSchema.describe(description) : objectSchema;
|
|
47
|
+
}
|
|
48
|
+
case "array": {
|
|
49
|
+
const itemSchema = jsonSchemaToZod(obj.items);
|
|
50
|
+
let arraySchema = z.array(itemSchema);
|
|
51
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
52
|
+
if (typeof obj.minItems === "number") {
|
|
53
|
+
arraySchema = arraySchema.min(obj.minItems);
|
|
54
|
+
}
|
|
55
|
+
if (typeof obj.maxItems === "number") {
|
|
56
|
+
arraySchema = arraySchema.max(obj.maxItems);
|
|
57
|
+
}
|
|
58
|
+
return description ? arraySchema.describe(description) : arraySchema;
|
|
59
|
+
}
|
|
60
|
+
case "string": {
|
|
61
|
+
let s = z.string();
|
|
62
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
63
|
+
if (typeof obj.minLength === "number") {
|
|
64
|
+
s = s.min(obj.minLength);
|
|
65
|
+
}
|
|
66
|
+
if (typeof obj.maxLength === "number") {
|
|
67
|
+
s = s.max(obj.maxLength);
|
|
68
|
+
}
|
|
69
|
+
return description ? s.describe(description) : s;
|
|
70
|
+
}
|
|
71
|
+
case "number": {
|
|
72
|
+
let n = z.number();
|
|
73
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
74
|
+
if (typeof obj.minimum === "number") {
|
|
75
|
+
n = n.min(obj.minimum);
|
|
76
|
+
}
|
|
77
|
+
if (typeof obj.maximum === "number") {
|
|
78
|
+
n = n.max(obj.maximum);
|
|
79
|
+
}
|
|
80
|
+
return description ? n.describe(description) : n;
|
|
81
|
+
}
|
|
82
|
+
case "integer": {
|
|
83
|
+
let n = z.number().int();
|
|
84
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
85
|
+
if (typeof obj.minimum === "number") {
|
|
86
|
+
n = n.min(obj.minimum);
|
|
87
|
+
}
|
|
88
|
+
if (typeof obj.maximum === "number") {
|
|
89
|
+
n = n.max(obj.maximum);
|
|
90
|
+
}
|
|
91
|
+
return description ? n.describe(description) : n;
|
|
92
|
+
}
|
|
93
|
+
case "boolean": {
|
|
94
|
+
const b = z.boolean();
|
|
95
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
96
|
+
return description ? b.describe(description) : b;
|
|
97
|
+
}
|
|
98
|
+
default: {
|
|
99
|
+
const anySchema = z.any();
|
|
100
|
+
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
101
|
+
return description ? anySchema.describe(description) : anySchema;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// implements REQ-002, REQ-013
|
|
2
|
+
export function registerConfiguredTools(server, runtime, registerTool) {
|
|
3
|
+
const toolDef = (name) => {
|
|
4
|
+
const t = runtime.tools.find((tool) => tool.name === name);
|
|
5
|
+
if (!t)
|
|
6
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
7
|
+
return t;
|
|
8
|
+
};
|
|
9
|
+
const register = ({ name, handler }) => {
|
|
10
|
+
const definition = toolDef(name);
|
|
11
|
+
registerTool(server, name, definition.description, definition.inputSchema, handler, runtime);
|
|
12
|
+
};
|
|
13
|
+
// INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
|
|
14
|
+
// bridge the generic ToolHandler (which receives Record<string, unknown>) to the
|
|
15
|
+
// specific handler argument types. Argument shapes are validated by Zod schemas
|
|
16
|
+
// (via jsonSchemaToZod) before the handler is invoked, so the casts are safe at runtime.
|
|
17
|
+
register({
|
|
18
|
+
name: "kb_query",
|
|
19
|
+
handler: async (args) => {
|
|
20
|
+
const prolog = await runtime.ensureProlog();
|
|
21
|
+
return runtime.handleKbQuery(prolog, args);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
register({
|
|
25
|
+
name: "kb_search",
|
|
26
|
+
handler: async (args) => {
|
|
27
|
+
const prolog = await runtime.ensureProlog();
|
|
28
|
+
return runtime.handleKbSearch(prolog, args);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
register({
|
|
32
|
+
name: "kb_status",
|
|
33
|
+
handler: async (args) => {
|
|
34
|
+
const prolog = await runtime.ensureProlog();
|
|
35
|
+
return runtime.handleKbStatus(prolog, args);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
register({
|
|
39
|
+
name: "kb_skills_list",
|
|
40
|
+
handler: async (args) => runtime.handleKbSkillsList(args),
|
|
41
|
+
});
|
|
42
|
+
register({
|
|
43
|
+
name: "kb_skills_load",
|
|
44
|
+
handler: async (args) => runtime.handleKbSkillsLoad(args),
|
|
45
|
+
});
|
|
46
|
+
register({
|
|
47
|
+
name: "kb_skills_read",
|
|
48
|
+
handler: async (args) => runtime.handleKbSkillsRead(args),
|
|
49
|
+
});
|
|
50
|
+
register({
|
|
51
|
+
name: "kb_find_gaps",
|
|
52
|
+
handler: async (args) => {
|
|
53
|
+
const prolog = await runtime.ensureProlog();
|
|
54
|
+
return runtime.handleKbFindGaps(prolog, args);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
register({
|
|
58
|
+
name: "kb_coverage",
|
|
59
|
+
handler: async (args) => {
|
|
60
|
+
const prolog = await runtime.ensureProlog();
|
|
61
|
+
return runtime.handleKbCoverage(prolog, args);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
register({
|
|
65
|
+
name: "kb_graph",
|
|
66
|
+
handler: async (args) => {
|
|
67
|
+
const prolog = await runtime.ensureProlog();
|
|
68
|
+
return runtime.handleKbGraph(prolog, args);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
register({
|
|
72
|
+
name: "kb_sparql_remote",
|
|
73
|
+
handler: async (args) => {
|
|
74
|
+
const prolog = await runtime.ensureProlog();
|
|
75
|
+
return runtime.handleSparql(prolog, args);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
register({
|
|
79
|
+
name: "kb_semantic_advisor",
|
|
80
|
+
handler: async (args) => runtime.handleKbSemanticAdvisor(args),
|
|
81
|
+
});
|
|
82
|
+
register({
|
|
83
|
+
name: "kb_upsert",
|
|
84
|
+
handler: async (args) => {
|
|
85
|
+
const prolog = await runtime.ensureProlog();
|
|
86
|
+
return runtime.handleKbUpsert(prolog, args);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
register({
|
|
90
|
+
name: "kb_validate_upsert",
|
|
91
|
+
handler: async (args) => {
|
|
92
|
+
const prolog = await runtime.ensureProlog();
|
|
93
|
+
return runtime.handleKbValidateUpsert(prolog, args);
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
register({
|
|
97
|
+
name: "kb_delete",
|
|
98
|
+
handler: async (args) => {
|
|
99
|
+
const prolog = await runtime.ensureProlog();
|
|
100
|
+
return runtime.handleKbDelete(prolog, args);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
register({
|
|
104
|
+
name: "kb_check",
|
|
105
|
+
handler: async (args) => {
|
|
106
|
+
const prolog = await runtime.ensureProlog();
|
|
107
|
+
return runtime.handleKbCheck(prolog, args);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
register({
|
|
111
|
+
name: "kb_model_requirement",
|
|
112
|
+
handler: async (args) => {
|
|
113
|
+
const prolog = await runtime.ensureProlog();
|
|
114
|
+
return runtime.handleKbModelRequirement(prolog, args);
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
register({
|
|
118
|
+
name: "kb_suggest_predicates",
|
|
119
|
+
handler: async (args) => {
|
|
120
|
+
const prolog = await runtime.ensureProlog();
|
|
121
|
+
return runtime.handleKbSuggestPredicates(prolog, args);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
register({
|
|
125
|
+
name: "kb_autopilot_generate",
|
|
126
|
+
handler: async (args) => {
|
|
127
|
+
const prolog = await runtime.ensureProlog();
|
|
128
|
+
return runtime.handleKbAutopilotGenerate(prolog, args);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
|
|
2
|
+
import { TOOLS } from "../tools-config.js";
|
|
3
|
+
import { handleKbAutopilotGenerate } from "../tools/autopilot-generate.js";
|
|
4
|
+
import { handleKbCheck } from "../tools/check.js";
|
|
5
|
+
import { handleKbCoverage } from "../tools/coverage.js";
|
|
6
|
+
import { handleKbDelete } from "../tools/delete.js";
|
|
7
|
+
import { handleKbFindGaps } from "../tools/find-gaps.js";
|
|
8
|
+
import { handleKbGraph } from "../tools/graph.js";
|
|
9
|
+
import { handleKbModelRequirement } from "../tools/model-requirement.js";
|
|
10
|
+
import { handleKbQuery } from "../tools/query.js";
|
|
11
|
+
import { handleKbSearch } from "../tools/search.js";
|
|
12
|
+
import { handleKbSemanticAdvisor } from "../tools/semantic-advisor.js";
|
|
13
|
+
import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
|
|
14
|
+
import { handleSparql } from "../tools/sparql.js";
|
|
15
|
+
import { handleKbStatus } from "../tools/status.js";
|
|
16
|
+
import { handleKbSuggestPredicates } from "../tools/suggest-predicates.js";
|
|
17
|
+
import { handleKbUpsert } from "../tools/upsert.js";
|
|
18
|
+
import { handleKbValidateUpsert } from "../tools/validate-upsert.js";
|
|
19
|
+
const defaultToolsServerDeps = {
|
|
20
|
+
getSessionModule: () => import("./session.js"),
|
|
21
|
+
};
|
|
22
|
+
let sessionModulePromise = null;
|
|
23
|
+
// implements REQ-008
|
|
24
|
+
export function _setToolsServerDepsForTests(deps, resetPromise = false) {
|
|
25
|
+
defaultToolsServerDeps.getSessionModule =
|
|
26
|
+
deps.getSessionModule ?? defaultToolsServerDeps.getSessionModule;
|
|
27
|
+
if (resetPromise) {
|
|
28
|
+
sessionModulePromise = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// implements REQ-012
|
|
32
|
+
export function _resetSessionModulePromise() {
|
|
33
|
+
sessionModulePromise = null;
|
|
34
|
+
}
|
|
35
|
+
/* v8 ignore next (3 lines) — lazy async module loader; body only executes once per process
|
|
36
|
+
* when DEFAULT_TOOLS_RUNTIME.activeBranchName/ensureProlog/etc. are first called.
|
|
37
|
+
* Cannot be re-triggered without process restart (sessionModulePromise is module-level). */
|
|
38
|
+
async function getSessionModule() {
|
|
39
|
+
sessionModulePromise ??= defaultToolsServerDeps.getSessionModule();
|
|
40
|
+
return sessionModulePromise;
|
|
41
|
+
}
|
|
42
|
+
export const DEFAULT_TOOLS_RUNTIME = {
|
|
43
|
+
diagnosticModeEnabled: () => DIAGNOSTIC_MODE_ENABLED,
|
|
44
|
+
appendUsageLogLine,
|
|
45
|
+
classifyDiagnosticError,
|
|
46
|
+
deriveDiagnosticFields,
|
|
47
|
+
extractToolCallPayload,
|
|
48
|
+
// INTENTIONAL: TOOLS is imported as a Zod-inferred schema type; ToolConfig is the
|
|
49
|
+
// runtime interface with looser Record<string, unknown> inputSchema. The cast is safe
|
|
50
|
+
// because the tool definitions are statically authored and validated at startup.
|
|
51
|
+
tools: TOOLS,
|
|
52
|
+
activeBranchName: async () => (await getSessionModule()).activeBranchName,
|
|
53
|
+
ensureProlog: async () => (await getSessionModule()).ensureProlog(),
|
|
54
|
+
resetProlog: async (reason) => (await getSessionModule()).resetProlog(reason),
|
|
55
|
+
inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
|
|
56
|
+
isShuttingDown: async () => (await getSessionModule()).isShuttingDown,
|
|
57
|
+
prologProcess: async () => (await getSessionModule()).prologProcess,
|
|
58
|
+
handleKbCheck,
|
|
59
|
+
handleKbCoverage,
|
|
60
|
+
handleKbDelete,
|
|
61
|
+
handleKbFindGaps,
|
|
62
|
+
handleKbGraph,
|
|
63
|
+
handleSparql,
|
|
64
|
+
handleKbQuery,
|
|
65
|
+
handleKbSearch,
|
|
66
|
+
handleKbStatus,
|
|
67
|
+
handleKbSemanticAdvisor,
|
|
68
|
+
handleKbSkillsList,
|
|
69
|
+
handleKbSkillsLoad,
|
|
70
|
+
handleKbSkillsRead,
|
|
71
|
+
handleKbUpsert,
|
|
72
|
+
handleKbValidateUpsert,
|
|
73
|
+
handleKbModelRequirement,
|
|
74
|
+
handleKbSuggestPredicates,
|
|
75
|
+
handleKbAutopilotGenerate,
|
|
76
|
+
};
|
package/dist/server/tools.js
CHANGED
|
@@ -16,86 +16,15 @@
|
|
|
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 { z } from "zod";
|
|
20
|
-
import { DIAGNOSTIC_MODE_ENABLED, appendUsageLogLine, classifyDiagnosticError, deriveDiagnosticFields, extractToolCallPayload, } from "../diagnostics.js";
|
|
21
19
|
import { isMcpDebugEnabled } from "../env.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import { handleKbGraph } from "../tools/graph.js";
|
|
29
|
-
import { handleKbModelRequirement, } from "../tools/model-requirement.js";
|
|
30
|
-
import { handleKbQuery } from "../tools/query.js";
|
|
31
|
-
import { handleKbSearch } from "../tools/search.js";
|
|
32
|
-
import { handleKbSemanticAdvisor, } from "../tools/semantic-advisor.js";
|
|
33
|
-
import { handleKbSkillsList, handleKbSkillsLoad, handleKbSkillsRead, } from "../tools/skills.js";
|
|
34
|
-
import { handleSparql } from "../tools/sparql.js";
|
|
35
|
-
import { handleKbStatus } from "../tools/status.js";
|
|
36
|
-
import { handleKbSuggestPredicates, } from "../tools/suggest-predicates.js";
|
|
37
|
-
import { handleKbUpsert } from "../tools/upsert.js";
|
|
38
|
-
import { handleKbValidateUpsert } from "../tools/validate-upsert.js";
|
|
20
|
+
import { appendDiagnosticErrorUsage, appendDiagnosticSuccessUsage, } from "./diagnostic-usage.js";
|
|
21
|
+
import { jsonSchemaToZod } from "./json-schema-to-zod.js";
|
|
22
|
+
import { registerConfiguredTools } from "./tool-registration.js";
|
|
23
|
+
import { DEFAULT_TOOLS_RUNTIME, _resetSessionModulePromise, _setToolsServerDepsForTests, } from "./tools-runtime.js";
|
|
24
|
+
export { jsonSchemaToZod } from "./json-schema-to-zod.js";
|
|
25
|
+
export { _resetSessionModulePromise, _setToolsServerDepsForTests };
|
|
39
26
|
const DEFAULT_TOOL_TIMEOUT_MS = 90_000;
|
|
40
27
|
const TOOL_TIMEOUT_ENV = "KIBI_MCP_TOOL_TIMEOUT_MS";
|
|
41
|
-
const defaultToolsServerDeps = {
|
|
42
|
-
getSessionModule: () => import("./session.js"),
|
|
43
|
-
};
|
|
44
|
-
// implements REQ-008
|
|
45
|
-
export function _setToolsServerDepsForTests(deps, resetPromise = false) {
|
|
46
|
-
defaultToolsServerDeps.getSessionModule =
|
|
47
|
-
deps.getSessionModule ?? defaultToolsServerDeps.getSessionModule;
|
|
48
|
-
if (resetPromise) {
|
|
49
|
-
sessionModulePromise = null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// implements REQ-012
|
|
53
|
-
export function _resetSessionModulePromise() {
|
|
54
|
-
sessionModulePromise = null;
|
|
55
|
-
}
|
|
56
|
-
let sessionModulePromise = null;
|
|
57
|
-
/* v8 ignore next (3 lines) — lazy async module loader; body only executes once per process
|
|
58
|
-
* when DEFAULT_TOOLS_RUNTIME.activeBranchName/ensureProlog/etc. are first called.
|
|
59
|
-
* Cannot be re-triggered without process restart (sessionModulePromise is module-level). */
|
|
60
|
-
async function getSessionModule() {
|
|
61
|
-
sessionModulePromise ??= defaultToolsServerDeps.getSessionModule();
|
|
62
|
-
return sessionModulePromise;
|
|
63
|
-
}
|
|
64
|
-
const DEFAULT_TOOLS_RUNTIME = {
|
|
65
|
-
diagnosticModeEnabled: () => DIAGNOSTIC_MODE_ENABLED,
|
|
66
|
-
appendUsageLogLine,
|
|
67
|
-
classifyDiagnosticError,
|
|
68
|
-
deriveDiagnosticFields,
|
|
69
|
-
extractToolCallPayload,
|
|
70
|
-
// INTENTIONAL: TOOLS is imported as a Zod-inferred schema type; ToolConfig is the
|
|
71
|
-
// runtime interface with looser Record<string, unknown> inputSchema. The cast is safe
|
|
72
|
-
// because the tool definitions are statically authored and validated at startup.
|
|
73
|
-
tools: TOOLS,
|
|
74
|
-
activeBranchName: async () => (await getSessionModule()).activeBranchName,
|
|
75
|
-
ensureProlog: async () => (await getSessionModule()).ensureProlog(),
|
|
76
|
-
resetProlog: async (reason) => (await getSessionModule()).resetProlog(reason),
|
|
77
|
-
inFlightRequests: async () => (await getSessionModule()).inFlightRequests,
|
|
78
|
-
isShuttingDown: async () => (await getSessionModule()).isShuttingDown,
|
|
79
|
-
prologProcess: async () => (await getSessionModule()).prologProcess,
|
|
80
|
-
handleKbCheck,
|
|
81
|
-
handleKbCoverage,
|
|
82
|
-
handleKbDelete,
|
|
83
|
-
handleKbFindGaps,
|
|
84
|
-
handleKbGraph,
|
|
85
|
-
handleSparql,
|
|
86
|
-
handleKbQuery,
|
|
87
|
-
handleKbSearch,
|
|
88
|
-
handleKbStatus,
|
|
89
|
-
handleKbSemanticAdvisor,
|
|
90
|
-
handleKbSkillsList,
|
|
91
|
-
handleKbSkillsLoad,
|
|
92
|
-
handleKbSkillsRead,
|
|
93
|
-
handleKbUpsert,
|
|
94
|
-
handleKbValidateUpsert,
|
|
95
|
-
handleKbModelRequirement,
|
|
96
|
-
handleKbSuggestPredicates,
|
|
97
|
-
handleKbAutopilotGenerate,
|
|
98
|
-
};
|
|
99
28
|
// implements REQ-008
|
|
100
29
|
function debugLog(...args) {
|
|
101
30
|
if (isMcpDebugEnabled()) {
|
|
@@ -140,109 +69,6 @@ async function withToolTimeout(toolName, operation, onTimeout) {
|
|
|
140
69
|
}
|
|
141
70
|
}
|
|
142
71
|
// implements REQ-002
|
|
143
|
-
export function jsonSchemaToZod(schema) {
|
|
144
|
-
if (!schema || typeof schema !== "object") {
|
|
145
|
-
return z.any();
|
|
146
|
-
}
|
|
147
|
-
const obj = schema;
|
|
148
|
-
if (Array.isArray(obj.enum) && obj.enum.length > 0) {
|
|
149
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
150
|
-
const literals = obj.enum.filter((value) => typeof value === "string" ||
|
|
151
|
-
typeof value === "number" ||
|
|
152
|
-
typeof value === "boolean" ||
|
|
153
|
-
value === null);
|
|
154
|
-
if (literals.length === 0) {
|
|
155
|
-
return description ? z.any().describe(description) : z.any();
|
|
156
|
-
}
|
|
157
|
-
const literalSchemas = literals.map((value) => z.literal(value));
|
|
158
|
-
if (literalSchemas.length === 1) {
|
|
159
|
-
const single = literalSchemas[0];
|
|
160
|
-
if (!single) {
|
|
161
|
-
return description ? z.any().describe(description) : z.any();
|
|
162
|
-
}
|
|
163
|
-
return description ? single.describe(description) : single;
|
|
164
|
-
}
|
|
165
|
-
const union = z.union(literalSchemas);
|
|
166
|
-
return description ? union.describe(description) : union;
|
|
167
|
-
}
|
|
168
|
-
const schemaType = typeof obj.type === "string" ? obj.type : undefined;
|
|
169
|
-
switch (schemaType) {
|
|
170
|
-
case "object": {
|
|
171
|
-
const properties = obj.properties && typeof obj.properties === "object"
|
|
172
|
-
? obj.properties
|
|
173
|
-
: {};
|
|
174
|
-
const required = new Set(Array.isArray(obj.required)
|
|
175
|
-
? obj.required.filter((k) => typeof k === "string" && k.length > 0)
|
|
176
|
-
: []);
|
|
177
|
-
const shape = {};
|
|
178
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
179
|
-
const propSchema = jsonSchemaToZod(value);
|
|
180
|
-
shape[key] = required.has(key) ? propSchema : propSchema.optional();
|
|
181
|
-
}
|
|
182
|
-
const objectSchema = obj.additionalProperties === false
|
|
183
|
-
? z.object(shape)
|
|
184
|
-
: z.looseObject(shape);
|
|
185
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
186
|
-
return description ? objectSchema.describe(description) : objectSchema;
|
|
187
|
-
}
|
|
188
|
-
case "array": {
|
|
189
|
-
const itemSchema = jsonSchemaToZod(obj.items);
|
|
190
|
-
let arraySchema = z.array(itemSchema);
|
|
191
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
192
|
-
if (typeof obj.minItems === "number") {
|
|
193
|
-
arraySchema = arraySchema.min(obj.minItems);
|
|
194
|
-
}
|
|
195
|
-
if (typeof obj.maxItems === "number") {
|
|
196
|
-
arraySchema = arraySchema.max(obj.maxItems);
|
|
197
|
-
}
|
|
198
|
-
return description ? arraySchema.describe(description) : arraySchema;
|
|
199
|
-
}
|
|
200
|
-
case "string": {
|
|
201
|
-
let s = z.string();
|
|
202
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
203
|
-
if (typeof obj.minLength === "number") {
|
|
204
|
-
s = s.min(obj.minLength);
|
|
205
|
-
}
|
|
206
|
-
if (typeof obj.maxLength === "number") {
|
|
207
|
-
s = s.max(obj.maxLength);
|
|
208
|
-
}
|
|
209
|
-
return description ? s.describe(description) : s;
|
|
210
|
-
}
|
|
211
|
-
case "number": {
|
|
212
|
-
let n = z.number();
|
|
213
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
214
|
-
if (typeof obj.minimum === "number") {
|
|
215
|
-
n = n.min(obj.minimum);
|
|
216
|
-
}
|
|
217
|
-
if (typeof obj.maximum === "number") {
|
|
218
|
-
n = n.max(obj.maximum);
|
|
219
|
-
}
|
|
220
|
-
return description ? n.describe(description) : n;
|
|
221
|
-
}
|
|
222
|
-
case "integer": {
|
|
223
|
-
let n = z.number().int();
|
|
224
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
225
|
-
if (typeof obj.minimum === "number") {
|
|
226
|
-
n = n.min(obj.minimum);
|
|
227
|
-
}
|
|
228
|
-
if (typeof obj.maximum === "number") {
|
|
229
|
-
n = n.max(obj.maximum);
|
|
230
|
-
}
|
|
231
|
-
return description ? n.describe(description) : n;
|
|
232
|
-
}
|
|
233
|
-
case "boolean": {
|
|
234
|
-
const b = z.boolean();
|
|
235
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
236
|
-
return description ? b.describe(description) : b;
|
|
237
|
-
}
|
|
238
|
-
default: {
|
|
239
|
-
const anySchema = z.any();
|
|
240
|
-
const description = typeof obj.description === "string" ? obj.description : undefined;
|
|
241
|
-
return description ? anySchema.describe(description) : anySchema;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// implements REQ-002
|
|
246
72
|
export function addTool(server, name, description, inputSchema, handler,
|
|
247
73
|
// INTENTIONAL: DEFAULT_TOOLS_RUNTIME is typed as ToolsRuntime<PrologProcess>; the
|
|
248
74
|
// generic TProlog parameter exists so tests can inject a mock type. The cast is safe
|
|
@@ -293,23 +119,15 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
|
293
119
|
});
|
|
294
120
|
// Log usage in diagnostic mode
|
|
295
121
|
if (diagnosticModeEnabled) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
request_id: requestId,
|
|
303
|
-
tool: name,
|
|
122
|
+
await appendDiagnosticSuccessUsage({
|
|
123
|
+
runtime,
|
|
124
|
+
toolName: name,
|
|
125
|
+
requestId,
|
|
126
|
+
args,
|
|
127
|
+
businessArgs,
|
|
304
128
|
telemetry,
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
started_at: startedAt.toISOString(),
|
|
308
|
-
finished_at: finishedAt.toISOString(),
|
|
309
|
-
duration_ms: finishedAt.getTime() - startedAt.getTime(),
|
|
310
|
-
prolog_pid: processHandle?.getPid() ?? null,
|
|
311
|
-
active_branch: branchName,
|
|
312
|
-
...diagnosticFields,
|
|
129
|
+
startedAt,
|
|
130
|
+
result,
|
|
313
131
|
});
|
|
314
132
|
}
|
|
315
133
|
return result;
|
|
@@ -317,27 +135,16 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
|
317
135
|
catch (error) {
|
|
318
136
|
// Log error in diagnostic mode
|
|
319
137
|
if (diagnosticModeEnabled) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
timestamp: finishedAt.toISOString(),
|
|
327
|
-
request_id: requestId,
|
|
328
|
-
tool: name,
|
|
138
|
+
await appendDiagnosticErrorUsage({
|
|
139
|
+
runtime,
|
|
140
|
+
toolName: name,
|
|
141
|
+
requestId,
|
|
142
|
+
args,
|
|
143
|
+
businessArgs,
|
|
329
144
|
telemetry,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
finished_at: finishedAt.toISOString(),
|
|
334
|
-
duration_ms: finishedAt.getTime() - startedAt.getTime(),
|
|
335
|
-
prolog_pid: processHandle?.getPid() ?? null,
|
|
336
|
-
active_branch: branchName,
|
|
337
|
-
reset_attempted: resetAttempted,
|
|
338
|
-
reset_succeeded: resetSucceeded,
|
|
339
|
-
reset_error: resetError,
|
|
340
|
-
...diagnosticErrorFields,
|
|
145
|
+
startedAt,
|
|
146
|
+
error,
|
|
147
|
+
resetState: { resetAttempted, resetSucceeded, resetError },
|
|
341
148
|
});
|
|
342
149
|
}
|
|
343
150
|
throw error;
|
|
@@ -362,75 +169,5 @@ runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
|
362
169
|
export function registerAllTools(server,
|
|
363
170
|
// INTENTIONAL: same generic bridge cast as addTool — see comment there.
|
|
364
171
|
runtime = DEFAULT_TOOLS_RUNTIME) {
|
|
365
|
-
|
|
366
|
-
const t = runtime.tools.find((tool) => tool.name === name);
|
|
367
|
-
if (!t)
|
|
368
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
369
|
-
return t;
|
|
370
|
-
};
|
|
371
|
-
// INTENTIONAL ARGUMENT CASTS: The `args as (unknown as)? XyzArgs` casts below
|
|
372
|
-
// bridge the generic ToolHandler (which receives Record<string, unknown>) to the
|
|
373
|
-
// specific handler argument types. Argument shapes are validated by Zod schemas
|
|
374
|
-
// (via jsonSchemaToZod) before the handler is invoked, so the casts are safe at runtime.
|
|
375
|
-
addTool(server, "kb_query", toolDef("kb_query").description, toolDef("kb_query").inputSchema, async (args) => {
|
|
376
|
-
const prolog = await runtime.ensureProlog();
|
|
377
|
-
return runtime.handleKbQuery(prolog, args);
|
|
378
|
-
}, runtime);
|
|
379
|
-
addTool(server, "kb_search", toolDef("kb_search").description, toolDef("kb_search").inputSchema, async (args) => {
|
|
380
|
-
const prolog = await runtime.ensureProlog();
|
|
381
|
-
return runtime.handleKbSearch(prolog, args);
|
|
382
|
-
}, runtime);
|
|
383
|
-
addTool(server, "kb_status", toolDef("kb_status").description, toolDef("kb_status").inputSchema, async (args) => {
|
|
384
|
-
const prolog = await runtime.ensureProlog();
|
|
385
|
-
return runtime.handleKbStatus(prolog, args);
|
|
386
|
-
}, runtime);
|
|
387
|
-
addTool(server, "kb_skills_list", toolDef("kb_skills_list").description, toolDef("kb_skills_list").inputSchema, async (args) => runtime.handleKbSkillsList(args), runtime);
|
|
388
|
-
addTool(server, "kb_skills_load", toolDef("kb_skills_load").description, toolDef("kb_skills_load").inputSchema, async (args) => runtime.handleKbSkillsLoad(args), runtime);
|
|
389
|
-
addTool(server, "kb_skills_read", toolDef("kb_skills_read").description, toolDef("kb_skills_read").inputSchema, async (args) => runtime.handleKbSkillsRead(args), runtime);
|
|
390
|
-
addTool(server, "kb_find_gaps", toolDef("kb_find_gaps").description, toolDef("kb_find_gaps").inputSchema, async (args) => {
|
|
391
|
-
const prolog = await runtime.ensureProlog();
|
|
392
|
-
return runtime.handleKbFindGaps(prolog, args);
|
|
393
|
-
}, runtime);
|
|
394
|
-
addTool(server, "kb_coverage", toolDef("kb_coverage").description, toolDef("kb_coverage").inputSchema, async (args) => {
|
|
395
|
-
const prolog = await runtime.ensureProlog();
|
|
396
|
-
return runtime.handleKbCoverage(prolog, args);
|
|
397
|
-
}, runtime);
|
|
398
|
-
addTool(server, "kb_graph", toolDef("kb_graph").description, toolDef("kb_graph").inputSchema, async (args) => {
|
|
399
|
-
const prolog = await runtime.ensureProlog();
|
|
400
|
-
return runtime.handleKbGraph(prolog, args);
|
|
401
|
-
}, runtime);
|
|
402
|
-
addTool(server, "kb_sparql_remote", toolDef("kb_sparql_remote").description, toolDef("kb_sparql_remote").inputSchema, async (args) => {
|
|
403
|
-
const prolog = await runtime.ensureProlog();
|
|
404
|
-
return runtime.handleSparql(prolog, args);
|
|
405
|
-
}, runtime);
|
|
406
|
-
addTool(server, "kb_semantic_advisor", toolDef("kb_semantic_advisor").description, toolDef("kb_semantic_advisor").inputSchema, async (args) => {
|
|
407
|
-
return runtime.handleKbSemanticAdvisor(args);
|
|
408
|
-
}, runtime);
|
|
409
|
-
addTool(server, "kb_upsert", toolDef("kb_upsert").description, toolDef("kb_upsert").inputSchema, async (args) => {
|
|
410
|
-
const prolog = await runtime.ensureProlog();
|
|
411
|
-
return runtime.handleKbUpsert(prolog, args);
|
|
412
|
-
}, runtime);
|
|
413
|
-
addTool(server, "kb_validate_upsert", toolDef("kb_validate_upsert").description, toolDef("kb_validate_upsert").inputSchema, async (args) => {
|
|
414
|
-
return runtime.handleKbValidateUpsert(args);
|
|
415
|
-
}, runtime);
|
|
416
|
-
addTool(server, "kb_delete", toolDef("kb_delete").description, toolDef("kb_delete").inputSchema, async (args) => {
|
|
417
|
-
const prolog = await runtime.ensureProlog();
|
|
418
|
-
return runtime.handleKbDelete(prolog, args);
|
|
419
|
-
}, runtime);
|
|
420
|
-
addTool(server, "kb_check", toolDef("kb_check").description, toolDef("kb_check").inputSchema, async (args) => {
|
|
421
|
-
const prolog = await runtime.ensureProlog();
|
|
422
|
-
return runtime.handleKbCheck(prolog, args);
|
|
423
|
-
}, runtime);
|
|
424
|
-
addTool(server, "kb_model_requirement", toolDef("kb_model_requirement").description, toolDef("kb_model_requirement").inputSchema, async (args) => {
|
|
425
|
-
const prolog = await runtime.ensureProlog();
|
|
426
|
-
return runtime.handleKbModelRequirement(prolog, args);
|
|
427
|
-
}, runtime);
|
|
428
|
-
addTool(server, "kb_suggest_predicates", toolDef("kb_suggest_predicates").description, toolDef("kb_suggest_predicates").inputSchema, async (args) => {
|
|
429
|
-
const prolog = await runtime.ensureProlog();
|
|
430
|
-
return runtime.handleKbSuggestPredicates(prolog, args);
|
|
431
|
-
}, runtime);
|
|
432
|
-
addTool(server, "kb_autopilot_generate", toolDef("kb_autopilot_generate").description, toolDef("kb_autopilot_generate").inputSchema, async (args) => {
|
|
433
|
-
const prolog = await runtime.ensureProlog();
|
|
434
|
-
return runtime.handleKbAutopilotGenerate(prolog, args);
|
|
435
|
-
}, runtime);
|
|
172
|
+
registerConfiguredTools(server, runtime, addTool);
|
|
436
173
|
}
|