@webpieces/mcp-server 0.4.893 → 0.4.895
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 +10 -6
- package/package.json +6 -6
- package/src/McpToolCallRendering.d.ts +16 -1
- package/src/McpToolCallRendering.js +44 -20
- package/src/McpToolCallRendering.js.map +1 -1
- package/src/__tests__/McpRemoteFixtures.js +4 -0
- package/src/__tests__/McpRemoteFixtures.js.map +1 -1
- package/src/__tests__/WpMcpServerTestFixtures.js +3 -0
- package/src/__tests__/WpMcpServerTestFixtures.js.map +1 -1
package/README.md
CHANGED
|
@@ -288,12 +288,16 @@ precise `kind`, a small ownership `category`, explicit `retry` guidance, a safe
|
|
|
288
288
|
`requestId`. It may also carry safe fields such as `field`, `callerMessage`, `errorCode`,
|
|
289
289
|
`retryAfterSeconds`, and `statusCode`. It never repeats `isError` inside the content.
|
|
290
290
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
291
|
+
MCP keeps no retry table of its own: the advice is a function of the ONE outcome
|
|
292
|
+
`ClientRegistry.classify` gives every reader (`RetryStrategy`, `LogApiCall`), the endpoint's
|
|
293
|
+
operation, and `retryAfterSeconds`. Implementation failures are `category: "bug", retry: "never"` and
|
|
294
|
+
tell the caller to give the request ID to support; operator details remain redacted. Generic
|
|
295
|
+
dependency failures are also non-retryable, and so is `retries-exhausted` (`category: "dependency",
|
|
296
|
+
retry: "never"`): this service already retried that dependency, so the model must not retry it again.
|
|
297
|
+
A `CallOutcome.TRANSIENT_FAILURE` — gateway, timeout, unavailable, throttling, backoff, or anything an
|
|
298
|
+
app's classifier marks transient — is temporary, but a retry is described as safe only for a `read`
|
|
299
|
+
or `write-idempotent` endpoint. A `write` reports `retry: "unsafe-outcome-unknown"`, because a lost
|
|
300
|
+
response does not prove the write failed to commit.
|
|
297
301
|
|
|
298
302
|
Every reply carries the requestId so a user can quote it: `_meta["webpieces/requestId"]` on every
|
|
299
303
|
`tools/call` result (success or `isError`), `requestId` in the `isError` payload, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.895",
|
|
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.
|
|
28
|
-
"@webpieces/core-util": "0.4.
|
|
29
|
-
"@webpieces/http-routing": "0.4.
|
|
30
|
-
"@webpieces/http-server": "0.4.
|
|
27
|
+
"@webpieces/core-context": "0.4.895",
|
|
28
|
+
"@webpieces/core-util": "0.4.895",
|
|
29
|
+
"@webpieces/http-routing": "0.4.895",
|
|
30
|
+
"@webpieces/http-server": "0.4.895",
|
|
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.
|
|
36
|
+
"@webpieces/http-client-node": "0.4.895"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -115,8 +115,23 @@ export interface McpErrorTranslator {
|
|
|
115
115
|
export declare class McpDefaultToolCallRenderer implements McpErrorTranslator {
|
|
116
116
|
private readonly boundary;
|
|
117
117
|
toWire(error: Error): CallToolResult;
|
|
118
|
+
/**
|
|
119
|
+
* MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and
|
|
120
|
+
* the outcome is the ONE verdict `ClientRegistry.classify` gives every other reader (RetryStrategy,
|
|
121
|
+
* LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is
|
|
122
|
+
* rendered by kind, with `retry: 'never'` or `'after-correction'`.
|
|
123
|
+
*
|
|
124
|
+
* The one thing decided before the classifier is the published `implementation` kind: the
|
|
125
|
+
* boundary has already ruled that this server is at fault — including a caller-local
|
|
126
|
+
* `ApiConnectionError` (#959) — so it is a bug, and a model is never told a bug is worth retrying.
|
|
127
|
+
*/
|
|
118
128
|
private modelVisible;
|
|
119
|
-
|
|
129
|
+
/** Rendering for an outcome that repeating will not change: EXPECTED or FAILURE. */
|
|
130
|
+
private settled;
|
|
131
|
+
/** A FAILURE the caller cannot correct: a missing operation, an exhausted or broken dependency. */
|
|
132
|
+
private settledFailure;
|
|
133
|
+
/** The situation text for a TRANSIENT_FAILURE; `transient` adds the operation-aware advice. */
|
|
134
|
+
private transientMessage;
|
|
120
135
|
private coded;
|
|
121
136
|
private bug;
|
|
122
137
|
private transient;
|
|
@@ -120,7 +120,7 @@ class McpDefaultToolCallRenderer {
|
|
|
120
120
|
boundary = new core_util_1.ApiErrorBoundary();
|
|
121
121
|
toWire(error) {
|
|
122
122
|
const requestId = McpCorrelation.requestId();
|
|
123
|
-
const visible = new ModelVisibleToolErrorEnvelope(this.modelVisible(this.boundary.encode(error), requestId));
|
|
123
|
+
const visible = new ModelVisibleToolErrorEnvelope(this.modelVisible(error, this.boundary.encode(error), requestId));
|
|
124
124
|
const text = JSON.stringify(visible);
|
|
125
125
|
return {
|
|
126
126
|
content: [{ type: 'text', text }],
|
|
@@ -128,8 +128,30 @@ class McpDefaultToolCallRenderer {
|
|
|
128
128
|
_meta: { [exports.MCP_REQUEST_ID_META_KEY]: requestId },
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
/**
|
|
132
|
+
* MCP has no retry table of its own: the advice is f(outcome, operation, retryAfterSeconds), and
|
|
133
|
+
* the outcome is the ONE verdict `ClientRegistry.classify` gives every other reader (RetryStrategy,
|
|
134
|
+
* LogApiCall). A TRANSIENT_FAILURE becomes operation-aware retry guidance; everything else is
|
|
135
|
+
* rendered by kind, with `retry: 'never'` or `'after-correction'`.
|
|
136
|
+
*
|
|
137
|
+
* The one thing decided before the classifier is the published `implementation` kind: the
|
|
138
|
+
* boundary has already ruled that this server is at fault — including a caller-local
|
|
139
|
+
* `ApiConnectionError` (#959) — so it is a bug, and a model is never told a bug is worth retrying.
|
|
140
|
+
*/
|
|
141
|
+
modelVisible(error, payload, requestId) {
|
|
132
142
|
const support = `Give requestId ${requestId} to support so the internal failure can be located and fixed.`;
|
|
143
|
+
if (payload.kind === 'implementation') {
|
|
144
|
+
return this.bug(payload, requestId, support);
|
|
145
|
+
}
|
|
146
|
+
const toolName = McpCorrelation.current().toolName ?? 'unknown';
|
|
147
|
+
const methodInfo = new core_util_1.ApiMethodInfo('server', 'WpMcpServer', toolName);
|
|
148
|
+
if (core_util_1.ClientRegistry.classify(error, methodInfo) === core_util_1.CallOutcome.TRANSIENT_FAILURE) {
|
|
149
|
+
return this.transient(payload, requestId, this.transientMessage(payload));
|
|
150
|
+
}
|
|
151
|
+
return this.settled(payload, requestId, support);
|
|
152
|
+
}
|
|
153
|
+
/** Rendering for an outcome that repeating will not change: EXPECTED or FAILURE. */
|
|
154
|
+
settled(payload, requestId, support) {
|
|
133
155
|
switch (payload.kind) {
|
|
134
156
|
case 'end-user':
|
|
135
157
|
return this.visible(payload, requestId, 'caller', 'after-correction', payload.message);
|
|
@@ -145,41 +167,43 @@ class McpDefaultToolCallRenderer {
|
|
|
145
167
|
case 'precondition-failed':
|
|
146
168
|
case 'unsupported-media-type':
|
|
147
169
|
return this.visible(payload, requestId, 'caller', 'after-correction', `${payload.message}. Correct the request or current resource state before trying again.`);
|
|
170
|
+
default:
|
|
171
|
+
return this.settledFailure(payload, requestId, support);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** A FAILURE the caller cannot correct: a missing operation, an exhausted or broken dependency. */
|
|
175
|
+
settledFailure(payload, requestId, support) {
|
|
176
|
+
switch (payload.kind) {
|
|
148
177
|
case 'not-implemented':
|
|
149
178
|
return this.visible(payload, requestId, 'bug', 'never', `The tool does not implement this operation. Retrying or changing arguments will not help. ${support}`);
|
|
150
|
-
case '
|
|
151
|
-
return this.visible(payload, requestId, 'dependency', 'never', `A downstream dependency
|
|
179
|
+
case 'retries-exhausted':
|
|
180
|
+
return this.visible(payload, requestId, 'dependency', 'never', `A downstream dependency kept failing after this service already retried it. Retrying now will not help. If the failure persists, ${support}`);
|
|
181
|
+
case 'coded':
|
|
182
|
+
return this.coded(payload, requestId, support);
|
|
152
183
|
default:
|
|
153
|
-
return this.
|
|
184
|
+
return this.visible(payload, requestId, 'dependency', 'never', `A downstream dependency failed. Retrying or changing arguments will not help. If the failure persists, ${support}`);
|
|
154
185
|
}
|
|
155
186
|
}
|
|
156
|
-
|
|
187
|
+
/** The situation text for a TRANSIENT_FAILURE; `transient` adds the operation-aware advice. */
|
|
188
|
+
transientMessage(payload) {
|
|
157
189
|
switch (payload.kind) {
|
|
158
190
|
case 'request-timeout':
|
|
159
191
|
case 'dependency-timeout':
|
|
160
|
-
return
|
|
192
|
+
return 'The operation timed out; the previous operation may already have completed.';
|
|
161
193
|
case 'bad-gateway':
|
|
162
|
-
return
|
|
163
|
-
case 'unavailable':
|
|
164
|
-
return this.transient(payload, requestId, 'A required service is temporarily unavailable; the previous operation may already have completed.');
|
|
194
|
+
return 'A gateway returned an invalid upstream response; the previous operation may already have completed.';
|
|
165
195
|
case 'rate-limited':
|
|
166
196
|
case 'dependency-backoff':
|
|
167
|
-
return
|
|
197
|
+
return payload.retryAfterSeconds === undefined
|
|
168
198
|
? 'The operation was throttled. Do not retry immediately.'
|
|
169
|
-
: `The operation was throttled. Wait at least ${payload.retryAfterSeconds} seconds before retrying
|
|
199
|
+
: `The operation was throttled. Wait at least ${payload.retryAfterSeconds} seconds before retrying.`;
|
|
170
200
|
case 'coded':
|
|
171
|
-
return
|
|
172
|
-
case 'implementation':
|
|
173
|
-
case 'connection':
|
|
174
|
-
return this.bug(payload, requestId, support);
|
|
201
|
+
return `The operation failed with HTTP ${payload.statusCode ?? 500}; the previous operation's outcome may be unknown.`;
|
|
175
202
|
default:
|
|
176
|
-
return
|
|
203
|
+
return 'A required service is temporarily unavailable; the previous operation may already have completed.';
|
|
177
204
|
}
|
|
178
205
|
}
|
|
179
206
|
coded(payload, requestId, support) {
|
|
180
|
-
if (payload.statusCode === 408 || payload.statusCode === 429) {
|
|
181
|
-
return this.transient(payload, requestId, `The operation failed with HTTP ${payload.statusCode}; the previous operation's outcome may be unknown.`);
|
|
182
|
-
}
|
|
183
207
|
if ((payload.statusCode ?? 500) >= 500) {
|
|
184
208
|
return this.visible(payload, requestId, 'dependency', 'never', `A downstream service failed with HTTP ${payload.statusCode ?? 500}. Retrying or changing arguments will not help. ${support}`);
|
|
185
209
|
}
|
|
@@ -1 +1 @@
|
|
|
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 ContextKey,\n DtoValue,\n EndpointOperation,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\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 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);\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(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 private modelVisible(payload: ApiErrorPayload, requestId: string): ModelVisibleToolError {\n const support = `Give requestId ${requestId} to support so the internal failure can be located and fixed.`;\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 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 'dependency':\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 default:\n return this.modelVisibleRuntime(payload, requestId, support);\n }\n }\n\n private modelVisibleRuntime(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n switch (payload.kind) {\n case 'request-timeout':\n case 'dependency-timeout':\n return this.transient(\n payload,\n requestId,\n 'The operation timed out; the previous operation may already have completed.',\n );\n case 'bad-gateway':\n return this.transient(\n payload,\n requestId,\n 'A gateway returned an invalid upstream response; the previous operation may already have completed.',\n );\n case 'unavailable':\n return this.transient(\n payload,\n requestId,\n 'A required service is temporarily unavailable; the previous operation may already have completed.',\n );\n case 'rate-limited':\n case 'dependency-backoff':\n return this.transient(\n payload,\n requestId,\n 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 );\n case 'coded':\n return this.coded(payload, requestId, support);\n case 'implementation':\n case 'connection':\n return this.bug(payload, requestId, support);\n default:\n return this.bug(payload, requestId, support);\n }\n }\n\n private coded(\n payload: ApiErrorPayload,\n requestId: string,\n support: string,\n ): ModelVisibleToolError {\n if (payload.statusCode === 408 || payload.statusCode === 429) {\n return this.transient(\n payload,\n requestId,\n `The operation failed with HTTP ${payload.statusCode}; the previous operation's outcome may be unknown.`,\n );\n }\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"]}
|
|
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 ClientRegistry,\n ContextKey,\n DtoValue,\n EndpointOperation,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\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 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);\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 toolName = McpCorrelation.current().toolName ?? 'unknown';\n const methodInfo = new ApiMethodInfo('server', 'WpMcpServer', toolName);\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"]}
|
|
@@ -301,6 +301,10 @@ exports.THROW_CASES = [
|
|
|
301
301
|
new ThrowCase('dependency-backoff', 'dependency-backoff', 'error', () => {
|
|
302
302
|
throw new core_util_3.ApiDependencyBackoffError('backoff internals', 42);
|
|
303
303
|
}),
|
|
304
|
+
// A lower layer already retried and gave up: 502, decoded as itself on the remote hop, retry never.
|
|
305
|
+
new ThrowCase('retries-exhausted', 'retries-exhausted', 'error', () => {
|
|
306
|
+
throw new core_util_3.ApiRetriesExhaustedError(4, new core_util_3.ApiUnavailableError('createTask reset internals'));
|
|
307
|
+
}),
|
|
304
308
|
new ThrowCase('connection', 'implementation', 'error', () => {
|
|
305
309
|
throw new core_util_3.ApiConnectionError('ECONNRESET internals');
|
|
306
310
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpRemoteFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/McpRemoteFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { AuthenticatedMachineIdentity } from '@webpieces/http-routing';\nimport { ClientRole, WpAuthorization, AuthorizationType, WpAuth, oidc as oidcAuth, jwt as jwtAuth } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiCodedError, ApiConflictError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndpointNotFoundError, ApiEndUserError, ApiErrorCodec, ApiErrorHttpStatus, ApiForbiddenError, ApiImplementationError, ApiNotFoundError, ApiNotImplementedError, ApiPath, ApiType, ApiPreconditionFailedError, ApiRateLimitedError, ApiRequestTimeoutError, ApiUnauthorizedError, ApiUnavailableError, ApiUnprocessableError, ApiUnsupportedMediaTypeError, ContextKey, Endpoint, ErrorTranslator, Filter, WebpiecesDefaultErrorTranslator, HttpResponseDto, LogLevel, Service, WebpiecesCoreHeaders, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { MethodMeta, OidcHook, WpResponse } from '@webpieces/http-routing';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\n/** Contracts, controllers and test doubles for McpRemoteBinding.integration.spec.ts. */\n\nexport const REMOTE_USER = ContextKey.trusted<string>(\n 'mcpRemoteUser',\n 'verified by the MCP access-token authority before delegation',\n 'x-mcp-remote-user',\n);\nexport const REMOTE_ROLES = ContextKey.trusted<string>(\n 'mcpRemoteRoles',\n 'verified by the MCP access-token authority before delegation',\n 'x-mcp-remote-roles',\n);\nexport const REMOTE_SERVICE = 'mcp-remote-integration';\nexport const REFUSED_SERVICE = 'mcp-remote-refused';\nexport const GARBAGE_SERVICE = 'mcp-remote-garbage';\nexport const OIDC_TOKEN = 'oidc-for-mcp-remote-integration';\nexport const EXTERNAL_MCP_BEARER = 'external-mcp-access-token';\nexport const LOCAL_ENDPOINT_JWT = 'local-endpoint-jwt-that-must-not-cross-the-remote-hop';\nexport const GATEWAY_PATH = '/gateway/mcp';\n\nexport class RemoteRequest {\n /** Search text */\n query!: string;\n\n constructor(query?: string) {\n if (query !== undefined) this.query = query;\n }\n}\n\nexport class RemoteResponse {\n /** Delegated user */\n user!: string;\n\n /** Delegated roles */\n roles!: string;\n\n /** Result */\n result!: string;\n\n constructor(user?: string, roles?: string, result?: string) {\n if (user !== undefined) this.user = user;\n if (roles !== undefined) this.roles = roles;\n if (result !== undefined) this.result = result;\n }\n}\n\n/**\n * The generated tool catalogs these contracts would produce — what `wp-openapi` writes, one\n * `mcp-<ContractClass>-tools.json` per contract. Hand-built here because `@webpieces/mcp-server` does not depend on the\n * TypeScript compiler API; the runtime's job is to BE HANDED a catalog.\n */\nfunction describedString(description: string): ApiJsonSchema {\n const schema = new ApiJsonSchema('string');\n schema.description = description;\n return schema;\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n new WpMcpToolHints(true, false, true, false),\n new ObjectSchemaBuilder().required('query', describedString('Search text')).build(),\n new ObjectSchemaBuilder()\n .required('user', describedString('Delegated user'))\n .required('roles', describedString('Delegated roles'))\n .required('result', describedString('Result'))\n .build(), [Mcp.DEFAULT],\n );\n}\n\n/** One contract's hand-built catalog, labelled as built in memory. */\nfunction contractCatalog(contractName: string, tool: McpToolDefinition): McpToolCatalog {\n return new McpToolCatalog(new McpToolCatalogFile(contractName, [tool]), '(built in memory by the spec)');\n}\n\nexport const REMOTE_MCP_CATALOG = contractCatalog(\n 'RemoteMcpApi',\n searchTool('remote_integration_search', 'Remote integration search', 'search', 'Calls a remote Webpieces API.'),\n);\n\n/** The catalogs of every contract the gateway binds — one per contract, exactly as a build writes them. */\nexport const GATEWAY_CATALOGS: readonly McpToolCatalog[] = [\n contractCatalog(\n 'MissingRemoteMcpApi',\n searchTool('missing_remote_integration_search', 'Missing remote integration search', 'search', 'Intentionally absent route.'),\n ),\n contractCatalog('RefusedRemoteApi', searchTool('refused_remote', 'Refused remote call', 'search', 'Nothing listens on this port.')),\n contractCatalog('GarbageRemoteApi', searchTool('garbage_remote', 'Garbage remote response', 'search', 'Answers an undecodable body.')),\n contractCatalog(\n 'OidcFailRemoteApi',\n searchTool('oidc_fail_remote', 'OIDC failure on remote', 'search', 'Its OIDC token cannot be minted.'),\n ),\n contractCatalog('LocalThrowApi', searchTool('local_throw', 'Local throw', 'fail', 'Throws the requested failure in-process.')),\n contractCatalog('RemoteThrowApi', searchTool('remote_throw', 'Remote throw', 'fail', 'Throws the requested failure remotely.')),\n];\n\n@ApiPath('/remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteMcpApi {\n /** Calls a remote Webpieces API. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('remote_integration_search', 'Remote integration search')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/missing-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class MissingRemoteMcpApi {\n /** Intentionally absent route. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('missing_remote_integration_search', 'Missing remote integration search')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/refused-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RefusedRemoteApi {\n /** Nothing listens on this port. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('refused_remote', 'Refused remote call')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/garbage-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class GarbageRemoteApi {\n /** Answers an undecodable body. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('garbage_remote', 'Garbage remote response')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/oidc-fail-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class OidcFailRemoteApi {\n /** Its OIDC token cannot be minted. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('oidc_fail_remote', 'OIDC failure on remote')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/local-throw')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class LocalThrowApi {\n /** Throws the requested failure in-process. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/throw', READ, RPC)\n @WpMcpTool('local_throw', 'Local throw')\n fail(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-throw')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteThrowApi {\n /** Throws the requested failure remotely. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/throw', READ, RPC)\n @WpMcpTool('remote_throw', 'Remote throw')\n fail(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n/**\n * One named throw, run identically behind the local and the remote binding.\n *\n * `expectedServerLevel` is the level of the ONE operator line the failure now produces on the server\n * that raised it — `LogApiCall`'s, at `warn` for `[API-server-resp-OTHER]` (a healthy rejection of\n * the caller's mistake) and `error` for `[API-server-resp-FAIL]`. `ApiErrorBoundary` no longer\n * writes a second line of its own (#961).\n */\nexport class ThrowCase {\n constructor(\n public readonly name: string,\n public readonly expectedKind: string,\n public readonly expectedServerLevel: LogLevel,\n public readonly raise: () => never,\n ) {}\n}\n\nexport const THROW_CASES: readonly ThrowCase[] = [\n new ThrowCase('end-user', 'end-user', 'warn', () => {\n throw new ApiEndUserError('The two passwords you entered do not match.', 'PW_MISMATCH');\n }),\n new ThrowCase('bad-request', 'bad-request', 'warn', () => {\n throw new ApiBadRequestError('internal column name', '$.query', 'query must be a word');\n }),\n new ThrowCase('unauthorized', 'unauthorized', 'warn', () => {\n throw new ApiUnauthorizedError('session internals');\n }),\n new ThrowCase('forbidden', 'forbidden', 'warn', () => {\n throw new ApiForbiddenError('acl internals');\n }),\n new ThrowCase('not-found', 'not-found', 'warn', () => {\n throw new ApiNotFoundError('row 7 missing');\n }),\n new ThrowCase('endpoint-not-found', 'endpoint-not-found', 'warn', () => {\n throw new ApiEndpointNotFoundError('route internals');\n }),\n new ThrowCase('request-timeout', 'request-timeout', 'error', () => {\n throw new ApiRequestTimeoutError('slow internals');\n }),\n new ThrowCase('rate-limited', 'rate-limited', 'error', () => {\n throw new ApiRateLimitedError('quota internals');\n }),\n new ThrowCase('conflict', 'conflict', 'warn', () => {\n throw new ApiConflictError('version internals');\n }),\n new ThrowCase('unprocessable', 'unprocessable', 'warn', () => {\n throw new ApiUnprocessableError('rule internals');\n }),\n new ThrowCase('precondition-failed', 'precondition-failed', 'warn', () => {\n throw new ApiPreconditionFailedError('etag internals');\n }),\n new ThrowCase('unsupported-media-type', 'unsupported-media-type', 'warn', () => {\n throw new ApiUnsupportedMediaTypeError('parser internals');\n }),\n new ThrowCase('not-implemented', 'not-implemented', 'error', () => {\n throw new ApiNotImplementedError('feature internals');\n }),\n new ThrowCase('coded-4xx', 'coded', 'warn', () => {\n throw new ApiCodedError('quota internals', 460, 'QUOTA');\n }),\n new ThrowCase('coded-5xx', 'coded', 'error', () => {\n throw new ApiCodedError('disk internals', 507);\n }),\n new ThrowCase('implementation', 'implementation', 'error', () => {\n throw new ApiImplementationError('bug internals');\n }),\n new ThrowCase('dependency', 'dependency', 'error', () => {\n throw new ApiDependencyError('upstream internals');\n }),\n new ThrowCase('unavailable', 'unavailable', 'error', () => {\n throw new ApiUnavailableError('maintenance internals');\n }),\n new ThrowCase('dependency-timeout', 'dependency-timeout', 'error', () => {\n throw new ApiDependencyTimeoutError('upstream slow internals');\n }),\n new ThrowCase('dependency-backoff', 'dependency-backoff', 'error', () => {\n throw new ApiDependencyBackoffError('backoff internals', 42);\n }),\n new ThrowCase('connection', 'implementation', 'error', () => {\n throw new ApiConnectionError('ECONNRESET internals');\n }),\n new ThrowCase('raw-error', 'implementation', 'error', () => {\n throw new Error('SECRET-raw-internals');\n }),\n new ThrowCase('thrown-string', 'implementation', 'error', () => {\n throw 'SECRET-string-internals';\n }),\n];\n\nexport function raiseFor(query: string): never {\n const found = THROW_CASES.find((candidate: ThrowCase) => candidate.name === query);\n if (!found) throw new Error(`unknown throw case ${query}`);\n return found.raise();\n}\n\n@injectable()\nexport class RemoteMcpController extends RemoteMcpApi {\n calls = 0;\n authorization?: string;\n\n override search(request: RemoteRequest): Promise<RemoteResponse> {\n this.calls += 1;\n this.authorization = RequestContext.getRequest()?.getHeader('authorization');\n return Promise.resolve(\n new RemoteResponse(\n RequestContext.getTrusted(REMOTE_USER) ?? 'missing-user',\n RequestContext.getTrusted(REMOTE_ROLES) ?? 'missing-roles',\n `remote:${request.query}`,\n ),\n );\n }\n}\n\n@injectable()\nexport class LocalThrowController extends LocalThrowApi {\n override async fail(request: RemoteRequest): Promise<RemoteResponse> {\n return raiseFor(request.query);\n }\n}\n\n@injectable()\nexport class RemoteThrowController extends RemoteThrowApi {\n override async fail(request: RemoteRequest): Promise<RemoteResponse> {\n return raiseFor(request.query);\n }\n}\n\nexport class RecordingOidcMinter {\n readonly audiences: string[] = [];\n\n constructor(\n private readonly failure?: Error,\n private readonly token = OIDC_TOKEN,\n ) {}\n\n mintIdToken(audience: string): Promise<string> {\n this.audiences.push(audience);\n if (this.failure) return Promise.reject(this.failure);\n return Promise.resolve(this.token);\n }\n}\n\nexport class RecordingOidcVerifier extends OidcHook {\n readonly tokens: string[] = [];\n readonly callerLists: string[][] = [];\n\n override verifyOidc(token: string, callers: string[]): Promise<AuthenticatedMachineIdentity> {\n this.tokens.push(token);\n this.callerLists.push(callers);\n if (token !== OIDC_TOKEN) throw new Error(`unexpected OIDC token '${token}'`);\n return Promise.resolve(new AuthenticatedMachineIdentity('oidc','test-service@example.test'));\n }\n}\n\n@injectable()\nexport class BoundaryProbeFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n calls = 0;\n sawLogIdentity = false;\n sawTrustedUser?: string;\n\n override filter(\n meta: MethodMeta,\n next: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n this.calls += 1;\n this.sawLogIdentity =\n RequestContext.getUntrusted(WebpiecesCoreHeaders.CONTROLLER) ===\n 'RemoteMcpController' &&\n RequestContext.getUntrusted(WebpiecesCoreHeaders.METHOD) === 'search';\n this.sawTrustedUser = RequestContext.getTrusted(REMOTE_USER);\n return next.invoke(meta);\n }\n}\n\n/**\n * The documented gateway opt-out from http-client-node's \"a dependency's 4xx is OUR 500\" invariant:\n * an MCP gateway relays a Webpieces peer's typed failure so the model sees the same kind it would see\n * for a local binding. `relay = false` answers \"not mine\", which is the framework default.\n */\nexport class RelayWebpiecesPeerErrors implements ErrorTranslator {\n relay = true;\n\n private readonly fallback = new WebpiecesDefaultErrorTranslator();\n\n toWire(error: Error): HttpResponseDto {\n return this.fallback.toWire(error);\n }\n\n fromWire(response: HttpResponseDto, role: ClientRole): void {\n if (this.relay && ApiErrorCodec.isPayload(response.body)) {\n const decoded = ApiErrorCodec.decode(response.body);\n const statusCode = decoded instanceof ApiCodedError ? decoded.statusCode : undefined;\n if (\n ApiErrorHttpStatus.hasCode(decoded) &&\n ApiErrorHttpStatus.codeFor(decoded.kind, statusCode) === response.status.code\n ) {\n throw decoded;\n }\n }\n this.fallback.fromWire(response, role);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"McpRemoteFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/McpRemoteFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { AuthenticatedMachineIdentity } from '@webpieces/http-routing';\nimport { ClientRole, WpAuthorization, AuthorizationType, WpAuth, oidc as oidcAuth, jwt as jwtAuth } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiCodedError, ApiConflictError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndpointNotFoundError, ApiEndUserError, ApiErrorCodec, ApiErrorHttpStatus, ApiForbiddenError, ApiImplementationError, ApiNotFoundError, ApiNotImplementedError, ApiPath, ApiType, ApiPreconditionFailedError, ApiRateLimitedError, ApiRequestTimeoutError, ApiRetriesExhaustedError, ApiUnauthorizedError, ApiUnavailableError, ApiUnprocessableError, ApiUnsupportedMediaTypeError, ContextKey, Endpoint, ErrorTranslator, Filter, WebpiecesDefaultErrorTranslator, HttpResponseDto, LogLevel, Service, WebpiecesCoreHeaders, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { MethodMeta, OidcHook, WpResponse } from '@webpieces/http-routing';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\n/** Contracts, controllers and test doubles for McpRemoteBinding.integration.spec.ts. */\n\nexport const REMOTE_USER = ContextKey.trusted<string>(\n 'mcpRemoteUser',\n 'verified by the MCP access-token authority before delegation',\n 'x-mcp-remote-user',\n);\nexport const REMOTE_ROLES = ContextKey.trusted<string>(\n 'mcpRemoteRoles',\n 'verified by the MCP access-token authority before delegation',\n 'x-mcp-remote-roles',\n);\nexport const REMOTE_SERVICE = 'mcp-remote-integration';\nexport const REFUSED_SERVICE = 'mcp-remote-refused';\nexport const GARBAGE_SERVICE = 'mcp-remote-garbage';\nexport const OIDC_TOKEN = 'oidc-for-mcp-remote-integration';\nexport const EXTERNAL_MCP_BEARER = 'external-mcp-access-token';\nexport const LOCAL_ENDPOINT_JWT = 'local-endpoint-jwt-that-must-not-cross-the-remote-hop';\nexport const GATEWAY_PATH = '/gateway/mcp';\n\nexport class RemoteRequest {\n /** Search text */\n query!: string;\n\n constructor(query?: string) {\n if (query !== undefined) this.query = query;\n }\n}\n\nexport class RemoteResponse {\n /** Delegated user */\n user!: string;\n\n /** Delegated roles */\n roles!: string;\n\n /** Result */\n result!: string;\n\n constructor(user?: string, roles?: string, result?: string) {\n if (user !== undefined) this.user = user;\n if (roles !== undefined) this.roles = roles;\n if (result !== undefined) this.result = result;\n }\n}\n\n/**\n * The generated tool catalogs these contracts would produce — what `wp-openapi` writes, one\n * `mcp-<ContractClass>-tools.json` per contract. Hand-built here because `@webpieces/mcp-server` does not depend on the\n * TypeScript compiler API; the runtime's job is to BE HANDED a catalog.\n */\nfunction describedString(description: string): ApiJsonSchema {\n const schema = new ApiJsonSchema('string');\n schema.description = description;\n return schema;\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n new WpMcpToolHints(true, false, true, false),\n new ObjectSchemaBuilder().required('query', describedString('Search text')).build(),\n new ObjectSchemaBuilder()\n .required('user', describedString('Delegated user'))\n .required('roles', describedString('Delegated roles'))\n .required('result', describedString('Result'))\n .build(), [Mcp.DEFAULT],\n );\n}\n\n/** One contract's hand-built catalog, labelled as built in memory. */\nfunction contractCatalog(contractName: string, tool: McpToolDefinition): McpToolCatalog {\n return new McpToolCatalog(new McpToolCatalogFile(contractName, [tool]), '(built in memory by the spec)');\n}\n\nexport const REMOTE_MCP_CATALOG = contractCatalog(\n 'RemoteMcpApi',\n searchTool('remote_integration_search', 'Remote integration search', 'search', 'Calls a remote Webpieces API.'),\n);\n\n/** The catalogs of every contract the gateway binds — one per contract, exactly as a build writes them. */\nexport const GATEWAY_CATALOGS: readonly McpToolCatalog[] = [\n contractCatalog(\n 'MissingRemoteMcpApi',\n searchTool('missing_remote_integration_search', 'Missing remote integration search', 'search', 'Intentionally absent route.'),\n ),\n contractCatalog('RefusedRemoteApi', searchTool('refused_remote', 'Refused remote call', 'search', 'Nothing listens on this port.')),\n contractCatalog('GarbageRemoteApi', searchTool('garbage_remote', 'Garbage remote response', 'search', 'Answers an undecodable body.')),\n contractCatalog(\n 'OidcFailRemoteApi',\n searchTool('oidc_fail_remote', 'OIDC failure on remote', 'search', 'Its OIDC token cannot be minted.'),\n ),\n contractCatalog('LocalThrowApi', searchTool('local_throw', 'Local throw', 'fail', 'Throws the requested failure in-process.')),\n contractCatalog('RemoteThrowApi', searchTool('remote_throw', 'Remote throw', 'fail', 'Throws the requested failure remotely.')),\n];\n\n@ApiPath('/remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteMcpApi {\n /** Calls a remote Webpieces API. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('remote_integration_search', 'Remote integration search')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/missing-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class MissingRemoteMcpApi {\n /** Intentionally absent route. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('missing_remote_integration_search', 'Missing remote integration search')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/refused-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RefusedRemoteApi {\n /** Nothing listens on this port. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('refused_remote', 'Refused remote call')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/garbage-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class GarbageRemoteApi {\n /** Answers an undecodable body. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('garbage_remote', 'Garbage remote response')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/oidc-fail-remote-mcp')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class OidcFailRemoteApi {\n /** Its OIDC token cannot be minted. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('oidc_fail_remote', 'OIDC failure on remote')\n search(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/local-throw')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class LocalThrowApi {\n /** Throws the requested failure in-process. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/throw', READ, RPC)\n @WpMcpTool('local_throw', 'Local throw')\n fail(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-throw')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteThrowApi {\n /** Throws the requested failure remotely. */\n\n @WpAuth([oidcAuth('mcp-gateway')])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/throw', READ, RPC)\n @WpMcpTool('remote_throw', 'Remote throw')\n fail(_request: RemoteRequest): Promise<RemoteResponse> {\n throw new Error('contract only');\n }\n}\n\n/**\n * One named throw, run identically behind the local and the remote binding.\n *\n * `expectedServerLevel` is the level of the ONE operator line the failure now produces on the server\n * that raised it — `LogApiCall`'s, at `warn` for `[API-server-resp-OTHER]` (a healthy rejection of\n * the caller's mistake) and `error` for `[API-server-resp-FAIL]`. `ApiErrorBoundary` no longer\n * writes a second line of its own (#961).\n */\nexport class ThrowCase {\n constructor(\n public readonly name: string,\n public readonly expectedKind: string,\n public readonly expectedServerLevel: LogLevel,\n public readonly raise: () => never,\n ) {}\n}\n\nexport const THROW_CASES: readonly ThrowCase[] = [\n new ThrowCase('end-user', 'end-user', 'warn', () => {\n throw new ApiEndUserError('The two passwords you entered do not match.', 'PW_MISMATCH');\n }),\n new ThrowCase('bad-request', 'bad-request', 'warn', () => {\n throw new ApiBadRequestError('internal column name', '$.query', 'query must be a word');\n }),\n new ThrowCase('unauthorized', 'unauthorized', 'warn', () => {\n throw new ApiUnauthorizedError('session internals');\n }),\n new ThrowCase('forbidden', 'forbidden', 'warn', () => {\n throw new ApiForbiddenError('acl internals');\n }),\n new ThrowCase('not-found', 'not-found', 'warn', () => {\n throw new ApiNotFoundError('row 7 missing');\n }),\n new ThrowCase('endpoint-not-found', 'endpoint-not-found', 'warn', () => {\n throw new ApiEndpointNotFoundError('route internals');\n }),\n new ThrowCase('request-timeout', 'request-timeout', 'error', () => {\n throw new ApiRequestTimeoutError('slow internals');\n }),\n new ThrowCase('rate-limited', 'rate-limited', 'error', () => {\n throw new ApiRateLimitedError('quota internals');\n }),\n new ThrowCase('conflict', 'conflict', 'warn', () => {\n throw new ApiConflictError('version internals');\n }),\n new ThrowCase('unprocessable', 'unprocessable', 'warn', () => {\n throw new ApiUnprocessableError('rule internals');\n }),\n new ThrowCase('precondition-failed', 'precondition-failed', 'warn', () => {\n throw new ApiPreconditionFailedError('etag internals');\n }),\n new ThrowCase('unsupported-media-type', 'unsupported-media-type', 'warn', () => {\n throw new ApiUnsupportedMediaTypeError('parser internals');\n }),\n new ThrowCase('not-implemented', 'not-implemented', 'error', () => {\n throw new ApiNotImplementedError('feature internals');\n }),\n new ThrowCase('coded-4xx', 'coded', 'warn', () => {\n throw new ApiCodedError('quota internals', 460, 'QUOTA');\n }),\n new ThrowCase('coded-5xx', 'coded', 'error', () => {\n throw new ApiCodedError('disk internals', 507);\n }),\n new ThrowCase('implementation', 'implementation', 'error', () => {\n throw new ApiImplementationError('bug internals');\n }),\n new ThrowCase('dependency', 'dependency', 'error', () => {\n throw new ApiDependencyError('upstream internals');\n }),\n new ThrowCase('unavailable', 'unavailable', 'error', () => {\n throw new ApiUnavailableError('maintenance internals');\n }),\n new ThrowCase('dependency-timeout', 'dependency-timeout', 'error', () => {\n throw new ApiDependencyTimeoutError('upstream slow internals');\n }),\n new ThrowCase('dependency-backoff', 'dependency-backoff', 'error', () => {\n throw new ApiDependencyBackoffError('backoff internals', 42);\n }),\n // A lower layer already retried and gave up: 502, decoded as itself on the remote hop, retry never.\n new ThrowCase('retries-exhausted', 'retries-exhausted', 'error', () => {\n throw new ApiRetriesExhaustedError(4, new ApiUnavailableError('createTask reset internals'));\n }),\n new ThrowCase('connection', 'implementation', 'error', () => {\n throw new ApiConnectionError('ECONNRESET internals');\n }),\n new ThrowCase('raw-error', 'implementation', 'error', () => {\n throw new Error('SECRET-raw-internals');\n }),\n new ThrowCase('thrown-string', 'implementation', 'error', () => {\n throw 'SECRET-string-internals';\n }),\n];\n\nexport function raiseFor(query: string): never {\n const found = THROW_CASES.find((candidate: ThrowCase) => candidate.name === query);\n if (!found) throw new Error(`unknown throw case ${query}`);\n return found.raise();\n}\n\n@injectable()\nexport class RemoteMcpController extends RemoteMcpApi {\n calls = 0;\n authorization?: string;\n\n override search(request: RemoteRequest): Promise<RemoteResponse> {\n this.calls += 1;\n this.authorization = RequestContext.getRequest()?.getHeader('authorization');\n return Promise.resolve(\n new RemoteResponse(\n RequestContext.getTrusted(REMOTE_USER) ?? 'missing-user',\n RequestContext.getTrusted(REMOTE_ROLES) ?? 'missing-roles',\n `remote:${request.query}`,\n ),\n );\n }\n}\n\n@injectable()\nexport class LocalThrowController extends LocalThrowApi {\n override async fail(request: RemoteRequest): Promise<RemoteResponse> {\n return raiseFor(request.query);\n }\n}\n\n@injectable()\nexport class RemoteThrowController extends RemoteThrowApi {\n override async fail(request: RemoteRequest): Promise<RemoteResponse> {\n return raiseFor(request.query);\n }\n}\n\nexport class RecordingOidcMinter {\n readonly audiences: string[] = [];\n\n constructor(\n private readonly failure?: Error,\n private readonly token = OIDC_TOKEN,\n ) {}\n\n mintIdToken(audience: string): Promise<string> {\n this.audiences.push(audience);\n if (this.failure) return Promise.reject(this.failure);\n return Promise.resolve(this.token);\n }\n}\n\nexport class RecordingOidcVerifier extends OidcHook {\n readonly tokens: string[] = [];\n readonly callerLists: string[][] = [];\n\n override verifyOidc(token: string, callers: string[]): Promise<AuthenticatedMachineIdentity> {\n this.tokens.push(token);\n this.callerLists.push(callers);\n if (token !== OIDC_TOKEN) throw new Error(`unexpected OIDC token '${token}'`);\n return Promise.resolve(new AuthenticatedMachineIdentity('oidc','test-service@example.test'));\n }\n}\n\n@injectable()\nexport class BoundaryProbeFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n calls = 0;\n sawLogIdentity = false;\n sawTrustedUser?: string;\n\n override filter(\n meta: MethodMeta,\n next: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n this.calls += 1;\n this.sawLogIdentity =\n RequestContext.getUntrusted(WebpiecesCoreHeaders.CONTROLLER) ===\n 'RemoteMcpController' &&\n RequestContext.getUntrusted(WebpiecesCoreHeaders.METHOD) === 'search';\n this.sawTrustedUser = RequestContext.getTrusted(REMOTE_USER);\n return next.invoke(meta);\n }\n}\n\n/**\n * The documented gateway opt-out from http-client-node's \"a dependency's 4xx is OUR 500\" invariant:\n * an MCP gateway relays a Webpieces peer's typed failure so the model sees the same kind it would see\n * for a local binding. `relay = false` answers \"not mine\", which is the framework default.\n */\nexport class RelayWebpiecesPeerErrors implements ErrorTranslator {\n relay = true;\n\n private readonly fallback = new WebpiecesDefaultErrorTranslator();\n\n toWire(error: Error): HttpResponseDto {\n return this.fallback.toWire(error);\n }\n\n fromWire(response: HttpResponseDto, role: ClientRole): void {\n if (this.relay && ApiErrorCodec.isPayload(response.body)) {\n const decoded = ApiErrorCodec.decode(response.body);\n const statusCode = decoded instanceof ApiCodedError ? decoded.statusCode : undefined;\n if (\n ApiErrorHttpStatus.hasCode(decoded) &&\n ApiErrorHttpStatus.codeFor(decoded.kind, statusCode) === response.status.code\n ) {\n throw decoded;\n }\n }\n this.fallback.fromWire(response, role);\n }\n}\n"]}
|
|
@@ -152,6 +152,9 @@ let SearchController = class SearchController extends SearchApi {
|
|
|
152
152
|
}
|
|
153
153
|
if (request.query === 'unavailable')
|
|
154
154
|
throw new core_util_3.ApiUnavailableError('private deployment');
|
|
155
|
+
if (request.query === 'exhausted') {
|
|
156
|
+
throw new core_util_3.ApiRetriesExhaustedError(4, new core_util_3.ApiUnavailableError('private retries'));
|
|
157
|
+
}
|
|
155
158
|
const invocation = core_context_1.RequestContext.getTrusted(McpInvocationContext_1.MCP_INVOCATION_CONTEXT);
|
|
156
159
|
if (request.query === 'progress') {
|
|
157
160
|
await invocation?.reportProgress?.(1, 2, 'halfway');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WpMcpServerTestFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/WpMcpServerTestFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { WpAuthorization, AuthorizationType, WpAuth, jwt as jwtAuth, oidc as oidcAuth } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiBadGatewayError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndUserError, ApiPath, ApiType, ApiUnauthorizedError, ApiUnavailableError, Logger, LoggerFactory, LogLevel, ContextKey, ContextTuple, Endpoint, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC, WRITE } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { AuthenticatedCaller, JwtHook, MintedJwt } from '@webpieces/http-routing';\nimport { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';\nimport { MCP_INVOCATION_CONTEXT } from '../McpInvocationContext';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\nexport const USER_ID = ContextKey.trusted<string>(\n 'mcpSpecUserId',\n 'proven by a credential verifier',\n);\nexport const ENDPOINT_PATH = '/app-owned/mcp';\nexport const MODERN_VERSION = '2026-07-28';\n/** What every shipping MCP client opens with today — the top of the 2025 negotiation table. */\nexport const LEGACY_VERSION = '2025-11-25';\n/** An older 2025-era revision the negotiation table still carries. */\nexport const OLDER_LEGACY_VERSION = '2025-03-26';\n/** A revision NO era knows: the one case a server is still right to refuse. */\nexport const UNKNOWN_VERSION = '1999-01-01';\n\nexport class SearchRequest {\n /**\n * Search text\n * @mcpHeader query\n */\n query!: string;\n}\n\nexport class SearchResponse {\n /** Authenticated user */\n userId!: string;\n\n /** Search result */\n result!: string;\n}\n\n/**\n * The tool catalogs these specs boot `WpMcpServer` with — ONE PER CONTRACT, the same shape\n * `wp-openapi` writes to `mcp-<ContractClass>-tools.json` from the contracts below.\n *\n * It is built by hand here rather than extracted, because `@webpieces/mcp-server` deliberately does\n * not depend on the TypeScript compiler API: the runtime's job is to BE HANDED a catalog, and these\n * specs exercise exactly that. The extractor's own suite proves the catalog matches these contracts.\n */\nfunction searchInputSchema(): ApiJsonSchema {\n const query = new ApiJsonSchema('string');\n query.description = 'Search text';\n query['x-mcp-header'] = 'query';\n return new ObjectSchemaBuilder().required('query', query).build();\n}\n\nfunction searchOutputSchema(): ApiJsonSchema {\n const userId = new ApiJsonSchema('string');\n userId.description = 'Authenticated user';\n const result = new ApiJsonSchema('string');\n result.description = 'Search result';\n return new ObjectSchemaBuilder().required('userId', userId).required('result', result).build();\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n hints: WpMcpToolHints,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n hints,\n searchInputSchema(),\n searchOutputSchema(), [Mcp.DEFAULT],\n );\n}\n\n/** The label a hand-built catalog carries where a read one names its directory. */\nexport const IN_MEMORY = '(built in memory by the spec)';\n\nexport const SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('SearchApi', [\n searchTool(\n 'account_search',\n 'Search accounts',\n 'search',\n 'Search records owned by the authenticated user.',\n new WpMcpToolHints(true, false, true, false),\n ),\n searchTool(\n 'admin_search',\n 'Admin search',\n 'admin',\n 'Administrative search.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\nexport const REMOTE_SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('RemoteSearchApi', [\n searchTool(\n 'remote_search',\n 'Remote search',\n 'search',\n 'Search a remote binding.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\n@ApiPath('/mcp-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class SearchApi {\n /** Search records owned by the authenticated user. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search', 'Search accounts')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /** Administrative search. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('admin_search', 'Admin search')\n admin(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteSearchApi {\n /** Search a remote binding. */\n\n @WpAuth([oidcAuth()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('remote_search', 'Remote search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@injectable()\nexport class SearchController extends SearchApi {\n static waitStartedHook?: () => void;\n static waitAbortedHook?: () => void;\n adminInvocations = 0;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n if (request.query === 'internal') throw new Error('database password appeared here');\n // A DOWNSTREAM call of ours failed. From the model's seat that is OUR bug, never a kind of\n // its own on the wire — see #959 and ApiErrorBoundary.encode.\n if (request.query === 'downstream') {\n throw new ApiConnectionError('ECONNREFUSED private-host:8443');\n }\n if (request.query === 'human') throw new ApiEndUserError('Safe human message', 'SAFE');\n if (request.query === 'malformed') {\n throw new ApiBadRequestError(\n 'operator-only: column tenant_7 rejected',\n '$.query',\n 'query is malformed',\n );\n }\n if (request.query === 'dependency') throw new ApiDependencyError('private upstream');\n if (request.query === 'bad-gateway') throw new ApiBadGatewayError('private proxy');\n if (request.query === 'timeout') throw new ApiDependencyTimeoutError('private timeout');\n if (request.query === 'backoff') {\n throw new ApiDependencyBackoffError('private throttling detail', 37);\n }\n if (request.query === 'unavailable') throw new ApiUnavailableError('private deployment');\n const invocation = RequestContext.getTrusted(MCP_INVOCATION_CONTEXT);\n if (request.query === 'progress') {\n await invocation?.reportProgress?.(1, 2, 'halfway');\n }\n if (request.query === 'wait' && invocation) {\n await invocation.reportProgress?.(0, 1, 'waiting');\n SearchController.waitStartedHook?.();\n await new Promise<void>((resolve: () => void) => {\n const finish = (): void => {\n SearchController.waitAbortedHook?.();\n resolve();\n };\n if (invocation.signal.aborted) finish();\n else invocation.signal.addEventListener('abort', finish, { once: true });\n });\n }\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n\n override async admin(request: SearchRequest): Promise<SearchResponse> {\n this.adminInvocations += 1;\n return this.search(request);\n }\n}\n\nexport class RemoteSearchClient extends RemoteSearchApi {\n seenAuthorization?: string;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n this.seenAuthorization = RequestContext.getRequest()?.getHeader('authorization');\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n}\n\nexport class TestJwtHook extends JwtHook<string> {\n mintedTokens: string[] = [];\n lifetimeSeconds = 60;\n failWith?: Error;\n\n override async mint(subject: string): Promise<MintedJwt> {\n if (this.failWith) throw this.failWith;\n const token =\n subject === 'passthrough'\n ? 'mcp-passthrough'\n : `${subject}-endpoint-${this.mintedTokens.length + 1}`;\n this.mintedTokens.push(token);\n return new MintedJwt(token, Math.floor(Date.now() / 1000) + this.lifetimeSeconds);\n }\n\n override async parseJwt(token: string): Promise<AuthenticatedCaller> {\n if (token.startsWith('admin-endpoint-')) {\n return new AuthenticatedCaller(\n 'admin-7',\n ['admin'],\n [new ContextTuple(USER_ID, 'admin-7')],\n );\n }\n if (!token.startsWith('user-endpoint-')) throw new Error('invalid endpoint token');\n return new AuthenticatedCaller('user-7', [], [new ContextTuple(USER_ID, 'user-7')]);\n }\n}\n\nexport class TestTokenAuthority implements McpAccessTokenAuthority<string> {\n verificationCount = 0;\n roles: readonly string[] = [];\n\n async mintAccessToken(_grant: string): Promise<never> {\n throw new Error('not used');\n }\n\n async verifyAccessToken(token: string, resource: string): Promise<VerifiedMcpCredential> {\n this.verificationCount += 1;\n if (token === 'invalid') throw new ApiUnauthorizedError('invalid token');\n if (token === 'authority-bug') throw new Error('SECRET-internal-detail');\n const now = Math.floor(Date.now() / 1000);\n const actualResource =\n token === 'wrong-resource' ? 'https://attacker.example/mcp' : resource;\n const subject = token.startsWith('mcp-admin')\n ? 'admin'\n : token === 'mcp-passthrough'\n ? 'passthrough'\n : 'user';\n const issuer =\n token === 'wrong-issuer' ? 'https://attacker.example' : 'https://login.example.test';\n const expiresAt = token === 'expired' ? now - 1 : now + 60;\n const scopes = token === 'missing-scope' ? [] : ['tools'];\n const validatedAt = token === 'stale-account' ? now - 3_601 : now;\n const credential = new VerifiedMcpCredential(\n subject,\n issuer,\n actualResource,\n token === 'expired' ? now - 61 : now,\n expiresAt,\n scopes,\n validatedAt,\n new AuthenticatedCaller(\n `${subject}-7`,\n subject == 'admin' ? ['admin'] : [...this.roles],\n [new ContextTuple(USER_ID, `${subject}-7`)],\n ),\n );\n if (token === 'list-bug') {\n Object.defineProperty(credential.caller, 'roles', {\n get: (): readonly string[] => {\n throw new Error('SECRET-internal-detail');\n },\n });\n }\n return credential;\n }\n}\n\nexport class RecordedLogLine {\n constructor(\n public readonly logger: string,\n public readonly level: LogLevel,\n public readonly message: string,\n public readonly error?: Error,\n ) {}\n\n /** The rendered line an operator would see, including an attached error's message and stack. */\n rendered(): string {\n return `${this.message} ${this.error?.message ?? ''} ${this.error?.stack ?? ''}`;\n }\n}\n\nclass RecordingLogger implements Logger {\n constructor(\n private readonly name: string,\n private readonly lines: RecordedLogLine[],\n ) {}\n\n trace(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'trace', message, err));\n }\n\n debug(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'debug', message, err));\n }\n\n info(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'info', message, err));\n }\n\n warn(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'warn', message, err));\n }\n\n error(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'error', message, err));\n }\n}\n\n/** Captures every log line in-process so tests can count and level-check operator output. */\nexport class RecordingLoggerFactory implements LoggerFactory {\n readonly lines: RecordedLogLine[] = [];\n\n getLogger(name: string): Logger {\n return new RecordingLogger(name, this.lines);\n }\n\n containing(text: string): RecordedLogLine[] {\n return this.lines.filter((line: RecordedLogLine) => line.rendered().includes(text));\n }\n\n /** The lines ONE logger wrote that mention `text` — to count each owner's line separately. */\n fromLogger(logger: string, text: string): RecordedLogLine[] {\n return this.containing(text).filter((line: RecordedLogLine) => line.logger === logger);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WpMcpServerTestFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/WpMcpServerTestFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { WpAuthorization, AuthorizationType, WpAuth, jwt as jwtAuth, oidc as oidcAuth } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiBadGatewayError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndUserError, ApiRetriesExhaustedError, ApiPath, ApiType, ApiUnauthorizedError, ApiUnavailableError, Logger, LoggerFactory, LogLevel, ContextKey, ContextTuple, Endpoint, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC, WRITE } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { AuthenticatedCaller, JwtHook, MintedJwt } from '@webpieces/http-routing';\nimport { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';\nimport { MCP_INVOCATION_CONTEXT } from '../McpInvocationContext';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\nexport const USER_ID = ContextKey.trusted<string>(\n 'mcpSpecUserId',\n 'proven by a credential verifier',\n);\nexport const ENDPOINT_PATH = '/app-owned/mcp';\nexport const MODERN_VERSION = '2026-07-28';\n/** What every shipping MCP client opens with today — the top of the 2025 negotiation table. */\nexport const LEGACY_VERSION = '2025-11-25';\n/** An older 2025-era revision the negotiation table still carries. */\nexport const OLDER_LEGACY_VERSION = '2025-03-26';\n/** A revision NO era knows: the one case a server is still right to refuse. */\nexport const UNKNOWN_VERSION = '1999-01-01';\n\nexport class SearchRequest {\n /**\n * Search text\n * @mcpHeader query\n */\n query!: string;\n}\n\nexport class SearchResponse {\n /** Authenticated user */\n userId!: string;\n\n /** Search result */\n result!: string;\n}\n\n/**\n * The tool catalogs these specs boot `WpMcpServer` with — ONE PER CONTRACT, the same shape\n * `wp-openapi` writes to `mcp-<ContractClass>-tools.json` from the contracts below.\n *\n * It is built by hand here rather than extracted, because `@webpieces/mcp-server` deliberately does\n * not depend on the TypeScript compiler API: the runtime's job is to BE HANDED a catalog, and these\n * specs exercise exactly that. The extractor's own suite proves the catalog matches these contracts.\n */\nfunction searchInputSchema(): ApiJsonSchema {\n const query = new ApiJsonSchema('string');\n query.description = 'Search text';\n query['x-mcp-header'] = 'query';\n return new ObjectSchemaBuilder().required('query', query).build();\n}\n\nfunction searchOutputSchema(): ApiJsonSchema {\n const userId = new ApiJsonSchema('string');\n userId.description = 'Authenticated user';\n const result = new ApiJsonSchema('string');\n result.description = 'Search result';\n return new ObjectSchemaBuilder().required('userId', userId).required('result', result).build();\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n hints: WpMcpToolHints,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n hints,\n searchInputSchema(),\n searchOutputSchema(), [Mcp.DEFAULT],\n );\n}\n\n/** The label a hand-built catalog carries where a read one names its directory. */\nexport const IN_MEMORY = '(built in memory by the spec)';\n\nexport const SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('SearchApi', [\n searchTool(\n 'account_search',\n 'Search accounts',\n 'search',\n 'Search records owned by the authenticated user.',\n new WpMcpToolHints(true, false, true, false),\n ),\n searchTool(\n 'admin_search',\n 'Admin search',\n 'admin',\n 'Administrative search.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\nexport const REMOTE_SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('RemoteSearchApi', [\n searchTool(\n 'remote_search',\n 'Remote search',\n 'search',\n 'Search a remote binding.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\n@ApiPath('/mcp-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class SearchApi {\n /** Search records owned by the authenticated user. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search', 'Search accounts')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /** Administrative search. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('admin_search', 'Admin search')\n admin(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteSearchApi {\n /** Search a remote binding. */\n\n @WpAuth([oidcAuth()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('remote_search', 'Remote search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@injectable()\nexport class SearchController extends SearchApi {\n static waitStartedHook?: () => void;\n static waitAbortedHook?: () => void;\n adminInvocations = 0;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n if (request.query === 'internal') throw new Error('database password appeared here');\n // A DOWNSTREAM call of ours failed. From the model's seat that is OUR bug, never a kind of\n // its own on the wire — see #959 and ApiErrorBoundary.encode.\n if (request.query === 'downstream') {\n throw new ApiConnectionError('ECONNREFUSED private-host:8443');\n }\n if (request.query === 'human') throw new ApiEndUserError('Safe human message', 'SAFE');\n if (request.query === 'malformed') {\n throw new ApiBadRequestError(\n 'operator-only: column tenant_7 rejected',\n '$.query',\n 'query is malformed',\n );\n }\n if (request.query === 'dependency') throw new ApiDependencyError('private upstream');\n if (request.query === 'bad-gateway') throw new ApiBadGatewayError('private proxy');\n if (request.query === 'timeout') throw new ApiDependencyTimeoutError('private timeout');\n if (request.query === 'backoff') {\n throw new ApiDependencyBackoffError('private throttling detail', 37);\n }\n if (request.query === 'unavailable') throw new ApiUnavailableError('private deployment');\n if (request.query === 'exhausted') {\n throw new ApiRetriesExhaustedError(4, new ApiUnavailableError('private retries'));\n }\n const invocation = RequestContext.getTrusted(MCP_INVOCATION_CONTEXT);\n if (request.query === 'progress') {\n await invocation?.reportProgress?.(1, 2, 'halfway');\n }\n if (request.query === 'wait' && invocation) {\n await invocation.reportProgress?.(0, 1, 'waiting');\n SearchController.waitStartedHook?.();\n await new Promise<void>((resolve: () => void) => {\n const finish = (): void => {\n SearchController.waitAbortedHook?.();\n resolve();\n };\n if (invocation.signal.aborted) finish();\n else invocation.signal.addEventListener('abort', finish, { once: true });\n });\n }\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n\n override async admin(request: SearchRequest): Promise<SearchResponse> {\n this.adminInvocations += 1;\n return this.search(request);\n }\n}\n\nexport class RemoteSearchClient extends RemoteSearchApi {\n seenAuthorization?: string;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n this.seenAuthorization = RequestContext.getRequest()?.getHeader('authorization');\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n}\n\nexport class TestJwtHook extends JwtHook<string> {\n mintedTokens: string[] = [];\n lifetimeSeconds = 60;\n failWith?: Error;\n\n override async mint(subject: string): Promise<MintedJwt> {\n if (this.failWith) throw this.failWith;\n const token =\n subject === 'passthrough'\n ? 'mcp-passthrough'\n : `${subject}-endpoint-${this.mintedTokens.length + 1}`;\n this.mintedTokens.push(token);\n return new MintedJwt(token, Math.floor(Date.now() / 1000) + this.lifetimeSeconds);\n }\n\n override async parseJwt(token: string): Promise<AuthenticatedCaller> {\n if (token.startsWith('admin-endpoint-')) {\n return new AuthenticatedCaller(\n 'admin-7',\n ['admin'],\n [new ContextTuple(USER_ID, 'admin-7')],\n );\n }\n if (!token.startsWith('user-endpoint-')) throw new Error('invalid endpoint token');\n return new AuthenticatedCaller('user-7', [], [new ContextTuple(USER_ID, 'user-7')]);\n }\n}\n\nexport class TestTokenAuthority implements McpAccessTokenAuthority<string> {\n verificationCount = 0;\n roles: readonly string[] = [];\n\n async mintAccessToken(_grant: string): Promise<never> {\n throw new Error('not used');\n }\n\n async verifyAccessToken(token: string, resource: string): Promise<VerifiedMcpCredential> {\n this.verificationCount += 1;\n if (token === 'invalid') throw new ApiUnauthorizedError('invalid token');\n if (token === 'authority-bug') throw new Error('SECRET-internal-detail');\n const now = Math.floor(Date.now() / 1000);\n const actualResource =\n token === 'wrong-resource' ? 'https://attacker.example/mcp' : resource;\n const subject = token.startsWith('mcp-admin')\n ? 'admin'\n : token === 'mcp-passthrough'\n ? 'passthrough'\n : 'user';\n const issuer =\n token === 'wrong-issuer' ? 'https://attacker.example' : 'https://login.example.test';\n const expiresAt = token === 'expired' ? now - 1 : now + 60;\n const scopes = token === 'missing-scope' ? [] : ['tools'];\n const validatedAt = token === 'stale-account' ? now - 3_601 : now;\n const credential = new VerifiedMcpCredential(\n subject,\n issuer,\n actualResource,\n token === 'expired' ? now - 61 : now,\n expiresAt,\n scopes,\n validatedAt,\n new AuthenticatedCaller(\n `${subject}-7`,\n subject == 'admin' ? ['admin'] : [...this.roles],\n [new ContextTuple(USER_ID, `${subject}-7`)],\n ),\n );\n if (token === 'list-bug') {\n Object.defineProperty(credential.caller, 'roles', {\n get: (): readonly string[] => {\n throw new Error('SECRET-internal-detail');\n },\n });\n }\n return credential;\n }\n}\n\nexport class RecordedLogLine {\n constructor(\n public readonly logger: string,\n public readonly level: LogLevel,\n public readonly message: string,\n public readonly error?: Error,\n ) {}\n\n /** The rendered line an operator would see, including an attached error's message and stack. */\n rendered(): string {\n return `${this.message} ${this.error?.message ?? ''} ${this.error?.stack ?? ''}`;\n }\n}\n\nclass RecordingLogger implements Logger {\n constructor(\n private readonly name: string,\n private readonly lines: RecordedLogLine[],\n ) {}\n\n trace(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'trace', message, err));\n }\n\n debug(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'debug', message, err));\n }\n\n info(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'info', message, err));\n }\n\n warn(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'warn', message, err));\n }\n\n error(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'error', message, err));\n }\n}\n\n/** Captures every log line in-process so tests can count and level-check operator output. */\nexport class RecordingLoggerFactory implements LoggerFactory {\n readonly lines: RecordedLogLine[] = [];\n\n getLogger(name: string): Logger {\n return new RecordingLogger(name, this.lines);\n }\n\n containing(text: string): RecordedLogLine[] {\n return this.lines.filter((line: RecordedLogLine) => line.rendered().includes(text));\n }\n\n /** The lines ONE logger wrote that mention `text` — to count each owner's line separately. */\n fromLogger(logger: string, text: string): RecordedLogLine[] {\n return this.containing(text).filter((line: RecordedLogLine) => line.logger === logger);\n }\n}\n"]}
|