@webpieces/mcp-server 0.4.962 → 0.4.964

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/README.md CHANGED
@@ -330,7 +330,7 @@ precise `kind`, a small ownership `category`, explicit `retry` guidance, a safe
330
330
  `retryAfterSeconds`, and `statusCode`. It never repeats `isError` inside the content.
331
331
 
332
332
  MCP keeps no retry table of its own: the advice is a function of the ONE outcome
333
- `ClientRegistry.classify` gives every reader (`RetryStrategy`, `LogApiCall`), the endpoint's
333
+ `ApiRegistry.classify` gives every reader (`RetryStrategy`, `LogApiCall`), the endpoint's
334
334
  operation, and `retryAfterSeconds`. Implementation failures are `category: "bug", retry: "never"` and
335
335
  tell the caller to give the request ID to support; operator details remain redacted. Generic
336
336
  dependency failures are also non-retryable, and so is `retries-exhausted` (`category: "dependency",
@@ -349,7 +349,7 @@ Every reply carries the requestId so a user can quote it: `_meta["webpieces/requ
349
349
  An app owns its error taxonomy and owns how those errors should be explained to a model, so a
350
350
  registered translator REPLACES the webpieces default for every `tools/call` failure — the same
351
351
  convention `ExpressWrapper.handleError` applies on the HTTP path. Register one with
352
- `McpRegistry.setErrorTranslator(...)`: ONE process-global per protocol, mirroring `ClientRegistry`
352
+ `McpRegistry.setErrorTranslator(...)`: ONE process-global per protocol, mirroring `ApiRegistry`
353
353
  for HTTP and `IpcRegistry` for IPC, so every call site is one unconditional line. (Two MCP servers in
354
354
  one process therefore share one translator, and registration order matters rather than being fixed at
355
355
  construction — the trade taken deliberately in issue #968 to make all three protocols read alike.)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/mcp-server",
3
- "version": "0.4.962",
3
+ "version": "0.4.964",
4
4
  "description": "Secure MCP tool generation from annotated Webpieces API contracts",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -24,15 +24,15 @@
24
24
  "dependencies": {
25
25
  "@modelcontextprotocol/node": "2.0.0",
26
26
  "@modelcontextprotocol/server": "2.0.0",
27
- "@webpieces/core-context": "0.4.962",
28
- "@webpieces/core-util": "0.4.962",
29
- "@webpieces/http-routing": "0.4.962",
30
- "@webpieces/http-server": "0.4.962",
27
+ "@webpieces/core-context": "0.4.964",
28
+ "@webpieces/core-util": "0.4.964",
29
+ "@webpieces/http-routing": "0.4.964",
30
+ "@webpieces/http-server": "0.4.964",
31
31
  "express": "5.1.0",
32
32
  "reflect-metadata": "0.2.2",
33
33
  "tslib": "2.8.1"
34
34
  },
35
35
  "devDependencies": {
36
- "@webpieces/http-client-node": "0.4.962"
36
+ "@webpieces/http-client-node": "0.4.964"
37
37
  }
38
38
  }
@@ -6,7 +6,7 @@
6
6
  * ladder; an app that wants MCP-protocol-specific classification registers for this class:
7
7
  *
8
8
  * ```ts
9
- * ClientRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), McpProtocol);
9
+ * ApiRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), CallScope.api(McpProtocol));
10
10
  * ```
11
11
  *
12
12
  * A `tools/call` whose tool WAS resolved names the tool's bound `@ApiPath` contract instead.
@@ -9,7 +9,7 @@ exports.McpProtocol = void 0;
9
9
  * ladder; an app that wants MCP-protocol-specific classification registers for this class:
10
10
  *
11
11
  * ```ts
12
- * ClientRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), McpProtocol);
12
+ * ApiRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), CallScope.api(McpProtocol));
13
13
  * ```
14
14
  *
15
15
  * A `tools/call` whose tool WAS resolved names the tool's bound `@ApiPath` contract instead.
@@ -1 +1 @@
1
- {"version":3,"file":"McpProtocol.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpProtocol.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,MAAsB,WAAW;CAAG;AAApC,kCAAoC","sourcesContent":["/**\n * The framework-owned contract CLASS for MCP protocol steps — `initialize`, `tools/list`, the HTTP\n * edge, and a `tools/call` that failed before its tool was resolved. Those steps have no user\n * contract, but an `ApiMethodInfo` / `CallContext` always names a contract CLASS (#1350), so they name\n * this one. Nothing is registered for it by default, so they reach the `ALL` rung of the `CallScope`\n * ladder; an app that wants MCP-protocol-specific classification registers for this class:\n *\n * ```ts\n * ClientRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), McpProtocol);\n * ```\n *\n * A `tools/call` whose tool WAS resolved names the tool's bound `@ApiPath` contract instead.\n */\nexport abstract class McpProtocol {}\n"]}
1
+ {"version":3,"file":"McpProtocol.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpProtocol.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;GAYG;AACH,MAAsB,WAAW;CAAG;AAApC,kCAAoC","sourcesContent":["/**\n * The framework-owned contract CLASS for MCP protocol steps — `initialize`, `tools/list`, the HTTP\n * edge, and a `tools/call` that failed before its tool was resolved. Those steps have no user\n * contract, but an `ApiMethodInfo` / `CallContext` always names a contract CLASS (#1350), so they name\n * this one. Nothing is registered for it by default, so they reach the `ALL` rung of the `CallScope`\n * ladder; an app that wants MCP-protocol-specific classification registers for this class:\n *\n * ```ts\n * ApiRegistry.setErrorClassifier(new MyMcpProtocolClassifier(), CallScope.api(McpProtocol));\n * ```\n *\n * A `tools/call` whose tool WAS resolved names the tool's bound `@ApiPath` contract instead.\n */\nexport abstract class McpProtocol {}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { McpErrorTranslator } from './McpToolCallRendering';
2
2
  /**
3
3
  * McpRegistry - the process-global home of the ONE {@link McpErrorTranslator}, mirroring
4
- * `ClientRegistry` for HTTP and `IpcRegistry` for IPC.
4
+ * `ApiRegistry` for HTTP and `IpcRegistry` for IPC.
5
5
  *
6
6
  * ```ts
7
7
  * // startup, ONCE per process
@@ -4,7 +4,7 @@ exports.McpRegistry = void 0;
4
4
  const McpToolCallRendering_1 = require("./McpToolCallRendering");
5
5
  /**
6
6
  * McpRegistry - the process-global home of the ONE {@link McpErrorTranslator}, mirroring
7
- * `ClientRegistry` for HTTP and `IpcRegistry` for IPC.
7
+ * `ApiRegistry` for HTTP and `IpcRegistry` for IPC.
8
8
  *
9
9
  * ```ts
10
10
  * // startup, ONCE per process
@@ -1 +1 @@
1
- {"version":3,"file":"McpRegistry.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpRegistry.ts"],"names":[],"mappings":";;;AAAA,iEAAwF;AAExF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,WAAW;IACpB;;;OAGG;IACK,MAAM,CAAC,eAAe,GAAuB,IAAI,iDAA0B,EAAE,CAAC;IAEtF;;;;OAIG;IACH,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB,CAAC,UAA8B;QACpD,WAAW,CAAC,eAAe,GAAG,UAAU,CAAC;IAC7C,CAAC;IAED,kGAAkG;IAClG,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB;QACrB,OAAO,WAAW,CAAC,eAAe,CAAC;IACvC,CAAC;IAED,6FAA6F;IAC7F,4JAA4J;IAC5J,MAAM,CAAC,aAAa;QAChB,WAAW,CAAC,eAAe,GAAG,IAAI,iDAA0B,EAAE,CAAC;IACnE,CAAC;;AA3BL,kCA4BC","sourcesContent":["import { McpDefaultToolCallRenderer, McpErrorTranslator } from './McpToolCallRendering';\n\n/**\n * McpRegistry - the process-global home of the ONE {@link McpErrorTranslator}, mirroring\n * `ClientRegistry` for HTTP and `IpcRegistry` for IPC.\n *\n * ```ts\n * // startup, ONCE per process\n * McpRegistry.setErrorTranslator(new MyMcpErrorTranslator());\n * ```\n *\n * # This REVERSES the constructor-argument decision of #953, deliberately\n *\n * `WpMcpServerConfig.setErrorTranslator(...)` used to carry this, on the argument that `WpMcpServer`\n * is constructed by app code and two servers may run in one process. The trade is now taken the other\n * way, with the repo owner's explicit agreement: two MCP servers in one process share ONE translator,\n * and registration order matters rather than being fixed at construction.\n *\n * What buys that back is uniformity. HTTP, MCP and IPC now have the identical shape — one registry per\n * protocol, a non-optional `getErrorTranslator()`, a webpieces default that is always installed, and\n * therefore exactly one unconditional line at every call site. The \"did anyone register one\" branch\n * that the optional config member forced on `WpMcpErrorTranslator` is gone, and an app reads one\n * pattern instead of three.\n */\nexport class McpRegistry {\n /**\n * THE translator. NEVER undefined — it starts life holding a {@link McpDefaultToolCallRenderer},\n * and {@link McpRegistry.setErrorTranslator} REPLACES it.\n */\n private static errorTranslator: McpErrorTranslator = new McpDefaultToolCallRenderer();\n\n /**\n * Install the app's {@link McpErrorTranslator} — it REPLACES the webpieces default for every\n * `tools/call` failure, owning the ENTIRE result, and declines by delegating to\n * `new McpDefaultToolCallRenderer().toWire(error)`.\n */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static setErrorTranslator(translator: McpErrorTranslator): void {\n McpRegistry.errorTranslator = translator;\n }\n\n /** THE {@link McpErrorTranslator} for this process — never `undefined`, so no caller branches. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static getErrorTranslator(): McpErrorTranslator {\n return McpRegistry.errorTranslator;\n }\n\n /** Put the process-global back to the webpieces default. For TESTS, so specs cannot leak. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static resetForTests(): void {\n McpRegistry.errorTranslator = new McpDefaultToolCallRenderer();\n }\n}\n"]}
1
+ {"version":3,"file":"McpRegistry.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpRegistry.ts"],"names":[],"mappings":";;;AAAA,iEAAwF;AAExF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,WAAW;IACpB;;;OAGG;IACK,MAAM,CAAC,eAAe,GAAuB,IAAI,iDAA0B,EAAE,CAAC;IAEtF;;;;OAIG;IACH,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB,CAAC,UAA8B;QACpD,WAAW,CAAC,eAAe,GAAG,UAAU,CAAC;IAC7C,CAAC;IAED,kGAAkG;IAClG,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB;QACrB,OAAO,WAAW,CAAC,eAAe,CAAC;IACvC,CAAC;IAED,6FAA6F;IAC7F,4JAA4J;IAC5J,MAAM,CAAC,aAAa;QAChB,WAAW,CAAC,eAAe,GAAG,IAAI,iDAA0B,EAAE,CAAC;IACnE,CAAC;;AA3BL,kCA4BC","sourcesContent":["import { McpDefaultToolCallRenderer, McpErrorTranslator } from './McpToolCallRendering';\n\n/**\n * McpRegistry - the process-global home of the ONE {@link McpErrorTranslator}, mirroring\n * `ApiRegistry` for HTTP and `IpcRegistry` for IPC.\n *\n * ```ts\n * // startup, ONCE per process\n * McpRegistry.setErrorTranslator(new MyMcpErrorTranslator());\n * ```\n *\n * # This REVERSES the constructor-argument decision of #953, deliberately\n *\n * `WpMcpServerConfig.setErrorTranslator(...)` used to carry this, on the argument that `WpMcpServer`\n * is constructed by app code and two servers may run in one process. The trade is now taken the other\n * way, with the repo owner's explicit agreement: two MCP servers in one process share ONE translator,\n * and registration order matters rather than being fixed at construction.\n *\n * What buys that back is uniformity. HTTP, MCP and IPC now have the identical shape — one registry per\n * protocol, a non-optional `getErrorTranslator()`, a webpieces default that is always installed, and\n * therefore exactly one unconditional line at every call site. The \"did anyone register one\" branch\n * that the optional config member forced on `WpMcpErrorTranslator` is gone, and an app reads one\n * pattern instead of three.\n */\nexport class McpRegistry {\n /**\n * THE translator. NEVER undefined — it starts life holding a {@link McpDefaultToolCallRenderer},\n * and {@link McpRegistry.setErrorTranslator} REPLACES it.\n */\n private static errorTranslator: McpErrorTranslator = new McpDefaultToolCallRenderer();\n\n /**\n * Install the app's {@link McpErrorTranslator} — it REPLACES the webpieces default for every\n * `tools/call` failure, owning the ENTIRE result, and declines by delegating to\n * `new McpDefaultToolCallRenderer().toWire(error)`.\n */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static setErrorTranslator(translator: McpErrorTranslator): void {\n McpRegistry.errorTranslator = translator;\n }\n\n /** THE {@link McpErrorTranslator} for this process — never `undefined`, so no caller branches. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static getErrorTranslator(): McpErrorTranslator {\n return McpRegistry.errorTranslator;\n }\n\n /** Put the process-global back to the webpieces default. For TESTS, so specs cannot leak. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static resetForTests(): void {\n McpRegistry.errorTranslator = new McpDefaultToolCallRenderer();\n }\n}\n"]}
@@ -74,7 +74,7 @@ export declare class McpHttpErrorDetail {
74
74
  }
75
75
  /**
76
76
  * The application's own `tools/call` error translation — the MCP twin of the `ErrorTranslator` an app
77
- * registers on `ClientRegistry` for HTTP and the `IpcErrorTranslator` it registers on `IpcRegistry`.
77
+ * registers on `ApiRegistry` for HTTP and the `IpcErrorTranslator` it registers on `IpcRegistry`.
78
78
  * Register one with {@link McpRegistry.setErrorTranslator}.
79
79
  *
80
80
  * An app owns its error taxonomy and owns how those errors should be explained to a model, so a
@@ -127,7 +127,7 @@ export declare class McpDefaultToolCallRenderer implements McpErrorTranslator {
127
127
  toWire(error: Error): CallToolResult;
128
128
  /**
129
129
  * MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and
130
- * the outcome is the ONE verdict `ClientRegistry.classify` gives every other reader (RetryStrategy,
130
+ * the outcome is the ONE verdict `ApiRegistry.classify` gives every other reader (RetryStrategy,
131
131
  * LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is
132
132
  * rendered by kind, with `retry: 'never'` or `'after-correction'`.
133
133
  *
@@ -138,7 +138,7 @@ class McpDefaultToolCallRenderer {
138
138
  }
139
139
  /**
140
140
  * MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and
141
- * the outcome is the ONE verdict `ClientRegistry.classify` gives every other reader (RetryStrategy,
141
+ * the outcome is the ONE verdict `ApiRegistry.classify` gives every other reader (RetryStrategy,
142
142
  * LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is
143
143
  * rendered by kind, with `retry: 'never'` or `'after-correction'`.
144
144
  *
@@ -154,7 +154,7 @@ class McpDefaultToolCallRenderer {
154
154
  const correlation = McpCorrelation.current();
155
155
  const toolName = correlation.toolName ?? 'unknown';
156
156
  const methodInfo = new core_util_1.ApiMethodInfo('server', 'WpMcpServer', toolName, correlation.contract);
157
- if (core_util_1.ClientRegistry.classify(error, methodInfo) === core_util_1.CallOutcome.TRANSIENT_FAILURE) {
157
+ if (core_util_1.ApiRegistry.classify(error, methodInfo) === core_util_1.CallOutcome.TRANSIENT_FAILURE) {
158
158
  return this.transient(payload, requestId, this.transientMessage(payload));
159
159
  }
160
160
  return this.settled(payload, requestId, support);
@@ -1 +1 @@
1
- {"version":3,"file":"McpToolCallRendering.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpToolCallRendering.ts"],"names":[],"mappings":";;;AACA,oDAU8B;AAC9B,0DAAyD;AACzD,+CAA4C;AAE5C,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,qBAAqB,CAAC;AAE7D,6FAA6F;AAC7F,MAAa,YAAY;IACO;IAA5B,YAA4B,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;CACpD;AAFD,oCAEC;AAED;;;;;;;;;GASG;AACH,MAAa,cAAc;IAUH;IAKA;IACA;IACA;IAhBpB,mGAAmG;IACnG,MAAM,CAAU,GAAG,GAAG,sBAAU,CAAC,SAAS,CACtC,2BAA2B,EAC3B,SAAS,EACT,KAAK;IACL,YAAY,CAAC,KAAK,CACrB,CAAC;IAEF,YACoB,SAAiC;IACjD;;;OAGG;IACa,QAAkB,EAClB,QAAiB,EACjB,SAA6B;QAP7B,cAAS,GAAT,SAAS,CAAwB;QAKjC,aAAQ,GAAR,QAAQ,CAAU;QAClB,aAAQ,GAAR,QAAQ,CAAS;QACjB,cAAS,GAAT,SAAS,CAAoB;IAC9C,CAAC;IAEJ,iGAAiG;IACjG,0FAA0F;IAC1F,MAAM,CAAC,KAAK,CAAC,WAA2B;QACpC,6BAAc,CAAC,YAAY,CAAC,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACjE,CAAC;IAED,mGAAmG;IACnG,0FAA0F;IAC1F,MAAM,CAAC,OAAO;QACV,OAAO,6BAAc,CAAC,YAAY,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,IAAI,cAAc,CAAC,IAAI,EAAE,yBAAW,CAAC,CAAC;IACpG,CAAC;IAED,0FAA0F;IAC1F,0FAA0F;IAC1F,MAAM,CAAC,SAAS;QACZ,OAAO,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,UAAU,CAAC,IAAI,oBAAoB,CAAC;IAChG,CAAC;;AApCL,wCAqCC;AAED,yEAAyE;AACzE,MAAa,qBAAqB;IAEV;IACA;IACA;IAMA;IACA;IACA;IACA;IACA;IACA;IACA;IAfpB,YACoB,IAAY,EACZ,QAAkE,EAClE,KAKc,EACd,OAAe,EACf,SAAiB,EACjB,KAAc,EACd,aAAsB,EACtB,SAAkB,EAClB,iBAA0B,EAC1B,UAAmB;QAdnB,SAAI,GAAJ,IAAI,CAAQ;QACZ,aAAQ,GAAR,QAAQ,CAA0D;QAClE,UAAK,GAAL,KAAK,CAKS;QACd,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAQ;QACjB,UAAK,GAAL,KAAK,CAAS;QACd,kBAAa,GAAb,aAAa,CAAS;QACtB,cAAS,GAAT,SAAS,CAAS;QAClB,sBAAiB,GAAjB,iBAAiB,CAAS;QAC1B,eAAU,GAAV,UAAU,CAAS;IACpC,CAAC;CACP;AAlBD,sDAkBC;AAED,oFAAoF;AACpF,MAAa,6BAA6B;IACV;IAA5B,YAA4B,KAA4B;QAA5B,UAAK,GAAL,KAAK,CAAuB;IAAG,CAAC;CAC/D;AAFD,sEAEC;AAED,mFAAmF;AACnF,MAAa,gBAAgB;IAGL;IACA;IAHX,OAAO,GAAG,KAAK,CAAC;IACzB,YACoB,KAAyB,EACzB,EAA0B;QAD1B,UAAK,GAAL,KAAK,CAAoB;QACzB,OAAE,GAAF,EAAE,CAAwB;IAC3C,CAAC;CACP;AAND,4CAMC;AAED,MAAa,kBAAkB;IAEP;IACA;IACA;IAHpB,YACoB,IAAY,EACZ,OAAe,EACf,IAAkB;QAFlB,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAQ;QACf,SAAI,GAAJ,IAAI,CAAc;IACnC,CAAC;CACP;AAND,gDAMC;AA6CD;;;;;;;GAOG;AACH,MAAa,0BAA0B;IAClB,QAAQ,GAAG,IAAI,4BAAgB,EAAE,CAAC;IAEnD,MAAM,CAAC,KAAY;QACf,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,6BAA6B,CAC7C,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CACnE,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAmB,CAAC,CAAC;QACjD,OAAO;YACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,EAAE,CAAC,+BAAuB,CAAC,EAAE,SAAS,EAAE;SAClD,CAAC;IACN,CAAC;IAED;;;;;;;;;OASG;IACK,YAAY,CAChB,KAAY,EACZ,OAAwB,EACxB,SAAiB;QAEjB,MAAM,OAAO,GAAG,kBAAkB,SAAS,+DAA+D,CAAC;QAC3G,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,IAAI,SAAS,CAAC;QACnD,MAAM,UAAU,GAAG,IAAI,yBAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC9F,IAAI,0BAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,uBAAW,CAAC,iBAAiB,EAAE,CAAC;YAC/E,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,oFAAoF;IAC5E,OAAO,CACX,OAAwB,EACxB,SAAiB,EACjB,OAAe;QAEf,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,UAAU;gBACX,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,kBAAkB,EAClB,OAAO,CAAC,OAAO,CAClB,CAAC;YACN,KAAK,aAAa;gBACd,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,kBAAkB,EAClB,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,OAAO,CAC3C,CAAC;YACN,KAAK,cAAc,CAAC;YACpB,KAAK,WAAW;gBACZ,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,kBAAkB,EAClB,8HAA8H,CACjI,CAAC;YACN,KAAK,WAAW,CAAC;YACjB,KAAK,oBAAoB,CAAC;YAC1B,KAAK,UAAU,CAAC;YAChB,KAAK,eAAe,CAAC;YACrB,KAAK,qBAAqB,CAAC;YAC3B,KAAK,wBAAwB;gBACzB,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,kBAAkB,EAClB,GAAG,OAAO,CAAC,OAAO,sEAAsE,CAC3F,CAAC;YACN;gBACI,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC;IACL,CAAC;IAED,mGAAmG;IAC3F,cAAc,CAClB,OAAwB,EACxB,SAAiB,EACjB,OAAe;QAEf,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,iBAAiB;gBAClB,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,KAAK,EACL,OAAO,EACP,6FAA6F,OAAO,EAAE,CACzG,CAAC;YACN,KAAK,mBAAmB;gBACpB,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,YAAY,EACZ,OAAO,EACP,oIAAoI,OAAO,EAAE,CAChJ,CAAC;YACN,KAAK,OAAO;gBACR,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACnD;gBACI,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,YAAY,EACZ,OAAO,EACP,0GAA0G,OAAO,EAAE,CACtH,CAAC;QACV,CAAC;IACL,CAAC;IAED,+FAA+F;IACvF,gBAAgB,CAAC,OAAwB;QAC7C,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,iBAAiB,CAAC;YACvB,KAAK,oBAAoB;gBACrB,OAAO,6EAA6E,CAAC;YACzF,KAAK,aAAa;gBACd,OAAO,qGAAqG,CAAC;YACjH,KAAK,cAAc,CAAC;YACpB,KAAK,oBAAoB;gBACrB,OAAO,OAAO,CAAC,iBAAiB,KAAK,SAAS;oBAC1C,CAAC,CAAC,wDAAwD;oBAC1D,CAAC,CAAC,8CAA8C,OAAO,CAAC,iBAAiB,2BAA2B,CAAC;YAC7G,KAAK,OAAO;gBACR,OAAO,kCAAkC,OAAO,CAAC,UAAU,IAAI,GAAG,oDAAoD,CAAC;YAC3H;gBACI,OAAO,mGAAmG,CAAC;QACnH,CAAC;IACL,CAAC;IAEO,KAAK,CACT,OAAwB,EACxB,SAAiB,EACjB,OAAe;QAEf,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,YAAY,EACZ,OAAO,EACP,yCAAyC,OAAO,CAAC,UAAU,IAAI,GAAG,mDAAmD,OAAO,EAAE,CACjI,CAAC;QACN,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3F,CAAC;IAEO,GAAG,CACP,OAAwB,EACxB,SAAiB,EACjB,OAAe;QAEf,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,KAAK,EACL,OAAO,EACP,YAAY,cAAc,CAAC,OAAO,EAAE,CAAC,QAAQ,IAAI,SAAS,gCAAgC;YACtF,qDAAqD,OAAO,EAAE,CACrE,CAAC;IACN,CAAC;IAEO,SAAS,CACb,OAAwB,EACxB,SAAiB,EACjB,OAAe;QAEf,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC,SAAS,IAAI,OAAO,CAAC;QAChE,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,WAAW,EACX,wBAAwB,EACxB,GAAG,OAAO,+GAA+G,CAC5H,CAAC;QACN,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;QAC/E,OAAO,IAAI,CAAC,OAAO,CACf,OAAO,EACP,SAAS,EACT,WAAW,EACX,KAAK,EACL,GAAG,OAAO,qBAAqB,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,wBAAwB,OAAO,CAAC,iBAAiB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,iBAAiB,UAAU,GAAG,CACxN,CAAC;IACN,CAAC;IAEO,OAAO,CACX,OAAwB,EACxB,SAAiB,EACjB,QAA2C,EAC3C,KAAqC,EACrC,OAAe;QAEf,OAAO,IAAI,qBAAqB,CAC5B,OAAO,CAAC,IAAI,EACZ,QAAQ,EACR,KAAK,EACL,OAAO,EACP,SAAS,EACT,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,iBAAiB,EACzB,OAAO,CAAC,UAAU,CACrB,CAAC;IACN,CAAC;CACJ;AAnOD,gEAmOC","sourcesContent":["import { CallToolResult } from '@modelcontextprotocol/server';\nimport {\n ApiErrorBoundary,\n ApiErrorPayload,\n ApiMethodInfo,\n CallOutcome,\n ClientRegistry,\n ContextKey,\n DtoValue,\n EndpointOperation,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { McpProtocol } from './McpProtocol';\n\n/** `_meta` key carrying the Webpieces requestId on every tools/call result, success or failure. */\nexport const MCP_REQUEST_ID_META_KEY = 'webpieces/requestId';\n\n/** JSON-RPC error `data` so a user can quote the requestId of any protocol-level failure. */\nexport class McpErrorData {\n constructor(public readonly requestId: string) {}\n}\n\n/**\n * The two per-request facts a renderer needs that are NOT the error: the JSON-RPC `id` it must echo,\n * and the tool being called. They are stamped into the request scope by `WpMcpServer` rather than\n * threaded through every renderer signature, because `requestId` already travels that way\n * ({@link WebpiecesCoreHeaders.REQUEST_ID}) and a second, parallel correlation parameter was a COPY\n * of the context — which is what the deleted `McpFailureScope` was.\n *\n * Context-only and never logged: the logging backends read `RequestContext` for correlation on every\n * record already, and this object exists purely so the renderers can be one-argument functions.\n */\nexport class McpCorrelation {\n // webpieces-disable no-any-unknown -- ContextKey value types are per-key; this one is context-only\n static readonly KEY = ContextKey.untrusted<McpCorrelation>(\n 'webpieces-mcp-correlation',\n undefined,\n false,\n /*isLogged*/ false,\n );\n\n constructor(\n public readonly jsonRpcId: string | number | null,\n /**\n * The contract CLASS this request is classified under: the resolved tool's bound `@ApiPath`\n * contract, or {@link McpProtocol} while no tool is resolved (a protocol step, an unknown tool).\n */\n public readonly contract: Function,\n public readonly toolName?: string,\n public readonly operation?: EndpointOperation,\n ) {}\n\n /** Stamp what this request knows so far; `WpMcpServer` re-stamps once the tool name is known. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static stamp(correlation: McpCorrelation): void {\n RequestContext.putUntrusted(McpCorrelation.KEY, correlation);\n }\n\n /** A renderer reached before anything stamped (a failure with no parseable body) still renders. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static current(): McpCorrelation {\n return RequestContext.getUntrusted(McpCorrelation.KEY) ?? new McpCorrelation(null, McpProtocol);\n }\n\n /** The webpieces requestId of the request being served, as every MCP reply reports it. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static requestId(): string {\n return RequestContext.getUntrusted(WebpiecesCoreHeaders.REQUEST_ID) ?? 'missing-request-id';\n }\n}\n\n/** The only error shape rendered into model-visible MCP tool content. */\nexport class ModelVisibleToolError {\n constructor(\n public readonly kind: string,\n public readonly category: 'bug' | 'caller' | 'dependency' | 'temporary' | 'access',\n public readonly retry:\n | 'never'\n | 'after-correction'\n | 'after-delay'\n | 'safe'\n | 'unsafe-outcome-unknown',\n public readonly message: string,\n public readonly requestId: string,\n public readonly field?: string,\n public readonly callerMessage?: string,\n public readonly errorCode?: string,\n public readonly retryAfterSeconds?: number,\n public readonly statusCode?: number,\n ) {}\n}\n\n/** Explicit content-level envelope for clients that hide CallToolResult.isError. */\nexport class ModelVisibleToolErrorEnvelope {\n constructor(public readonly error: ModelVisibleToolError) {}\n}\n\n/** JSON-RPC error body written by the HTTP boundary before the SDK is involved. */\nexport class McpHttpErrorBody {\n readonly jsonrpc = '2.0';\n constructor(\n public readonly error: McpHttpErrorDetail,\n public readonly id: string | number | null,\n ) {}\n}\n\nexport class McpHttpErrorDetail {\n constructor(\n public readonly code: number,\n public readonly message: string,\n public readonly data: McpErrorData,\n ) {}\n}\n\n/**\n * The application's own `tools/call` error translation — the MCP twin of the `ErrorTranslator` an app\n * registers on `ClientRegistry` for HTTP and the `IpcErrorTranslator` it registers on `IpcRegistry`.\n * Register one with {@link McpRegistry.setErrorTranslator}.\n *\n * An app owns its error taxonomy and owns how those errors should be explained to a model, so a\n * claimed error yields the ENTIRE `CallToolResult` — content, `structuredContent`, `isError`, the lot.\n *\n * # There is NO `fromWire`, and that is the protocol, not an oversight\n *\n * The HTTP and IPC translators have two halves because webpieces sits on BOTH ends of those wires: it\n * writes the response AND, in another process, reads one. **webpieces is never the MCP client.** The\n * client is Claude (or another model host); there is no return path for webpieces to translate, so\n * the pair is one-directional by nature. Do not \"restore the symmetry\" by adding a half with nothing\n * to call it.\n *\n * # The pre-SDK boundary does NOT share the HTTP `ErrorTranslator`, despite the identical type\n *\n * `WpMcpErrorTranslator.toBearerBoundaryResponse` returns an `HttpResponseDto`, exactly like\n * `ErrorTranslator.toWire` — and it must STILL not be routed through it. Two reasons, both hard:\n *\n * - its body must stay JSON-RPC shaped (`McpHttpErrorBody`) or an MCP client cannot parse the reply\n * at all, whereas an app's HTTP translator publishes the app's own REST envelope;\n * - it emits the `401 + WWW-Authenticate: Bearer resource_metadata=...` that MCP clients use for OAuth\n * discovery, so an app rewriting it breaks connector onboarding.\n *\n * Same TYPE, different OWNER. `tools/list` is framework-owned for the same reason.\n *\n * Contract:\n * - `error` is the RAW thrown value: an app must be able to `instanceof` its own error classes.\n * `ApiErrorBoundary` never substitutes an object for the thrown error, so there is exactly one\n * error value on this path.\n * - There is no \"not mine\" return. A registered translator REPLACES the webpieces default and\n * declines by DELEGATING to it: `new McpDefaultToolCallRenderer().toWire(error)`.\n * - webpieces default-fills `_meta['webpieces/requestId']` only when the returned result has NO\n * `_meta`. An app that sets `_meta` owns it untouched.\n * - scope is `tools/call` ONLY.\n */\nexport interface McpErrorTranslator {\n /** An error in, the whole `tools/call` reply out. Named for its HTTP and IPC twins. */\n toWire(error: Error): CallToolResult;\n}\n\n/**\n * webpieces' DEFAULT `tools/call` rendering, and what {@link McpRegistry} holds until an app installs\n * its own. Public so an app's own {@link McpErrorTranslator} can DECLINE an error by delegating to it\n * — the MCP twin of `WebpiecesDefaultErrorTranslator.toWire` on the HTTP side.\n *\n * Published text comes only from {@link ApiErrorBoundary.encode}: this never puts an error's own\n * message in front of a model unless it is an `ApiEndUserError`.\n */\nexport class McpDefaultToolCallRenderer implements McpErrorTranslator {\n private readonly boundary = new ApiErrorBoundary();\n\n toWire(error: Error): CallToolResult {\n const requestId = McpCorrelation.requestId();\n const visible = new ModelVisibleToolErrorEnvelope(\n this.modelVisible(error, this.boundary.encode(error), requestId),\n );\n const text = JSON.stringify(visible as DtoValue);\n return {\n content: [{ type: 'text', text }],\n isError: true,\n _meta: { [MCP_REQUEST_ID_META_KEY]: requestId },\n };\n }\n\n /**\n * MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and\n * the outcome is the ONE verdict `ClientRegistry.classify` gives every other reader (RetryStrategy,\n * LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is\n * rendered by kind, with `retry: 'never'` or `'after-correction'`.\n *\n * The one thing decided before the classifier is the published `implementation` kind: the\n * boundary has already ruled that this server is at fault — including a caller-local\n * `ApiConnectionError` (#959) — so it is a bug, and a model is never told a bug is worth retrying.\n */\n private modelVisible(\n error: Error,\n payload: ApiErrorPayload,\n requestId: string,\n ): ModelVisibleToolError {\n const support = `Give requestId ${requestId} to support so the internal failure can be located and fixed.`;\n if (payload.kind === 'implementation') {\n return this.bug(payload, requestId, support);\n }\n const correlation = McpCorrelation.current();\n const toolName = correlation.toolName ?? 'unknown';\n const methodInfo = new ApiMethodInfo('server', 'WpMcpServer', toolName, correlation.contract);\n if (ClientRegistry.classify(error, methodInfo) === CallOutcome.TRANSIENT_FAILURE) {\n return this.transient(payload, requestId, this.transientMessage(payload));\n }\n return this.settled(payload, requestId, support);\n }\n\n /** Rendering for an outcome that repeating will not change: EXPECTED or FAILURE. */\n private settled(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n switch (payload.kind) {\n case 'end-user':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n payload.message,\n );\n case 'bad-request':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n payload.callerMessage ?? payload.message,\n );\n case 'unauthorized':\n case 'forbidden':\n return this.visible(\n payload,\n requestId,\n 'access',\n 'after-correction',\n 'Access was denied. Retrying unchanged credentials and arguments will not help; correct the credentials or permissions first.',\n );\n case 'not-found':\n case 'endpoint-not-found':\n case 'conflict':\n case 'unprocessable':\n case 'precondition-failed':\n case 'unsupported-media-type':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n `${payload.message}. Correct the request or current resource state before trying again.`,\n );\n default:\n return this.settledFailure(payload, requestId, support);\n }\n }\n\n /** A FAILURE the caller cannot correct: a missing operation, an exhausted or broken dependency. */\n private settledFailure(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n switch (payload.kind) {\n case 'not-implemented':\n return this.visible(\n payload,\n requestId,\n 'bug',\n 'never',\n `The tool does not implement this operation. Retrying or changing arguments will not help. ${support}`,\n );\n case 'retries-exhausted':\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream dependency kept failing after this service already retried it. Retrying now will not help. If the failure persists, ${support}`,\n );\n case 'coded':\n return this.coded(payload, requestId, support);\n default:\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream dependency failed. Retrying or changing arguments will not help. If the failure persists, ${support}`,\n );\n }\n }\n\n /** The situation text for a TRANSIENT_FAILURE; `transient` adds the operation-aware advice. */\n private transientMessage(payload: ApiErrorPayload): string {\n switch (payload.kind) {\n case 'request-timeout':\n case 'dependency-timeout':\n return 'The operation timed out; the previous operation may already have completed.';\n case 'bad-gateway':\n return 'A gateway returned an invalid upstream response; the previous operation may already have completed.';\n case 'rate-limited':\n case 'dependency-backoff':\n return payload.retryAfterSeconds === undefined\n ? 'The operation was throttled. Do not retry immediately.'\n : `The operation was throttled. Wait at least ${payload.retryAfterSeconds} seconds before retrying.`;\n case 'coded':\n return `The operation failed with HTTP ${payload.statusCode ?? 500}; the previous operation's outcome may be unknown.`;\n default:\n return 'A required service is temporarily unavailable; the previous operation may already have completed.';\n }\n }\n\n private coded(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n if ((payload.statusCode ?? 500) >= 500) {\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream service failed with HTTP ${payload.statusCode ?? 500}. Retrying or changing arguments will not help. ${support}`,\n );\n }\n return this.visible(payload, requestId, 'caller', 'after-correction', payload.message);\n }\n\n private bug(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n return this.visible(\n payload,\n requestId,\n 'bug',\n 'never',\n `The tool ${McpCorrelation.current().toolName ?? 'unknown'} encountered an internal bug. ` +\n `Retrying or changing the arguments will not help. ${support}`,\n );\n }\n\n private transient(\n payload: ApiErrorPayload,\n requestId: string,\n message: string,\n ): ModelVisibleToolError {\n const operation = McpCorrelation.current().operation ?? 'write';\n if (operation === 'write') {\n return this.visible(\n payload,\n requestId,\n 'temporary',\n 'unsafe-outcome-unknown',\n `${message} This endpoint is a non-idempotent write, so retrying could duplicate it; verify the outcome before retrying.`,\n );\n }\n const retry = payload.retryAfterSeconds === undefined ? 'safe' : 'after-delay';\n return this.visible(\n payload,\n requestId,\n 'temporary',\n retry,\n `${message} This endpoint is ${operation === 'read' ? 'read-only' : 'idempotent'}, so retrying is safe${payload.retryAfterSeconds === undefined ? ' after a delay' : ` after ${payload.retryAfterSeconds} seconds`}.`,\n );\n }\n\n private visible(\n payload: ApiErrorPayload,\n requestId: string,\n category: ModelVisibleToolError['category'],\n retry: ModelVisibleToolError['retry'],\n message: string,\n ): ModelVisibleToolError {\n return new ModelVisibleToolError(\n payload.kind,\n category,\n retry,\n message,\n requestId,\n payload.field,\n payload.callerMessage,\n payload.errorCode,\n payload.retryAfterSeconds,\n payload.statusCode,\n );\n }\n}\n\n"]}
1
+ {"version":3,"file":"McpToolCallRendering.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpToolCallRendering.ts"],"names":[],"mappings":"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","sourcesContent":["import { CallToolResult } from '@modelcontextprotocol/server';\nimport {\n ApiErrorBoundary,\n ApiErrorPayload,\n ApiMethodInfo,\n CallOutcome,\n ContextKey,\n DtoValue,\n EndpointOperation,\n WebpiecesCoreHeaders,\n ApiRegistry,\n} from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { McpProtocol } from './McpProtocol';\n\n/** `_meta` key carrying the Webpieces requestId on every tools/call result, success or failure. */\nexport const MCP_REQUEST_ID_META_KEY = 'webpieces/requestId';\n\n/** JSON-RPC error `data` so a user can quote the requestId of any protocol-level failure. */\nexport class McpErrorData {\n constructor(public readonly requestId: string) {}\n}\n\n/**\n * The two per-request facts a renderer needs that are NOT the error: the JSON-RPC `id` it must echo,\n * and the tool being called. They are stamped into the request scope by `WpMcpServer` rather than\n * threaded through every renderer signature, because `requestId` already travels that way\n * ({@link WebpiecesCoreHeaders.REQUEST_ID}) and a second, parallel correlation parameter was a COPY\n * of the context — which is what the deleted `McpFailureScope` was.\n *\n * Context-only and never logged: the logging backends read `RequestContext` for correlation on every\n * record already, and this object exists purely so the renderers can be one-argument functions.\n */\nexport class McpCorrelation {\n // webpieces-disable no-any-unknown -- ContextKey value types are per-key; this one is context-only\n static readonly KEY = ContextKey.untrusted<McpCorrelation>(\n 'webpieces-mcp-correlation',\n undefined,\n false,\n /*isLogged*/ false,\n );\n\n constructor(\n public readonly jsonRpcId: string | number | null,\n /**\n * The contract CLASS this request is classified under: the resolved tool's bound `@ApiPath`\n * contract, or {@link McpProtocol} while no tool is resolved (a protocol step, an unknown tool).\n */\n public readonly contract: Function,\n public readonly toolName?: string,\n public readonly operation?: EndpointOperation,\n ) {}\n\n /** Stamp what this request knows so far; `WpMcpServer` re-stamps once the tool name is known. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static stamp(correlation: McpCorrelation): void {\n RequestContext.putUntrusted(McpCorrelation.KEY, correlation);\n }\n\n /** A renderer reached before anything stamped (a failure with no parseable body) still renders. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static current(): McpCorrelation {\n return RequestContext.getUntrusted(McpCorrelation.KEY) ?? new McpCorrelation(null, McpProtocol);\n }\n\n /** The webpieces requestId of the request being served, as every MCP reply reports it. */\n // webpieces-disable no-function-outside-class -- static accessor trio for one context key\n static requestId(): string {\n return RequestContext.getUntrusted(WebpiecesCoreHeaders.REQUEST_ID) ?? 'missing-request-id';\n }\n}\n\n/** The only error shape rendered into model-visible MCP tool content. */\nexport class ModelVisibleToolError {\n constructor(\n public readonly kind: string,\n public readonly category: 'bug' | 'caller' | 'dependency' | 'temporary' | 'access',\n public readonly retry:\n | 'never'\n | 'after-correction'\n | 'after-delay'\n | 'safe'\n | 'unsafe-outcome-unknown',\n public readonly message: string,\n public readonly requestId: string,\n public readonly field?: string,\n public readonly callerMessage?: string,\n public readonly errorCode?: string,\n public readonly retryAfterSeconds?: number,\n public readonly statusCode?: number,\n ) {}\n}\n\n/** Explicit content-level envelope for clients that hide CallToolResult.isError. */\nexport class ModelVisibleToolErrorEnvelope {\n constructor(public readonly error: ModelVisibleToolError) {}\n}\n\n/** JSON-RPC error body written by the HTTP boundary before the SDK is involved. */\nexport class McpHttpErrorBody {\n readonly jsonrpc = '2.0';\n constructor(\n public readonly error: McpHttpErrorDetail,\n public readonly id: string | number | null,\n ) {}\n}\n\nexport class McpHttpErrorDetail {\n constructor(\n public readonly code: number,\n public readonly message: string,\n public readonly data: McpErrorData,\n ) {}\n}\n\n/**\n * The application's own `tools/call` error translation — the MCP twin of the `ErrorTranslator` an app\n * registers on `ApiRegistry` for HTTP and the `IpcErrorTranslator` it registers on `IpcRegistry`.\n * Register one with {@link McpRegistry.setErrorTranslator}.\n *\n * An app owns its error taxonomy and owns how those errors should be explained to a model, so a\n * claimed error yields the ENTIRE `CallToolResult` — content, `structuredContent`, `isError`, the lot.\n *\n * # There is NO `fromWire`, and that is the protocol, not an oversight\n *\n * The HTTP and IPC translators have two halves because webpieces sits on BOTH ends of those wires: it\n * writes the response AND, in another process, reads one. **webpieces is never the MCP client.** The\n * client is Claude (or another model host); there is no return path for webpieces to translate, so\n * the pair is one-directional by nature. Do not \"restore the symmetry\" by adding a half with nothing\n * to call it.\n *\n * # The pre-SDK boundary does NOT share the HTTP `ErrorTranslator`, despite the identical type\n *\n * `WpMcpErrorTranslator.toBearerBoundaryResponse` returns an `HttpResponseDto`, exactly like\n * `ErrorTranslator.toWire` — and it must STILL not be routed through it. Two reasons, both hard:\n *\n * - its body must stay JSON-RPC shaped (`McpHttpErrorBody`) or an MCP client cannot parse the reply\n * at all, whereas an app's HTTP translator publishes the app's own REST envelope;\n * - it emits the `401 + WWW-Authenticate: Bearer resource_metadata=...` that MCP clients use for OAuth\n * discovery, so an app rewriting it breaks connector onboarding.\n *\n * Same TYPE, different OWNER. `tools/list` is framework-owned for the same reason.\n *\n * Contract:\n * - `error` is the RAW thrown value: an app must be able to `instanceof` its own error classes.\n * `ApiErrorBoundary` never substitutes an object for the thrown error, so there is exactly one\n * error value on this path.\n * - There is no \"not mine\" return. A registered translator REPLACES the webpieces default and\n * declines by DELEGATING to it: `new McpDefaultToolCallRenderer().toWire(error)`.\n * - webpieces default-fills `_meta['webpieces/requestId']` only when the returned result has NO\n * `_meta`. An app that sets `_meta` owns it untouched.\n * - scope is `tools/call` ONLY.\n */\nexport interface McpErrorTranslator {\n /** An error in, the whole `tools/call` reply out. Named for its HTTP and IPC twins. */\n toWire(error: Error): CallToolResult;\n}\n\n/**\n * webpieces' DEFAULT `tools/call` rendering, and what {@link McpRegistry} holds until an app installs\n * its own. Public so an app's own {@link McpErrorTranslator} can DECLINE an error by delegating to it\n * — the MCP twin of `WebpiecesDefaultErrorTranslator.toWire` on the HTTP side.\n *\n * Published text comes only from {@link ApiErrorBoundary.encode}: this never puts an error's own\n * message in front of a model unless it is an `ApiEndUserError`.\n */\nexport class McpDefaultToolCallRenderer implements McpErrorTranslator {\n private readonly boundary = new ApiErrorBoundary();\n\n toWire(error: Error): CallToolResult {\n const requestId = McpCorrelation.requestId();\n const visible = new ModelVisibleToolErrorEnvelope(\n this.modelVisible(error, this.boundary.encode(error), requestId),\n );\n const text = JSON.stringify(visible as DtoValue);\n return {\n content: [{ type: 'text', text }],\n isError: true,\n _meta: { [MCP_REQUEST_ID_META_KEY]: requestId },\n };\n }\n\n /**\n * MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and\n * the outcome is the ONE verdict `ApiRegistry.classify` gives every other reader (RetryStrategy,\n * LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is\n * rendered by kind, with `retry: 'never'` or `'after-correction'`.\n *\n * The one thing decided before the classifier is the published `implementation` kind: the\n * boundary has already ruled that this server is at fault — including a caller-local\n * `ApiConnectionError` (#959) — so it is a bug, and a model is never told a bug is worth retrying.\n */\n private modelVisible(\n error: Error,\n payload: ApiErrorPayload,\n requestId: string,\n ): ModelVisibleToolError {\n const support = `Give requestId ${requestId} to support so the internal failure can be located and fixed.`;\n if (payload.kind === 'implementation') {\n return this.bug(payload, requestId, support);\n }\n const correlation = McpCorrelation.current();\n const toolName = correlation.toolName ?? 'unknown';\n const methodInfo = new ApiMethodInfo('server', 'WpMcpServer', toolName, correlation.contract);\n if (ApiRegistry.classify(error, methodInfo) === CallOutcome.TRANSIENT_FAILURE) {\n return this.transient(payload, requestId, this.transientMessage(payload));\n }\n return this.settled(payload, requestId, support);\n }\n\n /** Rendering for an outcome that repeating will not change: EXPECTED or FAILURE. */\n private settled(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n switch (payload.kind) {\n case 'end-user':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n payload.message,\n );\n case 'bad-request':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n payload.callerMessage ?? payload.message,\n );\n case 'unauthorized':\n case 'forbidden':\n return this.visible(\n payload,\n requestId,\n 'access',\n 'after-correction',\n 'Access was denied. Retrying unchanged credentials and arguments will not help; correct the credentials or permissions first.',\n );\n case 'not-found':\n case 'endpoint-not-found':\n case 'conflict':\n case 'unprocessable':\n case 'precondition-failed':\n case 'unsupported-media-type':\n return this.visible(\n payload,\n requestId,\n 'caller',\n 'after-correction',\n `${payload.message}. Correct the request or current resource state before trying again.`,\n );\n default:\n return this.settledFailure(payload, requestId, support);\n }\n }\n\n /** A FAILURE the caller cannot correct: a missing operation, an exhausted or broken dependency. */\n private settledFailure(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n switch (payload.kind) {\n case 'not-implemented':\n return this.visible(\n payload,\n requestId,\n 'bug',\n 'never',\n `The tool does not implement this operation. Retrying or changing arguments will not help. ${support}`,\n );\n case 'retries-exhausted':\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream dependency kept failing after this service already retried it. Retrying now will not help. If the failure persists, ${support}`,\n );\n case 'coded':\n return this.coded(payload, requestId, support);\n default:\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream dependency failed. Retrying or changing arguments will not help. If the failure persists, ${support}`,\n );\n }\n }\n\n /** The situation text for a TRANSIENT_FAILURE; `transient` adds the operation-aware advice. */\n private transientMessage(payload: ApiErrorPayload): string {\n switch (payload.kind) {\n case 'request-timeout':\n case 'dependency-timeout':\n return 'The operation timed out; the previous operation may already have completed.';\n case 'bad-gateway':\n return 'A gateway returned an invalid upstream response; the previous operation may already have completed.';\n case 'rate-limited':\n case 'dependency-backoff':\n return payload.retryAfterSeconds === undefined\n ? 'The operation was throttled. Do not retry immediately.'\n : `The operation was throttled. Wait at least ${payload.retryAfterSeconds} seconds before retrying.`;\n case 'coded':\n return `The operation failed with HTTP ${payload.statusCode ?? 500}; the previous operation's outcome may be unknown.`;\n default:\n return 'A required service is temporarily unavailable; the previous operation may already have completed.';\n }\n }\n\n private coded(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n if ((payload.statusCode ?? 500) >= 500) {\n return this.visible(\n payload,\n requestId,\n 'dependency',\n 'never',\n `A downstream service failed with HTTP ${payload.statusCode ?? 500}. Retrying or changing arguments will not help. ${support}`,\n );\n }\n return this.visible(payload, requestId, 'caller', 'after-correction', payload.message);\n }\n\n private bug(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n return this.visible(\n payload,\n requestId,\n 'bug',\n 'never',\n `The tool ${McpCorrelation.current().toolName ?? 'unknown'} encountered an internal bug. ` +\n `Retrying or changing the arguments will not help. ${support}`,\n );\n }\n\n private transient(\n payload: ApiErrorPayload,\n requestId: string,\n message: string,\n ): ModelVisibleToolError {\n const operation = McpCorrelation.current().operation ?? 'write';\n if (operation === 'write') {\n return this.visible(\n payload,\n requestId,\n 'temporary',\n 'unsafe-outcome-unknown',\n `${message} This endpoint is a non-idempotent write, so retrying could duplicate it; verify the outcome before retrying.`,\n );\n }\n const retry = payload.retryAfterSeconds === undefined ? 'safe' : 'after-delay';\n return this.visible(\n payload,\n requestId,\n 'temporary',\n retry,\n `${message} This endpoint is ${operation === 'read' ? 'read-only' : 'idempotent'}, so retrying is safe${payload.retryAfterSeconds === undefined ? ' after a delay' : ` after ${payload.retryAfterSeconds} seconds`}.`,\n );\n }\n\n private visible(\n payload: ApiErrorPayload,\n requestId: string,\n category: ModelVisibleToolError['category'],\n retry: ModelVisibleToolError['retry'],\n message: string,\n ): ModelVisibleToolError {\n return new ModelVisibleToolError(\n payload.kind,\n category,\n retry,\n message,\n requestId,\n payload.field,\n payload.callerMessage,\n payload.errorCode,\n payload.retryAfterSeconds,\n payload.statusCode,\n );\n }\n}\n\n"]}
package/src/index.js CHANGED
@@ -42,7 +42,7 @@ Object.defineProperty(exports, "McpHttpErrorDetail", { enumerable: true, get: fu
42
42
  Object.defineProperty(exports, "ModelVisibleToolError", { enumerable: true, get: function () { return McpToolCallRendering_1.ModelVisibleToolError; } });
43
43
  var WpMcpErrorTranslator_1 = require("./WpMcpErrorTranslator");
44
44
  Object.defineProperty(exports, "WpMcpErrorTranslator", { enumerable: true, get: function () { return WpMcpErrorTranslator_1.WpMcpErrorTranslator; } });
45
- // The process-global home of the ONE MCP translator, mirroring ClientRegistry / IpcRegistry.
45
+ // The process-global home of the ONE MCP translator, mirroring ApiRegistry / IpcRegistry.
46
46
  var McpRegistry_1 = require("./McpRegistry");
47
47
  Object.defineProperty(exports, "McpRegistry", { enumerable: true, get: function () { return McpRegistry_1.McpRegistry; } });
48
48
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/index.ts"],"names":[],"mappings":";;;AAAA,qCASmB;AARf,gIAAA,qCAAqC,OAAA;AACrC,iIAAA,sCAAsC,OAAA;AACtC,4HAAA,iCAAiC,OAAA;AACjC,sHAAA,2BAA2B,OAAA;AAC3B,+GAAA,oBAAoB,OAAA;AACpB,uHAAA,4BAA4B,OAAA;AAC5B,gHAAA,qBAAqB,OAAA;AACrB,4GAAA,iBAAiB,OAAA;AAIrB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,qDAAuE;AAA9D,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,+DAAsF;AAA7E,8HAAA,sBAAsB,OAAA;AAAE,4HAAA,oBAAoB,OAAA;AAErD,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,+DAQgC;AAP5B,+HAAA,uBAAuB,OAAA;AACvB,sHAAA,cAAc,OAAA;AACd,kIAAA,0BAA0B,OAAA;AAC1B,oHAAA,YAAY,OAAA;AACZ,wHAAA,gBAAgB,OAAA;AAChB,0HAAA,kBAAkB,OAAA;AAClB,6HAAA,qBAAqB,OAAA;AAEzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,6FAA6F;AAC7F,6CAA4C;AAAnC,0GAAA,WAAW,OAAA","sourcesContent":["export {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS,\n MAX_MCP_SERVER_DESCRIPTION_LENGTH,\n MAX_MCP_SERVER_TITLE_LENGTH,\n MintedMcpAccessToken,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nexport type { McpAccessTokenAuthority } from './McpAuth';\nexport type { Icon } from '@modelcontextprotocol/server';\nexport { McpIcon } from './McpIcon';\nexport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nexport { McpApiBinding } from './McpApiBinding';\nexport type { McpBindingTopology } from './McpApiBinding';\nexport { MCP_INVOCATION_CONTEXT, McpInvocationContext } from './McpInvocationContext';\nexport type { McpProgressReporter } from './McpInvocationContext';\nexport { McpBindOptions } from './McpBindOptions';\nexport { McpToolCatalog } from './McpToolCatalog';\nexport { McpDeployment } from './McpDeployment';\nexport type { McpDeploymentMode } from './McpDeployment';\nexport { McpApiDispatcher } from './McpApiDispatcher';\nexport { WpMcpServer } from './WpMcpServer';\nexport { McpProtocol } from './McpProtocol';\nexport {\n MCP_REQUEST_ID_META_KEY,\n McpCorrelation,\n McpDefaultToolCallRenderer,\n McpErrorData,\n McpHttpErrorBody,\n McpHttpErrorDetail,\n ModelVisibleToolError,\n} from './McpToolCallRendering';\nexport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\nexport type { McpErrorTranslator } from './McpToolCallRendering';\n// The process-global home of the ONE MCP translator, mirroring ClientRegistry / IpcRegistry.\nexport { McpRegistry } from './McpRegistry';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/index.ts"],"names":[],"mappings":";;;AAAA,qCASmB;AARf,gIAAA,qCAAqC,OAAA;AACrC,iIAAA,sCAAsC,OAAA;AACtC,4HAAA,iCAAiC,OAAA;AACjC,sHAAA,2BAA2B,OAAA;AAC3B,+GAAA,oBAAoB,OAAA;AACpB,uHAAA,4BAA4B,OAAA;AAC5B,gHAAA,qBAAqB,OAAA;AACrB,4GAAA,iBAAiB,OAAA;AAIrB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,qDAAuE;AAA9D,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,+DAAsF;AAA7E,8HAAA,sBAAsB,OAAA;AAAE,4HAAA,oBAAoB,OAAA;AAErD,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,+DAQgC;AAP5B,+HAAA,uBAAuB,OAAA;AACvB,sHAAA,cAAc,OAAA;AACd,kIAAA,0BAA0B,OAAA;AAC1B,oHAAA,YAAY,OAAA;AACZ,wHAAA,gBAAgB,OAAA;AAChB,0HAAA,kBAAkB,OAAA;AAClB,6HAAA,qBAAqB,OAAA;AAEzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,0FAA0F;AAC1F,6CAA4C;AAAnC,0GAAA,WAAW,OAAA","sourcesContent":["export {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS,\n MAX_MCP_SERVER_DESCRIPTION_LENGTH,\n MAX_MCP_SERVER_TITLE_LENGTH,\n MintedMcpAccessToken,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nexport type { McpAccessTokenAuthority } from './McpAuth';\nexport type { Icon } from '@modelcontextprotocol/server';\nexport { McpIcon } from './McpIcon';\nexport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nexport { McpApiBinding } from './McpApiBinding';\nexport type { McpBindingTopology } from './McpApiBinding';\nexport { MCP_INVOCATION_CONTEXT, McpInvocationContext } from './McpInvocationContext';\nexport type { McpProgressReporter } from './McpInvocationContext';\nexport { McpBindOptions } from './McpBindOptions';\nexport { McpToolCatalog } from './McpToolCatalog';\nexport { McpDeployment } from './McpDeployment';\nexport type { McpDeploymentMode } from './McpDeployment';\nexport { McpApiDispatcher } from './McpApiDispatcher';\nexport { WpMcpServer } from './WpMcpServer';\nexport { McpProtocol } from './McpProtocol';\nexport {\n MCP_REQUEST_ID_META_KEY,\n McpCorrelation,\n McpDefaultToolCallRenderer,\n McpErrorData,\n McpHttpErrorBody,\n McpHttpErrorDetail,\n ModelVisibleToolError,\n} from './McpToolCallRendering';\nexport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\nexport type { McpErrorTranslator } from './McpToolCallRendering';\n// The process-global home of the ONE MCP translator, mirroring ApiRegistry / IpcRegistry.\nexport { McpRegistry } from './McpRegistry';\n"]}