@webpieces/mcp-server 0.4.934 → 0.4.936
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -20
- package/package.json +6 -6
- package/src/McpAuth.d.ts +37 -0
- package/src/McpAuth.js +73 -1
- package/src/McpAuth.js.map +1 -1
- package/src/McpToolRegistry.d.ts +13 -3
- package/src/McpToolRegistry.js +8 -8
- package/src/McpToolRegistry.js.map +1 -1
- package/src/WpMcpServer.js +5 -1
- package/src/WpMcpServer.js.map +1 -1
- package/src/__tests__/McpProfileFixtures.d.ts +20 -4
- package/src/__tests__/McpProfileFixtures.js +25 -9
- package/src/__tests__/McpProfileFixtures.js.map +1 -1
- package/src/__tests__/McpRemoteFixtures.d.ts +35 -7
- package/src/__tests__/McpRemoteFixtures.js +42 -14
- package/src/__tests__/McpRemoteFixtures.js.map +1 -1
- package/src/__tests__/WpMcpServerTestFixtures.d.ts +15 -3
- package/src/__tests__/WpMcpServerTestFixtures.js +18 -6
- package/src/__tests__/WpMcpServerTestFixtures.js.map +1 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpToolRegistry.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpToolRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolPolicy } from './McpToolPolicy';\nimport {\n ApiJsonSchema,\n AuthMeta,\n assertApiTypeMatchesMcpTools,\n getAuthMeta,\n getEndpointKind,\n getEndpointOperation,\n getEndpoints,\n getWpMcpTools,\n getAuthorization,\n AuthorizationRequirement,\n EndpointOperation,\n McpToolCatalogError,\n McpToolCatalogFile,\n McpToolDefinition,\n WpMcpToolHints,\n WpMcpToolMetadata,\n} from '@webpieces/core-util';\nimport { ClassType, AuthorizationService } from '@webpieces/http-routing';\nimport { McpApiBinding } from './McpApiBinding';\nimport { McpToolCatalog } from './McpToolCatalog';\n\n/** Fully resolved contract metadata for one MCP tool. */\nexport class RegisteredMcpTool {\n constructor(\n public readonly apiClass: ClassType,\n public readonly methodName: string,\n public readonly name: string,\n /** The human-readable display name; published as BOTH `Tool.title` and `annotations.title` (#1180). */\n public readonly title: string,\n public readonly description: string,\n public readonly annotations: WpMcpToolHints,\n public readonly operation: EndpointOperation,\n public readonly authMeta: AuthMeta,\n // webpieces-disable no-any-unknown -- custom policy is validated by AuthorizationService\n public readonly authorization: AuthorizationRequirement<unknown>,\n public readonly binding: McpApiBinding,\n public readonly inputSchema: ApiJsonSchema,\n public readonly outputSchema: ApiJsonSchema,\n public readonly profiles: readonly string[],\n ) {}\n}\n\n/**\n * Fail-fast registry: the CONTRACT says which methods are tools and how they are authorized, and the\n * build's generated catalog OF THAT CONTRACT says what each tool's documentation and schemas are.\n *\n * ## Why the schemas come from the catalog and not from here\n *\n * They used to be built at boot by `DtoSchemaBuilder` walking reflect-metadata. That made the\n * document a partner reads and the schema a server accepts two independent derivations of one\n * contract, free to disagree; and it could not see a field's declared TYPE at all, so every fact\n * about a field had to be restated in a `@WpDtoField` argument. #983 measured the compiler against\n * it and found the compiler reproduces all of it, so #984 deleted the decorator and this registry\n * now READS the same catalogs the documents were rendered beside.\n *\n * ## One catalog per bound contract, exactly (#1021)\n *\n * `wp-openapi` writes one `mcp-<ContractClass>-tools.json` per contract, and this registry pairs every\n * `McpApiBinding` with the file of its own contract. Three mismatches refuse the boot, all reported at\n * once, each naming every directory the catalogs were read from:\n *\n * - a bound contract with no catalog — its tools were never given a schema by the build;\n * - a catalog whose contract is not bound — the server was handed tools it does not serve;\n * - a tool name declared twice — the protocol namespace is flat.\n *\n * A registered `@WpMcpTool` the catalog does not name is likewise a HARD FAILURE, not a fallback: a\n * tool the build never saw is a tool whose schema nobody checked.\n */\nexport class McpToolRegistry {\n readonly tools: readonly RegisteredMcpTool[];\n\n constructor(\n bindings: readonly McpApiBinding[],\n catalogs: readonly McpToolCatalog[],\n private readonly authorizationService: AuthorizationService,\n ) {\n const pairing = new McpCatalogPairing(catalogs);\n const registered: RegisteredMcpTool[] = [];\n const names = new Set<string>();\n for (const binding of bindings) {\n const apiClass = binding.api;\n // MCP membership is declared twice — on @ApiType and on the methods — and this is the\n // one call that makes the two disagree impossible. It existed before #984 and nothing\n // reached it, so a contract could carry tools nobody published to agents.\n assertApiTypeMatchesMcpTools(apiClass);\n const declared = getWpMcpTools(apiClass);\n const catalog = pairing.claim(apiClass, declared.length);\n for (const entry of catalog?.file.tools ?? []) {\n if (!declared.some((metadata: WpMcpToolMetadata) => metadata.name === entry.name)) {\n pairing.problem(\n `Stale tool '${entry.name}' in ${catalog!.file.fileName}; rebuild the api library.`,\n );\n }\n }\n for (const metadata of declared) {\n if (names.has(metadata.name)) {\n pairing.problem(\n `Duplicate @WpMcpTool name '${metadata.name}' (again on ${apiClass.name}). Tool ` +\n 'names are the protocol identity and must be globally unique — rename one.',\n );\n continue;\n }\n names.add(metadata.name);\n const tool = this.resolve(apiClass, metadata, binding, catalog, pairing);\n if (tool !== undefined) registered.push(tool);\n }\n }\n pairing.assertComplete();\n this.tools = registered;\n }\n\n find(name: string): RegisteredMcpTool | undefined {\n return this.tools.find((tool: RegisteredMcpTool) => tool.name === name);\n }\n\n /**\n * The contract checks THROW at once — they are about the contract source, not the build. A tool\n * missing from its catalog is RECORDED on `pairing`, so one boot names every catalog mismatch.\n */\n private resolve(\n apiClass: ClassType,\n metadata: WpMcpToolMetadata,\n binding: McpApiBinding,\n catalog: McpToolCatalog | undefined,\n pairing: McpCatalogPairing,\n ): RegisteredMcpTool | undefined {\n const endpoints = getEndpoints(apiClass) ?? {};\n if (!endpoints[metadata.methodName]) {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must also be an @Endpoint.`,\n );\n }\n if (getEndpointKind(apiClass, metadata.methodName) !== 'rpc') {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must be an RPC endpoint.`,\n );\n }\n const authMeta = getAuthMeta(apiClass, metadata.methodName);\n if (!authMeta)\n throw new Error(`@WpMcpTool ${apiClass.name}.${metadata.methodName} has no HTTP auth.`);\n const authorization = getAuthorization(apiClass, metadata.methodName);\n if (!authorization) {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must declare @WpAuthorization(...).`,\n );\n }\n this.authorizationService.validate(authorization);\n binding.validateMethod(metadata.methodName, this.authorizationService);\n if (catalog === undefined) return undefined;\n const published = this.published(apiClass, metadata, catalog, pairing);\n if (published === undefined) return undefined;\n return new RegisteredMcpTool(\n apiClass,\n metadata.methodName,\n metadata.name,\n published.title,\n published.description,\n published.hints,\n getEndpointOperation(apiClass, metadata.methodName),\n authMeta,\n authorization,\n binding,\n published.inputSchema,\n published.outputSchema,\n published.profiles,\n );\n }\n\n /** The generated entry for this tool, or a recorded refusal naming what the build DID publish. */\n private published(\n apiClass: ClassType,\n metadata: WpMcpToolMetadata,\n catalog: McpToolCatalog,\n pairing: McpCatalogPairing,\n ): McpToolDefinition | undefined {\n const published = catalog.find(metadata.name);\n if (published === undefined) {\n pairing.problem(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} publishes '${metadata.name}', which ` +\n `${catalog.file.fileName} (${catalog.directory}) does not contain. It has: ` +\n `${catalog.names().join(', ') || '(nothing)'}. The catalog is older than the contract — ` +\n 'rebuild the api library; a tool the build never saw is a tool whose schema nobody checked.',\n );\n return undefined;\n }\n if (\n published.methodName !== metadata.methodName ||\n published.profiles.join(',') !== metadata.profiles.join(',')\n ) {\n pairing.problem(\n `MCP tool '${metadata.name}' has stale method/profile metadata in ${catalog.file.fileName}; rebuild the api library.`,\n );\n return undefined;\n }\n if (published.title !== metadata.title) {\n pairing.problem(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} is titled '${metadata.title}', but ` +\n `${catalog.file.fileName} (${catalog.directory}) publishes '${metadata.name}' as ` +\n `'${published.title}'. The catalog is older than the contract — rebuild the api library.`,\n );\n return undefined;\n }\n return published;\n }\n}\n\n/**\n * Pairs each bound contract with the catalog of exactly that contract, and collects every mismatch so\n * the boot refusal lists them all at once instead of one per restart.\n */\nclass McpCatalogPairing {\n private readonly byContract = new Map<string, McpToolCatalog>();\n private readonly claimed = new Set<string>();\n private readonly problems: string[] = [];\n\n constructor(private readonly catalogs: readonly McpToolCatalog[]) {\n for (const catalog of catalogs) {\n const earlier = this.byContract.get(catalog.contractName);\n if (earlier !== undefined) {\n this.problem(\n `Two MCP tool catalogs for ${catalog.contractName}: ${earlier.directory} and ` +\n `${catalog.directory}. Name each api library in fromPackages(...) once, and bind ` +\n 'each contract from exactly one of them.',\n );\n continue;\n }\n this.byContract.set(catalog.contractName, catalog);\n }\n }\n\n /** The catalog of `apiClass`, recording a problem when there is none. */\n claim(apiClass: ClassType, declaredTools: number): McpToolCatalog | undefined {\n const catalog = this.byContract.get(apiClass.name);\n this.claimed.add(apiClass.name);\n if (catalog !== undefined) return catalog;\n this.problem(\n declaredTools === 0\n ? `The server binds ${apiClass.name}, which declares no @WpMcpTool method, so the build ` +\n `wrote no ${McpToolCatalogFile.fileNameFor(apiClass.name)} for it. Delete its ` +\n 'McpApiBinding — it publishes nothing.'\n : `The server binds ${apiClass.name}, and no ${McpToolCatalogFile.fileNameFor(apiClass.name)} ` +\n 'was handed to it. Add the api library that declares it to McpToolCatalog.fromPackages([...]) ' +\n 'and rebuild that library (its openapi-generate target writes the file).',\n );\n return undefined;\n }\n\n problem(text: string): void {\n this.problems.push(text);\n }\n\n /** Refuse the boot on any mismatch, naming every problem and every directory searched. */\n assertComplete(): void {\n for (const catalog of this.byContract.values()) {\n if (this.claimed.has(catalog.contractName)) continue;\n this.problem(\n `${catalog.file.fileName} (${catalog.directory}) is the catalog of ${catalog.contractName}, ` +\n `which the server does not bind. Bind it with McpApiBinding.local(${catalog.contractName}, ...) ` +\n 'or .remote(...), or leave it out of toolCatalogs, e.g. ' +\n `catalogs.filter((catalog: McpToolCatalog) => catalog.contractName !== '${catalog.contractName}').`,\n );\n }\n if (this.problems.length === 0) return;\n const directories = [\n ...new Set(this.catalogs.map((catalog: McpToolCatalog) => catalog.directory)),\n ];\n throw new McpToolCatalogError(\n 'The MCP tool catalogs do not match the bound contracts:\\n' +\n this.problems.map((text: string) => ` - ${text}`).join('\\n') +\n '\\nDirectories searched for mcp-<ContractClass>-tools.json:\\n' +\n (directories.length === 0\n ? ' (none — toolCatalogs is empty)'\n : directories.map((dir: string) => ` ${dir}`).join('\\n')) +\n '\\n',\n 'Each bound contract needs exactly the one catalog its api library build writes, and nothing else.',\n );\n }\n}\n\n/** Request-specific authorized projection, shared by documentation, schema lookup and name lookup. */\nexport class AuthorizedMcpTools {\n constructor(public readonly tools: readonly RegisteredMcpTool[]) {}\n\n find(name: string): RegisteredMcpTool | undefined {\n return this.tools.find((tool: RegisteredMcpTool) => tool.name === name);\n }\n\n // webpieces-disable no-function-outside-class -- asynchronous projection factory\n static async create(\n registry: McpToolRegistry,\n policy: AuthorizationService,\n profiles: readonly string[],\n ): Promise<AuthorizedMcpTools> {\n const tools: RegisteredMcpTool[] = [];\n const authorization = new McpToolPolicy(policy);\n for (const tool of [...registry.tools].sort((a: RegisteredMcpTool, b: RegisteredMcpTool) =>\n a.name.localeCompare(b.name),\n )) {\n if (!tool.profiles.some((profile: string) => profiles.includes(profile))) continue;\n if (await authorization.permits(tool.authorization)) tools.push(tool);\n }\n return new AuthorizedMcpTools(tools);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"McpToolRegistry.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpToolRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolPolicy } from './McpToolPolicy';\nimport {\n ApiJsonSchema,\n AuthMeta,\n assertApiTypeMatchesMcpTools,\n getAuthMeta,\n getEndpointKind,\n getEndpointOperation,\n getEndpoints,\n getWpMcpTools,\n getAuthorization,\n AuthorizationRequirement,\n EndpointOperation,\n McpToolCatalogError,\n McpToolCatalogFile,\n McpToolDefinition,\n WpMcpToolHints,\n WpMcpToolMetadata,\n} from '@webpieces/core-util';\nimport { ClassType, AuthorizationService } from '@webpieces/http-routing';\nimport { McpApiBinding } from './McpApiBinding';\nimport { McpToolCatalog } from './McpToolCatalog';\n\n/** Fully resolved contract metadata for one MCP tool. */\nexport class RegisteredMcpTool {\n constructor(\n public readonly apiClass: ClassType,\n public readonly methodName: string,\n public readonly name: string,\n /**\n * The human-readable display name, read from the CATALOG — which the generator wrote from the\n * method's `@summary` JSDoc tag (#1296). Published as BOTH `Tool.title` and `annotations.title`.\n * The contract carries no title at runtime, so there is nothing to compare it with: one source.\n */\n public readonly title: string,\n public readonly description: string,\n public readonly annotations: WpMcpToolHints,\n public readonly operation: EndpointOperation,\n public readonly authMeta: AuthMeta,\n // webpieces-disable no-any-unknown -- custom policy is validated by AuthorizationService\n public readonly authorization: AuthorizationRequirement<unknown>,\n public readonly binding: McpApiBinding,\n public readonly inputSchema: ApiJsonSchema,\n public readonly outputSchema: ApiJsonSchema,\n public readonly profiles: readonly string[],\n ) {}\n}\n\n/**\n * Fail-fast registry: the CONTRACT says which methods are tools and how they are authorized, and the\n * build's generated catalog OF THAT CONTRACT says what each tool's title, documentation and schemas\n * are. The title and the description are JSDoc (`@summary` and the body), which only the compiler can\n * read, so the catalog is their one runtime source (#1296).\n *\n * ## Why the schemas come from the catalog and not from here\n *\n * They used to be built at boot by `DtoSchemaBuilder` walking reflect-metadata. That made the\n * document a partner reads and the schema a server accepts two independent derivations of one\n * contract, free to disagree; and it could not see a field's declared TYPE at all, so every fact\n * about a field had to be restated in a `@WpDtoField` argument. #983 measured the compiler against\n * it and found the compiler reproduces all of it, so #984 deleted the decorator and this registry\n * now READS the same catalogs the documents were rendered beside.\n *\n * ## One catalog per bound contract, exactly (#1021)\n *\n * `wp-openapi` writes one `mcp-<ContractClass>-tools.json` per contract, and this registry pairs every\n * `McpApiBinding` with the file of its own contract. Three mismatches refuse the boot, all reported at\n * once, each naming every directory the catalogs were read from:\n *\n * - a bound contract with no catalog — its tools were never given a schema by the build;\n * - a catalog whose contract is not bound — the server was handed tools it does not serve;\n * - a tool name declared twice — the protocol namespace is flat.\n *\n * A registered `@WpMcpTool` the catalog does not name is likewise a HARD FAILURE, not a fallback: a\n * tool the build never saw is a tool whose schema nobody checked.\n */\nexport class McpToolRegistry {\n readonly tools: readonly RegisteredMcpTool[];\n\n constructor(\n bindings: readonly McpApiBinding[],\n catalogs: readonly McpToolCatalog[],\n private readonly authorizationService: AuthorizationService,\n ) {\n const pairing = new McpCatalogPairing(catalogs);\n const registered: RegisteredMcpTool[] = [];\n const names = new Set<string>();\n for (const binding of bindings) {\n const apiClass = binding.api;\n // MCP membership is declared twice — on @ApiType and on the methods — and this is the\n // one call that makes the two disagree impossible. It existed before #984 and nothing\n // reached it, so a contract could carry tools nobody published to agents.\n assertApiTypeMatchesMcpTools(apiClass);\n const declared = getWpMcpTools(apiClass);\n const catalog = pairing.claim(apiClass, declared.length);\n for (const entry of catalog?.file.tools ?? []) {\n if (!declared.some((metadata: WpMcpToolMetadata) => metadata.name === entry.name)) {\n pairing.problem(\n `Stale tool '${entry.name}' in ${catalog!.file.fileName}; rebuild the api library.`,\n );\n }\n }\n for (const metadata of declared) {\n if (names.has(metadata.name)) {\n pairing.problem(\n `Duplicate @WpMcpTool name '${metadata.name}' (again on ${apiClass.name}). Tool ` +\n 'names are the protocol identity and must be globally unique — rename one.',\n );\n continue;\n }\n names.add(metadata.name);\n const tool = this.resolve(apiClass, metadata, binding, catalog, pairing);\n if (tool !== undefined) registered.push(tool);\n }\n }\n pairing.assertComplete();\n this.tools = registered;\n }\n\n find(name: string): RegisteredMcpTool | undefined {\n return this.tools.find((tool: RegisteredMcpTool) => tool.name === name);\n }\n\n /**\n * The contract checks THROW at once — they are about the contract source, not the build. A tool\n * missing from its catalog is RECORDED on `pairing`, so one boot names every catalog mismatch.\n */\n private resolve(\n apiClass: ClassType,\n metadata: WpMcpToolMetadata,\n binding: McpApiBinding,\n catalog: McpToolCatalog | undefined,\n pairing: McpCatalogPairing,\n ): RegisteredMcpTool | undefined {\n const endpoints = getEndpoints(apiClass) ?? {};\n if (!endpoints[metadata.methodName]) {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must also be an @Endpoint.`,\n );\n }\n if (getEndpointKind(apiClass, metadata.methodName) !== 'rpc') {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must be an RPC endpoint.`,\n );\n }\n const authMeta = getAuthMeta(apiClass, metadata.methodName);\n if (!authMeta)\n throw new Error(`@WpMcpTool ${apiClass.name}.${metadata.methodName} has no HTTP auth.`);\n const authorization = getAuthorization(apiClass, metadata.methodName);\n if (!authorization) {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must declare @WpAuthorization(...).`,\n );\n }\n this.authorizationService.validate(authorization);\n binding.validateMethod(metadata.methodName, this.authorizationService);\n if (catalog === undefined) return undefined;\n const published = this.published(apiClass, metadata, catalog, pairing);\n if (published === undefined) return undefined;\n return new RegisteredMcpTool(\n apiClass,\n metadata.methodName,\n metadata.name,\n published.title,\n published.description,\n published.hints,\n getEndpointOperation(apiClass, metadata.methodName),\n authMeta,\n authorization,\n binding,\n published.inputSchema,\n published.outputSchema,\n published.profiles,\n );\n }\n\n /** The generated entry for this tool, or a recorded refusal naming what the build DID publish. */\n private published(\n apiClass: ClassType,\n metadata: WpMcpToolMetadata,\n catalog: McpToolCatalog,\n pairing: McpCatalogPairing,\n ): McpToolDefinition | undefined {\n const published = catalog.find(metadata.name);\n if (published === undefined) {\n pairing.problem(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} publishes '${metadata.name}', which ` +\n `${catalog.file.fileName} (${catalog.directory}) does not contain. It has: ` +\n `${catalog.names().join(', ') || '(nothing)'}. The catalog is older than the contract — ` +\n 'rebuild the api library; a tool the build never saw is a tool whose schema nobody checked.',\n );\n return undefined;\n }\n if (\n published.methodName !== metadata.methodName ||\n published.profiles.join(',') !== metadata.profiles.join(',')\n ) {\n pairing.problem(\n `MCP tool '${metadata.name}' has stale method/profile metadata in ${catalog.file.fileName}; rebuild the api library.`,\n );\n return undefined;\n }\n return published;\n }\n}\n\n/**\n * Pairs each bound contract with the catalog of exactly that contract, and collects every mismatch so\n * the boot refusal lists them all at once instead of one per restart.\n */\nclass McpCatalogPairing {\n private readonly byContract = new Map<string, McpToolCatalog>();\n private readonly claimed = new Set<string>();\n private readonly problems: string[] = [];\n\n constructor(private readonly catalogs: readonly McpToolCatalog[]) {\n for (const catalog of catalogs) {\n const earlier = this.byContract.get(catalog.contractName);\n if (earlier !== undefined) {\n this.problem(\n `Two MCP tool catalogs for ${catalog.contractName}: ${earlier.directory} and ` +\n `${catalog.directory}. Name each api library in fromPackages(...) once, and bind ` +\n 'each contract from exactly one of them.',\n );\n continue;\n }\n this.byContract.set(catalog.contractName, catalog);\n }\n }\n\n /** The catalog of `apiClass`, recording a problem when there is none. */\n claim(apiClass: ClassType, declaredTools: number): McpToolCatalog | undefined {\n const catalog = this.byContract.get(apiClass.name);\n this.claimed.add(apiClass.name);\n if (catalog !== undefined) return catalog;\n this.problem(\n declaredTools === 0\n ? `The server binds ${apiClass.name}, which declares no @WpMcpTool method, so the build ` +\n `wrote no ${McpToolCatalogFile.fileNameFor(apiClass.name)} for it. Delete its ` +\n 'McpApiBinding — it publishes nothing.'\n : `The server binds ${apiClass.name}, and no ${McpToolCatalogFile.fileNameFor(apiClass.name)} ` +\n 'was handed to it. Add the api library that declares it to McpToolCatalog.fromPackages([...]) ' +\n 'and rebuild that library (its openapi-generate target writes the file).',\n );\n return undefined;\n }\n\n problem(text: string): void {\n this.problems.push(text);\n }\n\n /** Refuse the boot on any mismatch, naming every problem and every directory searched. */\n assertComplete(): void {\n for (const catalog of this.byContract.values()) {\n if (this.claimed.has(catalog.contractName)) continue;\n this.problem(\n `${catalog.file.fileName} (${catalog.directory}) is the catalog of ${catalog.contractName}, ` +\n `which the server does not bind. Bind it with McpApiBinding.local(${catalog.contractName}, ...) ` +\n 'or .remote(...), or leave it out of toolCatalogs, e.g. ' +\n `catalogs.filter((catalog: McpToolCatalog) => catalog.contractName !== '${catalog.contractName}').`,\n );\n }\n if (this.problems.length === 0) return;\n const directories = [\n ...new Set(this.catalogs.map((catalog: McpToolCatalog) => catalog.directory)),\n ];\n throw new McpToolCatalogError(\n 'The MCP tool catalogs do not match the bound contracts:\\n' +\n this.problems.map((text: string) => ` - ${text}`).join('\\n') +\n '\\nDirectories searched for mcp-<ContractClass>-tools.json:\\n' +\n (directories.length === 0\n ? ' (none — toolCatalogs is empty)'\n : directories.map((dir: string) => ` ${dir}`).join('\\n')) +\n '\\n',\n 'Each bound contract needs exactly the one catalog its api library build writes, and nothing else.',\n );\n }\n}\n\n/** Request-specific authorized projection, shared by documentation, schema lookup and name lookup. */\nexport class AuthorizedMcpTools {\n constructor(public readonly tools: readonly RegisteredMcpTool[]) {}\n\n find(name: string): RegisteredMcpTool | undefined {\n return this.tools.find((tool: RegisteredMcpTool) => tool.name === name);\n }\n\n // webpieces-disable no-function-outside-class -- asynchronous projection factory\n static async create(\n registry: McpToolRegistry,\n policy: AuthorizationService,\n profiles: readonly string[],\n ): Promise<AuthorizedMcpTools> {\n const tools: RegisteredMcpTool[] = [];\n const authorization = new McpToolPolicy(policy);\n for (const tool of [...registry.tools].sort((a: RegisteredMcpTool, b: RegisteredMcpTool) =>\n a.name.localeCompare(b.name),\n )) {\n if (!tool.profiles.some((profile: string) => profiles.includes(profile))) continue;\n if (await authorization.permits(tool.authorization)) tools.push(tool);\n }\n return new AuthorizedMcpTools(tools);\n }\n}\n"]}
|
package/src/WpMcpServer.js
CHANGED
|
@@ -37,7 +37,8 @@ class McpEdgeRequest {
|
|
|
37
37
|
/**
|
|
38
38
|
* `Tool.annotations` exactly as tools/list publishes it: the four hints PLUS the human-readable
|
|
39
39
|
* `title` (#1180). The Claude Connectors Directory checks `annotations.title`; clients on the
|
|
40
|
-
* 2025-06-18+ spec render the top-level `Tool.title`, so both carry the one
|
|
40
|
+
* 2025-06-18+ spec render the top-level `Tool.title`, so both carry the one title — the method's
|
|
41
|
+
* `@summary` JSDoc tag, read from the generated catalog (#1296).
|
|
41
42
|
*/
|
|
42
43
|
class McpPublishedToolAnnotations {
|
|
43
44
|
title;
|
|
@@ -311,6 +312,9 @@ class WpMcpServer {
|
|
|
311
312
|
}
|
|
312
313
|
const server = new WpSdkMcpServer({
|
|
313
314
|
name: this.config.name,
|
|
315
|
+
title: this.config.title,
|
|
316
|
+
description: this.config.description,
|
|
317
|
+
websiteUrl: this.config.websiteUrl,
|
|
314
318
|
version: `${this.config.version}+${this.revision}`,
|
|
315
319
|
...(this.icons === undefined ? {} : { icons: [...this.icons] }),
|
|
316
320
|
}, {
|
package/src/WpMcpServer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolDeniedError } from './McpToolPolicy';\nimport { createHash } from 'node:crypto';\nimport {\n AuthInfo,\n CallToolRequest,\n CallToolResult,\n createMcpHandler,\n ListToolsResult,\n McpHttpHandler,\n McpRequestContext,\n McpServer,\n ProgressToken,\n ProtocolError,\n ServerContext,\n ServerOptions,\n Tool,\n Implementation,\n Icon,\n} from '@modelcontextprotocol/server';\nimport { NodeMcpRequestHandler, toNodeHandler } from '@modelcontextprotocol/node';\nimport { Express, json, NextFunction, Request, Response } from 'express';\nimport {\n ApiBadRequestError,\n ApiErrorBoundary,\n ApiForbiddenError,\n ApiImplementationError,\n ApiJsonSchemaValidator,\n ApiMethodInfo,\n ApiUnauthorizedError,\n DtoValue,\n LogApiCallImpl,\n LogManager,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport {\n HttpRequest,\n RequestContext,\n RequestContextApiCallContext,\n RequestContextHeaders,\n} from '@webpieces/core-context';\nimport { ExpressResponseWriter } from '@webpieces/http-server';\nimport { AuthenticatedCallerContext } from '@webpieces/http-routing';\nimport {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpBindOptions } from './McpBindOptions';\nimport { McpInvocationContext, McpProgressReporter } from './McpInvocationContext';\nimport { AuthorizedMcpTools, McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nimport { McpCorrelation } from './McpToolCallRendering';\nimport { 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 `@WpMcpTool` title.\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),\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 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, name));\n const tool = authentication.tools.find(name);\n if (!tool) throw this.translator.unknownTool(name);\n McpCorrelation.stamp(new McpCorrelation(sdkContext.mcpReq.id, name, tool.operation));\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 typeof name === 'string' ? name : undefined,\n );\n }\n\n private challenge(): string {\n return `Bearer resource_metadata=\"${this.config.resourceMetadataUrl}\"`;\n }\n\n private bodyObject(value: DtoValue | undefined): Record<string, DtoValue> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;\n return value as Record<string, DtoValue>;\n }\n\n private hasProgressToken(body: DtoValue): boolean {\n const params = this.bodyObject(this.bodyObject(body)?.['params']);\n return this.bodyObject(params?.['_meta'])?.['progressToken'] !== undefined;\n }\n\n private toHttpRequest(req: Request): HttpRequest {\n const headers = new Map<string, string[]>();\n for (const [name, value] of Object.entries(req.headers)) {\n if (typeof value === 'string') headers.set(name, [value]);\n else if (Array.isArray(value)) headers.set(name, value);\n }\n return new HttpRequest(req.method, req.originalUrl || req.path, headers);\n }\n\n private calculateRegistryRevision(registry: McpToolRegistry): string {\n const surface = registry.tools.map((tool: RegisteredMcpTool) => [\n tool.name,\n tool.title,\n tool.description,\n tool.inputSchema,\n tool.outputSchema,\n tool.annotations,\n tool.profiles,\n ]);\n return createHash('sha256')\n .update(JSON.stringify([this.toolProfiles, surface]))\n .digest('hex')\n .slice(0, 12);\n }\n\n private requireRegistry(): McpToolRegistry {\n if (!this.registry) throw new Error('Call WpMcpServer.bind(...) before serving requests.');\n return this.registry;\n }\n\n private record(value: DtoValue): Record<string, DtoValue> {\n const jsonValue = JSON.stringify(value);\n if (jsonValue === undefined) {\n throw new ApiImplementationError('MCP structured content is not JSON serializable.');\n }\n const parsed = JSON.parse(jsonValue) as DtoValue;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { value: parsed };\n }\n return parsed as Record<string, DtoValue>;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { McpToolDeniedError } from './McpToolPolicy';\nimport { createHash } from 'node:crypto';\nimport {\n AuthInfo,\n CallToolRequest,\n CallToolResult,\n createMcpHandler,\n ListToolsResult,\n McpHttpHandler,\n McpRequestContext,\n McpServer,\n ProgressToken,\n ProtocolError,\n ServerContext,\n ServerOptions,\n Tool,\n Implementation,\n Icon,\n} from '@modelcontextprotocol/server';\nimport { NodeMcpRequestHandler, toNodeHandler } from '@modelcontextprotocol/node';\nimport { Express, json, NextFunction, Request, Response } from 'express';\nimport {\n ApiBadRequestError,\n ApiErrorBoundary,\n ApiForbiddenError,\n ApiImplementationError,\n ApiJsonSchemaValidator,\n ApiMethodInfo,\n ApiUnauthorizedError,\n DtoValue,\n LogApiCallImpl,\n LogManager,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport {\n HttpRequest,\n RequestContext,\n RequestContextApiCallContext,\n RequestContextHeaders,\n} from '@webpieces/core-context';\nimport { ExpressResponseWriter } from '@webpieces/http-server';\nimport { AuthenticatedCallerContext } from '@webpieces/http-routing';\nimport {\n MAX_MCP_ACCESS_TOKEN_LIFETIME_SECONDS,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpBindOptions } from './McpBindOptions';\nimport { McpInvocationContext, McpProgressReporter } from './McpInvocationContext';\nimport { AuthorizedMcpTools, McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nimport { McpCorrelation } from './McpToolCallRendering';\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),\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, name));\n const tool = authentication.tools.find(name);\n if (!tool) throw this.translator.unknownTool(name);\n McpCorrelation.stamp(new McpCorrelation(sdkContext.mcpReq.id, name, tool.operation));\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 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,13 +1,29 @@
|
|
|
1
1
|
import { McpToolCatalog } from '../McpToolCatalog';
|
|
2
2
|
import { SearchRequest, SearchResponse } from './WpMcpServerTestFixtures';
|
|
3
3
|
export declare abstract class ProfileApi {
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Learner-only tool.
|
|
6
|
+
*
|
|
7
|
+
* @summary Learner
|
|
8
|
+
*/
|
|
5
9
|
learner(_request: SearchRequest): Promise<SearchResponse>;
|
|
6
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Admin-only tool.
|
|
12
|
+
*
|
|
13
|
+
* @summary Admin
|
|
14
|
+
*/
|
|
7
15
|
admin(_request: SearchRequest): Promise<SearchResponse>;
|
|
8
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Shared tool that still requires admin authority.
|
|
18
|
+
*
|
|
19
|
+
* @summary Shared
|
|
20
|
+
*/
|
|
9
21
|
shared(_request: SearchRequest): Promise<SearchResponse>;
|
|
10
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* A third independently selectable group.
|
|
24
|
+
*
|
|
25
|
+
* @summary Course
|
|
26
|
+
*/
|
|
11
27
|
course(_request: SearchRequest): Promise<SearchResponse>;
|
|
12
28
|
}
|
|
13
29
|
export declare class ProfileController extends ProfileApi {
|
|
@@ -7,19 +7,35 @@ const core_util_1 = require("@webpieces/core-util");
|
|
|
7
7
|
const McpToolCatalog_1 = require("../McpToolCatalog");
|
|
8
8
|
const WpMcpServerTestFixtures_1 = require("./WpMcpServerTestFixtures");
|
|
9
9
|
let ProfileApi = class ProfileApi {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Learner-only tool.
|
|
12
|
+
*
|
|
13
|
+
* @summary Learner
|
|
14
|
+
*/
|
|
11
15
|
learner(_request) {
|
|
12
16
|
throw new Error('contract');
|
|
13
17
|
}
|
|
14
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Admin-only tool.
|
|
20
|
+
*
|
|
21
|
+
* @summary Admin
|
|
22
|
+
*/
|
|
15
23
|
admin(_request) {
|
|
16
24
|
throw new Error('contract');
|
|
17
25
|
}
|
|
18
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Shared tool that still requires admin authority.
|
|
28
|
+
*
|
|
29
|
+
* @summary Shared
|
|
30
|
+
*/
|
|
19
31
|
shared(_request) {
|
|
20
32
|
throw new Error('contract');
|
|
21
33
|
}
|
|
22
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* A third independently selectable group.
|
|
36
|
+
*
|
|
37
|
+
* @summary Course
|
|
38
|
+
*/
|
|
23
39
|
course(_request) {
|
|
24
40
|
throw new Error('contract');
|
|
25
41
|
}
|
|
@@ -29,7 +45,7 @@ tslib_1.__decorate([
|
|
|
29
45
|
(0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
|
|
30
46
|
(0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ALL_USERS }),
|
|
31
47
|
(0, core_util_1.Endpoint)(core_util_1.POST, '/learner', core_util_1.READ, core_util_1.RPC),
|
|
32
|
-
(0, core_util_1.WpMcpTool)('learner'
|
|
48
|
+
(0, core_util_1.WpMcpTool)('learner'),
|
|
33
49
|
tslib_1.__metadata("design:type", Function),
|
|
34
50
|
tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
|
|
35
51
|
tslib_1.__metadata("design:returntype", Promise)
|
|
@@ -38,7 +54,7 @@ tslib_1.__decorate([
|
|
|
38
54
|
(0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
|
|
39
55
|
(0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ROLES, roles: ['admin'] }),
|
|
40
56
|
(0, core_util_1.Endpoint)(core_util_1.POST, '/admin', core_util_1.READ, core_util_1.RPC),
|
|
41
|
-
(0, core_util_1.WpMcpTool)('admin',
|
|
57
|
+
(0, core_util_1.WpMcpTool)('admin', { profiles: ['admin'] }),
|
|
42
58
|
tslib_1.__metadata("design:type", Function),
|
|
43
59
|
tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
|
|
44
60
|
tslib_1.__metadata("design:returntype", Promise)
|
|
@@ -47,7 +63,7 @@ tslib_1.__decorate([
|
|
|
47
63
|
(0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
|
|
48
64
|
(0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ROLES, roles: ['admin'] }),
|
|
49
65
|
(0, core_util_1.Endpoint)(core_util_1.POST, '/shared', core_util_1.READ, core_util_1.RPC),
|
|
50
|
-
(0, core_util_1.WpMcpTool)('shared',
|
|
66
|
+
(0, core_util_1.WpMcpTool)('shared', { profiles: [core_util_1.Mcp.DEFAULT, 'admin'] }),
|
|
51
67
|
tslib_1.__metadata("design:type", Function),
|
|
52
68
|
tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
|
|
53
69
|
tslib_1.__metadata("design:returntype", Promise)
|
|
@@ -56,7 +72,7 @@ tslib_1.__decorate([
|
|
|
56
72
|
(0, core_util_1.WpAuth)([(0, core_util_1.jwt)()]),
|
|
57
73
|
(0, core_util_1.WpAuthorization)({ authType: core_util_1.AuthorizationType.ALL_USERS }),
|
|
58
74
|
(0, core_util_1.Endpoint)(core_util_1.POST, '/course', core_util_1.READ, core_util_1.RPC),
|
|
59
|
-
(0, core_util_1.WpMcpTool)('course',
|
|
75
|
+
(0, core_util_1.WpMcpTool)('course', { profiles: ['course-authoring'] }),
|
|
60
76
|
tslib_1.__metadata("design:type", Function),
|
|
61
77
|
tslib_1.__metadata("design:paramtypes", [WpMcpServerTestFixtures_1.SearchRequest]),
|
|
62
78
|
tslib_1.__metadata("design:returntype", Promise)
|
|
@@ -96,5 +112,5 @@ class SearchResponseValue extends WpMcpServerTestFixtures_1.SearchResponse {
|
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
const schema = WpMcpServerTestFixtures_1.SEARCH_API_CATALOG.file.tools[0];
|
|
99
|
-
exports.PROFILE_CATALOG = new McpToolCatalog_1.McpToolCatalog(new core_util_1.McpToolCatalogFile('ProfileApi', (0, core_util_1.getWpMcpTools)(ProfileApi).map((tool) => new core_util_1.McpToolDefinition(tool.name, tool.
|
|
115
|
+
exports.PROFILE_CATALOG = new McpToolCatalog_1.McpToolCatalog(new core_util_1.McpToolCatalogFile('ProfileApi', (0, core_util_1.getWpMcpTools)(ProfileApi).map((tool) => new core_util_1.McpToolDefinition(tool.name, `Profile ${tool.name} tool`, tool.methodName, 'Profile fixture', (0, core_util_1.mcpHintsForOperation)(core_util_1.READ, false), schema.inputSchema, schema.outputSchema, tool.profiles))), '(profile fixture)');
|
|
100
116
|
//# sourceMappingURL=McpProfileFixtures.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpProfileFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/McpProfileFixtures.ts"],"names":[],"mappings":";;;;AAAA,yCAAuC;AACvC,oDAoB8B;AAC9B,sDAAmD;AACnD,uEAA8F;AAIvF,IAAe,UAAU,GAAzB,MAAe,UAAU;IAC5B
|
|
1
|
+
{"version":3,"file":"McpProfileFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/McpProfileFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { injectable } from 'inversify';\nimport {\n ApiPath,\n ApiType,\n Endpoint,\n POST,\n READ,\n RPC,\n MCP,\n SVC_TO_SVC,\n Mcp,\n WpAuth,\n jwt,\n WpAuthorization,\n AuthorizationType,\n WpMcpTool,\n WpMcpToolMetadata,\n getWpMcpTools,\n McpToolCatalogFile,\n McpToolDefinition,\n mcpHintsForOperation,\n} from '@webpieces/core-util';\nimport { McpToolCatalog } from '../McpToolCatalog';\nimport { SEARCH_API_CATALOG, SearchRequest, SearchResponse } from './WpMcpServerTestFixtures';\n\n@ApiPath('/profile-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class ProfileApi {\n /**\n * Learner-only tool.\n *\n * @summary Learner\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/learner', READ, RPC)\n @WpMcpTool('learner')\n learner(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract');\n }\n\n /**\n * Admin-only tool.\n *\n * @summary Admin\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', READ, RPC)\n @WpMcpTool('admin', { profiles: ['admin'] })\n admin(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract');\n }\n\n /**\n * Shared tool that still requires admin authority.\n *\n * @summary Shared\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/shared', READ, RPC)\n @WpMcpTool('shared', { profiles: [Mcp.DEFAULT, 'admin'] })\n shared(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract');\n }\n\n /**\n * A third independently selectable group.\n *\n * @summary Course\n */\n @WpAuth([jwt()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/course', READ, RPC)\n @WpMcpTool('course', { profiles: ['course-authoring'] })\n course(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract');\n }\n}\n\n@injectable()\nexport class ProfileController extends ProfileApi {\n calls: string[] = [];\n override async learner(request: SearchRequest): Promise<SearchResponse> {\n this.calls.push('learner');\n return new SearchResponseValue(request.query);\n }\n override async admin(request: SearchRequest): Promise<SearchResponse> {\n this.calls.push('admin');\n return new SearchResponseValue(request.query);\n }\n override async shared(request: SearchRequest): Promise<SearchResponse> {\n this.calls.push('shared');\n return new SearchResponseValue(request.query);\n }\n override async course(request: SearchRequest): Promise<SearchResponse> {\n this.calls.push('course');\n return new SearchResponseValue(request.query);\n }\n}\n\nclass SearchResponseValue extends SearchResponse {\n constructor(query: string) {\n super();\n this.userId = 'profile';\n this.result = query;\n }\n}\n\nconst schema = SEARCH_API_CATALOG.file.tools[0];\nexport const PROFILE_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile(\n 'ProfileApi',\n getWpMcpTools(ProfileApi).map(\n (tool: WpMcpToolMetadata) =>\n new McpToolDefinition(\n tool.name,\n `Profile ${tool.name} tool`,\n tool.methodName,\n 'Profile fixture',\n mcpHintsForOperation(READ, false),\n schema.inputSchema,\n schema.outputSchema,\n tool.profiles,\n ),\n ),\n ),\n '(profile fixture)',\n);\n"]}
|
|
@@ -32,31 +32,59 @@ export declare const REMOTE_MCP_CATALOG: McpToolCatalog;
|
|
|
32
32
|
/** The catalogs of every contract the gateway binds — one per contract, exactly as a build writes them. */
|
|
33
33
|
export declare const GATEWAY_CATALOGS: readonly McpToolCatalog[];
|
|
34
34
|
export declare abstract class RemoteMcpApi {
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Calls a remote Webpieces API.
|
|
37
|
+
*
|
|
38
|
+
* @summary Remote integration search
|
|
39
|
+
*/
|
|
36
40
|
search(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
37
41
|
}
|
|
38
42
|
export declare abstract class MissingRemoteMcpApi {
|
|
39
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Intentionally absent route.
|
|
45
|
+
*
|
|
46
|
+
* @summary Missing remote integration search
|
|
47
|
+
*/
|
|
40
48
|
search(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
41
49
|
}
|
|
42
50
|
export declare abstract class RefusedRemoteApi {
|
|
43
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Nothing listens on this port.
|
|
53
|
+
*
|
|
54
|
+
* @summary Refused remote call
|
|
55
|
+
*/
|
|
44
56
|
search(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
45
57
|
}
|
|
46
58
|
export declare abstract class GarbageRemoteApi {
|
|
47
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Answers an undecodable body.
|
|
61
|
+
*
|
|
62
|
+
* @summary Garbage remote response
|
|
63
|
+
*/
|
|
48
64
|
search(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
49
65
|
}
|
|
50
66
|
export declare abstract class OidcFailRemoteApi {
|
|
51
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Its OIDC token cannot be minted.
|
|
69
|
+
*
|
|
70
|
+
* @summary OIDC failure on remote
|
|
71
|
+
*/
|
|
52
72
|
search(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
53
73
|
}
|
|
54
74
|
export declare abstract class LocalThrowApi {
|
|
55
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* Throws the requested failure in-process.
|
|
77
|
+
*
|
|
78
|
+
* @summary Local throw
|
|
79
|
+
*/
|
|
56
80
|
fail(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
57
81
|
}
|
|
58
82
|
export declare abstract class RemoteThrowApi {
|
|
59
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Throws the requested failure remotely.
|
|
85
|
+
*
|
|
86
|
+
* @summary Remote throw
|
|
87
|
+
*/
|
|
60
88
|
fail(_request: RemoteRequest): Promise<RemoteResponse>;
|
|
61
89
|
}
|
|
62
90
|
/**
|