@webpieces/mcp-server 0.4.990 → 0.4.991

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.
Files changed (48) hide show
  1. package/README.md +199 -42
  2. package/package.json +7 -6
  3. package/src/McpApiDispatcher.d.ts +6 -3
  4. package/src/McpApiDispatcher.js +6 -2
  5. package/src/McpApiDispatcher.js.map +1 -1
  6. package/src/McpAuth.d.ts +115 -56
  7. package/src/McpAuth.js +180 -111
  8. package/src/McpAuth.js.map +1 -1
  9. package/src/McpAuthorityCompileAssertions.d.ts +12 -2
  10. package/src/McpAuthorityCompileAssertions.js +32 -4
  11. package/src/McpAuthorityCompileAssertions.js.map +1 -1
  12. package/src/McpBindOptions.d.ts +5 -20
  13. package/src/McpBindOptions.js +5 -15
  14. package/src/McpBindOptions.js.map +1 -1
  15. package/src/McpClientSet.d.ts +35 -0
  16. package/src/McpClientSet.js +86 -0
  17. package/src/McpClientSet.js.map +1 -0
  18. package/src/McpDoorAuth.d.ts +117 -0
  19. package/src/McpDoorAuth.js +455 -0
  20. package/src/McpDoorAuth.js.map +1 -0
  21. package/src/McpToolCallRendering.d.ts +5 -4
  22. package/src/McpToolCallRendering.js.map +1 -1
  23. package/src/McpToolCatalog.d.ts +1 -1
  24. package/src/McpToolCatalog.js +1 -1
  25. package/src/McpToolCatalog.js.map +1 -1
  26. package/src/McpToolRegistry.js +8 -2
  27. package/src/McpToolRegistry.js.map +1 -1
  28. package/src/McpToolset.d.ts +115 -0
  29. package/src/McpToolset.js +323 -0
  30. package/src/McpToolset.js.map +1 -0
  31. package/src/WpMcpErrorTranslator.d.ts +5 -7
  32. package/src/WpMcpErrorTranslator.js +7 -13
  33. package/src/WpMcpErrorTranslator.js.map +1 -1
  34. package/src/WpMcpInMemory.d.ts +30 -0
  35. package/src/WpMcpInMemory.js +97 -0
  36. package/src/WpMcpInMemory.js.map +1 -0
  37. package/src/WpMcpRemote.d.ts +23 -0
  38. package/src/WpMcpRemote.js +89 -0
  39. package/src/WpMcpRemote.js.map +1 -0
  40. package/src/WpMcpServer.d.ts +45 -76
  41. package/src/WpMcpServer.js +101 -327
  42. package/src/WpMcpServer.js.map +1 -1
  43. package/src/__tests__/McpTransportFixtures.d.ts +107 -0
  44. package/src/__tests__/McpTransportFixtures.js +266 -0
  45. package/src/__tests__/McpTransportFixtures.js.map +1 -0
  46. package/src/index.d.ts +9 -2
  47. package/src/index.js +17 -1
  48. package/src/index.js.map +1 -1
@@ -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 '@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"]}
1
+ {"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":";;;AAAA,yDAOsC;AACtC,qDAAkF;AAClF,qCAAyE;AACzE,oDAQ8B;AAC9B,0DAA6F;AAC7F,wDAA+D;AAC/D,0DAAqE;AACrE,uCAKmB;AAEnB,+CAAkF;AAClF,iEAAwD;AACxD,+CAA4C;AAE5C,6CAA0D;AAC1D,iEAA8D;AAE9D,MAAM,GAAG,GAAG,sBAAU,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AAIhD,yFAAyF;AACzF,MAAM,uBAAuB;IAChB,KAAK,GAAG,oBAAoB,CAAC;CACzC;AAED,4EAA4E;AAC5E,MAAM,YAAY;IACd,kFAAkF;IAClF,SAAS,GAAG,KAAK,CAAC;CACrB;AAED,2FAA2F;AAC3F,MAAM,qBAAqB;IAEH;IACA;IAFpB,YACoB,IAAiB,EACjB,OAAuB;QADvB,SAAI,GAAJ,IAAI,CAAa;QACjB,YAAO,GAAP,OAAO,CAAgB;IACxC,CAAC;CACP;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,WAAW;IAYC;IACA;IAZJ,aAAa,GAAG,IAAI,yCAA0B,EAAE,CAAC;IACjD,cAAc,GAAG,IAAI,mCAAqB,EAAE,CAAC;IAC7C,UAAU,GAAyB,IAAI,2CAAoB,EAAE,CAAC;IACvE,IAAI,CAAwB;IAC5B,OAAO,CAAkB;IACzB,gBAAgB,CAAkB;IAClC,WAAW,CAAyB;IACpC,oBAAoB,CAAyB;IAC7C,KAAK,CAAmB;IAEhC,YACqB,MAAyB,EACzB,OAAmB;QADnB,WAAM,GAAN,MAAM,CAAmB;QACzB,YAAO,GAAP,OAAO,CAAY;IACrC,CAAC;IAEJ;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,GAAY,EAAE,OAAuB;QACtC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACX,iFAAiF;gBAC7E,uDAAuD,CAC9D,CAAC;QACN,CAAC;QACD,mFAAmF;QACnF,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;QAC5D,IAAI,YAAY,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACX,sBAAsB,YAAY,4BAA4B;gBAC1D,IAAI,OAAO,CAAC,YAAY,gCAAgC;gBACxD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,8CAA8C,CAC7E,CAAC;QACN,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,kCAAoB,CAAC,MAAM,CACnC,IAAI,CAAC,MAAM,CAAC,IAAI,EAChB,IAAI,CAAC,MAAM,CAAC,QAAQ,EACpB,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAClC,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACnD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,WAAW,GAAG,IAAA,oBAAa,EAAC,IAAI,CAAC,OAAO,EAAE;YAC3C,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC;SAC3E,CAAC,CAAC;QACH,IAAI,CAAC,oBAAoB,GAAG,IAAA,oBAAa,EAAC,IAAI,CAAC,gBAAgB,EAAE;YAC7D,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC;SACrF,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CACJ,OAAO,CAAC,YAAY,EACpB,IAAA,cAAI,GAAE,EACN,KAAK,EAAE,GAAY,EAAE,GAAa,EAAiB,EAAE,CACjD,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC;QACtC,sFAAsF;QACtF,CAAC,SAAgB,EAAE,GAAY,EAAE,GAAa,EAAE,KAAmB,EAAQ,EAAE;YACzE,KAAK,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC,CACJ,CAAC;QACF,4FAA4F;QAC5F,4FAA4F;QAC5F,0FAA0F;QAC1F,sFAAsF;QACtF,gCAAgC;QAChC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,IAAa,EAAE,GAAa,EAAQ,EAAE;YACjE,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,uBAAuB,EAAE,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACH,yBAAyB;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAC/B,CAAC,IAAiB,EAAwB,EAAE,CAAC,IAAI,YAAY,sBAAY,CAC5E,CAAC;QACF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CACX,sGAAsG;gBAClG,mDAAmD,CAC1D,CAAC;QACN,CAAC;QACD,OAAO,KAAK,CAAC,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,iGAAiG;IACjG,KAAK,CAAC,KAAK;QACP,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,+FAA+F;IAC/F,YAAY;QACR,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;IACxC,CAAC;IAED,IAAI,gBAAgB;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5D,CAAC;IAEO,aAAa,CAAC,OAAuB,EAAE,YAA4B;QACvE,OAAO,IAAA,yBAAgB,EACnB,CAAC,OAA0B,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,EACrE;YACI,8EAA8E;YAC9E,gFAAgF;YAChF,MAAM,EAAE,WAAW;YACnB,YAAY;YACZ,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG;YAC3B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;YAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,EAAE,KAAK,CAAC;SAC9E,CACJ,CAAC;IACN,CAAC;IAED,qFAAqF;IAC7E,KAAK,CAAC,UAAU,CAAC,GAAY,EAAE,GAAa,EAAE,OAAuB;QACzE,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAC7C,CAAC;IACN,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,KAAY,EAAE,GAAY,EAAE,GAAa;QACrE,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,YAAY,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3F,CAAC;IAEO,KAAK,CAAC,OAAO,CACjB,GAAY,EACZ,GAAa,EACb,IAAY,EACZ,IAAkB,EAClB,IAAyB;QAEzB,MAAM,6BAAc,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChC,+JAA+J;YAC/J,IAAI,CAAC;gBACD,IAAI,oCAAqB,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;gBACrE,qCAAc,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9C,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACvC,oLAAoL;YACxL,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,IAAA,mBAAO,EAAC,GAAG,CAAC,CAAC;gBAC3B,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YAC9C,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAED,8FAA8F;IACtF,KAAK,CAAC,UAAU,CAAC,KAAY;QACjC,MAAM,IAAI,8BAAkB,CACxB,8BAA8B,KAAK,CAAC,OAAO,EAAE,EAC7C,SAAS,EACT,SAAS,EACT,KAAK,CACR,CAAC;IACN,CAAC;IAED;;;;OAIG;IACK,kBAAkB,CAAC,GAAa,EAAE,KAAY,EAAE,IAAkB;QACtE,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YAClB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACX,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAC/F,CAAC;IAEO,KAAK,CAAC,YAAY,CACtB,GAAY,EACZ,GAAa,EACb,OAAuB,EACvB,IAAkB;QAElB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,6BAAiB,CAAC,uBAAuB,MAAM,mBAAmB,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,GAAkC,CAAC;QACnD,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;YACzC,CAAC,CAAC,IAAI,CAAC,oBAAoB;YAC3B,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QACvB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,kCAAsB,CAAC,wCAAwC,CAAC,CAAC;QACvF,MAAM,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,YAAY,CAAC,GAAY,EAAE,IAAkB;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,IAAI,4BAAc,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAClD,6BAAc,CAAC,UAAU,CAAC,gCAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/D,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3D,6BAAc,CAAC,UAAU,CAAC,gCAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QACnD,OAAO,IAAI,qBAAqB,CAC5B,IAAI,EACJ,IAAI,2BAAc,CAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CACxD,CAAC;IACN,CAAC;IAEO,gBAAgB,CAAC,GAAY;QACjC,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;QACpB,MAAM,MAAM,GAAG,GAAS,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAChD,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAS,EAAE;YAC3B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC3B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAChC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,OAAO,YAAY,CAAC,MAAM,CAAC;IAC/B,CAAC;IAEO,cAAc,CAAC,OAA0B,EAAE,OAAuB;QACtE,yFAAyF;QACzF,4FAA4F;QAC5F,uEAAuE;QACvE,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,yBAAyB,CAAC,CAAC;QAC5E,IAAI,CAAC,CAAC,cAAc,YAAY,qBAAqB,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,kCAAsB,CAC5B,0EAA0E,CAC7E,CAAC;QACN,CAAC;QACD,MAAM,IAAI,GAAuB,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAC/B;YACI,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACtB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACpC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;YAClC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;YAC1D,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;SAClE,EACD;YACI,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE;YAC9C,UAAU,EAAE;gBACR,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE;gBACxE,iBAAiB,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE;aAChF;SACJ,EACD,KAAK,IAA6B,EAAE,CAAC,cAAc,CAAC,OAAO,EAC3D,CAAC,IAAY,EAAiC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CACnE,CAAC;IACN,CAAC;IAEO,QAAQ,CAAC,cAAqC;QAClD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC;QACjC,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,OAAO;YACtB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACxB,SAAS,EAAE,IAAI,CAAC,qBAAqB;YACrC,QAAQ,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YACvC,KAAK,EAAE,EAAE,uBAAuB,EAAE,cAAc,EAAE;SACrD,CAAC;IACN,CAAC;IAED,gGAAgG;IACxF,aAAa,CAAC,GAAY;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC;QAC9B,OAAO,IAAI,qCAAc,CACrB,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAC5D,yBAAW,EACX,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAC9C,CAAC;IACN,CAAC;IAEO,SAAS;QACb,OAAO,6BAA6B,IAAI,CAAC,MAAM,CAAC,mBAAmB,GAAG,CAAC;IAC3E,CAAC;IAEO,UAAU,CAAC,KAA2B;QAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC1F,OAAO,KAAiC,CAAC;IAC7C,CAAC;IAEO,gBAAgB,CAAC,IAAc;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,SAAS,CAAC;IAC/E,CAAC;IAEO,aAAa,CAAC,GAAY;QAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC5C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;iBACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,IAAI,0BAAW,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7E,CAAC;IAEO,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACvF,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;CACJ;AA1UD,kCA0UC","sourcesContent":["import {\n AuthInfo,\n createMcpHandler,\n McpHttpHandler,\n McpRequestContext,\n McpServer,\n Icon,\n} from '@modelcontextprotocol/server';\nimport { NodeMcpRequestHandler, toNodeHandler } from '@modelcontextprotocol/node';\nimport { Express, json, NextFunction, Request, Response } from 'express';\nimport {\n ApiBadRequestError,\n ApiForbiddenError,\n ApiImplementationError,\n DtoValue,\n LogManager,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport { HttpRequest, RequestContext, RequestContextHeaders } from '@webpieces/core-context';\nimport { ExpressResponseWriter } from '@webpieces/http-server';\nimport { AuthenticatedCallerContext } from '@webpieces/http-routing';\nimport {\n McpHttpAuth,\n McpProtectedResourceMetadata,\n WpMcpServerConfig,\n McpOAuthMode,\n} from './McpAuth';\nimport { McpBindOptions } from './McpBindOptions';\nimport { McpDoorAuthenticator, McpDoorPass, McpDoorRequest } from './McpDoorAuth';\nimport { McpCorrelation } from './McpToolCallRendering';\nimport { McpProtocol } from './McpProtocol';\nimport { AuthorizedMcpTools, RegisteredMcpTool } from './McpToolRegistry';\nimport { McpToolRequest, McpToolset } from './McpToolset';\nimport { WpMcpErrorTranslator } from './WpMcpErrorTranslator';\n\nconst log = LogManager.getLogger('WpMcpServer');\n\ntype AuthenticatedExpressRequest = Request & { auth?: AuthInfo };\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/** Per-POST state the response-owning ingress needs after `work` failed. */\nclass McpPostState {\n /** Whether a 401 on this POST carries the `mcpOAuth(...)` discovery challenge. */\n challenge = false;\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 pass: McpDoorPass,\n public readonly request: McpToolRequest,\n ) {}\n}\n\n/**\n * The HTTP transport over an {@link McpToolset}: one server = one path = one toolset. `/mcp/user` and\n * `/mcp/admin` are two servers over two toolsets with two profile sets — paths split by WHICH TOOLS,\n * never by HOW THE CALLER AUTHENTICATES.\n *\n * HOW the caller authenticates is `WpMcpServerConfig.setAuth([...])`: an OR-set of the same `@WpAuth`\n * builders endpoints use plus `mcpOAuth(...)`, classified from unverified surface facts and verified by\n * exactly ONE verifier ({@link McpDoorAuthenticator}). That establishes the trusted `RequestContext` —\n * the caller, surface `llm`, and (only from an OIDC / shared-secret hop) the forwarded trusted context —\n * and the toolset does the rest exactly as it does for the in-memory transport.\n *\n * Serves BOTH wire eras from one registry: modern (2026-07-28, per-request `_meta` envelope) and legacy\n * (the 2025-11-25 family, negotiated by `initialize`). The SDK routes each request to the leg its shape\n * selects and negotiates the revision; only a revision no era knows is refused. Pinning one era\n * instead made every shipping client unreachable (issue #969).\n *\n * Error boundaries: HTTP ingress owns pre-SDK replies; the toolset's one 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. `subscriptions/listen` is\n * served entirely by the SDK's listen router. The credential is verified exactly once per POST, at the\n * HTTP boundary, before the SDK is involved.\n */\nexport class WpMcpServer {\n private readonly callerContext = new AuthenticatedCallerContext();\n private readonly responseWriter = new ExpressResponseWriter();\n private readonly translator: WpMcpErrorTranslator = new WpMcpErrorTranslator();\n private door?: McpDoorAuthenticator;\n private handler?: McpHttpHandler;\n private streamingHandler?: McpHttpHandler;\n private nodeHandler?: NodeMcpRequestHandler;\n private streamingNodeHandler?: NodeMcpRequestHandler;\n private icons?: readonly Icon[];\n\n constructor(\n private readonly config: WpMcpServerConfig,\n private readonly toolset: McpToolset,\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 resource, so this may be called only once\n * and `WpMcpServerConfig.setResource(...)`'s path must equal `endpointPath`. That resource URI is\n * fixed for the lifetime of the process and is never derived from the request `Host` — a\n * host-derived audience would make the boundary's own audience check compare two caller-controlled\n * values, which is the confused deputy this check exists to prevent.\n *\n * With `mcpOAuth(...)` in the set, the discovery half stays app-owned: publish\n * {@link protectedResourceMetadata} at `WpMcpServerConfig.resourceMetadataUrl`, which is where the\n * 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.\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.door = McpDoorAuthenticator.create(\n this.config.auth,\n this.config.resource,\n this.config.credentialVerifiers,\n );\n this.icons = this.config.icons;\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 /**\n * RFC 9728 metadata for this resource. Only an `mcpOAuth(...)` server has any: it is what a\n * connector reads at `WpMcpServerConfig.resourceMetadataUrl` to find the authorization server.\n */\n protectedResourceMetadata(): McpProtectedResourceMetadata {\n const oauth = this.config.auth.find(\n (mode: McpHttpAuth): mode is McpOAuthMode => mode instanceof McpOAuthMode,\n );\n if (oauth === undefined) {\n throw new Error(\n 'WpMcpServer.protectedResourceMetadata() requires mcpOAuth(...) in WpMcpServerConfig.setAuth([...]); ' +\n 'a server without it publishes no OAuth discovery.',\n );\n }\n return oauth.protectedResourceMetadata(this.config.resource);\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.handler ? this.toolset.revision : undefined;\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 const post = new McpPostState();\n await this.ingress(req, res, 'serve', post, () =>\n this.serveExpress(req, res, options, post),\n );\n }\n\n private async handleBodyFailure(cause: Error, req: Request, res: Response): Promise<void> {\n await this.ingress(req, res, 'body', new McpPostState(), () => this.rejectBody(cause));\n }\n\n private async ingress(\n req: Request,\n res: Response,\n step: string,\n post: McpPostState,\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.toolset.logEdge(step, work);\n // webpieces-disable catch-must-propagate -- the response-owning ingress hands the error WHOLE to the translator, which writes it as this POST's reply; LogApiCall already logged it\n } catch (err: unknown) {\n const error = toError(err);\n this.writeBoundaryError(res, error, post);\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, post: McpPostState): void {\n if (res.headersSent) {\n res.end();\n return;\n }\n const challenge = post.challenge ? this.challenge() : undefined;\n this.responseWriter.write(res, this.translator.toBearerBoundaryResponse(error, challenge));\n }\n\n private async serveExpress(\n req: Request,\n res: Response,\n options: McpBindOptions,\n post: McpPostState,\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, post);\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 /**\n * Verifies the caller's credential once for this POST — classify, then exactly ONE verifier — and\n * establishes the trusted context the toolset reads. Handlers never re-verify it.\n *\n * Surface `llm` is stamped BEFORE reconciliation, so on a caller-NOT-verified mode (jwt, apiKey,\n * mcpOAuth) a client that also SENDS `x-wp-surface` must say `llm` or be refused; and again AFTER,\n * because an OIDC / shared-secret hop admits its forwarded context wholesale, and the model on the\n * other end of an MCP door is always the surface.\n */\n private async authenticate(req: Request, post: McpPostState): Promise<McpPostAuthentication> {\n const door = this.requireDoor();\n const doorRequest = new McpDoorRequest(this.toHttpRequest(req));\n post.challenge = door.challengeApplies(doorRequest);\n const pass = await door.authenticate(doorRequest);\n RequestContext.putTrusted(WebpiecesCoreHeaders.SURFACE, 'llm');\n this.callerContext.reconcileWireTrust(pass.callerVerified);\n RequestContext.putTrusted(WebpiecesCoreHeaders.SURFACE, 'llm');\n const tools = await this.toolset.authorizedTools();\n return new McpPostAuthentication(\n pass,\n new McpToolRequest(tools, this.disconnectSignal(req)),\n );\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 credential is verified. A\n // 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 view: AuthorizedMcpTools = authentication.request.tools;\n return this.toolset.createSdkServer(\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.toolset.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 async (): Promise<McpToolRequest> => authentication.request,\n (name: string): RegisteredMcpTool | undefined => view.find(name),\n );\n }\n\n private authInfo(authentication: McpPostAuthentication): AuthInfo {\n const pass = authentication.pass;\n return {\n token: pass.token,\n clientId: pass.subject,\n scopes: [...pass.scopes],\n expiresAt: pass.expiresAtEpochSeconds,\n resource: new URL(this.config.resource),\n extra: { webpiecesAuthentication: authentication },\n };\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 requireDoor(): McpDoorAuthenticator {\n if (!this.door) throw new Error('Call WpMcpServer.bind(...) before serving requests.');\n return this.door;\n }\n}\n"]}
@@ -0,0 +1,107 @@
1
+ import 'reflect-metadata';
2
+ import { ContextKey, OidcAuthMethods } from '@webpieces/core-util';
3
+ import { HttpRequest } from '@webpieces/core-context';
4
+ import { ApiKeyHook, AuthenticatedCaller, AuthenticatedMachineIdentity, JwtHook, MintedJwt, OidcHook } from '@webpieces/http-routing';
5
+ import { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';
6
+ import { McpToolCatalog } from '../McpToolCatalog';
7
+ import { SearchRequest, SearchResponse } from './WpMcpServerTestFixtures';
8
+ /**
9
+ * One contract served over every transport. `stores_pause` needs the OPERATOR role and `stores_purge`
10
+ * is in the `admin` profile only, so projection by caller AND by toolset profile are both visible.
11
+ * The endpoints declare plain `jwt()`: an MCP transport never needs an endpoint auth mode of its own.
12
+ */
13
+ export declare abstract class StoreApi {
14
+ /**
15
+ * List the caller's stores.
16
+ *
17
+ * @summary List stores
18
+ */
19
+ list(_request: SearchRequest): Promise<SearchResponse>;
20
+ /**
21
+ * Pause a store.
22
+ *
23
+ * @summary Pause store
24
+ */
25
+ pause(_request: SearchRequest): Promise<SearchResponse>;
26
+ /**
27
+ * Purge a store; admin profile only.
28
+ *
29
+ * @summary Purge store
30
+ */
31
+ purge(_request: SearchRequest): Promise<SearchResponse>;
32
+ }
33
+ /** A contract that marks a SERVICE_ONLY method as an MCP tool, which `McpToolset` must refuse. */
34
+ export declare abstract class ServiceOnlyToolApi {
35
+ /**
36
+ * Only for a bare service hop.
37
+ *
38
+ * @summary Service only
39
+ */
40
+ run(_request: SearchRequest): Promise<SearchResponse>;
41
+ }
42
+ export declare class ServiceOnlyToolController extends ServiceOnlyToolApi {
43
+ run(request: SearchRequest): Promise<SearchResponse>;
44
+ }
45
+ /** A hold the test releases, so a call is provably still in flight while another caller runs. */
46
+ export declare class StoreGate {
47
+ private release?;
48
+ readonly entered: Promise<void>;
49
+ private enter;
50
+ readonly opened: Promise<void>;
51
+ constructor();
52
+ pass(): Promise<void>;
53
+ open(): void;
54
+ }
55
+ export declare class StoreController extends StoreApi {
56
+ static gate?: StoreGate;
57
+ static readonly calls: string[];
58
+ list(request: SearchRequest): Promise<SearchResponse>;
59
+ pause(request: SearchRequest): Promise<SearchResponse>;
60
+ purge(request: SearchRequest): Promise<SearchResponse>;
61
+ private answer;
62
+ }
63
+ export declare const STORE_CATALOG: McpToolCatalog;
64
+ export declare const SAME_PROJECT_SA = "ai-chat@this-project.iam.gserviceaccount.com";
65
+ export declare const OTHER_PROJECT_SA = "intruder@other-project.iam.gserviceaccount.com";
66
+ export declare const OAUTH_ISSUER = "https://login.example.test";
67
+ export declare const PARTNER_KEY: ContextKey<string, "untrusted">;
68
+ /** The unsigned off-GCP OIDC token `@webpieces/gcp-identity` mints, for `email`. */
69
+ export declare class DevOidcTokens {
70
+ static of(email: string, audience?: string): string;
71
+ /** A JWT that merely CLAIMS to be Google-issued; its signature is garbage. */
72
+ static forgedGoogleJwt(): string;
73
+ }
74
+ /**
75
+ * The OIDC verifier edge: admits a dev token whose email is a service account of `this-project`, the
76
+ * way `oidcSameProject()` admits this GCP project's accounts. Anything else — another project, or a
77
+ * JWT whose Google signature it cannot verify — is a 401.
78
+ */
79
+ export declare class ProjectOidcHook extends OidcHook {
80
+ readonly tokens: string[];
81
+ verifyOidc(token: string, _methods: OidcAuthMethods): Promise<AuthenticatedMachineIdentity>;
82
+ }
83
+ /** The app's own user JWT: `jwt-alice` is an OPERATOR, `jwt-bob` has no role. Records every token. */
84
+ export declare class TransportJwtHook extends JwtHook<string> {
85
+ readonly parsed: string[];
86
+ mint(_subject: string): Promise<MintedJwt>;
87
+ parseJwt(token: string): Promise<AuthenticatedCaller>;
88
+ }
89
+ /** A partner's api key on its own header. */
90
+ export declare class TransportApiKeyHook extends ApiKeyHook {
91
+ verifyApiKey(_regime: string, request: HttpRequest): Promise<AuthenticatedCaller>;
92
+ }
93
+ /** MCP OAuth access tokens minted as opaque `wpmcp_<user>` strings. */
94
+ export declare class PrefixTokenAuthority implements McpAccessTokenAuthority<string> {
95
+ mintAccessToken(_grant: string): Promise<never>;
96
+ verifyAccessToken(token: string, resource: string): Promise<VerifiedMcpCredential>;
97
+ }
98
+ /**
99
+ * Runs `work` as a caller an endpoint's AuthFilter already verified: one request scope with the user
100
+ * published and ingress completed — exactly the context an in-process agent calls its client from.
101
+ */
102
+ export declare class VerifiedCaller {
103
+ readonly userId: string;
104
+ readonly roles: string[];
105
+ constructor(userId: string, roles: string[]);
106
+ run<T>(work: () => Promise<T>): Promise<T>;
107
+ }
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ var StoreController_1;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.VerifiedCaller = exports.PrefixTokenAuthority = exports.TransportApiKeyHook = exports.TransportJwtHook = exports.ProjectOidcHook = exports.DevOidcTokens = exports.PARTNER_KEY = exports.OAUTH_ISSUER = exports.OTHER_PROJECT_SA = exports.SAME_PROJECT_SA = exports.STORE_CATALOG = exports.StoreController = exports.StoreGate = exports.ServiceOnlyToolController = exports.ServiceOnlyToolApi = exports.StoreApi = void 0;
5
+ const tslib_1 = require("tslib");
6
+ require("reflect-metadata");
7
+ const inversify_1 = require("inversify");
8
+ const core_util_1 = require("@webpieces/core-util");
9
+ const core_context_1 = require("@webpieces/core-context");
10
+ const http_routing_1 = require("@webpieces/http-routing");
11
+ const McpAuth_1 = require("../McpAuth");
12
+ const McpToolCatalog_1 = require("../McpToolCatalog");
13
+ const WpMcpServerTestFixtures_1 = require("./WpMcpServerTestFixtures");
14
+ /**
15
+ * One contract served over every transport. `stores_pause` needs the OPERATOR role and `stores_purge`
16
+ * is in the `admin` profile only, so projection by caller AND by toolset profile are both visible.
17
+ * The endpoints declare plain `jwt()`: an MCP transport never needs an endpoint auth mode of its own.
18
+ */
19
+ let StoreApi = class StoreApi {
20
+ /**
21
+ * List the caller's stores.
22
+ *
23
+ * @summary List stores
24
+ */
25
+ list(_request) {
26
+ throw new Error('contract only');
27
+ }
28
+ /**
29
+ * Pause a store.
30
+ *
31
+ * @summary Pause store
32
+ */
33
+ pause(_request) {
34
+ throw new Error('contract only');
35
+ }
36
+ /**
37
+ * Purge a store; admin profile only.
38
+ *
39
+ * @summary Purge store
40
+ */
41
+ purge(_request) {
42
+ throw new Error('contract only');
43
+ }
44
+ };
45
+ exports.StoreApi = StoreApi;
46
+ tslib_1.__decorate([
47
+ (0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
48
+ (0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ALL_USERS }),
49
+ (0, core_util_1.Endpoint)(core_util_1.POST, '/list', core_util_1.READ, core_util_1.RPC),
50
+ (0, core_util_1.WpMcpTool)('stores_list', { profiles: ['user'] }),
51
+ tslib_1.__metadata("design:type", Function),
52
+ tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
53
+ tslib_1.__metadata("design:returntype", Promise)
54
+ ], StoreApi.prototype, "list", null);
55
+ tslib_1.__decorate([
56
+ (0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
57
+ (0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ROLES, roles: ['OPERATOR'] }),
58
+ (0, core_util_1.Endpoint)(core_util_1.POST, '/pause', core_util_1.READ, core_util_1.RPC),
59
+ (0, core_util_1.WpMcpTool)('stores_pause', { profiles: ['user'] }),
60
+ tslib_1.__metadata("design:type", Function),
61
+ tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
62
+ tslib_1.__metadata("design:returntype", Promise)
63
+ ], StoreApi.prototype, "pause", null);
64
+ tslib_1.__decorate([
65
+ (0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
66
+ (0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ROLES, roles: ['OPERATOR'] }),
67
+ (0, core_util_1.Endpoint)(core_util_1.POST, '/purge', core_util_1.READ, core_util_1.RPC),
68
+ (0, core_util_1.WpMcpTool)('stores_purge', { profiles: ['admin'] }),
69
+ tslib_1.__metadata("design:type", Function),
70
+ tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
71
+ tslib_1.__metadata("design:returntype", Promise)
72
+ ], StoreApi.prototype, "purge", null);
73
+ exports.StoreApi = StoreApi = tslib_1.__decorate([
74
+ (0, core_util_1.ApiPath)('/stores'),
75
+ (0, core_util_1.ApiType)(core_util_1.SVC_TO_SVC, core_util_1.MCP)
76
+ ], StoreApi);
77
+ /** A contract that marks a SERVICE_ONLY method as an MCP tool, which `McpToolset` must refuse. */
78
+ let ServiceOnlyToolApi = class ServiceOnlyToolApi {
79
+ /**
80
+ * Only for a bare service hop.
81
+ *
82
+ * @summary Service only
83
+ */
84
+ run(_request) {
85
+ throw new Error('contract only');
86
+ }
87
+ };
88
+ exports.ServiceOnlyToolApi = ServiceOnlyToolApi;
89
+ tslib_1.__decorate([
90
+ (0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
91
+ (0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.SERVICE_ONLY }),
92
+ (0, core_util_1.Endpoint)(core_util_1.POST, '/run', core_util_1.READ, core_util_1.RPC),
93
+ (0, core_util_1.WpMcpTool)('service_only'),
94
+ tslib_1.__metadata("design:type", Function),
95
+ tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
96
+ tslib_1.__metadata("design:returntype", Promise)
97
+ ], ServiceOnlyToolApi.prototype, "run", null);
98
+ exports.ServiceOnlyToolApi = ServiceOnlyToolApi = tslib_1.__decorate([
99
+ (0, core_util_1.ApiPath)('/service-only'),
100
+ (0, core_util_1.ApiType)(core_util_1.SVC_TO_SVC, core_util_1.MCP)
101
+ ], ServiceOnlyToolApi);
102
+ let ServiceOnlyToolController = class ServiceOnlyToolController extends ServiceOnlyToolApi {
103
+ async run(request) {
104
+ const response = new WpMcpServerTestFixtures_1.SearchResponse();
105
+ response.userId = 'service';
106
+ response.result = request.query;
107
+ return response;
108
+ }
109
+ };
110
+ exports.ServiceOnlyToolController = ServiceOnlyToolController;
111
+ exports.ServiceOnlyToolController = ServiceOnlyToolController = tslib_1.__decorate([
112
+ (0, inversify_1.injectable)()
113
+ ], ServiceOnlyToolController);
114
+ /** A hold the test releases, so a call is provably still in flight while another caller runs. */
115
+ class StoreGate {
116
+ release;
117
+ entered;
118
+ enter;
119
+ opened;
120
+ constructor() {
121
+ this.entered = new Promise((resolve) => {
122
+ this.enter = resolve;
123
+ });
124
+ this.opened = new Promise((resolve) => {
125
+ this.release = resolve;
126
+ });
127
+ }
128
+ async pass() {
129
+ this.enter();
130
+ await this.opened;
131
+ }
132
+ open() {
133
+ this.release?.();
134
+ }
135
+ }
136
+ exports.StoreGate = StoreGate;
137
+ let StoreController = class StoreController extends StoreApi {
138
+ static { StoreController_1 = this; }
139
+ static gate;
140
+ static calls = [];
141
+ async list(request) {
142
+ return this.answer('list', request);
143
+ }
144
+ async pause(request) {
145
+ if (request.query === 'hold')
146
+ await StoreController_1.gate?.pass();
147
+ return this.answer('pause', request);
148
+ }
149
+ async purge(request) {
150
+ return this.answer('purge', request);
151
+ }
152
+ answer(method, request) {
153
+ StoreController_1.calls.push(method);
154
+ const response = new WpMcpServerTestFixtures_1.SearchResponse();
155
+ response.userId = core_context_1.RequestContext.getTrusted(core_util_1.WebpiecesCoreHeaders.USER_ID) ?? 'missing';
156
+ response.result = request.query;
157
+ return response;
158
+ }
159
+ };
160
+ exports.StoreController = StoreController;
161
+ exports.StoreController = StoreController = StoreController_1 = tslib_1.__decorate([
162
+ (0, inversify_1.injectable)()
163
+ ], StoreController);
164
+ const SCHEMA = WpMcpServerTestFixtures_1.SEARCH_API_CATALOG.file.tools[0];
165
+ exports.STORE_CATALOG = new McpToolCatalog_1.McpToolCatalog(new core_util_1.McpToolCatalogFile('StoreApi', (0, core_util_1.getWpMcpTools)(StoreApi).map((tool) => new core_util_1.McpToolDefinition(tool.name, `Store ${tool.name}`, tool.methodName, 'Store fixture', (0, core_util_1.mcpHintsForOperation)(core_util_1.READ, false), SCHEMA.inputSchema, SCHEMA.outputSchema, tool.profiles))), '(store fixture)');
166
+ exports.SAME_PROJECT_SA = 'ai-chat@this-project.iam.gserviceaccount.com';
167
+ exports.OTHER_PROJECT_SA = 'intruder@other-project.iam.gserviceaccount.com';
168
+ exports.OAUTH_ISSUER = 'https://login.example.test';
169
+ exports.PARTNER_KEY = core_util_1.ContextKey.untrusted('mcpPartnerKey', 'x-partner-key');
170
+ /** The unsigned off-GCP OIDC token `@webpieces/gcp-identity` mints, for `email`. */
171
+ class DevOidcTokens {
172
+ // webpieces-disable no-function-outside-class -- test token builder
173
+ static of(email, audience = 'https://svc-b.example.test') {
174
+ return ('dev-oidc.' +
175
+ Buffer.from(JSON.stringify({ email, aud: audience }), 'utf8').toString('base64url'));
176
+ }
177
+ /** A JWT that merely CLAIMS to be Google-issued; its signature is garbage. */
178
+ // webpieces-disable no-function-outside-class -- test token builder
179
+ static forgedGoogleJwt() {
180
+ const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');
181
+ const payload = Buffer.from(JSON.stringify({ iss: 'https://accounts.google.com', email: exports.SAME_PROJECT_SA })).toString('base64url');
182
+ return `${header}.${payload}.forged-signature`;
183
+ }
184
+ }
185
+ exports.DevOidcTokens = DevOidcTokens;
186
+ /**
187
+ * The OIDC verifier edge: admits a dev token whose email is a service account of `this-project`, the
188
+ * way `oidcSameProject()` admits this GCP project's accounts. Anything else — another project, or a
189
+ * JWT whose Google signature it cannot verify — is a 401.
190
+ */
191
+ class ProjectOidcHook extends http_routing_1.OidcHook {
192
+ tokens = [];
193
+ async verifyOidc(token, _methods) {
194
+ this.tokens.push(token);
195
+ if (!token.startsWith('dev-oidc.'))
196
+ throw new core_util_1.ApiUnauthorizedError('OIDC signature did not verify');
197
+ const claims = JSON.parse(Buffer.from(token.substring('dev-oidc.'.length), 'base64url').toString('utf8'));
198
+ if (!claims['email']?.endsWith('@this-project.iam.gserviceaccount.com')) {
199
+ throw new core_util_1.ApiUnauthorizedError('OIDC caller is not a service account of this project');
200
+ }
201
+ return new http_routing_1.AuthenticatedMachineIdentity('oidc', claims['email']);
202
+ }
203
+ }
204
+ exports.ProjectOidcHook = ProjectOidcHook;
205
+ /** The app's own user JWT: `jwt-alice` is an OPERATOR, `jwt-bob` has no role. Records every token. */
206
+ class TransportJwtHook extends http_routing_1.JwtHook {
207
+ parsed = [];
208
+ async mint(_subject) {
209
+ throw new Error('not used');
210
+ }
211
+ async parseJwt(token) {
212
+ this.parsed.push(token);
213
+ if (token === 'jwt-alice')
214
+ return new http_routing_1.AuthenticatedCaller('alice', ['OPERATOR']);
215
+ if (token === 'jwt-bob')
216
+ return new http_routing_1.AuthenticatedCaller('bob', []);
217
+ throw new core_util_1.ApiUnauthorizedError('invalid user token');
218
+ }
219
+ }
220
+ exports.TransportJwtHook = TransportJwtHook;
221
+ /** A partner's api key on its own header. */
222
+ class TransportApiKeyHook extends http_routing_1.ApiKeyHook {
223
+ async verifyApiKey(_regime, request) {
224
+ if (request.getHeader('x-partner-key') === 'key-carol') {
225
+ return new http_routing_1.AuthenticatedCaller('carol', ['OPERATOR']);
226
+ }
227
+ throw new core_util_1.ApiUnauthorizedError('unknown partner key');
228
+ }
229
+ }
230
+ exports.TransportApiKeyHook = TransportApiKeyHook;
231
+ /** MCP OAuth access tokens minted as opaque `wpmcp_<user>` strings. */
232
+ class PrefixTokenAuthority {
233
+ async mintAccessToken(_grant) {
234
+ throw new Error('not used');
235
+ }
236
+ async verifyAccessToken(token, resource) {
237
+ if (token !== 'wpmcp_dave')
238
+ throw new core_util_1.ApiUnauthorizedError('invalid access token');
239
+ const now = Math.floor(Date.now() / 1000);
240
+ return new McpAuth_1.VerifiedMcpCredential('dave', exports.OAUTH_ISSUER, resource, now, now + 60, ['tools'], now, new http_routing_1.AuthenticatedCaller('dave', ['OPERATOR']));
241
+ }
242
+ }
243
+ exports.PrefixTokenAuthority = PrefixTokenAuthority;
244
+ /**
245
+ * Runs `work` as a caller an endpoint's AuthFilter already verified: one request scope with the user
246
+ * published and ingress completed — exactly the context an in-process agent calls its client from.
247
+ */
248
+ class VerifiedCaller {
249
+ userId;
250
+ roles;
251
+ constructor(userId, roles) {
252
+ this.userId = userId;
253
+ this.roles = roles;
254
+ }
255
+ async run(work) {
256
+ return core_context_1.RequestContext.run(async () => {
257
+ new core_context_1.RequestContextHeaders().fillFromRequest(new core_context_1.HttpRequest('POST', '/chat', new Map()));
258
+ const context = new http_routing_1.AuthenticatedCallerContext();
259
+ context.publish(new http_routing_1.AuthenticatedCaller(this.userId, this.roles));
260
+ context.reconcileWireTrust(false);
261
+ return work();
262
+ });
263
+ }
264
+ }
265
+ exports.VerifiedCaller = VerifiedCaller;
266
+ //# sourceMappingURL=McpTransportFixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpTransportFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/McpTransportFixtures.ts"],"names":[],"mappings":";;;;;AAAA,4BAA0B;AAC1B,yCAAuC;AACvC,oDAuB8B;AAC9B,0DAA6F;AAC7F,0DAQiC;AACjC,wCAA4E;AAC5E,sDAAmD;AACnD,uEAA8F;AAE9F;;;;GAIG;AAGI,IAAe,QAAQ,GAAvB,MAAe,QAAQ;IAC1B;;;;OAIG;IAKH,IAAI,CAAC,QAAuB;QACxB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IAKH,KAAK,CAAC,QAAuB;QACzB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IAKH,KAAK,CAAC,QAAuB;QACzB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ,CAAA;AAvCqB,4BAAQ;AAU1B;IAJC,IAAA,kBAAM,EAAC,CAAC,IAAA,eAAG,GAAE,CAAC,CAAC;IACf,IAAA,2BAAe,EAAC,EAAE,QAAQ,EAAE,6BAAiB,CAAC,SAAS,EAAE,CAAC;IAC1D,IAAA,oBAAQ,EAAC,gBAAI,EAAE,OAAO,EAAE,gBAAI,EAAE,eAAG,CAAC;IAClC,IAAA,qBAAS,EAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;;6CAClC,uCAAa;;oCAE3B;AAWD;IAJC,IAAA,kBAAM,EAAC,CAAC,IAAA,eAAG,GAAE,CAAC,CAAC;IACf,IAAA,2BAAe,EAAC,EAAE,QAAQ,EAAE,6BAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3E,IAAA,oBAAQ,EAAC,gBAAI,EAAE,QAAQ,EAAE,gBAAI,EAAE,eAAG,CAAC;IACnC,IAAA,qBAAS,EAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;;6CAClC,uCAAa;;qCAE5B;AAWD;IAJC,IAAA,kBAAM,EAAC,CAAC,IAAA,eAAG,GAAE,CAAC,CAAC;IACf,IAAA,2BAAe,EAAC,EAAE,QAAQ,EAAE,6BAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;IAC3E,IAAA,oBAAQ,EAAC,gBAAI,EAAE,QAAQ,EAAE,gBAAI,EAAE,eAAG,CAAC;IACnC,IAAA,qBAAS,EAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;;6CACnC,uCAAa;;qCAE5B;mBAtCiB,QAAQ;IAF7B,IAAA,mBAAO,EAAC,SAAS,CAAC;IAClB,IAAA,mBAAO,EAAC,sBAAU,EAAE,eAAG,CAAC;GACH,QAAQ,CAuC7B;AAED,kGAAkG;AAG3F,IAAe,kBAAkB,GAAjC,MAAe,kBAAkB;IACpC;;;;OAIG;IAKH,GAAG,CAAC,QAAuB;QACvB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ,CAAA;AAbqB,gDAAkB;AAUpC;IAJC,IAAA,kBAAM,EAAC,CAAC,IAAA,eAAG,GAAE,CAAC,CAAC;IACf,IAAA,2BAAe,EAAC,EAAE,QAAQ,EAAE,6BAAiB,CAAC,YAAY,EAAE,CAAC;IAC7D,IAAA,oBAAQ,EAAC,gBAAI,EAAE,MAAM,EAAE,gBAAI,EAAE,eAAG,CAAC;IACjC,IAAA,qBAAS,EAAC,cAAc,CAAC;;6CACZ,uCAAa;;6CAE1B;6BAZiB,kBAAkB;IAFvC,IAAA,mBAAO,EAAC,eAAe,CAAC;IACxB,IAAA,mBAAO,EAAC,sBAAU,EAAE,eAAG,CAAC;GACH,kBAAkB,CAavC;AAGM,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,kBAAkB;IACpD,KAAK,CAAC,GAAG,CAAC,OAAsB;QACrC,MAAM,QAAQ,GAAG,IAAI,wCAAc,EAAE,CAAC;QACtC,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC;QAC5B,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAChC,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ,CAAA;AAPY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,sBAAU,GAAE;GACA,yBAAyB,CAOrC;AAED,iGAAiG;AACjG,MAAa,SAAS;IACV,OAAO,CAAc;IACpB,OAAO,CAAgB;IACxB,KAAK,CAAc;IAClB,MAAM,CAAgB;IAE/B;QACI,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAmB,EAAE,EAAE;YACrD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;QACzB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAmB,EAAE,EAAE;YACpD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,IAAI;QACN,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,IAAI;QACA,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;IACrB,CAAC;CACJ;AAvBD,8BAuBC;AAGM,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,QAAQ;;IACzC,MAAM,CAAC,IAAI,CAAa;IACxB,MAAM,CAAU,KAAK,GAAa,EAAE,CAAC;IAE5B,KAAK,CAAC,IAAI,CAAC,OAAsB;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAEQ,KAAK,CAAC,KAAK,CAAC,OAAsB;QACvC,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM;YAAE,MAAM,iBAAe,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAEQ,KAAK,CAAC,KAAK,CAAC,OAAsB;QACvC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAEO,MAAM,CAAC,MAAc,EAAE,OAAsB;QACjD,iBAAe,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,wCAAc,EAAE,CAAC;QACtC,QAAQ,CAAC,MAAM,GAAG,6BAAc,CAAC,UAAU,CAAC,gCAAoB,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;QACvF,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAChC,OAAO,QAAQ,CAAC;IACpB,CAAC;;AAvBQ,0CAAe;0BAAf,eAAe;IAD3B,IAAA,sBAAU,GAAE;GACA,eAAe,CAwB3B;AAED,MAAM,MAAM,GAAG,4CAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,QAAA,aAAa,GAAG,IAAI,+BAAc,CAC3C,IAAI,8BAAkB,CAClB,UAAU,EACV,IAAA,yBAAa,EAAC,QAAQ,CAAC,CAAC,GAAG,CACvB,CAAC,IAAuB,EAAE,EAAE,CACxB,IAAI,6BAAiB,CACjB,IAAI,CAAC,IAAI,EACT,SAAS,IAAI,CAAC,IAAI,EAAE,EACpB,IAAI,CAAC,UAAU,EACf,eAAe,EACf,IAAA,gCAAoB,EAAC,gBAAI,EAAE,KAAK,CAAC,EACjC,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,YAAY,EACnB,IAAI,CAAC,QAAQ,CAChB,CACR,CACJ,EACD,iBAAiB,CACpB,CAAC;AAEW,QAAA,eAAe,GAAG,8CAA8C,CAAC;AACjE,QAAA,gBAAgB,GAAG,gDAAgD,CAAC;AACpE,QAAA,YAAY,GAAG,4BAA4B,CAAC;AAC5C,QAAA,WAAW,GAAG,sBAAU,CAAC,SAAS,CAAS,eAAe,EAAE,eAAe,CAAC,CAAC;AAE1F,oFAAoF;AACpF,MAAa,aAAa;IACtB,oEAAoE;IACpE,MAAM,CAAC,EAAE,CAAC,KAAa,EAAE,QAAQ,GAAG,4BAA4B;QAC5D,OAAO,CACH,WAAW;YACX,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CACtF,CAAC;IACN,CAAC;IAED,8EAA8E;IAC9E,oEAAoE;IACpE,MAAM,CAAC,eAAe;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAC7E,WAAW,CACd,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CACvB,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,6BAA6B,EAAE,KAAK,EAAE,uBAAe,EAAE,CAAC,CACjF,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxB,OAAO,GAAG,MAAM,IAAI,OAAO,mBAAmB,CAAC;IACnD,CAAC;CACJ;AApBD,sCAoBC;AAED;;;;GAIG;AACH,MAAa,eAAgB,SAAQ,uBAAQ;IAChC,MAAM,GAAa,EAAE,CAAC;IAEtB,KAAK,CAAC,UAAU,CACrB,KAAa,EACb,QAAyB;QAEzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;YAC9B,MAAM,IAAI,gCAAoB,CAAC,+BAA+B,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CACrB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACvD,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,uCAAuC,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,gCAAoB,CAAC,sDAAsD,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,IAAI,2CAA4B,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,CAAC;CACJ;AAlBD,0CAkBC;AAED,sGAAsG;AACtG,MAAa,gBAAiB,SAAQ,sBAAe;IACxC,MAAM,GAAa,EAAE,CAAC;IAEtB,KAAK,CAAC,IAAI,CAAC,QAAgB;QAChC,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAEQ,KAAK,CAAC,QAAQ,CAAC,KAAa;QACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,WAAW;YAAE,OAAO,IAAI,kCAAmB,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QACjF,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,kCAAmB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,gCAAoB,CAAC,oBAAoB,CAAC,CAAC;IACzD,CAAC;CACJ;AAbD,4CAaC;AAED,6CAA6C;AAC7C,MAAa,mBAAoB,SAAQ,yBAAU;IACtC,KAAK,CAAC,YAAY,CACvB,OAAe,EACf,OAAoB;QAEpB,IAAI,OAAO,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,WAAW,EAAE,CAAC;YACrD,OAAO,IAAI,kCAAmB,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,IAAI,gCAAoB,CAAC,qBAAqB,CAAC,CAAC;IAC1D,CAAC;CACJ;AAVD,kDAUC;AAED,uEAAuE;AACvE,MAAa,oBAAoB;IAC7B,KAAK,CAAC,eAAe,CAAC,MAAc;QAChC,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,KAAa,EAAE,QAAgB;QACnD,IAAI,KAAK,KAAK,YAAY;YAAE,MAAM,IAAI,gCAAoB,CAAC,sBAAsB,CAAC,CAAC;QACnF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,OAAO,IAAI,+BAAqB,CAC5B,MAAM,EACN,oBAAY,EACZ,QAAQ,EACR,GAAG,EACH,GAAG,GAAG,EAAE,EACR,CAAC,OAAO,CAAC,EACT,GAAG,EACH,IAAI,kCAAmB,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,CAAC,CAChD,CAAC;IACN,CAAC;CACJ;AAnBD,oDAmBC;AAED;;;GAGG;AACH,MAAa,cAAc;IAEH;IACA;IAFpB,YACoB,MAAc,EACd,KAAe;QADf,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAU;IAChC,CAAC;IAEJ,KAAK,CAAC,GAAG,CAAI,IAAsB;QAC/B,OAAO,6BAAc,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YACjC,IAAI,oCAAqB,EAAE,CAAC,eAAe,CACvC,IAAI,0BAAW,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,CAAC,CAC9C,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,yCAA0B,EAAE,CAAC;YACjD,OAAO,CAAC,OAAO,CAAC,IAAI,kCAAmB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAClE,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClC,OAAO,IAAI,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AAjBD,wCAiBC","sourcesContent":["import 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport {\n ApiPath,\n ApiType,\n ApiUnauthorizedError,\n AuthorizationType,\n ContextKey,\n Endpoint,\n getWpMcpTools,\n jwt,\n MCP,\n McpToolCatalogFile,\n McpToolDefinition,\n mcpHintsForOperation,\n OidcAuthMethods,\n POST,\n READ,\n RPC,\n SVC_TO_SVC,\n WebpiecesCoreHeaders,\n WpAuth,\n WpAuthorization,\n WpMcpTool,\n WpMcpToolMetadata,\n} from '@webpieces/core-util';\nimport { HttpRequest, RequestContext, RequestContextHeaders } from '@webpieces/core-context';\nimport {\n ApiKeyHook,\n AuthenticatedCaller,\n AuthenticatedCallerContext,\n AuthenticatedMachineIdentity,\n JwtHook,\n MintedJwt,\n OidcHook,\n} from '@webpieces/http-routing';\nimport { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';\nimport { McpToolCatalog } from '../McpToolCatalog';\nimport { SEARCH_API_CATALOG, SearchRequest, SearchResponse } from './WpMcpServerTestFixtures';\n\n/**\n * One contract served over every transport. `stores_pause` needs the OPERATOR role and `stores_purge`\n * is in the `admin` profile only, so projection by caller AND by toolset profile are both visible.\n * The endpoints declare plain `jwt()`: an MCP transport never needs an endpoint auth mode of its own.\n */\n@ApiPath('/stores')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class StoreApi {\n /**\n * List the caller's stores.\n *\n * @summary List stores\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/list', READ, RPC)\n @WpMcpTool('stores_list', { profiles: ['user'] })\n list(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /**\n * Pause a store.\n *\n * @summary Pause store\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['OPERATOR'] })\n @Endpoint(POST, '/pause', READ, RPC)\n @WpMcpTool('stores_pause', { profiles: ['user'] })\n pause(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /**\n * Purge a store; admin profile only.\n *\n * @summary Purge store\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['OPERATOR'] })\n @Endpoint(POST, '/purge', READ, RPC)\n @WpMcpTool('stores_purge', { profiles: ['admin'] })\n purge(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n/** A contract that marks a SERVICE_ONLY method as an MCP tool, which `McpToolset` must refuse. */\n@ApiPath('/service-only')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class ServiceOnlyToolApi {\n /**\n * Only for a bare service hop.\n *\n * @summary Service only\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.SERVICE_ONLY })\n @Endpoint(POST, '/run', READ, RPC)\n @WpMcpTool('service_only')\n run(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@injectable()\nexport class ServiceOnlyToolController extends ServiceOnlyToolApi {\n override async run(request: SearchRequest): Promise<SearchResponse> {\n const response = new SearchResponse();\n response.userId = 'service';\n response.result = request.query;\n return response;\n }\n}\n\n/** A hold the test releases, so a call is provably still in flight while another caller runs. */\nexport class StoreGate {\n private release?: () => void;\n readonly entered: Promise<void>;\n private enter!: () => void;\n readonly opened: Promise<void>;\n\n constructor() {\n this.entered = new Promise<void>((resolve: () => void) => {\n this.enter = resolve;\n });\n this.opened = new Promise<void>((resolve: () => void) => {\n this.release = resolve;\n });\n }\n\n async pass(): Promise<void> {\n this.enter();\n await this.opened;\n }\n\n open(): void {\n this.release?.();\n }\n}\n\n@injectable()\nexport class StoreController extends StoreApi {\n static gate?: StoreGate;\n static readonly calls: string[] = [];\n\n override async list(request: SearchRequest): Promise<SearchResponse> {\n return this.answer('list', request);\n }\n\n override async pause(request: SearchRequest): Promise<SearchResponse> {\n if (request.query === 'hold') await StoreController.gate?.pass();\n return this.answer('pause', request);\n }\n\n override async purge(request: SearchRequest): Promise<SearchResponse> {\n return this.answer('purge', request);\n }\n\n private answer(method: string, request: SearchRequest): SearchResponse {\n StoreController.calls.push(method);\n const response = new SearchResponse();\n response.userId = RequestContext.getTrusted(WebpiecesCoreHeaders.USER_ID) ?? 'missing';\n response.result = request.query;\n return response;\n }\n}\n\nconst SCHEMA = SEARCH_API_CATALOG.file.tools[0];\nexport const STORE_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile(\n 'StoreApi',\n getWpMcpTools(StoreApi).map(\n (tool: WpMcpToolMetadata) =>\n new McpToolDefinition(\n tool.name,\n `Store ${tool.name}`,\n tool.methodName,\n 'Store fixture',\n mcpHintsForOperation(READ, false),\n SCHEMA.inputSchema,\n SCHEMA.outputSchema,\n tool.profiles,\n ),\n ),\n ),\n '(store fixture)',\n);\n\nexport const SAME_PROJECT_SA = 'ai-chat@this-project.iam.gserviceaccount.com';\nexport const OTHER_PROJECT_SA = 'intruder@other-project.iam.gserviceaccount.com';\nexport const OAUTH_ISSUER = 'https://login.example.test';\nexport const PARTNER_KEY = ContextKey.untrusted<string>('mcpPartnerKey', 'x-partner-key');\n\n/** The unsigned off-GCP OIDC token `@webpieces/gcp-identity` mints, for `email`. */\nexport class DevOidcTokens {\n // webpieces-disable no-function-outside-class -- test token builder\n static of(email: string, audience = 'https://svc-b.example.test'): string {\n return (\n 'dev-oidc.' +\n Buffer.from(JSON.stringify({ email, aud: audience }), 'utf8').toString('base64url')\n );\n }\n\n /** A JWT that merely CLAIMS to be Google-issued; its signature is garbage. */\n // webpieces-disable no-function-outside-class -- test token builder\n static forgedGoogleJwt(): string {\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString(\n 'base64url',\n );\n const payload = Buffer.from(\n JSON.stringify({ iss: 'https://accounts.google.com', email: SAME_PROJECT_SA }),\n ).toString('base64url');\n return `${header}.${payload}.forged-signature`;\n }\n}\n\n/**\n * The OIDC verifier edge: admits a dev token whose email is a service account of `this-project`, the\n * way `oidcSameProject()` admits this GCP project's accounts. Anything else — another project, or a\n * JWT whose Google signature it cannot verify — is a 401.\n */\nexport class ProjectOidcHook extends OidcHook {\n readonly tokens: string[] = [];\n\n override async verifyOidc(\n token: string,\n _methods: OidcAuthMethods,\n ): Promise<AuthenticatedMachineIdentity> {\n this.tokens.push(token);\n if (!token.startsWith('dev-oidc.'))\n throw new ApiUnauthorizedError('OIDC signature did not verify');\n const claims = JSON.parse(\n Buffer.from(token.substring('dev-oidc.'.length), 'base64url').toString('utf8'),\n ) as Record<string, string>;\n if (!claims['email']?.endsWith('@this-project.iam.gserviceaccount.com')) {\n throw new ApiUnauthorizedError('OIDC caller is not a service account of this project');\n }\n return new AuthenticatedMachineIdentity('oidc', claims['email']);\n }\n}\n\n/** The app's own user JWT: `jwt-alice` is an OPERATOR, `jwt-bob` has no role. Records every token. */\nexport class TransportJwtHook extends JwtHook<string> {\n readonly parsed: string[] = [];\n\n override async mint(_subject: string): Promise<MintedJwt> {\n throw new Error('not used');\n }\n\n override async parseJwt(token: string): Promise<AuthenticatedCaller> {\n this.parsed.push(token);\n if (token === 'jwt-alice') return new AuthenticatedCaller('alice', ['OPERATOR']);\n if (token === 'jwt-bob') return new AuthenticatedCaller('bob', []);\n throw new ApiUnauthorizedError('invalid user token');\n }\n}\n\n/** A partner's api key on its own header. */\nexport class TransportApiKeyHook extends ApiKeyHook {\n override async verifyApiKey(\n _regime: string,\n request: HttpRequest,\n ): Promise<AuthenticatedCaller> {\n if (request.getHeader('x-partner-key') === 'key-carol') {\n return new AuthenticatedCaller('carol', ['OPERATOR']);\n }\n throw new ApiUnauthorizedError('unknown partner key');\n }\n}\n\n/** MCP OAuth access tokens minted as opaque `wpmcp_<user>` strings. */\nexport class PrefixTokenAuthority implements McpAccessTokenAuthority<string> {\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 if (token !== 'wpmcp_dave') throw new ApiUnauthorizedError('invalid access token');\n const now = Math.floor(Date.now() / 1000);\n return new VerifiedMcpCredential(\n 'dave',\n OAUTH_ISSUER,\n resource,\n now,\n now + 60,\n ['tools'],\n now,\n new AuthenticatedCaller('dave', ['OPERATOR']),\n );\n }\n}\n\n/**\n * Runs `work` as a caller an endpoint's AuthFilter already verified: one request scope with the user\n * published and ingress completed — exactly the context an in-process agent calls its client from.\n */\nexport class VerifiedCaller {\n constructor(\n public readonly userId: string,\n public readonly roles: string[],\n ) {}\n\n async run<T>(work: () => Promise<T>): Promise<T> {\n return RequestContext.run(async () => {\n new RequestContextHeaders().fillFromRequest(\n new HttpRequest('POST', '/chat', new Map()),\n );\n const context = new AuthenticatedCallerContext();\n context.publish(new AuthenticatedCaller(this.userId, this.roles));\n context.reconcileWireTrust(false);\n return work();\n });\n }\n}\n"]}
package/src/index.d.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  export { MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS, MAX_MCP_ACCOUNT_VALIDATION_AGE_SECONDS, MAX_MCP_SERVER_DESCRIPTION_LENGTH, MAX_MCP_SERVER_TITLE_LENGTH, MintedMcpAccessToken, McpProtectedResourceMetadata, VerifiedMcpCredential, WpMcpServerConfig, } from './McpAuth';
2
- export type { McpAccessTokenAuthority } from './McpAuth';
2
+ export { mcpOAuth, McpAccessTokenFormat, McpOAuthMode } from './McpAuth';
3
+ export type { McpAccessTokenAuthority, McpAccessTokenFormatKind, McpAuthorizationServers, McpHttpAuth, McpHttpAuths, } from './McpAuth';
4
+ export { McpToolset, McpToolRequest } from './McpToolset';
5
+ export { WpMcpInMemory } from './WpMcpInMemory';
6
+ export { WpMcpRemote } from './WpMcpRemote';
7
+ export type { McpIdTokenMinter } from './WpMcpRemote';
8
+ export { McpClientSet, McpDuplicateToolError, McpUnknownToolError } from './McpClientSet';
9
+ export type { McpClientSetCall } from './McpClientSet';
3
10
  export type { Icon } from '@modelcontextprotocol/server';
4
11
  export { McpIcon } from './McpIcon';
5
- export { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';
12
+ export { AuthorizedMcpTools, McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';
6
13
  export { McpApiBinding } from './McpApiBinding';
7
14
  export type { McpBindingTopology } from './McpApiBinding';
8
15
  export { McpBindOptions } from './McpBindOptions';