@webpieces/mcp-server 0.4.934 → 0.4.935
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 +29 -17
- package/package.json +6 -6
- package/src/McpToolRegistry.d.ts +13 -3
- package/src/McpToolRegistry.js +8 -8
- package/src/McpToolRegistry.js.map +1 -1
- package/src/WpMcpServer.js +2 -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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WpMcpServerTestFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/WpMcpServerTestFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { WpAuthorization, AuthorizationType, WpAuth, jwt as jwtAuth, oidcSameProject } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiBadGatewayError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndUserError, ApiRetriesExhaustedError, ApiPath, ApiType, ApiUnauthorizedError, ApiUnavailableError, Logger, LoggerFactory, LogLevel, ContextKey, ContextTuple, Endpoint, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC, WRITE } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { AuthenticatedCaller, JwtHook, MintedJwt } from '@webpieces/http-routing';\nimport { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';\nimport { MCP_INVOCATION_CONTEXT } from '../McpInvocationContext';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\nexport const USER_ID = ContextKey.trusted<string>(\n 'mcpSpecUserId',\n 'proven by a credential verifier',\n);\nexport const ENDPOINT_PATH = '/app-owned/mcp';\nexport const MODERN_VERSION = '2026-07-28';\n/** What every shipping MCP client opens with today — the top of the 2025 negotiation table. */\nexport const LEGACY_VERSION = '2025-11-25';\n/** An older 2025-era revision the negotiation table still carries. */\nexport const OLDER_LEGACY_VERSION = '2025-03-26';\n/** A revision NO era knows: the one case a server is still right to refuse. */\nexport const UNKNOWN_VERSION = '1999-01-01';\n\nexport class SearchRequest {\n /**\n * Search text\n * @mcpHeader query\n */\n query!: string;\n}\n\nexport class SearchResponse {\n /** Authenticated user */\n userId!: string;\n\n /** Search result */\n result!: string;\n}\n\n/**\n * The tool catalogs these specs boot `WpMcpServer` with — ONE PER CONTRACT, the same shape\n * `wp-openapi` writes to `mcp-<ContractClass>-tools.json` from the contracts below.\n *\n * It is built by hand here rather than extracted, because `@webpieces/mcp-server` deliberately does\n * not depend on the TypeScript compiler API: the runtime's job is to BE HANDED a catalog, and these\n * specs exercise exactly that. The extractor's own suite proves the catalog matches these contracts.\n */\nfunction searchInputSchema(): ApiJsonSchema {\n const query = new ApiJsonSchema('string');\n query.description = 'Search text';\n query['x-mcp-header'] = 'query';\n return new ObjectSchemaBuilder().required('query', query).build();\n}\n\nfunction searchOutputSchema(): ApiJsonSchema {\n const userId = new ApiJsonSchema('string');\n userId.description = 'Authenticated user';\n const result = new ApiJsonSchema('string');\n result.description = 'Search result';\n return new ObjectSchemaBuilder().required('userId', userId).required('result', result).build();\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n hints: WpMcpToolHints,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n hints,\n searchInputSchema(),\n searchOutputSchema(), [Mcp.DEFAULT],\n );\n}\n\n/** The label a hand-built catalog carries where a read one names its directory. */\nexport const IN_MEMORY = '(built in memory by the spec)';\n\nexport const SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('SearchApi', [\n searchTool(\n 'account_search',\n 'Search accounts',\n 'search',\n 'Search records owned by the authenticated user.',\n new WpMcpToolHints(true, false, true, false),\n ),\n searchTool(\n 'admin_search',\n 'Admin search',\n 'admin',\n 'Administrative search.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\nexport const REMOTE_SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('RemoteSearchApi', [\n searchTool(\n 'remote_search',\n 'Remote search',\n 'search',\n 'Search a remote binding.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\n@ApiPath('/mcp-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class SearchApi {\n /** Search records owned by the authenticated user. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search', 'Search accounts')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /** Administrative search. */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('admin_search', 'Admin search')\n admin(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteSearchApi {\n /** Search a remote binding. */\n\n @WpAuth([oidcSameProject()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('remote_search', 'Remote search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@injectable()\nexport class SearchController extends SearchApi {\n static waitStartedHook?: () => void;\n static waitAbortedHook?: () => void;\n adminInvocations = 0;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n if (request.query === 'internal') throw new Error('database password appeared here');\n // A DOWNSTREAM call of ours failed. From the model's seat that is OUR bug, never a kind of\n // its own on the wire — see #959 and ApiErrorBoundary.encode.\n if (request.query === 'downstream') {\n throw new ApiConnectionError('ECONNREFUSED private-host:8443');\n }\n if (request.query === 'human') throw new ApiEndUserError('Safe human message', 'SAFE');\n if (request.query === 'malformed') {\n throw new ApiBadRequestError(\n 'operator-only: column tenant_7 rejected',\n '$.query',\n 'query is malformed',\n );\n }\n if (request.query === 'dependency') throw new ApiDependencyError('private upstream');\n if (request.query === 'bad-gateway') throw new ApiBadGatewayError('private proxy');\n if (request.query === 'timeout') throw new ApiDependencyTimeoutError('private timeout');\n if (request.query === 'backoff') {\n throw new ApiDependencyBackoffError('private throttling detail', 37);\n }\n if (request.query === 'unavailable') throw new ApiUnavailableError('private deployment');\n if (request.query === 'exhausted') {\n throw new ApiRetriesExhaustedError(4, new ApiUnavailableError('private retries'));\n }\n const invocation = RequestContext.getTrusted(MCP_INVOCATION_CONTEXT);\n if (request.query === 'progress') {\n await invocation?.reportProgress?.(1, 2, 'halfway');\n }\n if (request.query === 'wait' && invocation) {\n await invocation.reportProgress?.(0, 1, 'waiting');\n SearchController.waitStartedHook?.();\n await new Promise<void>((resolve: () => void) => {\n const finish = (): void => {\n SearchController.waitAbortedHook?.();\n resolve();\n };\n if (invocation.signal.aborted) finish();\n else invocation.signal.addEventListener('abort', finish, { once: true });\n });\n }\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n\n override async admin(request: SearchRequest): Promise<SearchResponse> {\n this.adminInvocations += 1;\n return this.search(request);\n }\n}\n\nexport class RemoteSearchClient extends RemoteSearchApi {\n seenAuthorization?: string;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n this.seenAuthorization = RequestContext.getRequest()?.getHeader('authorization');\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n}\n\nexport class TestJwtHook extends JwtHook<string> {\n mintedTokens: string[] = [];\n lifetimeSeconds = 60;\n failWith?: Error;\n\n override async mint(subject: string): Promise<MintedJwt> {\n if (this.failWith) throw this.failWith;\n const token =\n subject === 'passthrough'\n ? 'mcp-passthrough'\n : `${subject}-endpoint-${this.mintedTokens.length + 1}`;\n this.mintedTokens.push(token);\n return new MintedJwt(token, Math.floor(Date.now() / 1000) + this.lifetimeSeconds);\n }\n\n override async parseJwt(token: string): Promise<AuthenticatedCaller> {\n if (token.startsWith('admin-endpoint-')) {\n return new AuthenticatedCaller(\n 'admin-7',\n ['admin'],\n [new ContextTuple(USER_ID, 'admin-7')],\n );\n }\n if (!token.startsWith('user-endpoint-')) throw new Error('invalid endpoint token');\n return new AuthenticatedCaller('user-7', [], [new ContextTuple(USER_ID, 'user-7')]);\n }\n}\n\nexport class TestTokenAuthority implements McpAccessTokenAuthority<string> {\n verificationCount = 0;\n roles: readonly string[] = [];\n\n async mintAccessToken(_grant: string): Promise<never> {\n throw new Error('not used');\n }\n\n async verifyAccessToken(token: string, resource: string): Promise<VerifiedMcpCredential> {\n this.verificationCount += 1;\n if (token === 'invalid') throw new ApiUnauthorizedError('invalid token');\n if (token === 'authority-bug') throw new Error('SECRET-internal-detail');\n const now = Math.floor(Date.now() / 1000);\n const actualResource =\n token === 'wrong-resource' ? 'https://attacker.example/mcp' : resource;\n const subject = token.startsWith('mcp-admin')\n ? 'admin'\n : token === 'mcp-passthrough'\n ? 'passthrough'\n : 'user';\n const issuer =\n token === 'wrong-issuer' ? 'https://attacker.example' : 'https://login.example.test';\n const expiresAt = token === 'expired' ? now - 1 : now + 60;\n const scopes = token === 'missing-scope' ? [] : ['tools'];\n const validatedAt = token === 'stale-account' ? now - 3_601 : now;\n const credential = new VerifiedMcpCredential(\n subject,\n issuer,\n actualResource,\n token === 'expired' ? now - 61 : now,\n expiresAt,\n scopes,\n validatedAt,\n new AuthenticatedCaller(\n `${subject}-7`,\n subject == 'admin' ? ['admin'] : [...this.roles],\n [new ContextTuple(USER_ID, `${subject}-7`)],\n ),\n );\n if (token === 'list-bug') {\n Object.defineProperty(credential.caller, 'roles', {\n get: (): readonly string[] => {\n throw new Error('SECRET-internal-detail');\n },\n });\n }\n return credential;\n }\n}\n\nexport class RecordedLogLine {\n constructor(\n public readonly logger: string,\n public readonly level: LogLevel,\n public readonly message: string,\n public readonly error?: Error,\n ) {}\n\n /** The rendered line an operator would see, including an attached error's message and stack. */\n rendered(): string {\n return `${this.message} ${this.error?.message ?? ''} ${this.error?.stack ?? ''}`;\n }\n}\n\nclass RecordingLogger implements Logger {\n constructor(\n private readonly name: string,\n private readonly lines: RecordedLogLine[],\n ) {}\n\n trace(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'trace', message, err));\n }\n\n debug(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'debug', message, err));\n }\n\n info(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'info', message, err));\n }\n\n warn(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'warn', message, err));\n }\n\n error(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'error', message, err));\n }\n}\n\n/** Captures every log line in-process so tests can count and level-check operator output. */\nexport class RecordingLoggerFactory implements LoggerFactory {\n readonly lines: RecordedLogLine[] = [];\n\n getLogger(name: string): Logger {\n return new RecordingLogger(name, this.lines);\n }\n\n containing(text: string): RecordedLogLine[] {\n return this.lines.filter((line: RecordedLogLine) => line.rendered().includes(text));\n }\n\n /** The lines ONE logger wrote that mention `text` — to count each owner's line separately. */\n fromLogger(logger: string, text: string): RecordedLogLine[] {\n return this.containing(text).filter((line: RecordedLogLine) => line.logger === logger);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WpMcpServerTestFixtures.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/__tests__/WpMcpServerTestFixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Mcp } from '@webpieces/core-util';\nimport { WpAuthorization, AuthorizationType, WpAuth, jwt as jwtAuth, oidcSameProject } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { injectable } from 'inversify';\nimport { ApiBadRequestError, ApiBadGatewayError, ApiConnectionError, ApiDependencyBackoffError, ApiDependencyError, ApiDependencyTimeoutError, ApiEndUserError, ApiRetriesExhaustedError, ApiPath, ApiType, ApiUnauthorizedError, ApiUnavailableError, Logger, LoggerFactory, LogLevel, ContextKey, ContextTuple, Endpoint, ApiJsonSchema, McpToolCatalogFile, McpToolDefinition, ObjectSchemaBuilder, WpMcpTool, WpMcpToolHints, MCP, POST, READ, RPC, SVC_TO_SVC, WRITE } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\nimport { AuthenticatedCaller, JwtHook, MintedJwt } from '@webpieces/http-routing';\nimport { McpAccessTokenAuthority, VerifiedMcpCredential } from '../McpAuth';\nimport { MCP_INVOCATION_CONTEXT } from '../McpInvocationContext';\nimport { McpToolCatalog } from '../McpToolCatalog';\n\nexport const USER_ID = ContextKey.trusted<string>(\n 'mcpSpecUserId',\n 'proven by a credential verifier',\n);\nexport const ENDPOINT_PATH = '/app-owned/mcp';\nexport const MODERN_VERSION = '2026-07-28';\n/** What every shipping MCP client opens with today — the top of the 2025 negotiation table. */\nexport const LEGACY_VERSION = '2025-11-25';\n/** An older 2025-era revision the negotiation table still carries. */\nexport const OLDER_LEGACY_VERSION = '2025-03-26';\n/** A revision NO era knows: the one case a server is still right to refuse. */\nexport const UNKNOWN_VERSION = '1999-01-01';\n\nexport class SearchRequest {\n /**\n * Search text\n * @mcpHeader query\n */\n query!: string;\n}\n\nexport class SearchResponse {\n /** Authenticated user */\n userId!: string;\n\n /** Search result */\n result!: string;\n}\n\n/**\n * The tool catalogs these specs boot `WpMcpServer` with — ONE PER CONTRACT, the same shape\n * `wp-openapi` writes to `mcp-<ContractClass>-tools.json` from the contracts below.\n *\n * It is built by hand here rather than extracted, because `@webpieces/mcp-server` deliberately does\n * not depend on the TypeScript compiler API: the runtime's job is to BE HANDED a catalog, and these\n * specs exercise exactly that. The extractor's own suite proves the catalog matches these contracts.\n */\nfunction searchInputSchema(): ApiJsonSchema {\n const query = new ApiJsonSchema('string');\n query.description = 'Search text';\n query['x-mcp-header'] = 'query';\n return new ObjectSchemaBuilder().required('query', query).build();\n}\n\nfunction searchOutputSchema(): ApiJsonSchema {\n const userId = new ApiJsonSchema('string');\n userId.description = 'Authenticated user';\n const result = new ApiJsonSchema('string');\n result.description = 'Search result';\n return new ObjectSchemaBuilder().required('userId', userId).required('result', result).build();\n}\n\nfunction searchTool(\n name: string,\n title: string,\n methodName: string,\n description: string,\n hints: WpMcpToolHints,\n): McpToolDefinition {\n return new McpToolDefinition(\n name,\n title,\n methodName,\n description,\n hints,\n searchInputSchema(),\n searchOutputSchema(), [Mcp.DEFAULT],\n );\n}\n\n/** The label a hand-built catalog carries where a read one names its directory. */\nexport const IN_MEMORY = '(built in memory by the spec)';\n\nexport const SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('SearchApi', [\n searchTool(\n 'account_search',\n 'Search accounts',\n 'search',\n 'Search records owned by the authenticated user.',\n new WpMcpToolHints(true, false, true, false),\n ),\n searchTool(\n 'admin_search',\n 'Admin search',\n 'admin',\n 'Administrative search.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\nexport const REMOTE_SEARCH_API_CATALOG = new McpToolCatalog(\n new McpToolCatalogFile('RemoteSearchApi', [\n searchTool(\n 'remote_search',\n 'Remote search',\n 'search',\n 'Search a remote binding.',\n new WpMcpToolHints(false, true, false, false),\n ),\n ]),\n IN_MEMORY,\n);\n\n@ApiPath('/mcp-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class SearchApi {\n /**\n * Search records owned by the authenticated user.\n *\n * @summary Search accounts\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ALL_USERS })\n @Endpoint(POST, '/search', READ, RPC)\n @WpMcpTool('account_search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n\n /**\n * Administrative search.\n *\n * @summary Admin search\n */\n\n @WpAuth([jwtAuth()])\n @WpAuthorization({ authType: AuthorizationType.ROLES, roles: ['admin'] })\n @Endpoint(POST, '/admin', WRITE, RPC)\n @WpMcpTool('admin_search')\n admin(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@ApiPath('/remote-spec')\n@ApiType(SVC_TO_SVC, MCP)\nexport abstract class RemoteSearchApi {\n /**\n * Search a remote binding.\n *\n * @summary Remote search\n */\n\n @WpAuth([oidcSameProject()])\n @WpAuthorization({ authType: AuthorizationType.USERS_OR_SERVICES })\n @Endpoint(POST, '/search', WRITE, RPC)\n @WpMcpTool('remote_search')\n search(_request: SearchRequest): Promise<SearchResponse> {\n throw new Error('contract only');\n }\n}\n\n@injectable()\nexport class SearchController extends SearchApi {\n static waitStartedHook?: () => void;\n static waitAbortedHook?: () => void;\n adminInvocations = 0;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n if (request.query === 'internal') throw new Error('database password appeared here');\n // A DOWNSTREAM call of ours failed. From the model's seat that is OUR bug, never a kind of\n // its own on the wire — see #959 and ApiErrorBoundary.encode.\n if (request.query === 'downstream') {\n throw new ApiConnectionError('ECONNREFUSED private-host:8443');\n }\n if (request.query === 'human') throw new ApiEndUserError('Safe human message', 'SAFE');\n if (request.query === 'malformed') {\n throw new ApiBadRequestError(\n 'operator-only: column tenant_7 rejected',\n '$.query',\n 'query is malformed',\n );\n }\n if (request.query === 'dependency') throw new ApiDependencyError('private upstream');\n if (request.query === 'bad-gateway') throw new ApiBadGatewayError('private proxy');\n if (request.query === 'timeout') throw new ApiDependencyTimeoutError('private timeout');\n if (request.query === 'backoff') {\n throw new ApiDependencyBackoffError('private throttling detail', 37);\n }\n if (request.query === 'unavailable') throw new ApiUnavailableError('private deployment');\n if (request.query === 'exhausted') {\n throw new ApiRetriesExhaustedError(4, new ApiUnavailableError('private retries'));\n }\n const invocation = RequestContext.getTrusted(MCP_INVOCATION_CONTEXT);\n if (request.query === 'progress') {\n await invocation?.reportProgress?.(1, 2, 'halfway');\n }\n if (request.query === 'wait' && invocation) {\n await invocation.reportProgress?.(0, 1, 'waiting');\n SearchController.waitStartedHook?.();\n await new Promise<void>((resolve: () => void) => {\n const finish = (): void => {\n SearchController.waitAbortedHook?.();\n resolve();\n };\n if (invocation.signal.aborted) finish();\n else invocation.signal.addEventListener('abort', finish, { once: true });\n });\n }\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n\n override async admin(request: SearchRequest): Promise<SearchResponse> {\n this.adminInvocations += 1;\n return this.search(request);\n }\n}\n\nexport class RemoteSearchClient extends RemoteSearchApi {\n seenAuthorization?: string;\n\n override async search(request: SearchRequest): Promise<SearchResponse> {\n this.seenAuthorization = RequestContext.getRequest()?.getHeader('authorization');\n return { userId: RequestContext.getTrusted(USER_ID) ?? 'missing', result: request.query };\n }\n}\n\nexport class TestJwtHook extends JwtHook<string> {\n mintedTokens: string[] = [];\n lifetimeSeconds = 60;\n failWith?: Error;\n\n override async mint(subject: string): Promise<MintedJwt> {\n if (this.failWith) throw this.failWith;\n const token =\n subject === 'passthrough'\n ? 'mcp-passthrough'\n : `${subject}-endpoint-${this.mintedTokens.length + 1}`;\n this.mintedTokens.push(token);\n return new MintedJwt(token, Math.floor(Date.now() / 1000) + this.lifetimeSeconds);\n }\n\n override async parseJwt(token: string): Promise<AuthenticatedCaller> {\n if (token.startsWith('admin-endpoint-')) {\n return new AuthenticatedCaller(\n 'admin-7',\n ['admin'],\n [new ContextTuple(USER_ID, 'admin-7')],\n );\n }\n if (!token.startsWith('user-endpoint-')) throw new Error('invalid endpoint token');\n return new AuthenticatedCaller('user-7', [], [new ContextTuple(USER_ID, 'user-7')]);\n }\n}\n\nexport class TestTokenAuthority implements McpAccessTokenAuthority<string> {\n verificationCount = 0;\n roles: readonly string[] = [];\n\n async mintAccessToken(_grant: string): Promise<never> {\n throw new Error('not used');\n }\n\n async verifyAccessToken(token: string, resource: string): Promise<VerifiedMcpCredential> {\n this.verificationCount += 1;\n if (token === 'invalid') throw new ApiUnauthorizedError('invalid token');\n if (token === 'authority-bug') throw new Error('SECRET-internal-detail');\n const now = Math.floor(Date.now() / 1000);\n const actualResource =\n token === 'wrong-resource' ? 'https://attacker.example/mcp' : resource;\n const subject = token.startsWith('mcp-admin')\n ? 'admin'\n : token === 'mcp-passthrough'\n ? 'passthrough'\n : 'user';\n const issuer =\n token === 'wrong-issuer' ? 'https://attacker.example' : 'https://login.example.test';\n const expiresAt = token === 'expired' ? now - 1 : now + 60;\n const scopes = token === 'missing-scope' ? [] : ['tools'];\n const validatedAt = token === 'stale-account' ? now - 3_601 : now;\n const credential = new VerifiedMcpCredential(\n subject,\n issuer,\n actualResource,\n token === 'expired' ? now - 61 : now,\n expiresAt,\n scopes,\n validatedAt,\n new AuthenticatedCaller(\n `${subject}-7`,\n subject == 'admin' ? ['admin'] : [...this.roles],\n [new ContextTuple(USER_ID, `${subject}-7`)],\n ),\n );\n if (token === 'list-bug') {\n Object.defineProperty(credential.caller, 'roles', {\n get: (): readonly string[] => {\n throw new Error('SECRET-internal-detail');\n },\n });\n }\n return credential;\n }\n}\n\nexport class RecordedLogLine {\n constructor(\n public readonly logger: string,\n public readonly level: LogLevel,\n public readonly message: string,\n public readonly error?: Error,\n ) {}\n\n /** The rendered line an operator would see, including an attached error's message and stack. */\n rendered(): string {\n return `${this.message} ${this.error?.message ?? ''} ${this.error?.stack ?? ''}`;\n }\n}\n\nclass RecordingLogger implements Logger {\n constructor(\n private readonly name: string,\n private readonly lines: RecordedLogLine[],\n ) {}\n\n trace(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'trace', message, err));\n }\n\n debug(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'debug', message, err));\n }\n\n info(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'info', message, err));\n }\n\n warn(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'warn', message, err));\n }\n\n error(message: string, err?: Error): void {\n this.lines.push(new RecordedLogLine(this.name, 'error', message, err));\n }\n}\n\n/** Captures every log line in-process so tests can count and level-check operator output. */\nexport class RecordingLoggerFactory implements LoggerFactory {\n readonly lines: RecordedLogLine[] = [];\n\n getLogger(name: string): Logger {\n return new RecordingLogger(name, this.lines);\n }\n\n containing(text: string): RecordedLogLine[] {\n return this.lines.filter((line: RecordedLogLine) => line.rendered().includes(text));\n }\n\n /** The lines ONE logger wrote that mention `text` — to count each owner's line separately. */\n fromLogger(logger: string, text: string): RecordedLogLine[] {\n return this.containing(text).filter((line: RecordedLogLine) => line.logger === logger);\n }\n}\n"]}
|