@konneal/engine 0.2.137 → 0.2.139
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/mcp-proto.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export declare const PROTOCOL_VERSION = "2025-06-18";
|
|
2
|
+
/** Registry tool name → the MCP-presented name. */
|
|
3
|
+
export declare function mcpName(registryName: string): string;
|
|
4
|
+
/** MCP-presented name → the name the handlers dispatch on. Raw
|
|
5
|
+
* registry names pass through (transition tolerance for early
|
|
6
|
+
* consumers of the unprefixed surface). */
|
|
7
|
+
export declare function registryName(presented: string): string;
|
|
2
8
|
export interface McpTool {
|
|
3
9
|
name: string;
|
|
4
10
|
description: string;
|
|
@@ -8,7 +14,7 @@ export interface McpTool {
|
|
|
8
14
|
required: string[];
|
|
9
15
|
};
|
|
10
16
|
}
|
|
11
|
-
export declare
|
|
17
|
+
export declare function buildTools(): McpTool[];
|
|
12
18
|
export type McpResult = {
|
|
13
19
|
ok: true;
|
|
14
20
|
result: unknown;
|
|
@@ -961,41 +961,66 @@ async function deleteAttachment(deps, sub, id) {
|
|
|
961
961
|
|
|
962
962
|
// workers/worker_public/src/mcp-proto.ts
|
|
963
963
|
var PROTOCOL_VERSION = "2025-06-18";
|
|
964
|
-
var
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
{
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
]
|
|
964
|
+
var mcpPrefix = () => `${P().publisher.id}_`;
|
|
965
|
+
var mcpOverrides = () => ({
|
|
966
|
+
retrieve: `${P().publisher.id}_search`,
|
|
967
|
+
// the published retrieval contract
|
|
968
|
+
"documents.family": `${P().publisher.id}_documents`
|
|
969
|
+
// the published registry contract
|
|
970
|
+
});
|
|
971
|
+
function mcpName(registryName2) {
|
|
972
|
+
const overrides = mcpOverrides();
|
|
973
|
+
return overrides[registryName2] ?? `${mcpPrefix()}${registryName2.replace(/\./g, "_")}`;
|
|
974
|
+
}
|
|
975
|
+
function registryName(presented) {
|
|
976
|
+
const pid = P().publisher.id;
|
|
977
|
+
if (presented === `${pid}_ask`) return "ask";
|
|
978
|
+
const overrides = mcpOverrides();
|
|
979
|
+
for (const [reg, mc] of Object.entries(overrides)) if (mc === presented) return reg;
|
|
980
|
+
if (presented.startsWith(`${pid}_`)) {
|
|
981
|
+
const rest = presented.slice(pid.length + 1);
|
|
982
|
+
const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
|
|
983
|
+
if (hit) return hit.name;
|
|
984
|
+
}
|
|
985
|
+
return presented;
|
|
986
|
+
}
|
|
987
|
+
function buildTools() {
|
|
988
|
+
return [
|
|
989
|
+
{
|
|
990
|
+
name: mcpName("ask"),
|
|
991
|
+
description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
|
|
992
|
+
inputSchema: {
|
|
993
|
+
type: "object",
|
|
994
|
+
properties: {
|
|
995
|
+
query: { type: "string", description: "The question (1-8000 chars)" },
|
|
996
|
+
lang: { type: "string", description: "Answer language hint (e.g. en, fr)" }
|
|
997
|
+
},
|
|
998
|
+
required: ["query"]
|
|
999
|
+
}
|
|
1000
|
+
},
|
|
1001
|
+
{
|
|
1002
|
+
name: mcpName("retrieve"),
|
|
1003
|
+
description: "Retrieve the top passages for a query (hybrid dense + metadata steering, reranked).",
|
|
1004
|
+
inputSchema: {
|
|
1005
|
+
type: "object",
|
|
1006
|
+
properties: {
|
|
1007
|
+
query: { type: "string" },
|
|
1008
|
+
k: { type: "number", description: "Hits to return (default 5)" }
|
|
1009
|
+
},
|
|
1010
|
+
required: ["query"]
|
|
1011
|
+
}
|
|
1012
|
+
},
|
|
1013
|
+
...TOOLS_REGISTRY.filter((t) => t.audiences.includes("mcp")).map((t) => ({
|
|
1014
|
+
name: mcpName(t.name),
|
|
1015
|
+
description: t.description,
|
|
1016
|
+
inputSchema: {
|
|
1017
|
+
type: "object",
|
|
1018
|
+
properties: Object.fromEntries(t.params.map((p) => [p.key, { type: "string", description: p.description }])),
|
|
1019
|
+
required: t.params.filter((p) => p.required).map((p) => p.key)
|
|
1020
|
+
}
|
|
1021
|
+
}))
|
|
1022
|
+
];
|
|
1023
|
+
}
|
|
999
1024
|
function dispatch(method, params, callTool) {
|
|
1000
1025
|
switch (method) {
|
|
1001
1026
|
case "initialize":
|
|
@@ -1004,13 +1029,13 @@ function dispatch(method, params, callTool) {
|
|
|
1004
1029
|
case "ping":
|
|
1005
1030
|
return Promise.resolve({ ok: true, accepted: true });
|
|
1006
1031
|
case "tools/list":
|
|
1007
|
-
return Promise.resolve({ ok: true, result: { tools:
|
|
1032
|
+
return Promise.resolve({ ok: true, result: { tools: buildTools() } });
|
|
1008
1033
|
case "tools/call": {
|
|
1009
1034
|
const name = typeof params?.name === "string" ? params.name : "";
|
|
1010
|
-
if (!
|
|
1035
|
+
if (!buildTools().some((t) => t.name === name)) {
|
|
1011
1036
|
return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
|
|
1012
1037
|
}
|
|
1013
|
-
return callTool(name, params?.arguments ?? {}).then(
|
|
1038
|
+
return callTool(registryName(name), params?.arguments ?? {}).then(
|
|
1014
1039
|
(payload) => ({ ok: true, result: { content: [{ type: "text", text: JSON.stringify(payload) }] } })
|
|
1015
1040
|
);
|
|
1016
1041
|
}
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"playwright": "^1.62.1",
|
|
28
28
|
"yaml": "^2.9.1"
|
|
29
29
|
},
|
|
30
|
-
"version": "0.2.
|
|
30
|
+
"version": "0.2.139",
|
|
31
31
|
"description": "The Konneal engine: the publisher-agnostic build pipeline and API plane for standards intelligence (retrieval, answer contract, verdicts, evaluation).",
|
|
32
32
|
"license": "BSD-3-Clause",
|
|
33
33
|
"type": "module",
|
|
@@ -2,8 +2,45 @@
|
|
|
2
2
|
// dependency-free so plain node can load it for unit tests — the
|
|
3
3
|
// route adapter (mcp.ts) owns the handler wiring.
|
|
4
4
|
import { TOOLS_REGISTRY } from "./tools.ts";
|
|
5
|
+
import { P } from "./profile.ts";
|
|
5
6
|
export const PROTOCOL_VERSION = "2025-06-18";
|
|
6
7
|
|
|
8
|
+
// The MCP naming convention (2026-10-12): every tool the publisher
|
|
9
|
+
// exposes over MCP carries the publisher prefix — MCP clients render
|
|
10
|
+
// tool names in a SHARED namespace, so generic names ("ask") collide
|
|
11
|
+
// across servers. The three names docs/MCP.md already publishes keep
|
|
12
|
+
// their exact spelling; the mechanical transform covers the rest.
|
|
13
|
+
const mcpPrefix = () => `${P().publisher.id}_`;
|
|
14
|
+
// per call like everything else here — a module-level map froze the
|
|
15
|
+
// fixture prefix into the two published contracts (the freeze test
|
|
16
|
+
// caught this one AFTER catching the TOOLS array)
|
|
17
|
+
const mcpOverrides = (): Record<string, string> => ({
|
|
18
|
+
retrieve: `${P().publisher.id}_search`, // the published retrieval contract
|
|
19
|
+
"documents.family": `${P().publisher.id}_documents`, // the published registry contract
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/** Registry tool name → the MCP-presented name. */
|
|
23
|
+
export function mcpName(registryName: string): string {
|
|
24
|
+
const overrides = mcpOverrides();
|
|
25
|
+
return overrides[registryName] ?? `${mcpPrefix()}${registryName.replace(/\./g, "_")}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** MCP-presented name → the name the handlers dispatch on. Raw
|
|
29
|
+
* registry names pass through (transition tolerance for early
|
|
30
|
+
* consumers of the unprefixed surface). */
|
|
31
|
+
export function registryName(presented: string): string {
|
|
32
|
+
const pid = P().publisher.id;
|
|
33
|
+
if (presented === `${pid}_ask`) return "ask";
|
|
34
|
+
const overrides = mcpOverrides();
|
|
35
|
+
for (const [reg, mc] of Object.entries(overrides)) if (mc === presented) return reg;
|
|
36
|
+
if (presented.startsWith(`${pid}_`)) {
|
|
37
|
+
const rest = presented.slice(pid.length + 1);
|
|
38
|
+
const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
|
|
39
|
+
if (hit) return hit.name;
|
|
40
|
+
}
|
|
41
|
+
return presented;
|
|
42
|
+
}
|
|
43
|
+
|
|
7
44
|
export interface McpTool {
|
|
8
45
|
name: string;
|
|
9
46
|
description: string;
|
|
@@ -11,10 +48,16 @@ export interface McpTool {
|
|
|
11
48
|
}
|
|
12
49
|
|
|
13
50
|
// the registry's MCP-audience tools are GENERATED here (OCP: adding a
|
|
14
|
-
// tool registers it; this list is never hand-extended for them)
|
|
15
|
-
|
|
51
|
+
// tool registers it; this list is never hand-extended for them).
|
|
52
|
+
// BUILT PER CALL, never at module load: the names carry the publisher
|
|
53
|
+
// prefix, and the deployment's setProfile runs AFTER this module's
|
|
54
|
+
// imports evaluate — a module-level array froze the fixture prefix
|
|
55
|
+
// into production's tools/list (caught by the 2026-10-12 deploy smoke's
|
|
56
|
+
// tools/list line, which the "ask" substring grep was too weak to fail).
|
|
57
|
+
export function buildTools(): McpTool[] {
|
|
58
|
+
return [
|
|
16
59
|
{
|
|
17
|
-
name: "ask",
|
|
60
|
+
name: mcpName("ask"),
|
|
18
61
|
description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
|
|
19
62
|
inputSchema: {
|
|
20
63
|
type: "object",
|
|
@@ -26,7 +69,7 @@ export const TOOLS: McpTool[] = [
|
|
|
26
69
|
},
|
|
27
70
|
},
|
|
28
71
|
{
|
|
29
|
-
name: "retrieve",
|
|
72
|
+
name: mcpName("retrieve"),
|
|
30
73
|
description: "Retrieve the top passages for a query (hybrid dense + metadata steering, reranked).",
|
|
31
74
|
inputSchema: {
|
|
32
75
|
type: "object",
|
|
@@ -40,7 +83,7 @@ export const TOOLS: McpTool[] = [
|
|
|
40
83
|
...TOOLS_REGISTRY
|
|
41
84
|
.filter((t) => t.audiences.includes("mcp"))
|
|
42
85
|
.map((t): McpTool => ({
|
|
43
|
-
name: t.name,
|
|
86
|
+
name: mcpName(t.name),
|
|
44
87
|
description: t.description,
|
|
45
88
|
inputSchema: {
|
|
46
89
|
type: "object",
|
|
@@ -48,7 +91,8 @@ export const TOOLS: McpTool[] = [
|
|
|
48
91
|
required: t.params.filter((p) => p.required).map((p) => p.key),
|
|
49
92
|
},
|
|
50
93
|
})),
|
|
51
|
-
];
|
|
94
|
+
];
|
|
95
|
+
}
|
|
52
96
|
|
|
53
97
|
export type McpResult =
|
|
54
98
|
| { ok: true; result: unknown }
|
|
@@ -69,13 +113,13 @@ export function dispatch(
|
|
|
69
113
|
case "ping":
|
|
70
114
|
return Promise.resolve({ ok: true, accepted: true });
|
|
71
115
|
case "tools/list":
|
|
72
|
-
return Promise.resolve({ ok: true, result: { tools:
|
|
116
|
+
return Promise.resolve({ ok: true, result: { tools: buildTools() } });
|
|
73
117
|
case "tools/call": {
|
|
74
118
|
const name = typeof params?.name === "string" ? params.name : "";
|
|
75
|
-
if (!
|
|
119
|
+
if (!buildTools().some((t) => t.name === name)) {
|
|
76
120
|
return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
|
|
77
121
|
}
|
|
78
|
-
return callTool(name, params?.arguments ?? {}).then(
|
|
122
|
+
return callTool(registryName(name), params?.arguments ?? {}).then(
|
|
79
123
|
(payload) => ({ ok: true, result: { content: [{ type: "text", text: JSON.stringify(payload) }] } }) as McpResult,
|
|
80
124
|
);
|
|
81
125
|
}
|