@konneal/engine 0.2.137 → 0.2.138

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.
@@ -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;
@@ -961,9 +961,30 @@ 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 mcpPrefix = () => `${P().publisher.id}_`;
965
+ var MCP_NAME_OVERRIDES = {
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
+ return MCP_NAME_OVERRIDES[registryName2] ?? `${mcpPrefix()}${registryName2.replace(/\./g, "_")}`;
973
+ }
974
+ function registryName(presented) {
975
+ const pid = P().publisher.id;
976
+ if (presented === `${pid}_ask`) return "ask";
977
+ for (const [reg, mc] of Object.entries(MCP_NAME_OVERRIDES)) if (mc === presented) return reg;
978
+ if (presented.startsWith(`${pid}_`)) {
979
+ const rest = presented.slice(pid.length + 1);
980
+ const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
981
+ if (hit) return hit.name;
982
+ }
983
+ return presented;
984
+ }
964
985
  var TOOLS = [
965
986
  {
966
- name: "ask",
987
+ name: mcpName("ask"),
967
988
  description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
968
989
  inputSchema: {
969
990
  type: "object",
@@ -975,7 +996,7 @@ var TOOLS = [
975
996
  }
976
997
  },
977
998
  {
978
- name: "retrieve",
999
+ name: mcpName("retrieve"),
979
1000
  description: "Retrieve the top passages for a query (hybrid dense + metadata steering, reranked).",
980
1001
  inputSchema: {
981
1002
  type: "object",
@@ -987,7 +1008,7 @@ var TOOLS = [
987
1008
  }
988
1009
  },
989
1010
  ...TOOLS_REGISTRY.filter((t) => t.audiences.includes("mcp")).map((t) => ({
990
- name: t.name,
1011
+ name: mcpName(t.name),
991
1012
  description: t.description,
992
1013
  inputSchema: {
993
1014
  type: "object",
@@ -1010,7 +1031,7 @@ function dispatch(method, params, callTool) {
1010
1031
  if (!TOOLS.some((t) => t.name === name)) {
1011
1032
  return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
1012
1033
  }
1013
- return callTool(name, params?.arguments ?? {}).then(
1034
+ return callTool(registryName(name), params?.arguments ?? {}).then(
1014
1035
  (payload) => ({ ok: true, result: { content: [{ type: "text", text: JSON.stringify(payload) }] } })
1015
1036
  );
1016
1037
  }
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.137",
30
+ "version": "0.2.138",
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,40 @@
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
+ const MCP_NAME_OVERRIDES: Record<string, string> = {
15
+ retrieve: `${P().publisher.id}_search`, // the published retrieval contract
16
+ "documents.family": `${P().publisher.id}_documents`, // the published registry contract
17
+ };
18
+
19
+ /** Registry tool name → the MCP-presented name. */
20
+ export function mcpName(registryName: string): string {
21
+ return MCP_NAME_OVERRIDES[registryName] ?? `${mcpPrefix()}${registryName.replace(/\./g, "_")}`;
22
+ }
23
+
24
+ /** MCP-presented name → the name the handlers dispatch on. Raw
25
+ * registry names pass through (transition tolerance for early
26
+ * consumers of the unprefixed surface). */
27
+ export function registryName(presented: string): string {
28
+ const pid = P().publisher.id;
29
+ if (presented === `${pid}_ask`) return "ask";
30
+ for (const [reg, mc] of Object.entries(MCP_NAME_OVERRIDES)) if (mc === presented) return reg;
31
+ if (presented.startsWith(`${pid}_`)) {
32
+ const rest = presented.slice(pid.length + 1);
33
+ const hit = TOOLS_REGISTRY.find((t) => t.audiences.includes("mcp") && t.name.replace(/\./g, "_") === rest);
34
+ if (hit) return hit.name;
35
+ }
36
+ return presented;
37
+ }
38
+
7
39
  export interface McpTool {
8
40
  name: string;
9
41
  description: string;
@@ -14,7 +46,7 @@ export interface McpTool {
14
46
  // tool registers it; this list is never hand-extended for them)
15
47
  export const TOOLS: McpTool[] = [
16
48
  {
17
- name: "ask",
49
+ name: mcpName("ask"),
18
50
  description: "Ask the corpus a question; returns a citation-grounded answer with the passages it rests on.",
19
51
  inputSchema: {
20
52
  type: "object",
@@ -26,7 +58,7 @@ export const TOOLS: McpTool[] = [
26
58
  },
27
59
  },
28
60
  {
29
- name: "retrieve",
61
+ name: mcpName("retrieve"),
30
62
  description: "Retrieve the top passages for a query (hybrid dense + metadata steering, reranked).",
31
63
  inputSchema: {
32
64
  type: "object",
@@ -40,7 +72,7 @@ export const TOOLS: McpTool[] = [
40
72
  ...TOOLS_REGISTRY
41
73
  .filter((t) => t.audiences.includes("mcp"))
42
74
  .map((t): McpTool => ({
43
- name: t.name,
75
+ name: mcpName(t.name),
44
76
  description: t.description,
45
77
  inputSchema: {
46
78
  type: "object",
@@ -75,7 +107,7 @@ export function dispatch(
75
107
  if (!TOOLS.some((t) => t.name === name)) {
76
108
  return Promise.resolve({ ok: false, code: -32602, message: `unknown tool: ${name}` });
77
109
  }
78
- return callTool(name, params?.arguments ?? {}).then(
110
+ return callTool(registryName(name), params?.arguments ?? {}).then(
79
111
  (payload) => ({ ok: true, result: { content: [{ type: "text", text: JSON.stringify(payload) }] } }) as McpResult,
80
112
  );
81
113
  }