@webpieces/mcp-server 0.4.985 → 0.4.987
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 +4 -0
- package/package.json +6 -6
- package/src/McpApiDispatcher.d.ts +1 -1
- package/src/McpApiDispatcher.js +2 -2
- package/src/McpApiDispatcher.js.map +1 -1
- package/src/WpMcpServer.js +2 -2
- package/src/WpMcpServer.js.map +1 -1
- package/src/__tests__/WpMcpServerTestFixtures.js +2 -2
- package/src/__tests__/WpMcpServerTestFixtures.js.map +1 -1
- package/src/index.d.ts +0 -2
- package/src/index.js +1 -4
- package/src/index.js.map +1 -1
- package/src/McpInvocationContext.d.ts +0 -14
- package/src/McpInvocationContext.js +0 -25
- package/src/McpInvocationContext.js.map +0 -1
package/README.md
CHANGED
|
@@ -218,6 +218,10 @@ request-scoped SSE responses, backpressure, cancellation, keepalives, and subscr
|
|
|
218
218
|
owns the Express path, root `RequestContext`, authentication boundary, schema-derived tool registry,
|
|
219
219
|
and dispatch through the normal API proxy.
|
|
220
220
|
|
|
221
|
+
Import `MCP_INVOCATION_CONTEXT`, `McpInvocationContext` and the `McpProgressReporter` type from
|
|
222
|
+
`@webpieces/core-util`; these lightweight contracts are no longer exported by `@webpieces/mcp-server`.
|
|
223
|
+
They use the existing `RequestContext`, with no additional context scope or MCP SDK dependency.
|
|
224
|
+
|
|
221
225
|
During a tool invocation, `RequestContext.getTrusted(MCP_INVOCATION_CONTEXT)` exposes the verified
|
|
222
226
|
JSON-RPC ID, tool/user/role facts, the official SDK cancellation `AbortSignal`, and (when the client
|
|
223
227
|
supplied `_meta.progressToken`) a `reportProgress(...)` callback. Progress remains related to that
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.987",
|
|
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.987",
|
|
28
|
+
"@webpieces/core-util": "0.4.987",
|
|
29
|
+
"@webpieces/http-routing": "0.4.987",
|
|
30
|
+
"@webpieces/http-server": "0.4.987",
|
|
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.987"
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -2,7 +2,7 @@ import { DtoValue } from '@webpieces/core-util';
|
|
|
2
2
|
import { AuthorizationService } from '@webpieces/http-routing';
|
|
3
3
|
import { RegisteredMcpTool } from './McpToolRegistry';
|
|
4
4
|
import { VerifiedMcpCredential } from './McpAuth';
|
|
5
|
-
import { McpInvocationContext } from '
|
|
5
|
+
import { McpInvocationContext } from '@webpieces/core-util';
|
|
6
6
|
/** Authorize, validate, then issue a local credential and invoke the ordinary filters. No scope or catch. */
|
|
7
7
|
export declare class McpApiDispatcher {
|
|
8
8
|
private readonly schemas;
|
package/src/McpApiDispatcher.js
CHANGED
|
@@ -5,7 +5,7 @@ const core_util_1 = require("@webpieces/core-util");
|
|
|
5
5
|
const core_context_1 = require("@webpieces/core-context");
|
|
6
6
|
const http_routing_1 = require("@webpieces/http-routing");
|
|
7
7
|
const McpToolPolicy_1 = require("./McpToolPolicy");
|
|
8
|
-
const
|
|
8
|
+
const core_util_2 = require("@webpieces/core-util");
|
|
9
9
|
/** Authorize, validate, then issue a local credential and invoke the ordinary filters. No scope or catch. */
|
|
10
10
|
class McpApiDispatcher {
|
|
11
11
|
schemas = new core_util_1.ApiJsonSchemaValidator();
|
|
@@ -18,7 +18,7 @@ class McpApiDispatcher {
|
|
|
18
18
|
const authentication = tool.binding.topology === 'local'
|
|
19
19
|
? new http_routing_1.InvocationAuthentication(tool.apiClass, tool.methodName)
|
|
20
20
|
: undefined;
|
|
21
|
-
core_context_1.RequestContext.putTrusted(
|
|
21
|
+
core_context_1.RequestContext.putTrusted(core_util_2.MCP_INVOCATION_CONTEXT, invocation);
|
|
22
22
|
return tool.binding.invoke(tool.methodName, requestDto, authentication);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpApiDispatcher.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpApiDispatcher.ts"],"names":[],"mappings":";;;AAAA,oDAA4F;AAC5F,0DAAyD;AACzD,0DAAyF;AACzF,mDAAgD;AAGhD,
|
|
1
|
+
{"version":3,"file":"McpApiDispatcher.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpApiDispatcher.ts"],"names":[],"mappings":";;;AAAA,oDAA4F;AAC5F,0DAAyD;AACzD,0DAAyF;AACzF,mDAAgD;AAGhD,oDAAoF;AAEpF,6GAA6G;AAC7G,MAAa,gBAAgB;IACR,OAAO,GAAG,IAAI,kCAAsB,EAAE,CAAC;IAExD,KAAK,CAAC,IAAI,CACN,IAAuB,EACvB,UAAoB,EACpB,UAAiC,EACjC,UAAgC,EAChC,MAA4B;QAE5B,MAAM,IAAI,6BAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACzE,IAAI,YAAY,EAAE,CAAC;YACf,MAAM,IAAI,8BAAkB,CACxB,qBAAqB,IAAI,CAAC,IAAI,8CAA8C,YAAY,CAAC,OAAO,EAAE,EAClG,YAAY,CAAC,KAAK,EAClB,YAAY,CAAC,OAAO,CACvB,CAAC;QACN,CAAC;QACD,MAAM,cAAc,GAChB,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC7B,CAAC,CAAC,IAAI,uCAAwB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC;YAC9D,CAAC,CAAC,SAAS,CAAC;QACpB,6BAAc,CAAC,UAAU,CAAC,kCAAsB,EAAE,UAAU,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IAC5E,CAAC;CACJ;AA1BD,4CA0BC","sourcesContent":["import { ApiBadRequestError, ApiJsonSchemaValidator, DtoValue } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { InvocationAuthentication, AuthorizationService } from '@webpieces/http-routing';\nimport { McpToolPolicy } from './McpToolPolicy';\nimport { RegisteredMcpTool } from './McpToolRegistry';\nimport { VerifiedMcpCredential } from './McpAuth';\nimport { MCP_INVOCATION_CONTEXT, McpInvocationContext } from '@webpieces/core-util';\n\n/** Authorize, validate, then issue a local credential and invoke the ordinary filters. No scope or catch. */\nexport class McpApiDispatcher {\n private readonly schemas = new ApiJsonSchemaValidator();\n\n async call(\n tool: RegisteredMcpTool,\n requestDto: DtoValue,\n credential: VerifiedMcpCredential,\n invocation: McpInvocationContext,\n policy: AuthorizationService,\n ): Promise<DtoValue> {\n await new McpToolPolicy(policy).require(tool.authorization, tool.name);\n const inputFailure = this.schemas.validate(tool.inputSchema, requestDto);\n if (inputFailure) {\n throw new ApiBadRequestError(\n `MCP arguments for ${tool.name} did not match its published input schema: ${inputFailure.message}`,\n inputFailure.field,\n inputFailure.message,\n );\n }\n const authentication =\n tool.binding.topology === 'local'\n ? new InvocationAuthentication(tool.apiClass, tool.methodName)\n : undefined;\n RequestContext.putTrusted(MCP_INVOCATION_CONTEXT, invocation);\n return tool.binding.invoke(tool.methodName, requestDto, authentication);\n }\n}\n"]}
|
package/src/WpMcpServer.js
CHANGED
|
@@ -12,7 +12,7 @@ const http_server_1 = require("@webpieces/http-server");
|
|
|
12
12
|
const http_routing_1 = require("@webpieces/http-routing");
|
|
13
13
|
const McpAuth_1 = require("./McpAuth");
|
|
14
14
|
const McpApiDispatcher_1 = require("./McpApiDispatcher");
|
|
15
|
-
const
|
|
15
|
+
const core_util_2 = require("@webpieces/core-util");
|
|
16
16
|
const McpToolRegistry_1 = require("./McpToolRegistry");
|
|
17
17
|
const McpToolCallRendering_1 = require("./McpToolCallRendering");
|
|
18
18
|
const McpProtocol_1 = require("./McpProtocol");
|
|
@@ -405,7 +405,7 @@ class WpMcpServer {
|
|
|
405
405
|
/** Everything a tool call does. No catch in here: failures propagate to handleCallTool. */
|
|
406
406
|
async callTool(tool, request, authentication, sdkContext) {
|
|
407
407
|
const credential = authentication.credential;
|
|
408
|
-
const invocation = new
|
|
408
|
+
const invocation = new core_util_2.McpInvocationContext(sdkContext.mcpReq.id, tool.name, credential.subject, credential.principalRoles, AbortSignal.any([sdkContext.mcpReq.signal, authentication.disconnectSignal]), this.progressReporter(sdkContext));
|
|
409
409
|
const args = (request.params.arguments ?? {});
|
|
410
410
|
const value = await this.dispatcher.call(tool, args, credential, invocation, this.config.authorizationService);
|
|
411
411
|
const outputFailure = this.outputSchemas.validate(tool.outputSchema, value);
|
package/src/WpMcpServer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolDeniedError } from './McpToolPolicy';\nimport { createHash } from 'node:crypto';\nimport {\n AuthInfo,\n CallToolRequest,\n CallToolResult,\n createMcpHandler,\n ListToolsResult,\n McpHttpHandler,\n McpRequestContext,\n McpServer,\n ProgressToken,\n ProtocolError,\n ServerContext,\n ServerOptions,\n Tool,\n Implementation,\n Icon,\n} from '@modelcontextprotocol/server';\nimport { NodeMcpRequestHandler, toNodeHandler } from '@modelcontextprotocol/node';\nimport { Express, json, NextFunction, Request, Response } from 'express';\nimport {\n ApiBadRequestError,\n ApiErrorBoundary,\n ApiForbiddenError,\n ApiImplementationError,\n ApiJsonSchemaValidator,\n ApiMethodInfo,\n ApiUnauthorizedError,\n DtoValue,\n LogApiCallImpl,\n LogManager,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport {\n HttpRequest,\n RequestContext,\n RequestContextApiCallContext,\n RequestContextHeaders,\n} from '@webpieces/core-context';\nimport { ExpressResponseWriter } from '@webpieces/http-server';\nimport { AuthenticatedCallerContext } from '@webpieces/http-routing';\nimport {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpBindOptions } from './McpBindOptions';\nimport { McpInvocationContext, McpProgressReporter } from './McpInvocationContext';\nimport { AuthorizedMcpTools, McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nimport { McpCorrelation } from './McpToolCallRendering';\nimport { McpProtocol } from './McpProtocol';\nimport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\n\nconst log = LogManager.getLogger('WpMcpServer');\n\ntype AuthenticatedExpressRequest = Request & { auth?: AuthInfo };\n\n/**\n * The request DTO the edge `LogApiCall` lines report. These boundaries run BEFORE (or outside) any\n * API dispatch, so there is no contract DTO to log; the step name is the fact worth having.\n */\nclass McpSdkOperation {\n toolStage = false;\n constructor(public readonly name: string) {}\n}\n\nclass McpEdgeRequest {\n constructor(public readonly step: string) {}\n}\n\n/**\n * `Tool.annotations` exactly as tools/list publishes it: the four hints PLUS the human-readable\n * `title` (#1180). The Claude Connectors Directory checks `annotations.title`; clients on the\n * 2025-06-18+ spec render the top-level `Tool.title`, so both carry the one title — the method's\n * `@summary` JSDoc tag, read from the generated catalog (#1296).\n */\nclass McpPublishedToolAnnotations {\n readonly title: string;\n readonly readOnlyHint: boolean;\n readonly destructiveHint: boolean;\n readonly idempotentHint: boolean;\n readonly openWorldHint: boolean;\n\n constructor(tool: RegisteredMcpTool) {\n this.title = tool.title;\n this.readOnlyHint = tool.annotations.readOnlyHint;\n this.destructiveHint = tool.annotations.destructiveHint;\n this.idempotentHint = tool.annotations.idempotentHint;\n this.openWorldHint = tool.annotations.openWorldHint;\n }\n}\n\n/** Body of the 405 answered for every non-POST method at the bound MCP endpoint path. */\nclass McpMethodNotAllowedBody {\n readonly error = 'method_not_allowed';\n}\n\n/** Facts established once per POST at the bind boundary and handed to the SDK handlers. */\nclass McpPostAuthentication {\n constructor(\n public readonly accessToken: string,\n public readonly credential: VerifiedMcpCredential,\n public readonly disconnectSignal: AbortSignal,\n public readonly tools: AuthorizedMcpTools,\n ) {}\n}\n\n/**\n * The official SDK server with Webpieces-owned tools/list and tools/call handlers. It answers\n * `toolInputSchemaJson` from the request-authorized view so the SDK's pre-dispatch SEP-2243\n * `Mcp-Param-*` header validation still runs without registering SDK-side tool callbacks.\n */\nclass WpSdkMcpServer extends McpServer {\n constructor(\n info: Implementation,\n options: ServerOptions,\n private readonly registry: AuthorizedMcpTools,\n ) {\n super(info, options);\n }\n\n // webpieces-disable no-any-unknown -- signature is fixed by the SDK's JSON Schema record type\n override toolInputSchemaJson(name: string): Record<string, unknown> | undefined {\n return this.registry.find(name)?.inputSchema as Record<string, DtoValue> | undefined;\n }\n}\n\n/**\n * MCP adapter around the official SDK's request-scoped HTTP handler, serving BOTH wire eras from\n * one tool registry: modern (2026-07-28, per-request `_meta` envelope) and legacy (the 2025-11-25\n * family, negotiated by `initialize`). The SDK routes each request to the leg its shape selects and\n * negotiates the revision; only a revision no era knows is refused. Pinning one era instead made\n * every shipping client unreachable (issue #969), and the MCP lifecycle spec is explicit that a\n * server answers with a revision it supports rather than erroring.\n *\n * Error boundaries: HTTP ingress owns pre-SDK replies; one shared SDK callback wrapper owns\n * protocol/list/name-resolution errors and authorized tool-result errors. The SDK writes callback\n * replies, so it cannot safely delegate those failures back to HTTP ingress.\n * `subscriptions/listen` is served entirely by the SDK's listen router, so Webpieces has no handler\n * (and no catch) there. The external bearer is verified exactly once per POST, at the HTTP\n * boundary, before the SDK is involved.\n *\n * Before tools/list and tools/call hand an IMPLEMENTATION-kind failure to the translator, they\n * `log.error` it with its stack and the requestId ({@link logImplementationFailure}, #1055). The\n * translator reduces such a failure to \"Internal Error\" for the caller, so that line is the only place\n * its cause exists.\n */\nexport class WpMcpServer<TGrant> {\n private readonly callerContext = new AuthenticatedCallerContext();\n private readonly dispatcher = new McpApiDispatcher();\n /** Classifies a failure exactly as the translator will render it, so the two cannot disagree. */\n private readonly boundary = new ApiErrorBoundary();\n private readonly outputSchemas = new ApiJsonSchemaValidator();\n /**\n * These edges have NO filter chain above them — `LogApiFilter` never sees a rejected bearer, a\n * bad `Origin`, a body express could not parse, or a `tools/list` the SDK renders itself.\n * Wrapping each in `LogApiCall` is this repo's one line on logging, and it is why\n * `ApiErrorBoundary` no longer writes a second, barer line of its own.\n */\n private readonly logApiCall = new LogApiCallImpl(new RequestContextApiCallContext());\n private readonly responseWriter = new ExpressResponseWriter();\n /** tools/call reads `McpRegistry`; every other reply stays framework-owned. See McpErrorTranslator. */\n private readonly translator: WpMcpErrorTranslator;\n private registry?: McpToolRegistry;\n private toolProfiles: readonly string[] = [];\n private handler?: McpHttpHandler;\n private streamingHandler?: McpHttpHandler;\n private nodeHandler?: NodeMcpRequestHandler;\n private streamingNodeHandler?: NodeMcpRequestHandler;\n private revision?: string;\n private icons?: readonly Icon[];\n\n constructor(private readonly config: WpMcpServerConfig<TGrant>) {\n this.translator = new WpMcpErrorTranslator((): string => this.challenge());\n }\n\n /**\n * Mounts this MCP endpoint on `app`: POST at `options.endpointPath`, plus a 405 (`Allow: POST`)\n * for every other method there.\n *\n * SINGLE CANONICAL ORIGIN: one server serves exactly one protected resource, so this may be\n * called only once and `WpMcpServerConfig.setResource(...)`'s path must equal `endpointPath`.\n * That resource URI is fixed for the lifetime of the process and is never derived from the\n * request `Host` — a host-derived audience would make the boundary's own audience check compare\n * two caller-controlled values, which is the confused deputy this check exists to prevent.\n * Serving a second hostname is a second deployment, not a second audience.\n *\n * The OAuth/discovery half stays app-owned: publish `protectedResourceMetadata()` at\n * `WpMcpServerConfig.resourceMetadataUrl`, which is where the 401 challenge sends clients.\n */\n bind(app: Express, options: McpBindOptions): void {\n if (this.handler) {\n throw new Error(\n 'WpMcpServer.bind(...) may be called only once; an MCP resource has exactly one ' +\n 'canonical URI, fixed for the lifetime of the process.',\n );\n }\n // Fail at boot naming the forgotten setter, never on the first request with a 401 the client\n // answers by re-authenticating (see WpMcpServerConfig).\n this.config.validate();\n const resourcePath = new URL(this.config.resource).pathname;\n if (resourcePath !== options.endpointPath) {\n throw new Error(\n `MCP resource path '${resourcePath}' must equal endpointPath ` +\n `'${options.endpointPath}'; the canonical resource URI ` +\n `'${this.config.resource}' and the bound route are the same endpoint.`,\n );\n }\n this.toolProfiles = this.config.toolProfiles;\n this.icons = this.config.icons;\n this.registry = new McpToolRegistry(\n options.bindings,\n options.toolCatalogs,\n this.config.authorizationService,\n );\n this.revision = this.calculateRegistryRevision(this.registry);\n this.handler = this.createHandler(options, 'auto');\n this.streamingHandler = this.createHandler(options, 'sse');\n this.nodeHandler = toNodeHandler(this.handler, {\n onerror: (error: Error) => log.error('MCP Node transport failed', error),\n });\n this.streamingNodeHandler = toNodeHandler(this.streamingHandler, {\n onerror: (error: Error) => log.error('MCP streaming Node transport failed', error),\n });\n app.post(\n options.endpointPath,\n json(),\n async (req: Request, res: Response): Promise<void> =>\n this.handleHttp(req, res, options),\n // Express routes body-parser failures (bad JSON, body too large) to an error handler.\n (bodyError: Error, req: Request, res: Response, _next: NextFunction): void => {\n void this.handleBodyFailure(bodyError, req, res);\n },\n );\n // Registered AFTER the POST route so POST still wins. NEITHER era served here has a session\n // GET: 2026-07-28 has none at all (`subscriptions/listen` is a POST method), and the legacy\n // leg is the SDK's STATELESS fallback, which answers the 2025 session GET/DELETE with the\n // same 405. So every other method is a method error — and a discovery probe gets that\n // instead of Express' bare 404.\n app.all(options.endpointPath, (_req: Request, res: Response): void => {\n res.setHeader('Allow', 'POST');\n res.status(405).json(new McpMethodNotAllowedBody());\n });\n }\n\n protectedResourceMetadata(): McpProtectedResourceMetadata {\n return this.config.protectedResourceMetadata();\n }\n\n /** Gracefully closes active listen/request streams; clients must reconnect and refresh lists. */\n async close(): Promise<void> {\n await Promise.all([this.handler?.close(), this.streamingHandler?.close()]);\n }\n\n /** Level-triggered invalidation; the authoritative list is always fetched again by clients. */\n toolsChanged(): void {\n this.handler?.notify.toolsChanged();\n }\n\n get registryRevision(): string | undefined {\n return this.revision;\n }\n\n private createHandler(options: McpBindOptions, responseMode: 'auto' | 'sse'): McpHttpHandler {\n return createMcpHandler(\n (context: McpRequestContext) => this.buildSdkServer(context, options),\n {\n // Both eras, one factory: `stateless` serves 2025-era traffic through a fresh\n // instance of the SAME McpServerFactory, so the two eras can never drift apart.\n legacy: 'stateless',\n responseMode,\n bus: options.deployment.bus,\n maxSubscriptions: options.maxSubscriptions,\n keepAliveMs: options.keepAliveMs,\n onerror: (error: Error) => log.warn('MCP protocol request rejected', error),\n },\n );\n }\n\n /** Each HTTP entry uses the same full-request scope and ingress translation seam. */\n private async handleHttp(req: Request, res: Response, options: McpBindOptions): Promise<void> {\n res.setHeader('X-Accel-Buffering', 'no');\n await this.ingress(req, res, 'serve', () => this.serveExpress(req, res, options));\n }\n\n private async handleBodyFailure(cause: Error, req: Request, res: Response): Promise<void> {\n await this.ingress(req, res, 'body', () => this.rejectBody(cause));\n }\n\n private async ingress(\n req: Request,\n res: Response,\n step: string,\n work: () => Promise<void>,\n ): Promise<void> {\n await RequestContext.run(async () => {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- HTTP response-owning ingress boundary, including request publication and correlation failures\n try {\n new RequestContextHeaders().fillFromRequest(this.toHttpRequest(req));\n McpCorrelation.stamp(this.correlationOf(req));\n await this.logEdge(step, work);\n } catch (err: unknown) {\n const error = toError(err);\n this.writeBoundaryError(res, error);\n }\n });\n }\n\n /** A body express could not parse is a caller input error, reported through the same edge. */\n private async rejectBody(cause: Error): Promise<never> {\n throw new ApiBadRequestError(\n `MCP request body rejected: ${cause.message}`,\n undefined,\n undefined,\n cause,\n );\n }\n\n /**\n * The pre-SDK boundary owns the socket, so it produces a VALUE and writes it through the SAME\n * express writer `ExpressWrapper` uses. A failure after headers were sent can only end the\n * stream.\n */\n private writeBoundaryError(res: Response, error: Error): void {\n if (res.headersSent) {\n res.end();\n return;\n }\n this.responseWriter.write(res, this.translator.toBearerBoundaryResponse(error));\n }\n\n /** Run one un-filtered edge step under `LogApiCall`, so its failure gets exactly one log line. */\n private async logEdge<R>(step: string, work: () => Promise<R>): Promise<R> {\n return this.logApiCall.execute(\n new ApiMethodInfo('server', 'McpEndpoint', step, McpProtocol),\n new McpEdgeRequest(step),\n work,\n );\n }\n\n private async serveExpress(\n req: Request,\n res: Response,\n options: McpBindOptions,\n ): Promise<void> {\n const origin = req.header('origin');\n if (origin && !options.allowedOrigins.includes(origin)) {\n throw new ApiForbiddenError(`MCP request Origin '${origin}' is not allowed.`);\n }\n const authentication = await this.authenticate(req);\n const request = req as AuthenticatedExpressRequest;\n request.auth = this.authInfo(authentication);\n const serve = this.hasProgressToken(req.body)\n ? this.streamingNodeHandler\n : this.nodeHandler;\n if (!serve) throw new ApiImplementationError('MCP Node handlers are not initialized.');\n await serve(request, res, req.body);\n }\n\n /** Verifies the external bearer once for this POST. Handlers never re-verify it. */\n private async authenticate(req: Request): Promise<McpPostAuthentication> {\n const match = req.header('authorization')?.match(/^Bearer ([^\\s]+)$/i);\n const token = match?.[1];\n if (!token) throw new ApiUnauthorizedError('MCP request has no bearer access token.');\n const credential = await this.config.accessTokenAuthority.verifyAccessToken(\n token,\n this.config.resource,\n );\n this.validateCredential(credential);\n this.callerContext.publish(credential.caller);\n RequestContext.putTrusted(WebpiecesCoreHeaders.SURFACE, 'llm');\n this.callerContext.reconcileWireTrust(false);\n const tools = await AuthorizedMcpTools.create(\n this.requireRegistry(),\n this.config.authorizationService,\n this.toolProfiles,\n );\n return new McpPostAuthentication(token, credential, this.disconnectSignal(req), tools);\n }\n\n private disconnectSignal(req: Request): AbortSignal {\n const disconnected = new AbortController();\n const res = req.res;\n const cancel = (): void => disconnected.abort();\n req.once('aborted', cancel);\n req.socket.once('close', cancel);\n res?.once('close', cancel);\n res?.once('finish', (): void => {\n req.off('aborted', cancel);\n req.socket.off('close', cancel);\n res.off('close', cancel);\n });\n return disconnected.signal;\n }\n\n private buildSdkServer(context: McpRequestContext, options: McpBindOptions): McpServer {\n // The era is the SDK's to decide and BOTH are served; what is not negotiable is that the\n // request came through `bind`'s HTTP boundary, which is where the external bearer is\n // verified. A factory call without it is a wiring mistake, never a client's doing.\n const authentication = context.authInfo?.extra?.['webpiecesAuthentication'];\n if (!(authentication instanceof McpPostAuthentication)) {\n throw new ApiImplementationError(\n 'WpMcpServer serves only MCP requests authenticated by its bind boundary.',\n );\n }\n const server = new WpSdkMcpServer(\n {\n name: this.config.name,\n title: this.config.title,\n description: this.config.description,\n websiteUrl: this.config.websiteUrl,\n version: `${this.config.version}+${this.revision}`,\n ...(this.icons === undefined ? {} : { icons: [...this.icons] }),\n },\n {\n capabilities: { tools: { listChanged: true } },\n cacheHints: {\n 'tools/list': { ttlMs: options.deployment.ttlMs, cacheScope: 'private' },\n 'server/discover': { ttlMs: options.deployment.ttlMs, cacheScope: 'private' },\n },\n },\n authentication.tools,\n );\n server.server.removeRequestHandler('tools/list');\n server.server.removeRequestHandler('tools/call');\n server.server.setRequestHandler(\n 'tools/list',\n async (_request: object): Promise<ListToolsResult> =>\n this.sdkBoundary(new McpSdkOperation('tools/list'), () =>\n this.logEdge('tools/list', async () => this.listTools(authentication.tools)),\n ) as Promise<ListToolsResult>,\n );\n server.server.setRequestHandler(\n 'tools/call',\n async (request: CallToolRequest, sdkContext: ServerContext): Promise<CallToolResult> =>\n this.handleCallTool(server, request, authentication, sdkContext),\n );\n return server;\n }\n\n /** ONE SDK callback catch implementation; the SDK intercepts foreign throws itself. */\n private async sdkBoundary<R>(\n operation: McpSdkOperation,\n work: () => Promise<R>,\n ): Promise<R | CallToolResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- shared SDK response boundary, preserving protocol versus tool envelopes\n try {\n return await work();\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof McpToolDeniedError)\n throw this.translator.unknownTool(error.toolName);\n if (!operation.toolStage && error instanceof ProtocolError) throw error;\n this.logImplementationFailure(operation.name, error);\n if (operation.toolStage) return this.translator.toToolCallResult(error);\n this.translator.toListError(error);\n }\n }\n\n private listTools(view: AuthorizedMcpTools): ListToolsResult {\n const tools: Tool[] = view.tools.map((tool) => this.toolDefinition(tool));\n return { tools };\n }\n\n private toolDefinition(tool: RegisteredMcpTool): Tool {\n return {\n name: tool.name,\n title: tool.title,\n description: tool.description,\n inputSchema: tool.inputSchema as Tool['inputSchema'],\n outputSchema: tool.outputSchema as Tool['outputSchema'],\n annotations: new McpPublishedToolAnnotations(tool),\n _meta: { webpiecesRegistryRevision: this.revision },\n };\n }\n\n /**\n * SDK tool callback: an unknown or hidden tool is a JSON-RPC -32602; every failure after the tool is found\n * is an `isError: true` result, identically for local and remote bindings.\n */\n private async handleCallTool(\n server: WpSdkMcpServer,\n request: CallToolRequest,\n authentication: McpPostAuthentication,\n sdkContext: ServerContext,\n ): Promise<CallToolResult> {\n const name = request.params.name;\n const operation = new McpSdkOperation(`tools/call ${name}`);\n return this.sdkBoundary(operation, async () => {\n McpCorrelation.stamp(new McpCorrelation(sdkContext.mcpReq.id, McpProtocol, name));\n const tool = authentication.tools.find(name);\n if (!tool) throw this.translator.unknownTool(name);\n McpCorrelation.stamp(\n new McpCorrelation(sdkContext.mcpReq.id, tool.apiClass, name, tool.operation),\n );\n operation.toolStage = true;\n const result = await this.callTool(tool, request, authentication, sdkContext);\n result._meta = this.translator.resultMeta(McpCorrelation.requestId());\n return server.server.projectCallToolResult(\n result,\n tool.outputSchema as Record<string, DtoValue>,\n );\n }) as Promise<CallToolResult>;\n }\n\n /**\n * ONE `log.error` line, with the stack and the requestId, for a failure that is THIS server's bug\n * — the `implementation` kind, which the translator reduces to \"Internal Error\" and a requestId\n * for the caller (#1055).\n *\n * `LogApiCall` does not cover this. An MCP output-schema violation is raised AFTER the controller\n * returned, so the only `LogApiCall` line for that call reads `resp-SUCCESS`; before this line\n * existed, the requestId support was handed led to a log with no error in it. Where a\n * `[API-*-resp-FAIL]` line does exist it carries the error's message, not its stack. So this line\n * is not the bare duplicate `ApiErrorBoundary` stopped writing: it is the one that says WHERE.\n *\n * Every other kind (bad-request, end-user, dependency, ...) is a caller's or a downstream's\n * failure, published to the caller with its own text, and `LogApiCall` already records it.\n */\n private logImplementationFailure(entryPoint: string, error: Error): void {\n if (this.boundary.encode(error).kind !== 'implementation') return;\n log.error(\n `MCP ${entryPoint} failed with an implementation error requestId=${McpCorrelation.requestId()}`,\n error,\n );\n }\n\n /** Everything a tool call does. No catch in here: failures propagate to handleCallTool. */\n private async callTool(\n tool: RegisteredMcpTool,\n request: CallToolRequest,\n authentication: McpPostAuthentication,\n sdkContext: ServerContext,\n ): Promise<CallToolResult> {\n const credential = authentication.credential;\n const invocation = new McpInvocationContext(\n sdkContext.mcpReq.id,\n tool.name,\n credential.subject,\n credential.principalRoles,\n AbortSignal.any([sdkContext.mcpReq.signal, authentication.disconnectSignal]),\n this.progressReporter(sdkContext),\n );\n const args = (request.params.arguments ?? {}) as DtoValue;\n const value = await this.dispatcher.call(\n tool,\n args,\n credential,\n invocation,\n this.config.authorizationService,\n );\n const outputFailure = this.outputSchemas.validate(tool.outputSchema, value);\n if (outputFailure) {\n throw new ApiImplementationError(\n `MCP output schema violation for ${tool.apiClass.name}.${tool.methodName}: ${outputFailure.message}`,\n );\n }\n const structured = this.record(value);\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n };\n }\n\n private validateCredential(credential: VerifiedMcpCredential): void {\n const now = Math.floor(Date.now() / 1000);\n const reject = (reason: string): never => {\n throw new ApiUnauthorizedError(`MCP access token rejected: ${reason}`);\n };\n if (credential.subject.trim() === '') reject('no subject');\n const stamps = [\n credential.issuedAtEpochSeconds,\n credential.expiresAtEpochSeconds,\n credential.accountValidatedAtEpochSeconds,\n ];\n if (!stamps.every(Number.isFinite)) reject('security timestamps must be finite');\n if (credential.resource !== this.config.resource) reject('resource mismatch');\n if (!this.config.authorizationServers.includes(credential.issuer)) {\n reject('issuer is not trusted');\n }\n if (credential.issuedAtEpochSeconds > now || credential.expiresAtEpochSeconds <= now) {\n reject('outside its valid time window');\n }\n const lifetime = credential.expiresAtEpochSeconds - credential.issuedAtEpochSeconds;\n if (lifetime > MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS) reject('lifetime exceeds 30 days');\n for (const scope of this.config.requiredScopes) {\n if (!credential.scopes.includes(scope)) reject(`missing required scope '${scope}'`);\n }\n const validatedAge = now - credential.accountValidatedAtEpochSeconds;\n if (\n credential.accountValidatedAtEpochSeconds > now ||\n validatedAge > this.config.maxAccountValidationAgeSeconds\n ) {\n reject('account authorization state is not fresh enough for dispatch');\n }\n }\n\n private authInfo(authentication: McpPostAuthentication): AuthInfo {\n const credential = authentication.credential;\n return {\n token: authentication.accessToken,\n clientId: credential.subject,\n scopes: [...credential.scopes],\n expiresAt: credential.expiresAtEpochSeconds,\n resource: new URL(credential.resource),\n extra: { webpiecesAuthentication: authentication },\n };\n }\n\n private progressReporter(context: ServerContext): McpProgressReporter | undefined {\n const token = context.mcpReq._meta?.progressToken;\n if (token === undefined) return undefined;\n return async (progress: number, total?: number, message?: string): Promise<void> => {\n await context.mcpReq.notify({\n method: 'notifications/progress',\n params: this.progressParams(token, progress, total, message),\n });\n };\n }\n\n private progressParams(\n progressToken: ProgressToken,\n progress: number,\n total?: number,\n message?: string,\n ): Record<string, DtoValue> {\n const params: Record<string, DtoValue> = { progressToken, progress };\n if (total !== undefined) params['total'] = total;\n if (message !== undefined) params['message'] = message;\n return params;\n }\n\n /** What the raw POST body tells us before the SDK has parsed anything: the id, and the tool. */\n private correlationOf(req: Request): McpCorrelation {\n const body = this.bodyObject(req.body);\n const id = body?.['id'];\n const params = this.bodyObject(body?.['params']);\n const name = params?.['name'];\n return new McpCorrelation(\n typeof id === 'string' || typeof id === 'number' ? id : null,\n McpProtocol,\n typeof name === 'string' ? name : undefined,\n );\n }\n\n private challenge(): string {\n return `Bearer resource_metadata=\"${this.config.resourceMetadataUrl}\"`;\n }\n\n private bodyObject(value: DtoValue | undefined): Record<string, DtoValue> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n return value as Record<string, DtoValue>;\n }\n\n private hasProgressToken(body: DtoValue): boolean {\n const params = this.bodyObject(this.bodyObject(body)?.['params']);\n return this.bodyObject(params?.['_meta'])?.['progressToken'] !== undefined;\n }\n\n private toHttpRequest(req: Request): HttpRequest {\n const headers = new Map<string, string[]>();\n for (const [name, value] of Object.entries(req.headers)) {\n if (typeof value === 'string') headers.set(name, [value]);\n else if (Array.isArray(value)) headers.set(name, value);\n }\n return new HttpRequest(req.method, req.originalUrl || req.path, headers);\n }\n\n private calculateRegistryRevision(registry: McpToolRegistry): string {\n const surface = registry.tools.map((tool: RegisteredMcpTool) => [\n tool.name,\n tool.title,\n tool.description,\n tool.inputSchema,\n tool.outputSchema,\n tool.annotations,\n tool.profiles,\n ]);\n return createHash('sha256')\n .update(JSON.stringify([this.toolProfiles, surface]))\n .digest('hex')\n .slice(0, 12);\n }\n\n private requireRegistry(): McpToolRegistry {\n if (!this.registry) throw new Error('Call WpMcpServer.bind(...) before serving requests.');\n return this.registry;\n }\n\n private record(value: DtoValue): Record<string, DtoValue> {\n const jsonValue = JSON.stringify(value);\n if (jsonValue === undefined) {\n throw new ApiImplementationError('MCP structured content is not JSON serializable.');\n }\n const parsed = JSON.parse(jsonValue) as DtoValue;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { value: parsed };\n }\n return parsed as Record<string, DtoValue>;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolDeniedError } from './McpToolPolicy';\nimport { createHash } from 'node:crypto';\nimport {\n AuthInfo,\n CallToolRequest,\n CallToolResult,\n createMcpHandler,\n ListToolsResult,\n McpHttpHandler,\n McpRequestContext,\n McpServer,\n ProgressToken,\n ProtocolError,\n ServerContext,\n ServerOptions,\n Tool,\n Implementation,\n Icon,\n} from '@modelcontextprotocol/server';\nimport { NodeMcpRequestHandler, toNodeHandler } from '@modelcontextprotocol/node';\nimport { Express, json, NextFunction, Request, Response } from 'express';\nimport {\n ApiBadRequestError,\n ApiErrorBoundary,\n ApiForbiddenError,\n ApiImplementationError,\n ApiJsonSchemaValidator,\n ApiMethodInfo,\n ApiUnauthorizedError,\n DtoValue,\n LogApiCallImpl,\n LogManager,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport {\n HttpRequest,\n RequestContext,\n RequestContextApiCallContext,\n RequestContextHeaders,\n} from '@webpieces/core-context';\nimport { ExpressResponseWriter } from '@webpieces/http-server';\nimport { AuthenticatedCallerContext } from '@webpieces/http-routing';\nimport {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpBindOptions } from './McpBindOptions';\nimport { McpInvocationContext, McpProgressReporter } from '@webpieces/core-util';\nimport { AuthorizedMcpTools, McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nimport { McpCorrelation } from './McpToolCallRendering';\nimport { McpProtocol } from './McpProtocol';\nimport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\n\nconst log = LogManager.getLogger('WpMcpServer');\n\ntype AuthenticatedExpressRequest = Request & { auth?: AuthInfo };\n\n/**\n * The request DTO the edge `LogApiCall` lines report. These boundaries run BEFORE (or outside) any\n * API dispatch, so there is no contract DTO to log; the step name is the fact worth having.\n */\nclass McpSdkOperation {\n toolStage = false;\n constructor(public readonly name: string) {}\n}\n\nclass McpEdgeRequest {\n constructor(public readonly step: string) {}\n}\n\n/**\n * `Tool.annotations` exactly as tools/list publishes it: the four hints PLUS the human-readable\n * `title` (#1180). The Claude Connectors Directory checks `annotations.title`; clients on the\n * 2025-06-18+ spec render the top-level `Tool.title`, so both carry the one title — the method's\n * `@summary` JSDoc tag, read from the generated catalog (#1296).\n */\nclass McpPublishedToolAnnotations {\n readonly title: string;\n readonly readOnlyHint: boolean;\n readonly destructiveHint: boolean;\n readonly idempotentHint: boolean;\n readonly openWorldHint: boolean;\n\n constructor(tool: RegisteredMcpTool) {\n this.title = tool.title;\n this.readOnlyHint = tool.annotations.readOnlyHint;\n this.destructiveHint = tool.annotations.destructiveHint;\n this.idempotentHint = tool.annotations.idempotentHint;\n this.openWorldHint = tool.annotations.openWorldHint;\n }\n}\n\n/** Body of the 405 answered for every non-POST method at the bound MCP endpoint path. */\nclass McpMethodNotAllowedBody {\n readonly error = 'method_not_allowed';\n}\n\n/** Facts established once per POST at the bind boundary and handed to the SDK handlers. */\nclass McpPostAuthentication {\n constructor(\n public readonly accessToken: string,\n public readonly credential: VerifiedMcpCredential,\n public readonly disconnectSignal: AbortSignal,\n public readonly tools: AuthorizedMcpTools,\n ) {}\n}\n\n/**\n * The official SDK server with Webpieces-owned tools/list and tools/call handlers. It answers\n * `toolInputSchemaJson` from the request-authorized view so the SDK's pre-dispatch SEP-2243\n * `Mcp-Param-*` header validation still runs without registering SDK-side tool callbacks.\n */\nclass WpSdkMcpServer extends McpServer {\n constructor(\n info: Implementation,\n options: ServerOptions,\n private readonly registry: AuthorizedMcpTools,\n ) {\n super(info, options);\n }\n\n // webpieces-disable no-any-unknown -- signature is fixed by the SDK's JSON Schema record type\n override toolInputSchemaJson(name: string): Record<string, unknown> | undefined {\n return this.registry.find(name)?.inputSchema as Record<string, DtoValue> | undefined;\n }\n}\n\n/**\n * MCP adapter around the official SDK's request-scoped HTTP handler, serving BOTH wire eras from\n * one tool registry: modern (2026-07-28, per-request `_meta` envelope) and legacy (the 2025-11-25\n * family, negotiated by `initialize`). The SDK routes each request to the leg its shape selects and\n * negotiates the revision; only a revision no era knows is refused. Pinning one era instead made\n * every shipping client unreachable (issue #969), and the MCP lifecycle spec is explicit that a\n * server answers with a revision it supports rather than erroring.\n *\n * Error boundaries: HTTP ingress owns pre-SDK replies; one shared SDK callback wrapper owns\n * protocol/list/name-resolution errors and authorized tool-result errors. The SDK writes callback\n * replies, so it cannot safely delegate those failures back to HTTP ingress.\n * `subscriptions/listen` is served entirely by the SDK's listen router, so Webpieces has no handler\n * (and no catch) there. The external bearer is verified exactly once per POST, at the HTTP\n * boundary, before the SDK is involved.\n *\n * Before tools/list and tools/call hand an IMPLEMENTATION-kind failure to the translator, they\n * `log.error` it with its stack and the requestId ({@link logImplementationFailure}, #1055). The\n * translator reduces such a failure to \"Internal Error\" for the caller, so that line is the only place\n * its cause exists.\n */\nexport class WpMcpServer<TGrant> {\n private readonly callerContext = new AuthenticatedCallerContext();\n private readonly dispatcher = new McpApiDispatcher();\n /** Classifies a failure exactly as the translator will render it, so the two cannot disagree. */\n private readonly boundary = new ApiErrorBoundary();\n private readonly outputSchemas = new ApiJsonSchemaValidator();\n /**\n * These edges have NO filter chain above them — `LogApiFilter` never sees a rejected bearer, a\n * bad `Origin`, a body express could not parse, or a `tools/list` the SDK renders itself.\n * Wrapping each in `LogApiCall` is this repo's one line on logging, and it is why\n * `ApiErrorBoundary` no longer writes a second, barer line of its own.\n */\n private readonly logApiCall = new LogApiCallImpl(new RequestContextApiCallContext());\n private readonly responseWriter = new ExpressResponseWriter();\n /** tools/call reads `McpRegistry`; every other reply stays framework-owned. See McpErrorTranslator. */\n private readonly translator: WpMcpErrorTranslator;\n private registry?: McpToolRegistry;\n private toolProfiles: readonly string[] = [];\n private handler?: McpHttpHandler;\n private streamingHandler?: McpHttpHandler;\n private nodeHandler?: NodeMcpRequestHandler;\n private streamingNodeHandler?: NodeMcpRequestHandler;\n private revision?: string;\n private icons?: readonly Icon[];\n\n constructor(private readonly config: WpMcpServerConfig<TGrant>) {\n this.translator = new WpMcpErrorTranslator((): string => this.challenge());\n }\n\n /**\n * Mounts this MCP endpoint on `app`: POST at `options.endpointPath`, plus a 405 (`Allow: POST`)\n * for every other method there.\n *\n * SINGLE CANONICAL ORIGIN: one server serves exactly one protected resource, so this may be\n * called only once and `WpMcpServerConfig.setResource(...)`'s path must equal `endpointPath`.\n * That resource URI is fixed for the lifetime of the process and is never derived from the\n * request `Host` — a host-derived audience would make the boundary's own audience check compare\n * two caller-controlled values, which is the confused deputy this check exists to prevent.\n * Serving a second hostname is a second deployment, not a second audience.\n *\n * The OAuth/discovery half stays app-owned: publish `protectedResourceMetadata()` at\n * `WpMcpServerConfig.resourceMetadataUrl`, which is where the 401 challenge sends clients.\n */\n bind(app: Express, options: McpBindOptions): void {\n if (this.handler) {\n throw new Error(\n 'WpMcpServer.bind(...) may be called only once; an MCP resource has exactly one ' +\n 'canonical URI, fixed for the lifetime of the process.',\n );\n }\n // Fail at boot naming the forgotten setter, never on the first request with a 401 the client\n // answers by re-authenticating (see WpMcpServerConfig).\n this.config.validate();\n const resourcePath = new URL(this.config.resource).pathname;\n if (resourcePath !== options.endpointPath) {\n throw new Error(\n `MCP resource path '${resourcePath}' must equal endpointPath ` +\n `'${options.endpointPath}'; the canonical resource URI ` +\n `'${this.config.resource}' and the bound route are the same endpoint.`,\n );\n }\n this.toolProfiles = this.config.toolProfiles;\n this.icons = this.config.icons;\n this.registry = new McpToolRegistry(\n options.bindings,\n options.toolCatalogs,\n this.config.authorizationService,\n );\n this.revision = this.calculateRegistryRevision(this.registry);\n this.handler = this.createHandler(options, 'auto');\n this.streamingHandler = this.createHandler(options, 'sse');\n this.nodeHandler = toNodeHandler(this.handler, {\n onerror: (error: Error) => log.error('MCP Node transport failed', error),\n });\n this.streamingNodeHandler = toNodeHandler(this.streamingHandler, {\n onerror: (error: Error) => log.error('MCP streaming Node transport failed', error),\n });\n app.post(\n options.endpointPath,\n json(),\n async (req: Request, res: Response): Promise<void> =>\n this.handleHttp(req, res, options),\n // Express routes body-parser failures (bad JSON, body too large) to an error handler.\n (bodyError: Error, req: Request, res: Response, _next: NextFunction): void => {\n void this.handleBodyFailure(bodyError, req, res);\n },\n );\n // Registered AFTER the POST route so POST still wins. NEITHER era served here has a session\n // GET: 2026-07-28 has none at all (`subscriptions/listen` is a POST method), and the legacy\n // leg is the SDK's STATELESS fallback, which answers the 2025 session GET/DELETE with the\n // same 405. So every other method is a method error — and a discovery probe gets that\n // instead of Express' bare 404.\n app.all(options.endpointPath, (_req: Request, res: Response): void => {\n res.setHeader('Allow', 'POST');\n res.status(405).json(new McpMethodNotAllowedBody());\n });\n }\n\n protectedResourceMetadata(): McpProtectedResourceMetadata {\n return this.config.protectedResourceMetadata();\n }\n\n /** Gracefully closes active listen/request streams; clients must reconnect and refresh lists. */\n async close(): Promise<void> {\n await Promise.all([this.handler?.close(), this.streamingHandler?.close()]);\n }\n\n /** Level-triggered invalidation; the authoritative list is always fetched again by clients. */\n toolsChanged(): void {\n this.handler?.notify.toolsChanged();\n }\n\n get registryRevision(): string | undefined {\n return this.revision;\n }\n\n private createHandler(options: McpBindOptions, responseMode: 'auto' | 'sse'): McpHttpHandler {\n return createMcpHandler(\n (context: McpRequestContext) => this.buildSdkServer(context, options),\n {\n // Both eras, one factory: `stateless` serves 2025-era traffic through a fresh\n // instance of the SAME McpServerFactory, so the two eras can never drift apart.\n legacy: 'stateless',\n responseMode,\n bus: options.deployment.bus,\n maxSubscriptions: options.maxSubscriptions,\n keepAliveMs: options.keepAliveMs,\n onerror: (error: Error) => log.warn('MCP protocol request rejected', error),\n },\n );\n }\n\n /** Each HTTP entry uses the same full-request scope and ingress translation seam. */\n private async handleHttp(req: Request, res: Response, options: McpBindOptions): Promise<void> {\n res.setHeader('X-Accel-Buffering', 'no');\n await this.ingress(req, res, 'serve', () => this.serveExpress(req, res, options));\n }\n\n private async handleBodyFailure(cause: Error, req: Request, res: Response): Promise<void> {\n await this.ingress(req, res, 'body', () => this.rejectBody(cause));\n }\n\n private async ingress(\n req: Request,\n res: Response,\n step: string,\n work: () => Promise<void>,\n ): Promise<void> {\n await RequestContext.run(async () => {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- HTTP response-owning ingress boundary, including request publication and correlation failures\n try {\n new RequestContextHeaders().fillFromRequest(this.toHttpRequest(req));\n McpCorrelation.stamp(this.correlationOf(req));\n await this.logEdge(step, work);\n } catch (err: unknown) {\n const error = toError(err);\n this.writeBoundaryError(res, error);\n }\n });\n }\n\n /** A body express could not parse is a caller input error, reported through the same edge. */\n private async rejectBody(cause: Error): Promise<never> {\n throw new ApiBadRequestError(\n `MCP request body rejected: ${cause.message}`,\n undefined,\n undefined,\n cause,\n );\n }\n\n /**\n * The pre-SDK boundary owns the socket, so it produces a VALUE and writes it through the SAME\n * express writer `ExpressWrapper` uses. A failure after headers were sent can only end the\n * stream.\n */\n private writeBoundaryError(res: Response, error: Error): void {\n if (res.headersSent) {\n res.end();\n return;\n }\n this.responseWriter.write(res, this.translator.toBearerBoundaryResponse(error));\n }\n\n /** Run one un-filtered edge step under `LogApiCall`, so its failure gets exactly one log line. */\n private async logEdge<R>(step: string, work: () => Promise<R>): Promise<R> {\n return this.logApiCall.execute(\n new ApiMethodInfo('server', 'McpEndpoint', step, McpProtocol),\n new McpEdgeRequest(step),\n work,\n );\n }\n\n private async serveExpress(\n req: Request,\n res: Response,\n options: McpBindOptions,\n ): Promise<void> {\n const origin = req.header('origin');\n if (origin && !options.allowedOrigins.includes(origin)) {\n throw new ApiForbiddenError(`MCP request Origin '${origin}' is not allowed.`);\n }\n const authentication = await this.authenticate(req);\n const request = req as AuthenticatedExpressRequest;\n request.auth = this.authInfo(authentication);\n const serve = this.hasProgressToken(req.body)\n ? this.streamingNodeHandler\n : this.nodeHandler;\n if (!serve) throw new ApiImplementationError('MCP Node handlers are not initialized.');\n await serve(request, res, req.body);\n }\n\n /** Verifies the external bearer once for this POST. Handlers never re-verify it. */\n private async authenticate(req: Request): Promise<McpPostAuthentication> {\n const match = req.header('authorization')?.match(/^Bearer ([^\\s]+)$/i);\n const token = match?.[1];\n if (!token) throw new ApiUnauthorizedError('MCP request has no bearer access token.');\n const credential = await this.config.accessTokenAuthority.verifyAccessToken(\n token,\n this.config.resource,\n );\n this.validateCredential(credential);\n this.callerContext.publish(credential.caller);\n RequestContext.putTrusted(WebpiecesCoreHeaders.SURFACE, 'llm');\n this.callerContext.reconcileWireTrust(false);\n const tools = await AuthorizedMcpTools.create(\n this.requireRegistry(),\n this.config.authorizationService,\n this.toolProfiles,\n );\n return new McpPostAuthentication(token, credential, this.disconnectSignal(req), tools);\n }\n\n private disconnectSignal(req: Request): AbortSignal {\n const disconnected = new AbortController();\n const res = req.res;\n const cancel = (): void => disconnected.abort();\n req.once('aborted', cancel);\n req.socket.once('close', cancel);\n res?.once('close', cancel);\n res?.once('finish', (): void => {\n req.off('aborted', cancel);\n req.socket.off('close', cancel);\n res.off('close', cancel);\n });\n return disconnected.signal;\n }\n\n private buildSdkServer(context: McpRequestContext, options: McpBindOptions): McpServer {\n // The era is the SDK's to decide and BOTH are served; what is not negotiable is that the\n // request came through `bind`'s HTTP boundary, which is where the external bearer is\n // verified. A factory call without it is a wiring mistake, never a client's doing.\n const authentication = context.authInfo?.extra?.['webpiecesAuthentication'];\n if (!(authentication instanceof McpPostAuthentication)) {\n throw new ApiImplementationError(\n 'WpMcpServer serves only MCP requests authenticated by its bind boundary.',\n );\n }\n const server = new WpSdkMcpServer(\n {\n name: this.config.name,\n title: this.config.title,\n description: this.config.description,\n websiteUrl: this.config.websiteUrl,\n version: `${this.config.version}+${this.revision}`,\n ...(this.icons === undefined ? {} : { icons: [...this.icons] }),\n },\n {\n capabilities: { tools: { listChanged: true } },\n cacheHints: {\n 'tools/list': { ttlMs: options.deployment.ttlMs, cacheScope: 'private' },\n 'server/discover': { ttlMs: options.deployment.ttlMs, cacheScope: 'private' },\n },\n },\n authentication.tools,\n );\n server.server.removeRequestHandler('tools/list');\n server.server.removeRequestHandler('tools/call');\n server.server.setRequestHandler(\n 'tools/list',\n async (_request: object): Promise<ListToolsResult> =>\n this.sdkBoundary(new McpSdkOperation('tools/list'), () =>\n this.logEdge('tools/list', async () => this.listTools(authentication.tools)),\n ) as Promise<ListToolsResult>,\n );\n server.server.setRequestHandler(\n 'tools/call',\n async (request: CallToolRequest, sdkContext: ServerContext): Promise<CallToolResult> =>\n this.handleCallTool(server, request, authentication, sdkContext),\n );\n return server;\n }\n\n /** ONE SDK callback catch implementation; the SDK intercepts foreign throws itself. */\n private async sdkBoundary<R>(\n operation: McpSdkOperation,\n work: () => Promise<R>,\n ): Promise<R | CallToolResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- shared SDK response boundary, preserving protocol versus tool envelopes\n try {\n return await work();\n } catch (err: unknown) {\n const error = toError(err);\n if (error instanceof McpToolDeniedError)\n throw this.translator.unknownTool(error.toolName);\n if (!operation.toolStage && error instanceof ProtocolError) throw error;\n this.logImplementationFailure(operation.name, error);\n if (operation.toolStage) return this.translator.toToolCallResult(error);\n this.translator.toListError(error);\n }\n }\n\n private listTools(view: AuthorizedMcpTools): ListToolsResult {\n const tools: Tool[] = view.tools.map((tool) => this.toolDefinition(tool));\n return { tools };\n }\n\n private toolDefinition(tool: RegisteredMcpTool): Tool {\n return {\n name: tool.name,\n title: tool.title,\n description: tool.description,\n inputSchema: tool.inputSchema as Tool['inputSchema'],\n outputSchema: tool.outputSchema as Tool['outputSchema'],\n annotations: new McpPublishedToolAnnotations(tool),\n _meta: { webpiecesRegistryRevision: this.revision },\n };\n }\n\n /**\n * SDK tool callback: an unknown or hidden tool is a JSON-RPC -32602; every failure after the tool is found\n * is an `isError: true` result, identically for local and remote bindings.\n */\n private async handleCallTool(\n server: WpSdkMcpServer,\n request: CallToolRequest,\n authentication: McpPostAuthentication,\n sdkContext: ServerContext,\n ): Promise<CallToolResult> {\n const name = request.params.name;\n const operation = new McpSdkOperation(`tools/call ${name}`);\n return this.sdkBoundary(operation, async () => {\n McpCorrelation.stamp(new McpCorrelation(sdkContext.mcpReq.id, McpProtocol, name));\n const tool = authentication.tools.find(name);\n if (!tool) throw this.translator.unknownTool(name);\n McpCorrelation.stamp(\n new McpCorrelation(sdkContext.mcpReq.id, tool.apiClass, name, tool.operation),\n );\n operation.toolStage = true;\n const result = await this.callTool(tool, request, authentication, sdkContext);\n result._meta = this.translator.resultMeta(McpCorrelation.requestId());\n return server.server.projectCallToolResult(\n result,\n tool.outputSchema as Record<string, DtoValue>,\n );\n }) as Promise<CallToolResult>;\n }\n\n /**\n * ONE `log.error` line, with the stack and the requestId, for a failure that is THIS server's bug\n * — the `implementation` kind, which the translator reduces to \"Internal Error\" and a requestId\n * for the caller (#1055).\n *\n * `LogApiCall` does not cover this. An MCP output-schema violation is raised AFTER the controller\n * returned, so the only `LogApiCall` line for that call reads `resp-SUCCESS`; before this line\n * existed, the requestId support was handed led to a log with no error in it. Where a\n * `[API-*-resp-FAIL]` line does exist it carries the error's message, not its stack. So this line\n * is not the bare duplicate `ApiErrorBoundary` stopped writing: it is the one that says WHERE.\n *\n * Every other kind (bad-request, end-user, dependency, ...) is a caller's or a downstream's\n * failure, published to the caller with its own text, and `LogApiCall` already records it.\n */\n private logImplementationFailure(entryPoint: string, error: Error): void {\n if (this.boundary.encode(error).kind !== 'implementation') return;\n log.error(\n `MCP ${entryPoint} failed with an implementation error requestId=${McpCorrelation.requestId()}`,\n error,\n );\n }\n\n /** Everything a tool call does. No catch in here: failures propagate to handleCallTool. */\n private async callTool(\n tool: RegisteredMcpTool,\n request: CallToolRequest,\n authentication: McpPostAuthentication,\n sdkContext: ServerContext,\n ): Promise<CallToolResult> {\n const credential = authentication.credential;\n const invocation = new McpInvocationContext(\n sdkContext.mcpReq.id,\n tool.name,\n credential.subject,\n credential.principalRoles,\n AbortSignal.any([sdkContext.mcpReq.signal, authentication.disconnectSignal]),\n this.progressReporter(sdkContext),\n );\n const args = (request.params.arguments ?? {}) as DtoValue;\n const value = await this.dispatcher.call(\n tool,\n args,\n credential,\n invocation,\n this.config.authorizationService,\n );\n const outputFailure = this.outputSchemas.validate(tool.outputSchema, value);\n if (outputFailure) {\n throw new ApiImplementationError(\n `MCP output schema violation for ${tool.apiClass.name}.${tool.methodName}: ${outputFailure.message}`,\n );\n }\n const structured = this.record(value);\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n };\n }\n\n private validateCredential(credential: VerifiedMcpCredential): void {\n const now = Math.floor(Date.now() / 1000);\n const reject = (reason: string): never => {\n throw new ApiUnauthorizedError(`MCP access token rejected: ${reason}`);\n };\n if (credential.subject.trim() === '') reject('no subject');\n const stamps = [\n credential.issuedAtEpochSeconds,\n credential.expiresAtEpochSeconds,\n credential.accountValidatedAtEpochSeconds,\n ];\n if (!stamps.every(Number.isFinite)) reject('security timestamps must be finite');\n if (credential.resource !== this.config.resource) reject('resource mismatch');\n if (!this.config.authorizationServers.includes(credential.issuer)) {\n reject('issuer is not trusted');\n }\n if (credential.issuedAtEpochSeconds > now || credential.expiresAtEpochSeconds <= now) {\n reject('outside its valid time window');\n }\n const lifetime = credential.expiresAtEpochSeconds - credential.issuedAtEpochSeconds;\n if (lifetime > MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS) reject('lifetime exceeds 30 days');\n for (const scope of this.config.requiredScopes) {\n if (!credential.scopes.includes(scope)) reject(`missing required scope '${scope}'`);\n }\n const validatedAge = now - credential.accountValidatedAtEpochSeconds;\n if (\n credential.accountValidatedAtEpochSeconds > now ||\n validatedAge > this.config.maxAccountValidationAgeSeconds\n ) {\n reject('account authorization state is not fresh enough for dispatch');\n }\n }\n\n private authInfo(authentication: McpPostAuthentication): AuthInfo {\n const credential = authentication.credential;\n return {\n token: authentication.accessToken,\n clientId: credential.subject,\n scopes: [...credential.scopes],\n expiresAt: credential.expiresAtEpochSeconds,\n resource: new URL(credential.resource),\n extra: { webpiecesAuthentication: authentication },\n };\n }\n\n private progressReporter(context: ServerContext): McpProgressReporter | undefined {\n const token = context.mcpReq._meta?.progressToken;\n if (token === undefined) return undefined;\n return async (progress: number, total?: number, message?: string): Promise<void> => {\n await context.mcpReq.notify({\n method: 'notifications/progress',\n params: this.progressParams(token, progress, total, message),\n });\n };\n }\n\n private progressParams(\n progressToken: ProgressToken,\n progress: number,\n total?: number,\n message?: string,\n ): Record<string, DtoValue> {\n const params: Record<string, DtoValue> = { progressToken, progress };\n if (total !== undefined) params['total'] = total;\n if (message !== undefined) params['message'] = message;\n return params;\n }\n\n /** What the raw POST body tells us before the SDK has parsed anything: the id, and the tool. */\n private correlationOf(req: Request): McpCorrelation {\n const body = this.bodyObject(req.body);\n const id = body?.['id'];\n const params = this.bodyObject(body?.['params']);\n const name = params?.['name'];\n return new McpCorrelation(\n typeof id === 'string' || typeof id === 'number' ? id : null,\n McpProtocol,\n typeof name === 'string' ? name : undefined,\n );\n }\n\n private challenge(): string {\n return `Bearer resource_metadata=\"${this.config.resourceMetadataUrl}\"`;\n }\n\n private bodyObject(value: DtoValue | undefined): Record<string, DtoValue> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n return value as Record<string, DtoValue>;\n }\n\n private hasProgressToken(body: DtoValue): boolean {\n const params = this.bodyObject(this.bodyObject(body)?.['params']);\n return this.bodyObject(params?.['_meta'])?.['progressToken'] !== undefined;\n }\n\n private toHttpRequest(req: Request): HttpRequest {\n const headers = new Map<string, string[]>();\n for (const [name, value] of Object.entries(req.headers)) {\n if (typeof value === 'string') headers.set(name, [value]);\n else if (Array.isArray(value)) headers.set(name, value);\n }\n return new HttpRequest(req.method, req.originalUrl || req.path, headers);\n }\n\n private calculateRegistryRevision(registry: McpToolRegistry): string {\n const surface = registry.tools.map((tool: RegisteredMcpTool) => [\n tool.name,\n tool.title,\n tool.description,\n tool.inputSchema,\n tool.outputSchema,\n tool.annotations,\n tool.profiles,\n ]);\n return createHash('sha256')\n .update(JSON.stringify([this.toolProfiles, surface]))\n .digest('hex')\n .slice(0, 12);\n }\n\n private requireRegistry(): McpToolRegistry {\n if (!this.registry) throw new Error('Call WpMcpServer.bind(...) before serving requests.');\n return this.registry;\n }\n\n private record(value: DtoValue): Record<string, DtoValue> {\n const jsonValue = JSON.stringify(value);\n if (jsonValue === undefined) {\n throw new ApiImplementationError('MCP structured content is not JSON serializable.');\n }\n const parsed = JSON.parse(jsonValue) as DtoValue;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { value: parsed };\n }\n return parsed as Record<string, DtoValue>;\n }\n}\n"]}
|
|
@@ -11,7 +11,7 @@ const core_util_3 = require("@webpieces/core-util");
|
|
|
11
11
|
const core_context_1 = require("@webpieces/core-context");
|
|
12
12
|
const http_routing_1 = require("@webpieces/http-routing");
|
|
13
13
|
const McpAuth_1 = require("../McpAuth");
|
|
14
|
-
const
|
|
14
|
+
const core_util_4 = require("@webpieces/core-util");
|
|
15
15
|
const McpToolCatalog_1 = require("../McpToolCatalog");
|
|
16
16
|
exports.USER_ID = core_util_3.ContextKey.trusted('mcpSpecUserId', 'proven by a credential verifier');
|
|
17
17
|
exports.ENDPOINT_PATH = '/app-owned/mcp';
|
|
@@ -167,7 +167,7 @@ let SearchController = class SearchController extends SearchApi {
|
|
|
167
167
|
if (request.query === 'exhausted') {
|
|
168
168
|
throw new core_util_3.ApiRetriesExhaustedError(4, new core_util_3.ApiUnavailableError('private retries'));
|
|
169
169
|
}
|
|
170
|
-
const invocation = core_context_1.RequestContext.getTrusted(
|
|
170
|
+
const invocation = core_context_1.RequestContext.getTrusted(core_util_4.MCP_INVOCATION_CONTEXT);
|
|
171
171
|
if (request.query === 'progress') {
|
|
172
172
|
await invocation?.reportProgress?.(1, 2, 'halfway');
|
|
173
173
|
}
|
|
@@ -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, oidcSameProject } 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 /**\n * Search records owned by the authenticated user.\n *\n * @summary Search accounts\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /**\n * Administrative search.\n *\n * @summary Admin search\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('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 /**\n * Search a remote binding.\n *\n * @summary Remote search\n */\n\n @WpAuth([oidcSameProject()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('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"]}
|
|
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, oidcSameProject } 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 '@webpieces/core-util';\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 /**\n * Search records owned by the authenticated user.\n *\n * @summary Search accounts\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /**\n * Administrative search.\n *\n * @summary Admin search\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('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 /**\n * Search a remote binding.\n *\n * @summary Remote search\n */\n\n @WpAuth([oidcSameProject()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('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"]}
|
package/src/index.d.ts
CHANGED
|
@@ -5,8 +5,6 @@ export { McpIcon } from './McpIcon';
|
|
|
5
5
|
export { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';
|
|
6
6
|
export { McpApiBinding } from './McpApiBinding';
|
|
7
7
|
export type { McpBindingTopology } from './McpApiBinding';
|
|
8
|
-
export { MCP_INVOCATION_CONTEXT, McpInvocationContext } from './McpInvocationContext';
|
|
9
|
-
export type { McpProgressReporter } from './McpInvocationContext';
|
|
10
8
|
export { McpBindOptions } from './McpBindOptions';
|
|
11
9
|
export { McpToolCatalog } from './McpToolCatalog';
|
|
12
10
|
export { McpDeployment } from './McpDeployment';
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.McpRegistry = exports.WpMcpErrorTranslator = exports.ModelVisibleToolError = exports.McpHttpErrorDetail = exports.McpHttpErrorBody = exports.McpErrorData = exports.McpDefaultToolCallRenderer = exports.McpCorrelation = exports.MCP_REQUEST_ID_META_KEY = exports.McpProtocol = exports.WpMcpServer = exports.McpApiDispatcher = exports.McpDeployment = exports.McpToolCatalog = exports.McpBindOptions = exports.
|
|
3
|
+
exports.McpRegistry = exports.WpMcpErrorTranslator = exports.ModelVisibleToolError = exports.McpHttpErrorDetail = exports.McpHttpErrorBody = exports.McpErrorData = exports.McpDefaultToolCallRenderer = exports.McpCorrelation = exports.MCP_REQUEST_ID_META_KEY = exports.McpProtocol = exports.WpMcpServer = exports.McpApiDispatcher = exports.McpDeployment = exports.McpToolCatalog = exports.McpBindOptions = exports.McpApiBinding = exports.RegisteredMcpTool = exports.McpToolRegistry = exports.McpIcon = exports.WpMcpServerConfig = exports.VerifiedMcpCredential = exports.McpProtectedResourceMetadata = exports.MintedMcpAccessToken = exports.MAX_MCP_SERVER_TITLE_LENGTH = exports.MAX_MCP_SERVER_DESCRIPTION_LENGTH = exports.MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS = exports.MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS = void 0;
|
|
4
4
|
var McpAuth_1 = require("./McpAuth");
|
|
5
5
|
Object.defineProperty(exports, "MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS", { enumerable: true, get: function () { return McpAuth_1.MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS; } });
|
|
6
6
|
Object.defineProperty(exports, "MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS", { enumerable: true, get: function () { return McpAuth_1.MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS; } });
|
|
@@ -17,9 +17,6 @@ Object.defineProperty(exports, "McpToolRegistry", { enumerable: true, get: funct
|
|
|
17
17
|
Object.defineProperty(exports, "RegisteredMcpTool", { enumerable: true, get: function () { return McpToolRegistry_1.RegisteredMcpTool; } });
|
|
18
18
|
var McpApiBinding_1 = require("./McpApiBinding");
|
|
19
19
|
Object.defineProperty(exports, "McpApiBinding", { enumerable: true, get: function () { return McpApiBinding_1.McpApiBinding; } });
|
|
20
|
-
var McpInvocationContext_1 = require("./McpInvocationContext");
|
|
21
|
-
Object.defineProperty(exports, "MCP_INVOCATION_CONTEXT", { enumerable: true, get: function () { return McpInvocationContext_1.MCP_INVOCATION_CONTEXT; } });
|
|
22
|
-
Object.defineProperty(exports, "McpInvocationContext", { enumerable: true, get: function () { return McpInvocationContext_1.McpInvocationContext; } });
|
|
23
20
|
var McpBindOptions_1 = require("./McpBindOptions");
|
|
24
21
|
Object.defineProperty(exports, "McpBindOptions", { enumerable: true, get: function () { return McpBindOptions_1.McpBindOptions; } });
|
|
25
22
|
var McpToolCatalog_1 = require("./McpToolCatalog");
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/index.ts"],"names":[],"mappings":";;;AAAA,qCASmB;AARf,gIAAA,qCAAqC,OAAA;AACrC,iIAAA,sCAAsC,OAAA;AACtC,4HAAA,iCAAiC,OAAA;AACjC,sHAAA,2BAA2B,OAAA;AAC3B,+GAAA,oBAAoB,OAAA;AACpB,uHAAA,4BAA4B,OAAA;AAC5B,gHAAA,qBAAqB,OAAA;AACrB,4GAAA,iBAAiB,OAAA;AAIrB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,qDAAuE;AAA9D,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/index.ts"],"names":[],"mappings":";;;AAAA,qCASmB;AARf,gIAAA,qCAAqC,OAAA;AACrC,iIAAA,sCAAsC,OAAA;AACtC,4HAAA,iCAAiC,OAAA;AACjC,sHAAA,2BAA2B,OAAA;AAC3B,+GAAA,oBAAoB,OAAA;AACpB,uHAAA,4BAA4B,OAAA;AAC5B,gHAAA,qBAAqB,OAAA;AACrB,4GAAA,iBAAiB,OAAA;AAIrB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,qDAAuE;AAA9D,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA;AACvB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AAEtB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AACpB,+DAQgC;AAP5B,+HAAA,uBAAuB,OAAA;AACvB,sHAAA,cAAc,OAAA;AACd,kIAAA,0BAA0B,OAAA;AAC1B,oHAAA,YAAY,OAAA;AACZ,wHAAA,gBAAgB,OAAA;AAChB,0HAAA,kBAAkB,OAAA;AAClB,6HAAA,qBAAqB,OAAA;AAEzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,0FAA0F;AAC1F,6CAA4C;AAAnC,0GAAA,WAAW,OAAA","sourcesContent":["export {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS,\n MAX_MCP_SERVER_DESCRIPTION_LENGTH,\n MAX_MCP_SERVER_TITLE_LENGTH,\n MintedMcpAccessToken,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nexport type { McpAccessTokenAuthority } from './McpAuth';\nexport type { Icon } from '@modelcontextprotocol/server';\nexport { McpIcon } from './McpIcon';\nexport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nexport { McpApiBinding } from './McpApiBinding';\nexport type { McpBindingTopology } from './McpApiBinding';\nexport { McpBindOptions } from './McpBindOptions';\nexport { McpToolCatalog } from './McpToolCatalog';\nexport { McpDeployment } from './McpDeployment';\nexport type { McpDeploymentMode } from './McpDeployment';\nexport { McpApiDispatcher } from './McpApiDispatcher';\nexport { WpMcpServer } from './WpMcpServer';\nexport { McpProtocol } from './McpProtocol';\nexport {\n MCP_REQUEST_ID_META_KEY,\n McpCorrelation,\n McpDefaultToolCallRenderer,\n McpErrorData,\n McpHttpErrorBody,\n McpHttpErrorDetail,\n ModelVisibleToolError,\n} from './McpToolCallRendering';\nexport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\nexport type { McpErrorTranslator } from './McpToolCallRendering';\n// The process-global home of the ONE MCP translator, mirroring ApiRegistry / IpcRegistry.\nexport { McpRegistry } from './McpRegistry';\n"]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ContextKey } from '@webpieces/core-util';
|
|
2
|
-
export type McpProgressReporter = (progress: number, total?: number, message?: string) => Promise<void>;
|
|
3
|
-
/** Trusted, context-local MCP facts available to a bound application endpoint. */
|
|
4
|
-
export declare class McpInvocationContext {
|
|
5
|
-
readonly jsonRpcId: string | number;
|
|
6
|
-
readonly toolName: string;
|
|
7
|
-
readonly subject: string;
|
|
8
|
-
readonly roles: readonly string[];
|
|
9
|
-
readonly signal: AbortSignal;
|
|
10
|
-
readonly reportProgress?: McpProgressReporter | undefined;
|
|
11
|
-
constructor(jsonRpcId: string | number, toolName: string, subject: string, roles: readonly string[], signal: AbortSignal, reportProgress?: McpProgressReporter | undefined);
|
|
12
|
-
}
|
|
13
|
-
/** Context-only: it has no HTTP header and cannot be asserted by a remote caller. */
|
|
14
|
-
export declare const MCP_INVOCATION_CONTEXT: ContextKey<McpInvocationContext, "trusted">;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MCP_INVOCATION_CONTEXT = exports.McpInvocationContext = void 0;
|
|
4
|
-
const core_util_1 = require("@webpieces/core-util");
|
|
5
|
-
/** Trusted, context-local MCP facts available to a bound application endpoint. */
|
|
6
|
-
class McpInvocationContext {
|
|
7
|
-
jsonRpcId;
|
|
8
|
-
toolName;
|
|
9
|
-
subject;
|
|
10
|
-
roles;
|
|
11
|
-
signal;
|
|
12
|
-
reportProgress;
|
|
13
|
-
constructor(jsonRpcId, toolName, subject, roles, signal, reportProgress) {
|
|
14
|
-
this.jsonRpcId = jsonRpcId;
|
|
15
|
-
this.toolName = toolName;
|
|
16
|
-
this.subject = subject;
|
|
17
|
-
this.roles = roles;
|
|
18
|
-
this.signal = signal;
|
|
19
|
-
this.reportProgress = reportProgress;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
exports.McpInvocationContext = McpInvocationContext;
|
|
23
|
-
/** Context-only: it has no HTTP header and cannot be asserted by a remote caller. */
|
|
24
|
-
exports.MCP_INVOCATION_CONTEXT = core_util_1.ContextKey.trusted('mcpInvocationContext', 'constructed from the official MCP SDK request and the verified MCP credential', undefined, false, false);
|
|
25
|
-
//# sourceMappingURL=McpInvocationContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"McpInvocationContext.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpInvocationContext.ts"],"names":[],"mappings":";;;AAAA,oDAAkD;AAQlD,kFAAkF;AAClF,MAAa,oBAAoB;IAET;IACA;IACA;IACA;IACA;IACA;IANpB,YACoB,SAA0B,EAC1B,QAAgB,EAChB,OAAe,EACf,KAAwB,EACxB,MAAmB,EACnB,cAAoC;QALpC,cAAS,GAAT,SAAS,CAAiB;QAC1B,aAAQ,GAAR,QAAQ,CAAQ;QAChB,YAAO,GAAP,OAAO,CAAQ;QACf,UAAK,GAAL,KAAK,CAAmB;QACxB,WAAM,GAAN,MAAM,CAAa;QACnB,mBAAc,GAAd,cAAc,CAAsB;IACrD,CAAC;CACP;AATD,oDASC;AAED,qFAAqF;AACxE,QAAA,sBAAsB,GAAG,sBAAU,CAAC,OAAO,CACpD,sBAAsB,EACtB,+EAA+E,EAC/E,SAAS,EACT,KAAK,EACL,KAAK,CACR,CAAC","sourcesContent":["import { ContextKey } from '@webpieces/core-util';\n\nexport type McpProgressReporter = (\n progress: number,\n total?: number,\n message?: string,\n) => Promise<void>;\n\n/** Trusted, context-local MCP facts available to a bound application endpoint. */\nexport class McpInvocationContext {\n constructor(\n public readonly jsonRpcId: string | number,\n public readonly toolName: string,\n public readonly subject: string,\n public readonly roles: readonly string[],\n public readonly signal: AbortSignal,\n public readonly reportProgress?: McpProgressReporter,\n ) {}\n}\n\n/** Context-only: it has no HTTP header and cannot be asserted by a remote caller. */\nexport const MCP_INVOCATION_CONTEXT = ContextKey.trusted<McpInvocationContext>(\n 'mcpInvocationContext',\n 'constructed from the official MCP SDK request and the verified MCP credential',\n undefined,\n false,\n false,\n);\n"]}
|