@konneal/engine 0.2.138 → 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.
@@ -14,7 +14,7 @@ export interface McpTool {
14
14
  required: string[];
15
15
  };
16
16
  }
17
- export declare const TOOLS: McpTool[];
17
+ export declare function buildTools(): McpTool[];
18
18
  export type McpResult = {
19
19
  ok: true;
20
20
  result: unknown;
@@ -962,19 +962,21 @@ async function deleteAttachment(deps, sub, id) {
962
962
  // workers/worker_public/src/mcp-proto.ts
963
963
  var PROTOCOL_VERSION = "2025-06-18";
964
964
  var mcpPrefix = () => `${P().publisher.id}_`;
965
- var MCP_NAME_OVERRIDES = {
965
+ var mcpOverrides = () => ({
966
966
  retrieve: `${P().publisher.id}_search`,
967
967
  // the published retrieval contract
968
968
  "documents.family": `${P().publisher.id}_documents`
969
969
  // the published registry contract
970
- };
970
+ });
971
971
  function mcpName(registryName2) {
972
- return MCP_NAME_OVERRIDES[registryName2] ?? `${mcpPrefix()}${registryName2.replace(/\./g, "_")}`;
972
+ const overrides = mcpOverrides();
973
+ return overrides[registryName2] ?? `${mcpPrefix()}${registryName2.replace(/\./g, "_")}`;
973
974
  }
974
975
  function registryName(presented) {
975
976
  const pid = P().publisher.id;
976
977
  if (presented === `${pid}_ask`) return "ask";
977
- for (const [reg, mc] of Object.entries(MCP_NAME_OVERRIDES)) if (mc === presented) return reg;
978
+ const overrides = mcpOverrides();
979
+ for (const [reg, mc] of Object.entries(overrides)) if (mc === presented) return reg;
978
980
  if (presented.startsWith(`${pid}_`)) {
979
981
  const rest = presented.slice(pid.length + 1);
980
982
  const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
@@ -982,41 +984,43 @@ function registryName(presented) {
982
984
  }
983
985
  return presented;
984
986
  }
985
- var TOOLS = [
986
- {
987
- name: mcpName("ask"),
988
- description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
989
- inputSchema: {
990
- type: "object",
991
- properties: {
992
- query: { type: "string", description: "The question (1-8000 chars)" },
993
- lang: { type: "string", description: "Answer language hint (e.g. en, fr)" }
994
- },
995
- required: ["query"]
996
- }
997
- },
998
- {
999
- name: mcpName("retrieve"),
1000
- description: "Retrieve the top passages for a query (hybrid dense + metadata steering, reranked).",
1001
- inputSchema: {
1002
- type: "object",
1003
- properties: {
1004
- query: { type: "string" },
1005
- k: { type: "number", description: "Hits to return (default 5)" }
1006
- },
1007
- required: ["query"]
1008
- }
1009
- },
1010
- ...TOOLS_REGISTRY.filter((t) => t.audiences.includes("mcp")).map((t) => ({
1011
- name: mcpName(t.name),
1012
- description: t.description,
1013
- inputSchema: {
1014
- type: "object",
1015
- properties: Object.fromEntries(t.params.map((p) => [p.key, { type: "string", description: p.description }])),
1016
- required: t.params.filter((p) => p.required).map((p) => p.key)
1017
- }
1018
- }))
1019
- ];
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
+ }
1020
1024
  function dispatch(method, params, callTool) {
1021
1025
  switch (method) {
1022
1026
  case "initialize":
@@ -1025,10 +1029,10 @@ function dispatch(method, params, callTool) {
1025
1029
  case "ping":
1026
1030
  return Promise.resolve({ ok: true, accepted: true });
1027
1031
  case "tools/list":
1028
- return Promise.resolve({ ok: true, result: { tools: TOOLS } });
1032
+ return Promise.resolve({ ok: true, result: { tools: buildTools() } });
1029
1033
  case "tools/call": {
1030
1034
  const name = typeof params?.name === "string" ? params.name : "";
1031
- if (!TOOLS.some((t) => t.name === name)) {
1035
+ if (!buildTools().some((t) => t.name === name)) {
1032
1036
  return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
1033
1037
  }
1034
1038
  return callTool(registryName(name), params?.arguments ?? {}).then(
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.138",
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",
@@ -11,14 +11,18 @@ export const PROTOCOL_VERSION = "2025-06-18";
11
11
  // across servers. The three names docs/MCP.md already publishes keep
12
12
  // their exact spelling; the mechanical transform covers the rest.
13
13
  const mcpPrefix = () => `${P().publisher.id}_`;
14
- const MCP_NAME_OVERRIDES: Record<string, string> = {
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> => ({
15
18
  retrieve: `${P().publisher.id}_search`, // the published retrieval contract
16
19
  "documents.family": `${P().publisher.id}_documents`, // the published registry contract
17
- };
20
+ });
18
21
 
19
22
  /** Registry tool name → the MCP-presented name. */
20
23
  export function mcpName(registryName: string): string {
21
- return MCP_NAME_OVERRIDES[registryName] ?? `${mcpPrefix()}${registryName.replace(/\./g, "_")}`;
24
+ const overrides = mcpOverrides();
25
+ return overrides[registryName] ?? `${mcpPrefix()}${registryName.replace(/\./g, "_")}`;
22
26
  }
23
27
 
24
28
  /** MCP-presented name → the name the handlers dispatch on. Raw
@@ -27,7 +31,8 @@ export function mcpName(registryName: string): string {
27
31
  export function registryName(presented: string): string {
28
32
  const pid = P().publisher.id;
29
33
  if (presented === `${pid}_ask`) return "ask";
30
- for (const [reg, mc] of Object.entries(MCP_NAME_OVERRIDES)) if (mc === presented) return reg;
34
+ const overrides = mcpOverrides();
35
+ for (const [reg, mc] of Object.entries(overrides)) if (mc === presented) return reg;
31
36
  if (presented.startsWith(`${pid}_`)) {
32
37
  const rest = presented.slice(pid.length + 1);
33
38
  const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
@@ -43,8 +48,14 @@ export interface McpTool {
43
48
  }
44
49
 
45
50
  // the registry's MCP-audience tools are GENERATED here (OCP: adding a
46
- // tool registers it; this list is never hand-extended for them)
47
- export const TOOLS: McpTool[] = [
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 [
48
59
  {
49
60
  name: mcpName("ask"),
50
61
  description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
@@ -80,7 +91,8 @@ export const TOOLS: McpTool[] = [
80
91
  required: t.params.filter((p) => p.required).map((p) => p.key),
81
92
  },
82
93
  })),
83
- ];
94
+ ];
95
+ }
84
96
 
85
97
  export type McpResult =
86
98
  | { ok: true; result: unknown }
@@ -101,10 +113,10 @@ export function dispatch(
101
113
  case "ping":
102
114
  return Promise.resolve({ ok: true, accepted: true });
103
115
  case "tools/list":
104
- return Promise.resolve({ ok: true, result: { tools: TOOLS } });
116
+ return Promise.resolve({ ok: true, result: { tools: buildTools() } });
105
117
  case "tools/call": {
106
118
  const name = typeof params?.name === "string" ? params.name : "";
107
- if (!TOOLS.some((t) => t.name === name)) {
119
+ if (!buildTools().some((t) => t.name === name)) {
108
120
  return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
109
121
  }
110
122
  return callTool(registryName(name), params?.arguments ?? {}).then(