@frontmcp/testing 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/package.json +3 -3
  2. package/src/auth/mock-api-server.d.ts +99 -0
  3. package/src/auth/mock-api-server.js +200 -0
  4. package/src/auth/mock-api-server.js.map +1 -0
  5. package/src/auth/mock-oauth-server.d.ts +85 -0
  6. package/src/auth/mock-oauth-server.js +253 -0
  7. package/src/auth/mock-oauth-server.js.map +1 -0
  8. package/src/client/mcp-test-client.builder.d.ts +43 -1
  9. package/src/client/mcp-test-client.builder.js +52 -0
  10. package/src/client/mcp-test-client.builder.js.map +1 -1
  11. package/src/client/mcp-test-client.js +22 -14
  12. package/src/client/mcp-test-client.js.map +1 -1
  13. package/src/client/mcp-test-client.types.d.ts +67 -6
  14. package/src/client/mcp-test-client.types.js +9 -0
  15. package/src/client/mcp-test-client.types.js.map +1 -1
  16. package/src/example-tools/index.d.ts +19 -0
  17. package/src/example-tools/index.js +40 -0
  18. package/src/example-tools/index.js.map +1 -0
  19. package/src/example-tools/tool-configs.d.ts +170 -0
  20. package/src/example-tools/tool-configs.js +222 -0
  21. package/src/example-tools/tool-configs.js.map +1 -0
  22. package/src/expect.d.ts +6 -5
  23. package/src/expect.js.map +1 -1
  24. package/src/fixtures/fixture-types.d.ts +19 -0
  25. package/src/fixtures/fixture-types.js.map +1 -1
  26. package/src/fixtures/test-fixture.d.ts +3 -1
  27. package/src/fixtures/test-fixture.js +35 -4
  28. package/src/fixtures/test-fixture.js.map +1 -1
  29. package/src/index.d.ts +7 -0
  30. package/src/index.js +40 -1
  31. package/src/index.js.map +1 -1
  32. package/src/matchers/matcher-types.js.map +1 -1
  33. package/src/matchers/mcp-matchers.d.ts +7 -0
  34. package/src/matchers/mcp-matchers.js +8 -4
  35. package/src/matchers/mcp-matchers.js.map +1 -1
  36. package/src/platform/index.d.ts +28 -0
  37. package/src/platform/index.js +47 -0
  38. package/src/platform/index.js.map +1 -0
  39. package/src/platform/platform-client-info.d.ts +97 -0
  40. package/src/platform/platform-client-info.js +155 -0
  41. package/src/platform/platform-client-info.js.map +1 -0
  42. package/src/platform/platform-types.d.ts +72 -0
  43. package/src/platform/platform-types.js +110 -0
  44. package/src/platform/platform-types.js.map +1 -0
  45. package/src/server/test-server.d.ts +4 -0
  46. package/src/server/test-server.js +58 -3
  47. package/src/server/test-server.js.map +1 -1
  48. package/src/transport/streamable-http.transport.js +6 -0
  49. package/src/transport/streamable-http.transport.js.map +1 -1
  50. package/src/transport/transport.interface.d.ts +3 -0
  51. package/src/transport/transport.interface.js.map +1 -1
  52. package/src/ui/ui-assertions.d.ts +59 -0
  53. package/src/ui/ui-assertions.js +152 -0
  54. package/src/ui/ui-assertions.js.map +1 -1
  55. package/src/ui/ui-matchers.d.ts +8 -0
  56. package/src/ui/ui-matchers.js +218 -0
  57. package/src/ui/ui-matchers.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-oauth-server.js","sourceRoot":"","sources":["../../../src/auth/mock-oauth-server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @file mock-oauth-server.ts\n * @description Mock OAuth server for testing transparent auth mode\n *\n * This module provides a mock OAuth/OIDC server that serves:\n * - JWKS endpoint for token verification\n * - OAuth metadata endpoint (optional)\n * - Token endpoint for anonymous tokens (optional)\n *\n * @example\n * ```typescript\n * import { MockOAuthServer, TestTokenFactory } from '@frontmcp/testing';\n *\n * const tokenFactory = new TestTokenFactory();\n * const oauthServer = new MockOAuthServer(tokenFactory);\n *\n * // Start the mock server\n * await oauthServer.start();\n *\n * // Configure your MCP server to use this mock\n * // IDP_PROVIDER_URL = oauthServer.baseUrl\n *\n * // Create tokens using the same factory\n * const token = await tokenFactory.createTestToken({ sub: 'user-123' });\n *\n * // Stop when done\n * await oauthServer.stop();\n * ```\n */\n\nimport { createServer, Server, IncomingMessage, ServerResponse } from 'http';\nimport type { TestTokenFactory } from './token-factory';\n\n// ═══════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════\n\nexport interface MockOAuthServerOptions {\n /** Port to listen on (default: random available port) */\n port?: number;\n /** Issuer URL (default: http://localhost:{port}) */\n issuer?: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\nexport interface MockOAuthServerInfo {\n /** Base URL of the server */\n baseUrl: string;\n /** Port the server is listening on */\n port: number;\n /** Issuer URL */\n issuer: string;\n /** JWKS endpoint URL */\n jwksUrl: string;\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// MOCK OAUTH SERVER\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Mock OAuth/OIDC server for testing transparent auth mode\n *\n * Serves JWKS from a TestTokenFactory so that MCP servers can\n * validate test tokens without connecting to a real IdP.\n */\nexport class MockOAuthServer {\n private readonly tokenFactory: TestTokenFactory;\n private readonly options: MockOAuthServerOptions;\n private server: Server | null = null;\n private _info: MockOAuthServerInfo | null = null;\n private connections: Set<import('net').Socket> = new Set();\n\n constructor(tokenFactory: TestTokenFactory, options: MockOAuthServerOptions = {}) {\n this.tokenFactory = tokenFactory;\n this.options = options;\n }\n\n /**\n * Start the mock OAuth server\n */\n async start(): Promise<MockOAuthServerInfo> {\n if (this.server) {\n throw new Error('Mock OAuth server is already running');\n }\n\n const port = this.options.port ?? 0; // 0 = random available port\n\n return new Promise((resolve, reject) => {\n const server = createServer(this.handleRequest.bind(this));\n this.server = server;\n\n // Track connections for proper cleanup\n server.on('connection', (socket) => {\n this.connections.add(socket);\n socket.on('close', () => this.connections.delete(socket));\n });\n\n server.on('error', (err) => {\n this.log(`Server error: ${err.message}`);\n reject(err);\n });\n\n server.listen(port, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('Failed to get server address'));\n return;\n }\n\n const actualPort = address.port;\n const issuer = this.options.issuer ?? `http://localhost:${actualPort}`;\n\n this._info = {\n baseUrl: `http://localhost:${actualPort}`,\n port: actualPort,\n issuer,\n jwksUrl: `http://localhost:${actualPort}/.well-known/jwks.json`,\n };\n\n this.log(`Mock OAuth server started at ${this._info.baseUrl}`);\n resolve(this._info);\n });\n });\n }\n\n /**\n * Stop the mock OAuth server\n */\n async stop(): Promise<void> {\n const server = this.server;\n if (!server) {\n return;\n }\n\n // Destroy all active connections to allow server.close() to complete\n for (const socket of this.connections) {\n socket.destroy();\n }\n this.connections.clear();\n\n return new Promise((resolve, reject) => {\n server.close((err) => {\n if (err) {\n reject(err);\n } else {\n this.server = null;\n this._info = null;\n this.log('Mock OAuth server stopped');\n resolve();\n }\n });\n });\n }\n\n /**\n * Get server info\n */\n get info(): MockOAuthServerInfo {\n if (!this._info) {\n throw new Error('Mock OAuth server is not running');\n }\n return this._info;\n }\n\n /**\n * Get the token factory (for creating tokens)\n */\n getTokenFactory(): TestTokenFactory {\n return this.tokenFactory;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE\n // ═══════════════════════════════════════════════════════════════════\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? '/';\n this.log(`${req.method} ${url}`);\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (url === '/.well-known/jwks.json' || url === '/.well-known/jwks') {\n await this.handleJwks(req, res);\n } else if (url === '/.well-known/openid-configuration') {\n await this.handleOidcConfig(req, res);\n } else if (url === '/.well-known/oauth-authorization-server') {\n await this.handleOAuthMetadata(req, res);\n } else if (url === '/oauth/token') {\n await this.handleTokenEndpoint(req, res);\n } else {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'not_found', error_description: 'Endpoint not found' }));\n }\n } catch (error) {\n this.log(`Error handling request: ${error}`);\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'server_error', error_description: 'Internal server error' }));\n }\n }\n\n private async handleJwks(_req: IncomingMessage, res: ServerResponse): Promise<void> {\n const jwks = await this.tokenFactory.getPublicJwks();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(jwks));\n this.log('Served JWKS');\n }\n\n private async handleOidcConfig(_req: IncomingMessage, res: ServerResponse): Promise<void> {\n const issuer = this._info?.issuer ?? 'http://localhost';\n const config = {\n issuer,\n authorization_endpoint: `${issuer}/oauth/authorize`,\n token_endpoint: `${issuer}/oauth/token`,\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n response_types_supported: ['code', 'token'],\n subject_types_supported: ['public'],\n id_token_signing_alg_values_supported: ['RS256'],\n scopes_supported: ['openid', 'profile', 'email'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post', 'none'],\n claims_supported: ['sub', 'iss', 'aud', 'exp', 'iat', 'email', 'name'],\n grant_types_supported: ['authorization_code', 'refresh_token', 'client_credentials', 'anonymous'],\n };\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(config));\n this.log('Served OIDC configuration');\n }\n\n private async handleOAuthMetadata(_req: IncomingMessage, res: ServerResponse): Promise<void> {\n const issuer = this._info?.issuer ?? 'http://localhost';\n const metadata = {\n issuer,\n authorization_endpoint: `${issuer}/oauth/authorize`,\n token_endpoint: `${issuer}/oauth/token`,\n jwks_uri: `${issuer}/.well-known/jwks.json`,\n response_types_supported: ['code', 'token'],\n grant_types_supported: ['authorization_code', 'refresh_token', 'client_credentials', 'anonymous'],\n token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post', 'none'],\n scopes_supported: ['openid', 'profile', 'email', 'anonymous'],\n };\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(metadata));\n this.log('Served OAuth metadata');\n }\n\n private async handleTokenEndpoint(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // Parse request body\n const body = await this.readBody(req);\n const params = new URLSearchParams(body);\n const grantType = params.get('grant_type');\n\n if (grantType === 'anonymous') {\n // Issue an anonymous token\n const token = await this.tokenFactory.createAnonymousToken();\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n access_token: token,\n token_type: 'Bearer',\n expires_in: 3600,\n }),\n );\n this.log('Issued anonymous token');\n } else {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'unsupported_grant_type',\n error_description: 'Only anonymous grant type is supported in mock server',\n }),\n );\n }\n }\n\n private readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString()));\n req.on('error', reject);\n });\n }\n\n private log(message: string): void {\n if (this.options.debug) {\n console.log(`[MockOAuthServer] ${message}`);\n }\n }\n}\n"]}
@@ -2,8 +2,9 @@
2
2
  * @file mcp-test-client.builder.ts
3
3
  * @description Builder pattern for creating McpTestClient instances
4
4
  */
5
- import type { McpTestClientConfig, TestTransportType, TestAuthConfig } from './mcp-test-client.types';
5
+ import type { McpTestClientConfig, TestTransportType, TestAuthConfig, TestClientCapabilities } from './mcp-test-client.types';
6
6
  import { McpTestClient } from './mcp-test-client';
7
+ import type { TestPlatformType } from '../platform/platform-types';
7
8
  /**
8
9
  * Builder for creating McpTestClient instances with fluent API
9
10
  *
@@ -61,6 +62,47 @@ export declare class McpTestClientBuilder {
61
62
  name: string;
62
63
  version: string;
63
64
  }): this;
65
+ /**
66
+ * Set the platform type for testing platform-specific meta keys.
67
+ * Automatically configures clientInfo and capabilities for platform detection.
68
+ *
69
+ * Platform-specific behavior:
70
+ * - `openai`: Uses openai/* meta keys, sets User-Agent to "ChatGPT/1.0"
71
+ * - `ext-apps`: Uses ui/* meta keys per SEP-1865, sets io.modelcontextprotocol/ui capability
72
+ * - `claude`: Uses frontmcp/* + ui/* keys, sets User-Agent to "claude-desktop/1.0"
73
+ * - `cursor`: Uses frontmcp/* + ui/* keys, sets User-Agent to "cursor/1.0"
74
+ * - Other platforms follow similar patterns
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const client = await McpTestClient.create({ baseUrl })
79
+ * .withPlatform('openai')
80
+ * .buildAndConnect();
81
+ *
82
+ * // ext-apps automatically sets the io.modelcontextprotocol/ui capability
83
+ * const extAppsClient = await McpTestClient.create({ baseUrl })
84
+ * .withPlatform('ext-apps')
85
+ * .buildAndConnect();
86
+ * ```
87
+ */
88
+ withPlatform(platform: TestPlatformType): this;
89
+ /**
90
+ * Set custom client capabilities for MCP initialization.
91
+ * Use this for fine-grained control over capabilities sent during initialization.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const client = await McpTestClient.create({ baseUrl })
96
+ * .withCapabilities({
97
+ * sampling: {},
98
+ * experimental: {
99
+ * 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html+mcp'] }
100
+ * }
101
+ * })
102
+ * .buildAndConnect();
103
+ * ```
104
+ */
105
+ withCapabilities(capabilities: TestClientCapabilities): this;
64
106
  /**
65
107
  * Build the McpTestClient instance (does not connect)
66
108
  */
@@ -6,6 +6,7 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.McpTestClientBuilder = void 0;
8
8
  const mcp_test_client_1 = require("./mcp-test-client");
9
+ const platform_client_info_1 = require("../platform/platform-client-info");
9
10
  /**
10
11
  * Builder for creating McpTestClient instances with fluent API
11
12
  *
@@ -92,6 +93,57 @@ class McpTestClientBuilder {
92
93
  this.config.clientInfo = info;
93
94
  return this;
94
95
  }
96
+ /**
97
+ * Set the platform type for testing platform-specific meta keys.
98
+ * Automatically configures clientInfo and capabilities for platform detection.
99
+ *
100
+ * Platform-specific behavior:
101
+ * - `openai`: Uses openai/* meta keys, sets User-Agent to "ChatGPT/1.0"
102
+ * - `ext-apps`: Uses ui/* meta keys per SEP-1865, sets io.modelcontextprotocol/ui capability
103
+ * - `claude`: Uses frontmcp/* + ui/* keys, sets User-Agent to "claude-desktop/1.0"
104
+ * - `cursor`: Uses frontmcp/* + ui/* keys, sets User-Agent to "cursor/1.0"
105
+ * - Other platforms follow similar patterns
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const client = await McpTestClient.create({ baseUrl })
110
+ * .withPlatform('openai')
111
+ * .buildAndConnect();
112
+ *
113
+ * // ext-apps automatically sets the io.modelcontextprotocol/ui capability
114
+ * const extAppsClient = await McpTestClient.create({ baseUrl })
115
+ * .withPlatform('ext-apps')
116
+ * .buildAndConnect();
117
+ * ```
118
+ */
119
+ withPlatform(platform) {
120
+ this.config.platform = platform;
121
+ // Auto-set clientInfo based on platform for User-Agent detection
122
+ this.config.clientInfo = (0, platform_client_info_1.getPlatformClientInfo)(platform);
123
+ // Auto-set capabilities based on platform (ext-apps requires io.modelcontextprotocol/ui)
124
+ this.config.capabilities = (0, platform_client_info_1.getPlatformCapabilities)(platform);
125
+ return this;
126
+ }
127
+ /**
128
+ * Set custom client capabilities for MCP initialization.
129
+ * Use this for fine-grained control over capabilities sent during initialization.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * const client = await McpTestClient.create({ baseUrl })
134
+ * .withCapabilities({
135
+ * sampling: {},
136
+ * experimental: {
137
+ * 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html+mcp'] }
138
+ * }
139
+ * })
140
+ * .buildAndConnect();
141
+ * ```
142
+ */
143
+ withCapabilities(capabilities) {
144
+ this.config.capabilities = capabilities;
145
+ return this;
146
+ }
95
147
  /**
96
148
  * Build the McpTestClient instance (does not connect)
97
149
  */
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-test-client.builder.js","sourceRoot":"","sources":["../../../src/client/mcp-test-client.builder.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,uDAAkD;AAElD;;;;;;;;;;;;GAYG;AACH,MAAa,oBAAoB;IACvB,MAAM,CAAsB;IAEpC,YAAY,MAA2B;QACrC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAoB;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,KAAa;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,OAA+B;QACzC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG;YACjB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI;YACnB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE;SACtD,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,SAA4B;QACxC,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,SAAiB;QAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,OAAO,GAAG,IAAI;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,OAAO,GAAG,IAAI;QAC3B,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,OAAe;QACjC,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,OAAO,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,IAAuC;QACpD,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,OAAO,IAAI,+BAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAnGD,oDAmGC","sourcesContent":["/**\n * @file mcp-test-client.builder.ts\n * @description Builder pattern for creating McpTestClient instances\n */\n\nimport type { McpTestClientConfig, TestTransportType, TestAuthConfig } from './mcp-test-client.types';\nimport { McpTestClient } from './mcp-test-client';\n\n/**\n * Builder for creating McpTestClient instances with fluent API\n *\n * @example\n * ```typescript\n * const client = await McpTestClient.create({ baseUrl: 'http://localhost:3003' })\n * .withTransport('streamable-http')\n * .withToken('my-jwt-token')\n * .withTimeout(5000)\n * .withDebug()\n * .buildAndConnect();\n * ```\n */\nexport class McpTestClientBuilder {\n private config: McpTestClientConfig;\n\n constructor(config: McpTestClientConfig) {\n this.config = { ...config };\n }\n\n /**\n * Set the authentication configuration\n */\n withAuth(auth: TestAuthConfig): this {\n this.config.auth = { ...this.config.auth, ...auth };\n return this;\n }\n\n /**\n * Set the bearer token for authentication\n */\n withToken(token: string): this {\n this.config.auth = { ...this.config.auth, token };\n return this;\n }\n\n /**\n * Add custom headers to all requests\n */\n withHeaders(headers: Record<string, string>): this {\n this.config.auth = {\n ...this.config.auth,\n headers: { ...this.config.auth?.headers, ...headers },\n };\n return this;\n }\n\n /**\n * Set the transport type\n */\n withTransport(transport: TestTransportType): this {\n this.config.transport = transport;\n return this;\n }\n\n /**\n * Set the request timeout in milliseconds\n */\n withTimeout(timeoutMs: number): this {\n this.config.timeout = timeoutMs;\n return this;\n }\n\n /**\n * Enable debug logging\n */\n withDebug(enabled = true): this {\n this.config.debug = enabled;\n return this;\n }\n\n /**\n * Enable public mode - skip authentication entirely.\n * When true, no Authorization header is sent and anonymous token is not requested.\n * Use this for testing public/unauthenticated endpoints in CI/CD pipelines.\n */\n withPublicMode(enabled = true): this {\n this.config.publicMode = enabled;\n return this;\n }\n\n /**\n * Set the MCP protocol version to request\n */\n withProtocolVersion(version: string): this {\n this.config.protocolVersion = version;\n return this;\n }\n\n /**\n * Set the client info sent during initialization\n */\n withClientInfo(info: { name: string; version: string }): this {\n this.config.clientInfo = info;\n return this;\n }\n\n /**\n * Build the McpTestClient instance (does not connect)\n */\n build(): McpTestClient {\n return new McpTestClient(this.config);\n }\n\n /**\n * Build the McpTestClient and connect to the server\n */\n async buildAndConnect(): Promise<McpTestClient> {\n const client = this.build();\n await client.connect();\n return client;\n }\n}\n"]}
1
+ {"version":3,"file":"mcp-test-client.builder.js","sourceRoot":"","sources":["../../../src/client/mcp-test-client.builder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @file mcp-test-client.builder.ts\n * @description Builder pattern for creating McpTestClient instances\n */\n\nimport type {\n McpTestClientConfig,\n TestTransportType,\n TestAuthConfig,\n TestClientCapabilities,\n} from './mcp-test-client.types';\nimport { McpTestClient } from './mcp-test-client';\nimport type { TestPlatformType } from '../platform/platform-types';\nimport { getPlatformClientInfo, getPlatformCapabilities } from '../platform/platform-client-info';\n\n/**\n * Builder for creating McpTestClient instances with fluent API\n *\n * @example\n * ```typescript\n * const client = await McpTestClient.create({ baseUrl: 'http://localhost:3003' })\n * .withTransport('streamable-http')\n * .withToken('my-jwt-token')\n * .withTimeout(5000)\n * .withDebug()\n * .buildAndConnect();\n * ```\n */\nexport class McpTestClientBuilder {\n private config: McpTestClientConfig;\n\n constructor(config: McpTestClientConfig) {\n this.config = { ...config };\n }\n\n /**\n * Set the authentication configuration\n */\n withAuth(auth: TestAuthConfig): this {\n this.config.auth = { ...this.config.auth, ...auth };\n return this;\n }\n\n /**\n * Set the bearer token for authentication\n */\n withToken(token: string): this {\n this.config.auth = { ...this.config.auth, token };\n return this;\n }\n\n /**\n * Add custom headers to all requests\n */\n withHeaders(headers: Record<string, string>): this {\n this.config.auth = {\n ...this.config.auth,\n headers: { ...this.config.auth?.headers, ...headers },\n };\n return this;\n }\n\n /**\n * Set the transport type\n */\n withTransport(transport: TestTransportType): this {\n this.config.transport = transport;\n return this;\n }\n\n /**\n * Set the request timeout in milliseconds\n */\n withTimeout(timeoutMs: number): this {\n this.config.timeout = timeoutMs;\n return this;\n }\n\n /**\n * Enable debug logging\n */\n withDebug(enabled = true): this {\n this.config.debug = enabled;\n return this;\n }\n\n /**\n * Enable public mode - skip authentication entirely.\n * When true, no Authorization header is sent and anonymous token is not requested.\n * Use this for testing public/unauthenticated endpoints in CI/CD pipelines.\n */\n withPublicMode(enabled = true): this {\n this.config.publicMode = enabled;\n return this;\n }\n\n /**\n * Set the MCP protocol version to request\n */\n withProtocolVersion(version: string): this {\n this.config.protocolVersion = version;\n return this;\n }\n\n /**\n * Set the client info sent during initialization\n */\n withClientInfo(info: { name: string; version: string }): this {\n this.config.clientInfo = info;\n return this;\n }\n\n /**\n * Set the platform type for testing platform-specific meta keys.\n * Automatically configures clientInfo and capabilities for platform detection.\n *\n * Platform-specific behavior:\n * - `openai`: Uses openai/* meta keys, sets User-Agent to \"ChatGPT/1.0\"\n * - `ext-apps`: Uses ui/* meta keys per SEP-1865, sets io.modelcontextprotocol/ui capability\n * - `claude`: Uses frontmcp/* + ui/* keys, sets User-Agent to \"claude-desktop/1.0\"\n * - `cursor`: Uses frontmcp/* + ui/* keys, sets User-Agent to \"cursor/1.0\"\n * - Other platforms follow similar patterns\n *\n * @example\n * ```typescript\n * const client = await McpTestClient.create({ baseUrl })\n * .withPlatform('openai')\n * .buildAndConnect();\n *\n * // ext-apps automatically sets the io.modelcontextprotocol/ui capability\n * const extAppsClient = await McpTestClient.create({ baseUrl })\n * .withPlatform('ext-apps')\n * .buildAndConnect();\n * ```\n */\n withPlatform(platform: TestPlatformType): this {\n this.config.platform = platform;\n // Auto-set clientInfo based on platform for User-Agent detection\n this.config.clientInfo = getPlatformClientInfo(platform);\n // Auto-set capabilities based on platform (ext-apps requires io.modelcontextprotocol/ui)\n this.config.capabilities = getPlatformCapabilities(platform);\n return this;\n }\n\n /**\n * Set custom client capabilities for MCP initialization.\n * Use this for fine-grained control over capabilities sent during initialization.\n *\n * @example\n * ```typescript\n * const client = await McpTestClient.create({ baseUrl })\n * .withCapabilities({\n * sampling: {},\n * experimental: {\n * 'io.modelcontextprotocol/ui': { mimeTypes: ['text/html+mcp'] }\n * }\n * })\n * .buildAndConnect();\n * ```\n */\n withCapabilities(capabilities: TestClientCapabilities): this {\n this.config.capabilities = capabilities;\n return this;\n }\n\n /**\n * Build the McpTestClient instance (does not connect)\n */\n build(): McpTestClient {\n return new McpTestClient(this.config);\n }\n\n /**\n * Build the McpTestClient and connect to the server\n */\n async buildAndConnect(): Promise<McpTestClient> {\n const client = this.build();\n await client.connect();\n return client;\n }\n}\n"]}
@@ -21,6 +21,7 @@ const DEFAULT_CLIENT_INFO = {
21
21
  // MAIN CLIENT CLASS
22
22
  // ═══════════════════════════════════════════════════════════════════
23
23
  class McpTestClient {
24
+ // Platform and capabilities are optional - only set when testing platform-specific behavior
24
25
  config;
25
26
  transport = null;
26
27
  initResult = null;
@@ -49,16 +50,12 @@ class McpTestClient {
49
50
  debug: config.debug ?? false,
50
51
  protocolVersion: config.protocolVersion ?? DEFAULT_PROTOCOL_VERSION,
51
52
  clientInfo: config.clientInfo ?? DEFAULT_CLIENT_INFO,
53
+ platform: config.platform,
54
+ capabilities: config.capabilities,
52
55
  };
53
- // In public mode, user is always anonymous (no token authentication)
54
- if (config.publicMode) {
55
- this._authState = {
56
- isAnonymous: true,
57
- scopes: [],
58
- };
59
- }
60
- else if (config.auth?.token) {
61
- // Parse auth state from config
56
+ // If a token is provided, user is authenticated (even in public mode)
57
+ // Public mode just means anonymous access is allowed, not that tokens are ignored
58
+ if (config.auth?.token) {
62
59
  this._authState = {
63
60
  isAnonymous: false,
64
61
  token: config.auth.token,
@@ -66,6 +63,7 @@ class McpTestClient {
66
63
  user: this.parseUserFromToken(config.auth.token),
67
64
  };
68
65
  }
66
+ // Otherwise, user is anonymous (default _authState is already { isAnonymous: true, scopes: [] })
69
67
  // Initialize interceptor chain
70
68
  this._interceptors = new interceptor_1.DefaultInterceptorChain();
71
69
  }
@@ -598,11 +596,13 @@ class McpTestClient {
598
596
  // PRIVATE: MCP OPERATIONS
599
597
  // ═══════════════════════════════════════════════════════════════════
600
598
  async initialize() {
599
+ // Use configured capabilities or default to base capabilities
600
+ const capabilities = this.config.capabilities ?? {
601
+ sampling: {},
602
+ };
601
603
  return this.request('initialize', {
602
604
  protocolVersion: this.config.protocolVersion,
603
- capabilities: {
604
- sampling: {},
605
- },
605
+ capabilities,
606
606
  clientInfo: this.config.clientInfo,
607
607
  });
608
608
  }
@@ -646,6 +646,7 @@ class McpTestClient {
646
646
  publicMode: this.config.publicMode,
647
647
  debug: this.config.debug,
648
648
  interceptors: this._interceptors,
649
+ clientInfo: this.config.clientInfo,
649
650
  });
650
651
  case 'sse':
651
652
  // TODO: Implement SSE transport
@@ -717,9 +718,16 @@ class McpTestClient {
717
718
  wrapToolResult(response) {
718
719
  const raw = response.data ?? { content: [] };
719
720
  const isError = !response.success || raw.isError === true;
720
- // Check for Tool UI response - has structuredContent and ui/html in _meta
721
+ // Check for Tool UI response - has UI metadata in _meta
722
+ // Platform-specific HTML keys:
723
+ // - OpenAI: openai/html
724
+ // - ext-apps: ui/html
725
+ // - Others: frontmcp/html (+ ui/html for compatibility)
721
726
  const meta = raw._meta;
722
- const hasUI = meta?.['ui/html'] !== undefined;
727
+ const hasUI = meta?.['ui/html'] !== undefined ||
728
+ meta?.['ui/component'] !== undefined ||
729
+ meta?.['openai/html'] !== undefined ||
730
+ meta?.['frontmcp/html'] !== undefined;
723
731
  const structuredContent = raw['structuredContent'];
724
732
  return {
725
733
  raw,
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-test-client.js","sourceRoot":"","sources":["../../../src/client/mcp-test-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @file mcp-test-client.ts\n * @description Main MCP Test Client implementation for E2E testing\n */\n\nimport type {\n McpTestClientConfig,\n McpResponse,\n TestTransportType,\n TestAuthConfig,\n ToolResultWrapper,\n ResourceContentWrapper,\n PromptResultWrapper,\n LogEntry,\n RequestTrace,\n NotificationEntry,\n ProgressUpdate,\n SessionInfo,\n AuthState,\n McpErrorInfo,\n InitializeResult,\n ListToolsResult,\n CallToolResult,\n ListResourcesResult,\n ReadResourceResult,\n ListResourceTemplatesResult,\n ListPromptsResult,\n GetPromptResult,\n Tool,\n Resource,\n ResourceTemplate,\n Prompt,\n JSONRPCResponse,\n} from './mcp-test-client.types';\nimport { McpTestClientBuilder } from './mcp-test-client.builder';\nimport type { McpTransport } from '../transport/transport.interface';\nimport { StreamableHttpTransport } from '../transport/streamable-http.transport';\nimport type {\n InterceptorChain,\n MockDefinition,\n MockHandle,\n RequestInterceptor,\n ResponseInterceptor,\n} from '../interceptor';\nimport { DefaultInterceptorChain, mockResponse } from '../interceptor';\n\n// ═══════════════════════════════════════════════════════════════════\n// CONSTANTS\n// ═══════════════════════════════════════════════════════════════════\n\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_PROTOCOL_VERSION = '2025-06-18';\nconst DEFAULT_CLIENT_INFO = {\n name: '@frontmcp/testing',\n version: '0.4.0',\n};\n\n// ═══════════════════════════════════════════════════════════════════\n// MAIN CLIENT CLASS\n// ═══════════════════════════════════════════════════════════════════\n\nexport class McpTestClient {\n private readonly config: Required<McpTestClientConfig>;\n private transport: McpTransport | null = null;\n private initResult: InitializeResult | null = null;\n private requestIdCounter = 0;\n private _lastRequestId: string | number = 0;\n private _sessionId: string | undefined;\n private _sessionInfo: SessionInfo | null = null;\n private _authState: AuthState = { isAnonymous: true, scopes: [] };\n\n // Logging and tracing\n private _logs: LogEntry[] = [];\n private _traces: RequestTrace[] = [];\n private _notifications: NotificationEntry[] = [];\n private _progressUpdates: ProgressUpdate[] = [];\n\n // Interceptor chain\n private _interceptors: InterceptorChain;\n\n // ═══════════════════════════════════════════════════════════════════\n // CONSTRUCTOR & FACTORY\n // ═══════════════════════════════════════════════════════════════════\n\n constructor(config: McpTestClientConfig) {\n this.config = {\n baseUrl: config.baseUrl,\n transport: config.transport ?? 'streamable-http',\n auth: config.auth ?? {},\n publicMode: config.publicMode ?? false,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n debug: config.debug ?? false,\n protocolVersion: config.protocolVersion ?? DEFAULT_PROTOCOL_VERSION,\n clientInfo: config.clientInfo ?? DEFAULT_CLIENT_INFO,\n };\n\n // In public mode, user is always anonymous (no token authentication)\n if (config.publicMode) {\n this._authState = {\n isAnonymous: true,\n scopes: [],\n };\n } else if (config.auth?.token) {\n // Parse auth state from config\n this._authState = {\n isAnonymous: false,\n token: config.auth.token,\n scopes: this.parseScopesFromToken(config.auth.token),\n user: this.parseUserFromToken(config.auth.token),\n };\n }\n\n // Initialize interceptor chain\n this._interceptors = new DefaultInterceptorChain();\n }\n\n /**\n * Create a new McpTestClientBuilder for fluent configuration\n */\n static create(config: McpTestClientConfig): McpTestClientBuilder {\n return new McpTestClientBuilder(config);\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // CONNECTION & LIFECYCLE\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * Connect to the MCP server and perform initialization\n */\n async connect(): Promise<InitializeResult> {\n this.log('debug', `Connecting to ${this.config.baseUrl}...`);\n\n // Create transport based on config\n this.transport = this.createTransport();\n\n // Connect transport\n await this.transport.connect();\n\n // Perform MCP initialization\n const initResponse = await this.initialize();\n\n if (!initResponse.success || !initResponse.data) {\n throw new Error(`Failed to initialize MCP connection: ${initResponse.error?.message ?? 'Unknown error'}`);\n }\n\n this.initResult = initResponse.data;\n this._sessionId = this.transport.getSessionId();\n this._sessionInfo = {\n id: this._sessionId ?? `session-${Date.now()}`,\n createdAt: new Date(),\n lastActivityAt: new Date(),\n requestCount: 1,\n };\n\n // Send initialized notification per MCP protocol\n // This notification MUST be sent after receiving initialize response\n // before the client can make any other requests\n await this.transport.notify({\n jsonrpc: '2.0',\n method: 'notifications/initialized',\n });\n\n this.log('info', `Connected to ${this.initResult.serverInfo?.name ?? 'MCP Server'}`);\n\n return this.initResult;\n }\n\n /**\n * Disconnect from the MCP server\n */\n async disconnect(): Promise<void> {\n if (this.transport) {\n await this.transport.close();\n this.transport = null;\n }\n this.initResult = null;\n this.log('info', 'Disconnected from MCP server');\n }\n\n /**\n * Reconnect to the server, optionally with an existing session ID\n */\n async reconnect(options?: { sessionId?: string }): Promise<void> {\n await this.disconnect();\n\n if (options?.sessionId && this.transport) {\n // Set session ID before reconnecting\n this._sessionId = options.sessionId;\n }\n\n await this.connect();\n }\n\n /**\n * Check if the client is currently connected\n */\n isConnected(): boolean {\n return this.transport?.isConnected() ?? false;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // SESSION & AUTH PROPERTIES\n // ═══════════════════════════════════════════════════════════════════\n\n get sessionId(): string {\n return this._sessionId ?? '';\n }\n\n get session(): SessionInfo & { expire: () => Promise<void> } {\n const info = this._sessionInfo ?? {\n id: '',\n createdAt: new Date(),\n lastActivityAt: new Date(),\n requestCount: 0,\n };\n\n return {\n ...info,\n expire: async () => {\n // Force session expiration for testing\n this._sessionId = undefined;\n this._sessionInfo = null;\n },\n };\n }\n\n get auth(): AuthState {\n return this._authState;\n }\n\n /**\n * Authenticate with a token\n */\n async authenticate(token: string): Promise<void> {\n this._authState = {\n isAnonymous: false,\n token,\n scopes: this.parseScopesFromToken(token),\n user: this.parseUserFromToken(token),\n };\n\n // Update transport headers\n if (this.transport) {\n this.transport.setAuthToken(token);\n }\n\n this.log('debug', 'Authentication updated');\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // SERVER INFO & CAPABILITIES\n // ═══════════════════════════════════════════════════════════════════\n\n get serverInfo(): { name: string; version: string; title?: string } {\n return {\n name: this.initResult?.serverInfo?.name ?? '',\n version: this.initResult?.serverInfo?.version ?? '',\n };\n }\n\n get protocolVersion(): string {\n return this.initResult?.protocolVersion ?? '';\n }\n\n get instructions(): string {\n return this.initResult?.instructions ?? '';\n }\n\n get capabilities(): InitializeResult['capabilities'] {\n return this.initResult?.capabilities ?? {};\n }\n\n /**\n * Check if server has a specific capability\n */\n hasCapability(name: 'tools' | 'resources' | 'prompts' | 'logging' | 'sampling'): boolean {\n return !!this.capabilities[name];\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // TOOLS API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly tools = {\n /**\n * List all available tools\n */\n list: async (): Promise<Tool[]> => {\n const response = await this.listTools();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list tools: ${response.error?.message}`);\n }\n return response.data.tools;\n },\n\n /**\n * Call a tool by name with arguments\n */\n call: async (name: string, args?: Record<string, unknown>): Promise<ToolResultWrapper> => {\n const response = await this.callTool(name, args);\n return this.wrapToolResult(response);\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // RESOURCES API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly resources = {\n /**\n * List all static resources\n */\n list: async (): Promise<Resource[]> => {\n const response = await this.listResources();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list resources: ${response.error?.message}`);\n }\n return response.data.resources;\n },\n\n /**\n * List all resource templates\n */\n listTemplates: async (): Promise<ResourceTemplate[]> => {\n const response = await this.listResourceTemplates();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list resource templates: ${response.error?.message}`);\n }\n return response.data.resourceTemplates;\n },\n\n /**\n * Read a resource by URI\n */\n read: async (uri: string): Promise<ResourceContentWrapper> => {\n const response = await this.readResource(uri);\n return this.wrapResourceContent(response);\n },\n\n /**\n * Subscribe to resource changes (placeholder for future implementation)\n */\n subscribe: async (_uri: string): Promise<void> => {\n // TODO: Implement resource subscription\n this.log('warn', 'Resource subscription not yet implemented');\n },\n\n /**\n * Unsubscribe from resource changes (placeholder for future implementation)\n */\n unsubscribe: async (_uri: string): Promise<void> => {\n // TODO: Implement resource unsubscription\n this.log('warn', 'Resource unsubscription not yet implemented');\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // PROMPTS API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly prompts = {\n /**\n * List all available prompts\n */\n list: async (): Promise<Prompt[]> => {\n const response = await this.listPrompts();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list prompts: ${response.error?.message}`);\n }\n return response.data.prompts;\n },\n\n /**\n * Get a prompt with arguments\n */\n get: async (name: string, args?: Record<string, string>): Promise<PromptResultWrapper> => {\n const response = await this.getPrompt(name, args);\n return this.wrapPromptResult(response);\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // RAW PROTOCOL ACCESS\n // ═══════════════════════════════════════════════════════════════════\n\n readonly raw = {\n /**\n * Send any JSON-RPC request\n */\n request: async (message: {\n jsonrpc: '2.0';\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n }): Promise<JSONRPCResponse> => {\n this.ensureConnected();\n const start = Date.now();\n const response = await this.transport!.request(message);\n this.traceRequest(message.method, message.params, message.id, response, Date.now() - start);\n return response;\n },\n\n /**\n * Send a notification (no response expected)\n */\n notify: async (message: { jsonrpc: '2.0'; method: string; params?: Record<string, unknown> }): Promise<void> => {\n this.ensureConnected();\n await this.transport!.notify(message);\n },\n\n /**\n * Send raw string data (for error testing)\n */\n sendRaw: async (data: string): Promise<JSONRPCResponse> => {\n this.ensureConnected();\n return this.transport!.sendRaw(data);\n },\n };\n\n get lastRequestId(): string | number {\n return this._lastRequestId;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // TRANSPORT INFO\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * Get transport information and utilities\n */\n get transport_info(): {\n type: TestTransportType;\n isConnected: () => boolean;\n messageEndpoint: string | undefined;\n connectionCount: number;\n reconnectCount: number;\n lastRequestHeaders: Record<string, string>;\n simulateDisconnect: () => Promise<void>;\n waitForReconnect: (timeoutMs: number) => Promise<void>;\n } {\n return {\n type: this.config.transport,\n isConnected: () => this.transport?.isConnected() ?? false,\n messageEndpoint: this.transport?.getMessageEndpoint?.(),\n connectionCount: this.transport?.getConnectionCount?.() ?? 0,\n reconnectCount: this.transport?.getReconnectCount?.() ?? 0,\n lastRequestHeaders: this.transport?.getLastRequestHeaders?.() ?? {},\n simulateDisconnect: async () => {\n await this.transport?.simulateDisconnect?.();\n },\n waitForReconnect: async (timeoutMs: number) => {\n await this.transport?.waitForReconnect?.(timeoutMs);\n },\n };\n }\n\n // Alias for transport info\n get transport_() {\n return this.transport_info;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // NOTIFICATIONS\n // ═══════════════════════════════════════════════════════════════════\n\n readonly notifications = {\n /**\n * Start collecting server notifications\n */\n collect: (): NotificationCollector => {\n return new NotificationCollector(this._notifications);\n },\n\n /**\n * Collect progress notifications specifically\n */\n collectProgress: (): ProgressCollector => {\n return new ProgressCollector(this._progressUpdates);\n },\n\n /**\n * Send a notification to the server\n */\n send: async (method: string, params?: Record<string, unknown>): Promise<void> => {\n await this.raw.notify({ jsonrpc: '2.0', method, params });\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // LOGGING & DEBUGGING\n // ═══════════════════════════════════════════════════════════════════\n\n readonly logs = {\n all: (): LogEntry[] => [...this._logs],\n\n filter: (level: 'debug' | 'info' | 'warn' | 'error'): LogEntry[] => this._logs.filter((l) => l.level === level),\n\n search: (text: string): LogEntry[] => this._logs.filter((l) => l.message.includes(text)),\n\n last: (): LogEntry | undefined => this._logs[this._logs.length - 1],\n\n clear: (): void => {\n this._logs = [];\n },\n };\n\n readonly trace = {\n all: (): RequestTrace[] => [...this._traces],\n\n last: (): RequestTrace | undefined => this._traces[this._traces.length - 1],\n\n clear: (): void => {\n this._traces = [];\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // MOCKING & INTERCEPTION\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * API for mocking MCP requests\n *\n * @example\n * ```typescript\n * // Mock a specific tool call\n * const handle = mcp.mock.tool('my-tool', { result: 'mocked!' });\n *\n * // Mock with params matching\n * mcp.mock.add({\n * method: 'tools/call',\n * params: { name: 'my-tool' },\n * response: mockResponse.toolResult([{ type: 'text', text: 'mocked' }]),\n * });\n *\n * // Clear all mocks after test\n * mcp.mock.clear();\n * ```\n */\n readonly mock = {\n /**\n * Add a mock definition\n */\n add: (mock: MockDefinition): MockHandle => {\n return this._interceptors.mocks.add(mock);\n },\n\n /**\n * Mock a tools/call request for a specific tool\n */\n tool: (name: string, result: unknown, options?: { times?: number; delay?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/call',\n params: { name },\n response: mockResponse.toolResult([\n { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result) },\n ]),\n times: options?.times,\n delay: options?.delay,\n });\n },\n\n /**\n * Mock a tools/call request to return an error\n */\n toolError: (name: string, code: number, message: string, options?: { times?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/call',\n params: { name },\n response: mockResponse.error(code, message),\n times: options?.times,\n });\n },\n\n /**\n * Mock a resources/read request\n */\n resource: (\n uri: string,\n content: string | { text?: string; blob?: string; mimeType?: string },\n options?: { times?: number; delay?: number },\n ): MockHandle => {\n const contentObj = typeof content === 'string' ? { uri, text: content } : { uri, ...content };\n return this._interceptors.mocks.add({\n method: 'resources/read',\n params: { uri },\n response: mockResponse.resourceRead([contentObj]),\n times: options?.times,\n delay: options?.delay,\n });\n },\n\n /**\n * Mock a resources/read request to return an error\n */\n resourceError: (uri: string, options?: { times?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'resources/read',\n params: { uri },\n response: mockResponse.errors.resourceNotFound(uri),\n times: options?.times,\n });\n },\n\n /**\n * Mock the tools/list response\n */\n toolsList: (\n tools: Array<{ name: string; description?: string; inputSchema?: Record<string, unknown> }>,\n options?: { times?: number },\n ): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/list',\n response: mockResponse.toolsList(tools),\n times: options?.times,\n });\n },\n\n /**\n * Mock the resources/list response\n */\n resourcesList: (\n resources: Array<{ uri: string; name?: string; description?: string; mimeType?: string }>,\n options?: { times?: number },\n ): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'resources/list',\n response: mockResponse.resourcesList(resources),\n times: options?.times,\n });\n },\n\n /**\n * Clear all mocks\n */\n clear: (): void => {\n this._interceptors.mocks.clear();\n },\n\n /**\n * Get all active mocks\n */\n all: (): MockDefinition[] => {\n return this._interceptors.mocks.getAll();\n },\n };\n\n /**\n * API for intercepting requests and responses\n *\n * @example\n * ```typescript\n * // Log all requests\n * const remove = mcp.intercept.request((ctx) => {\n * console.log('Request:', ctx.request.method);\n * return { action: 'passthrough' };\n * });\n *\n * // Modify requests\n * mcp.intercept.request((ctx) => {\n * if (ctx.request.method === 'tools/call') {\n * return {\n * action: 'modify',\n * request: { ...ctx.request, params: { ...ctx.request.params, extra: true } },\n * };\n * }\n * return { action: 'passthrough' };\n * });\n *\n * // Add latency to all requests\n * mcp.intercept.delay(100);\n *\n * // Clean up\n * remove();\n * mcp.intercept.clear();\n * ```\n */\n readonly intercept = {\n /**\n * Add a request interceptor\n * @returns Function to remove the interceptor\n */\n request: (interceptor: RequestInterceptor): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor(interceptor);\n },\n\n /**\n * Add a response interceptor\n * @returns Function to remove the interceptor\n */\n response: (interceptor: ResponseInterceptor): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addResponseInterceptor(interceptor);\n },\n\n /**\n * Add latency to all requests\n * @returns Function to remove the interceptor\n */\n delay: (ms: number): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor(async () => {\n await new Promise((r) => setTimeout(r, ms));\n return { action: 'passthrough' };\n });\n },\n\n /**\n * Fail requests matching a method\n * @returns Function to remove the interceptor\n */\n failMethod: (method: string, error?: string): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor((ctx) => {\n if (ctx.request.method === method) {\n return { action: 'error', error: new Error(error ?? `Intercepted: ${method}`) };\n }\n return { action: 'passthrough' };\n });\n },\n\n /**\n * Clear all interceptors (but not mocks)\n */\n clear: (): void => {\n (this._interceptors as DefaultInterceptorChain).request = [];\n (this._interceptors as DefaultInterceptorChain).response = [];\n },\n\n /**\n * Clear everything (interceptors and mocks)\n */\n clearAll: (): void => {\n (this._interceptors as DefaultInterceptorChain).clear();\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // TIMEOUT\n // ═══════════════════════════════════════════════════════════════════\n\n setTimeout(ms: number): void {\n this.config.timeout = ms;\n if (this.transport) {\n this.transport.setTimeout(ms);\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: MCP OPERATIONS\n // ═══════════════════════════════════════════════════════════════════\n\n private async initialize(): Promise<McpResponse<InitializeResult>> {\n return this.request<InitializeResult>('initialize', {\n protocolVersion: this.config.protocolVersion,\n capabilities: {\n sampling: {},\n },\n clientInfo: this.config.clientInfo,\n });\n }\n\n private async listTools(): Promise<McpResponse<ListToolsResult>> {\n return this.request<ListToolsResult>('tools/list', {});\n }\n\n private async callTool(name: string, args?: Record<string, unknown>): Promise<McpResponse<CallToolResult>> {\n return this.request<CallToolResult>('tools/call', {\n name,\n arguments: args ?? {},\n });\n }\n\n private async listResources(): Promise<McpResponse<ListResourcesResult>> {\n return this.request<ListResourcesResult>('resources/list', {});\n }\n\n private async listResourceTemplates(): Promise<McpResponse<ListResourceTemplatesResult>> {\n return this.request<ListResourceTemplatesResult>('resources/templates/list', {});\n }\n\n private async readResource(uri: string): Promise<McpResponse<ReadResourceResult>> {\n return this.request<ReadResourceResult>('resources/read', { uri });\n }\n\n private async listPrompts(): Promise<McpResponse<ListPromptsResult>> {\n return this.request<ListPromptsResult>('prompts/list', {});\n }\n\n private async getPrompt(name: string, args?: Record<string, string>): Promise<McpResponse<GetPromptResult>> {\n return this.request<GetPromptResult>('prompts/get', {\n name,\n arguments: args ?? {},\n });\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: TRANSPORT & REQUEST HELPERS\n // ═══════════════════════════════════════════════════════════════════\n\n private createTransport(): McpTransport {\n switch (this.config.transport) {\n case 'streamable-http':\n return new StreamableHttpTransport({\n baseUrl: this.config.baseUrl,\n timeout: this.config.timeout,\n auth: this.config.auth,\n publicMode: this.config.publicMode,\n debug: this.config.debug,\n interceptors: this._interceptors,\n });\n case 'sse':\n // TODO: Implement SSE transport\n throw new Error('SSE transport not yet implemented');\n default:\n throw new Error(`Unknown transport type: ${this.config.transport}`);\n }\n }\n\n private async request<T>(method: string, params: Record<string, unknown>): Promise<McpResponse<T>> {\n this.ensureConnected();\n\n const id = ++this.requestIdCounter;\n this._lastRequestId = id;\n const start = Date.now();\n\n try {\n const response = await this.transport!.request<T>({\n jsonrpc: '2.0',\n id,\n method,\n params,\n });\n\n const durationMs = Date.now() - start;\n this.updateSessionActivity();\n\n if ('error' in response && response.error) {\n const error = response.error as McpErrorInfo;\n this.traceRequest(method, params, id, response, durationMs);\n return {\n success: false,\n error,\n durationMs,\n requestId: id,\n };\n }\n\n this.traceRequest(method, params, id, response, durationMs);\n return {\n success: true,\n data: response.result as T,\n durationMs,\n requestId: id,\n };\n } catch (err) {\n const durationMs = Date.now() - start;\n const error: McpErrorInfo = {\n code: -32603,\n message: err instanceof Error ? err.message : 'Unknown error',\n };\n return {\n success: false,\n error,\n durationMs,\n requestId: id,\n };\n }\n }\n\n private ensureConnected(): void {\n if (!this.transport?.isConnected()) {\n throw new Error('Not connected to MCP server. Call connect() first.');\n }\n }\n\n private updateSessionActivity(): void {\n if (this._sessionInfo) {\n this._sessionInfo.lastActivityAt = new Date();\n this._sessionInfo.requestCount++;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: RESULT WRAPPERS\n // ═══════════════════════════════════════════════════════════════════\n\n private wrapToolResult(response: McpResponse<CallToolResult>): ToolResultWrapper {\n const raw = response.data ?? { content: [] };\n const isError = !response.success || raw.isError === true;\n\n // Check for Tool UI response - has structuredContent and ui/html in _meta\n const meta = raw._meta as Record<string, unknown> | undefined;\n const hasUI = meta?.['ui/html'] !== undefined;\n const structuredContent = (raw as Record<string, unknown>)['structuredContent'];\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n json<T>(): T {\n // For Tool UI responses, return structuredContent (the typed output)\n if (hasUI && structuredContent !== undefined) {\n return structuredContent as T;\n }\n // For regular responses, parse text content as JSON\n const textContent = raw.content?.find((c) => c.type === 'text');\n if (textContent && 'text' in textContent) {\n return JSON.parse(textContent.text) as T;\n }\n throw new Error('No text content to parse as JSON');\n },\n text(): string | undefined {\n const textContent = raw.content?.find((c) => c.type === 'text');\n if (textContent && 'text' in textContent) {\n return textContent.text;\n }\n return undefined;\n },\n hasTextContent(): boolean {\n return raw.content?.some((c) => c.type === 'text') ?? false;\n },\n hasImageContent(): boolean {\n return raw.content?.some((c) => c.type === 'image') ?? false;\n },\n hasResourceContent(): boolean {\n return raw.content?.some((c) => c.type === 'resource') ?? false;\n },\n hasToolUI(): boolean {\n return hasUI;\n },\n };\n }\n\n private wrapResourceContent(response: McpResponse<ReadResourceResult>): ResourceContentWrapper {\n const raw = response.data ?? { contents: [] };\n const isError = !response.success;\n const firstContent = raw.contents?.[0];\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n json<T>(): T {\n if (firstContent && 'text' in firstContent) {\n return JSON.parse(firstContent.text) as T;\n }\n throw new Error('No text content to parse as JSON');\n },\n text(): string | undefined {\n if (firstContent && 'text' in firstContent) {\n return firstContent.text;\n }\n return undefined;\n },\n mimeType(): string | undefined {\n return firstContent?.mimeType;\n },\n hasMimeType(type: string): boolean {\n return firstContent?.mimeType === type;\n },\n };\n }\n\n private wrapPromptResult(response: McpResponse<GetPromptResult>): PromptResultWrapper {\n const raw = response.data ?? { messages: [] };\n const isError = !response.success;\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n messages: raw.messages ?? [],\n description: raw.description,\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: LOGGING & TRACING\n // ═══════════════════════════════════════════════════════════════════\n\n private log(level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: unknown): void {\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date(),\n data,\n };\n this._logs.push(entry);\n\n if (this.config.debug) {\n console.log(`[${level.toUpperCase()}] ${message}`, data ?? '');\n }\n }\n\n private traceRequest(\n method: string,\n params: unknown,\n id: string | number,\n response: JSONRPCResponse,\n durationMs: number,\n ): void {\n this._traces.push({\n request: { method, params, id },\n response: {\n result: 'result' in response ? response.result : undefined,\n error: 'error' in response ? (response.error as McpErrorInfo) : undefined,\n },\n durationMs,\n timestamp: new Date(),\n });\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: TOKEN PARSING\n // ═══════════════════════════════════════════════════════════════════\n\n private parseScopesFromToken(token: string): string[] {\n try {\n const payload = this.decodeJwtPayload(token);\n if (!payload) return [];\n const scope = payload['scope'];\n const scopes = payload['scopes'];\n if (typeof scope === 'string') {\n return scope.split(' ');\n }\n if (Array.isArray(scopes)) {\n return scopes as string[];\n }\n return [];\n } catch {\n return [];\n }\n }\n\n private parseUserFromToken(token: string): { sub: string; email?: string; name?: string } | undefined {\n try {\n const payload = this.decodeJwtPayload(token);\n const sub = payload?.['sub'];\n if (!sub || typeof sub !== 'string') return undefined;\n return {\n sub,\n email: payload['email'] as string | undefined,\n name: payload['name'] as string | undefined,\n };\n } catch {\n return undefined;\n }\n }\n\n private decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n const payload = Buffer.from(parts[1], 'base64url').toString('utf-8');\n return JSON.parse(payload);\n } catch {\n return null;\n }\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// NOTIFICATION COLLECTORS\n// ═══════════════════════════════════════════════════════════════════\n\nclass NotificationCollector {\n constructor(private readonly notifications: NotificationEntry[]) {}\n\n get received(): NotificationEntry[] {\n return [...this.notifications];\n }\n\n has(method: string): boolean {\n return this.notifications.some((n) => n.method === method);\n }\n\n async waitFor(method: string, timeoutMs: number): Promise<NotificationEntry> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const found = this.notifications.find((n) => n.method === method);\n if (found) return found;\n await new Promise((r) => setTimeout(r, 50));\n }\n throw new Error(`Timeout waiting for notification: ${method}`);\n }\n}\n\nclass ProgressCollector {\n constructor(private readonly updates: ProgressUpdate[]) {}\n\n get all(): ProgressUpdate[] {\n return [...this.updates];\n }\n\n async waitForComplete(timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const last = this.updates[this.updates.length - 1];\n if (last && last.total !== undefined && last.progress >= last.total) {\n return;\n }\n await new Promise((r) => setTimeout(r, 50));\n }\n throw new Error('Timeout waiting for progress to complete');\n }\n}\n"]}
1
+ {"version":3,"file":"mcp-test-client.js","sourceRoot":"","sources":["../../../src/client/mcp-test-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @file mcp-test-client.ts\n * @description Main MCP Test Client implementation for E2E testing\n */\n\nimport type {\n McpTestClientConfig,\n McpResponse,\n TestTransportType,\n TestAuthConfig,\n TestClientCapabilities,\n ToolResultWrapper,\n ResourceContentWrapper,\n PromptResultWrapper,\n LogEntry,\n RequestTrace,\n NotificationEntry,\n ProgressUpdate,\n SessionInfo,\n AuthState,\n McpErrorInfo,\n InitializeResult,\n ListToolsResult,\n CallToolResult,\n ListResourcesResult,\n ReadResourceResult,\n ListResourceTemplatesResult,\n ListPromptsResult,\n GetPromptResult,\n Tool,\n Resource,\n ResourceTemplate,\n Prompt,\n JSONRPCResponse,\n} from './mcp-test-client.types';\nimport { McpTestClientBuilder } from './mcp-test-client.builder';\nimport type { McpTransport } from '../transport/transport.interface';\nimport { StreamableHttpTransport } from '../transport/streamable-http.transport';\nimport type {\n InterceptorChain,\n MockDefinition,\n MockHandle,\n RequestInterceptor,\n ResponseInterceptor,\n} from '../interceptor';\nimport { DefaultInterceptorChain, mockResponse } from '../interceptor';\n\n// ═══════════════════════════════════════════════════════════════════\n// CONSTANTS\n// ═══════════════════════════════════════════════════════════════════\n\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_PROTOCOL_VERSION = '2025-06-18';\nconst DEFAULT_CLIENT_INFO = {\n name: '@frontmcp/testing',\n version: '0.4.0',\n};\n\n// ═══════════════════════════════════════════════════════════════════\n// MAIN CLIENT CLASS\n// ═══════════════════════════════════════════════════════════════════\n\nexport class McpTestClient {\n // Platform and capabilities are optional - only set when testing platform-specific behavior\n private readonly config: Required<Omit<McpTestClientConfig, 'platform' | 'capabilities'>> &\n Pick<McpTestClientConfig, 'platform' | 'capabilities'>;\n private transport: McpTransport | null = null;\n private initResult: InitializeResult | null = null;\n private requestIdCounter = 0;\n private _lastRequestId: string | number = 0;\n private _sessionId: string | undefined;\n private _sessionInfo: SessionInfo | null = null;\n private _authState: AuthState = { isAnonymous: true, scopes: [] };\n\n // Logging and tracing\n private _logs: LogEntry[] = [];\n private _traces: RequestTrace[] = [];\n private _notifications: NotificationEntry[] = [];\n private _progressUpdates: ProgressUpdate[] = [];\n\n // Interceptor chain\n private _interceptors: InterceptorChain;\n\n // ═══════════════════════════════════════════════════════════════════\n // CONSTRUCTOR & FACTORY\n // ═══════════════════════════════════════════════════════════════════\n\n constructor(config: McpTestClientConfig) {\n this.config = {\n baseUrl: config.baseUrl,\n transport: config.transport ?? 'streamable-http',\n auth: config.auth ?? {},\n publicMode: config.publicMode ?? false,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n debug: config.debug ?? false,\n protocolVersion: config.protocolVersion ?? DEFAULT_PROTOCOL_VERSION,\n clientInfo: config.clientInfo ?? DEFAULT_CLIENT_INFO,\n platform: config.platform,\n capabilities: config.capabilities,\n };\n\n // If a token is provided, user is authenticated (even in public mode)\n // Public mode just means anonymous access is allowed, not that tokens are ignored\n if (config.auth?.token) {\n this._authState = {\n isAnonymous: false,\n token: config.auth.token,\n scopes: this.parseScopesFromToken(config.auth.token),\n user: this.parseUserFromToken(config.auth.token),\n };\n }\n // Otherwise, user is anonymous (default _authState is already { isAnonymous: true, scopes: [] })\n\n // Initialize interceptor chain\n this._interceptors = new DefaultInterceptorChain();\n }\n\n /**\n * Create a new McpTestClientBuilder for fluent configuration\n */\n static create(config: McpTestClientConfig): McpTestClientBuilder {\n return new McpTestClientBuilder(config);\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // CONNECTION & LIFECYCLE\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * Connect to the MCP server and perform initialization\n */\n async connect(): Promise<InitializeResult> {\n this.log('debug', `Connecting to ${this.config.baseUrl}...`);\n\n // Create transport based on config\n this.transport = this.createTransport();\n\n // Connect transport\n await this.transport.connect();\n\n // Perform MCP initialization\n const initResponse = await this.initialize();\n\n if (!initResponse.success || !initResponse.data) {\n throw new Error(`Failed to initialize MCP connection: ${initResponse.error?.message ?? 'Unknown error'}`);\n }\n\n this.initResult = initResponse.data;\n this._sessionId = this.transport.getSessionId();\n this._sessionInfo = {\n id: this._sessionId ?? `session-${Date.now()}`,\n createdAt: new Date(),\n lastActivityAt: new Date(),\n requestCount: 1,\n };\n\n // Send initialized notification per MCP protocol\n // This notification MUST be sent after receiving initialize response\n // before the client can make any other requests\n await this.transport.notify({\n jsonrpc: '2.0',\n method: 'notifications/initialized',\n });\n\n this.log('info', `Connected to ${this.initResult.serverInfo?.name ?? 'MCP Server'}`);\n\n return this.initResult;\n }\n\n /**\n * Disconnect from the MCP server\n */\n async disconnect(): Promise<void> {\n if (this.transport) {\n await this.transport.close();\n this.transport = null;\n }\n this.initResult = null;\n this.log('info', 'Disconnected from MCP server');\n }\n\n /**\n * Reconnect to the server, optionally with an existing session ID\n */\n async reconnect(options?: { sessionId?: string }): Promise<void> {\n await this.disconnect();\n\n if (options?.sessionId && this.transport) {\n // Set session ID before reconnecting\n this._sessionId = options.sessionId;\n }\n\n await this.connect();\n }\n\n /**\n * Check if the client is currently connected\n */\n isConnected(): boolean {\n return this.transport?.isConnected() ?? false;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // SESSION & AUTH PROPERTIES\n // ═══════════════════════════════════════════════════════════════════\n\n get sessionId(): string {\n return this._sessionId ?? '';\n }\n\n get session(): SessionInfo & { expire: () => Promise<void> } {\n const info = this._sessionInfo ?? {\n id: '',\n createdAt: new Date(),\n lastActivityAt: new Date(),\n requestCount: 0,\n };\n\n return {\n ...info,\n expire: async () => {\n // Force session expiration for testing\n this._sessionId = undefined;\n this._sessionInfo = null;\n },\n };\n }\n\n get auth(): AuthState {\n return this._authState;\n }\n\n /**\n * Authenticate with a token\n */\n async authenticate(token: string): Promise<void> {\n this._authState = {\n isAnonymous: false,\n token,\n scopes: this.parseScopesFromToken(token),\n user: this.parseUserFromToken(token),\n };\n\n // Update transport headers\n if (this.transport) {\n this.transport.setAuthToken(token);\n }\n\n this.log('debug', 'Authentication updated');\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // SERVER INFO & CAPABILITIES\n // ═══════════════════════════════════════════════════════════════════\n\n get serverInfo(): { name: string; version: string; title?: string } {\n return {\n name: this.initResult?.serverInfo?.name ?? '',\n version: this.initResult?.serverInfo?.version ?? '',\n };\n }\n\n get protocolVersion(): string {\n return this.initResult?.protocolVersion ?? '';\n }\n\n get instructions(): string {\n return this.initResult?.instructions ?? '';\n }\n\n get capabilities(): InitializeResult['capabilities'] {\n return this.initResult?.capabilities ?? {};\n }\n\n /**\n * Check if server has a specific capability\n */\n hasCapability(name: 'tools' | 'resources' | 'prompts' | 'logging' | 'sampling'): boolean {\n return !!this.capabilities[name];\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // TOOLS API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly tools = {\n /**\n * List all available tools\n */\n list: async (): Promise<Tool[]> => {\n const response = await this.listTools();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list tools: ${response.error?.message}`);\n }\n return response.data.tools;\n },\n\n /**\n * Call a tool by name with arguments\n */\n call: async (name: string, args?: Record<string, unknown>): Promise<ToolResultWrapper> => {\n const response = await this.callTool(name, args);\n return this.wrapToolResult(response);\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // RESOURCES API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly resources = {\n /**\n * List all static resources\n */\n list: async (): Promise<Resource[]> => {\n const response = await this.listResources();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list resources: ${response.error?.message}`);\n }\n return response.data.resources;\n },\n\n /**\n * List all resource templates\n */\n listTemplates: async (): Promise<ResourceTemplate[]> => {\n const response = await this.listResourceTemplates();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list resource templates: ${response.error?.message}`);\n }\n return response.data.resourceTemplates;\n },\n\n /**\n * Read a resource by URI\n */\n read: async (uri: string): Promise<ResourceContentWrapper> => {\n const response = await this.readResource(uri);\n return this.wrapResourceContent(response);\n },\n\n /**\n * Subscribe to resource changes (placeholder for future implementation)\n */\n subscribe: async (_uri: string): Promise<void> => {\n // TODO: Implement resource subscription\n this.log('warn', 'Resource subscription not yet implemented');\n },\n\n /**\n * Unsubscribe from resource changes (placeholder for future implementation)\n */\n unsubscribe: async (_uri: string): Promise<void> => {\n // TODO: Implement resource unsubscription\n this.log('warn', 'Resource unsubscription not yet implemented');\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // PROMPTS API\n // ═══════════════════════════════════════════════════════════════════\n\n readonly prompts = {\n /**\n * List all available prompts\n */\n list: async (): Promise<Prompt[]> => {\n const response = await this.listPrompts();\n if (!response.success || !response.data) {\n throw new Error(`Failed to list prompts: ${response.error?.message}`);\n }\n return response.data.prompts;\n },\n\n /**\n * Get a prompt with arguments\n */\n get: async (name: string, args?: Record<string, string>): Promise<PromptResultWrapper> => {\n const response = await this.getPrompt(name, args);\n return this.wrapPromptResult(response);\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // RAW PROTOCOL ACCESS\n // ═══════════════════════════════════════════════════════════════════\n\n readonly raw = {\n /**\n * Send any JSON-RPC request\n */\n request: async (message: {\n jsonrpc: '2.0';\n id: string | number;\n method: string;\n params?: Record<string, unknown>;\n }): Promise<JSONRPCResponse> => {\n this.ensureConnected();\n const start = Date.now();\n const response = await this.transport!.request(message);\n this.traceRequest(message.method, message.params, message.id, response, Date.now() - start);\n return response;\n },\n\n /**\n * Send a notification (no response expected)\n */\n notify: async (message: { jsonrpc: '2.0'; method: string; params?: Record<string, unknown> }): Promise<void> => {\n this.ensureConnected();\n await this.transport!.notify(message);\n },\n\n /**\n * Send raw string data (for error testing)\n */\n sendRaw: async (data: string): Promise<JSONRPCResponse> => {\n this.ensureConnected();\n return this.transport!.sendRaw(data);\n },\n };\n\n get lastRequestId(): string | number {\n return this._lastRequestId;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // TRANSPORT INFO\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * Get transport information and utilities\n */\n get transport_info(): {\n type: TestTransportType;\n isConnected: () => boolean;\n messageEndpoint: string | undefined;\n connectionCount: number;\n reconnectCount: number;\n lastRequestHeaders: Record<string, string>;\n simulateDisconnect: () => Promise<void>;\n waitForReconnect: (timeoutMs: number) => Promise<void>;\n } {\n return {\n type: this.config.transport,\n isConnected: () => this.transport?.isConnected() ?? false,\n messageEndpoint: this.transport?.getMessageEndpoint?.(),\n connectionCount: this.transport?.getConnectionCount?.() ?? 0,\n reconnectCount: this.transport?.getReconnectCount?.() ?? 0,\n lastRequestHeaders: this.transport?.getLastRequestHeaders?.() ?? {},\n simulateDisconnect: async () => {\n await this.transport?.simulateDisconnect?.();\n },\n waitForReconnect: async (timeoutMs: number) => {\n await this.transport?.waitForReconnect?.(timeoutMs);\n },\n };\n }\n\n // Alias for transport info\n get transport_() {\n return this.transport_info;\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // NOTIFICATIONS\n // ═══════════════════════════════════════════════════════════════════\n\n readonly notifications = {\n /**\n * Start collecting server notifications\n */\n collect: (): NotificationCollector => {\n return new NotificationCollector(this._notifications);\n },\n\n /**\n * Collect progress notifications specifically\n */\n collectProgress: (): ProgressCollector => {\n return new ProgressCollector(this._progressUpdates);\n },\n\n /**\n * Send a notification to the server\n */\n send: async (method: string, params?: Record<string, unknown>): Promise<void> => {\n await this.raw.notify({ jsonrpc: '2.0', method, params });\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // LOGGING & DEBUGGING\n // ═══════════════════════════════════════════════════════════════════\n\n readonly logs = {\n all: (): LogEntry[] => [...this._logs],\n\n filter: (level: 'debug' | 'info' | 'warn' | 'error'): LogEntry[] => this._logs.filter((l) => l.level === level),\n\n search: (text: string): LogEntry[] => this._logs.filter((l) => l.message.includes(text)),\n\n last: (): LogEntry | undefined => this._logs[this._logs.length - 1],\n\n clear: (): void => {\n this._logs = [];\n },\n };\n\n readonly trace = {\n all: (): RequestTrace[] => [...this._traces],\n\n last: (): RequestTrace | undefined => this._traces[this._traces.length - 1],\n\n clear: (): void => {\n this._traces = [];\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // MOCKING & INTERCEPTION\n // ═══════════════════════════════════════════════════════════════════\n\n /**\n * API for mocking MCP requests\n *\n * @example\n * ```typescript\n * // Mock a specific tool call\n * const handle = mcp.mock.tool('my-tool', { result: 'mocked!' });\n *\n * // Mock with params matching\n * mcp.mock.add({\n * method: 'tools/call',\n * params: { name: 'my-tool' },\n * response: mockResponse.toolResult([{ type: 'text', text: 'mocked' }]),\n * });\n *\n * // Clear all mocks after test\n * mcp.mock.clear();\n * ```\n */\n readonly mock = {\n /**\n * Add a mock definition\n */\n add: (mock: MockDefinition): MockHandle => {\n return this._interceptors.mocks.add(mock);\n },\n\n /**\n * Mock a tools/call request for a specific tool\n */\n tool: (name: string, result: unknown, options?: { times?: number; delay?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/call',\n params: { name },\n response: mockResponse.toolResult([\n { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result) },\n ]),\n times: options?.times,\n delay: options?.delay,\n });\n },\n\n /**\n * Mock a tools/call request to return an error\n */\n toolError: (name: string, code: number, message: string, options?: { times?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/call',\n params: { name },\n response: mockResponse.error(code, message),\n times: options?.times,\n });\n },\n\n /**\n * Mock a resources/read request\n */\n resource: (\n uri: string,\n content: string | { text?: string; blob?: string; mimeType?: string },\n options?: { times?: number; delay?: number },\n ): MockHandle => {\n const contentObj = typeof content === 'string' ? { uri, text: content } : { uri, ...content };\n return this._interceptors.mocks.add({\n method: 'resources/read',\n params: { uri },\n response: mockResponse.resourceRead([contentObj]),\n times: options?.times,\n delay: options?.delay,\n });\n },\n\n /**\n * Mock a resources/read request to return an error\n */\n resourceError: (uri: string, options?: { times?: number }): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'resources/read',\n params: { uri },\n response: mockResponse.errors.resourceNotFound(uri),\n times: options?.times,\n });\n },\n\n /**\n * Mock the tools/list response\n */\n toolsList: (\n tools: Array<{ name: string; description?: string; inputSchema?: Record<string, unknown> }>,\n options?: { times?: number },\n ): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'tools/list',\n response: mockResponse.toolsList(tools),\n times: options?.times,\n });\n },\n\n /**\n * Mock the resources/list response\n */\n resourcesList: (\n resources: Array<{ uri: string; name?: string; description?: string; mimeType?: string }>,\n options?: { times?: number },\n ): MockHandle => {\n return this._interceptors.mocks.add({\n method: 'resources/list',\n response: mockResponse.resourcesList(resources),\n times: options?.times,\n });\n },\n\n /**\n * Clear all mocks\n */\n clear: (): void => {\n this._interceptors.mocks.clear();\n },\n\n /**\n * Get all active mocks\n */\n all: (): MockDefinition[] => {\n return this._interceptors.mocks.getAll();\n },\n };\n\n /**\n * API for intercepting requests and responses\n *\n * @example\n * ```typescript\n * // Log all requests\n * const remove = mcp.intercept.request((ctx) => {\n * console.log('Request:', ctx.request.method);\n * return { action: 'passthrough' };\n * });\n *\n * // Modify requests\n * mcp.intercept.request((ctx) => {\n * if (ctx.request.method === 'tools/call') {\n * return {\n * action: 'modify',\n * request: { ...ctx.request, params: { ...ctx.request.params, extra: true } },\n * };\n * }\n * return { action: 'passthrough' };\n * });\n *\n * // Add latency to all requests\n * mcp.intercept.delay(100);\n *\n * // Clean up\n * remove();\n * mcp.intercept.clear();\n * ```\n */\n readonly intercept = {\n /**\n * Add a request interceptor\n * @returns Function to remove the interceptor\n */\n request: (interceptor: RequestInterceptor): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor(interceptor);\n },\n\n /**\n * Add a response interceptor\n * @returns Function to remove the interceptor\n */\n response: (interceptor: ResponseInterceptor): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addResponseInterceptor(interceptor);\n },\n\n /**\n * Add latency to all requests\n * @returns Function to remove the interceptor\n */\n delay: (ms: number): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor(async () => {\n await new Promise((r) => setTimeout(r, ms));\n return { action: 'passthrough' };\n });\n },\n\n /**\n * Fail requests matching a method\n * @returns Function to remove the interceptor\n */\n failMethod: (method: string, error?: string): (() => void) => {\n return (this._interceptors as DefaultInterceptorChain).addRequestInterceptor((ctx) => {\n if (ctx.request.method === method) {\n return { action: 'error', error: new Error(error ?? `Intercepted: ${method}`) };\n }\n return { action: 'passthrough' };\n });\n },\n\n /**\n * Clear all interceptors (but not mocks)\n */\n clear: (): void => {\n (this._interceptors as DefaultInterceptorChain).request = [];\n (this._interceptors as DefaultInterceptorChain).response = [];\n },\n\n /**\n * Clear everything (interceptors and mocks)\n */\n clearAll: (): void => {\n (this._interceptors as DefaultInterceptorChain).clear();\n },\n };\n\n // ═══════════════════════════════════════════════════════════════════\n // TIMEOUT\n // ═══════════════════════════════════════════════════════════════════\n\n setTimeout(ms: number): void {\n this.config.timeout = ms;\n if (this.transport) {\n this.transport.setTimeout(ms);\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: MCP OPERATIONS\n // ═══════════════════════════════════════════════════════════════════\n\n private async initialize(): Promise<McpResponse<InitializeResult>> {\n // Use configured capabilities or default to base capabilities\n const capabilities: TestClientCapabilities = this.config.capabilities ?? {\n sampling: {},\n };\n\n return this.request<InitializeResult>('initialize', {\n protocolVersion: this.config.protocolVersion,\n capabilities,\n clientInfo: this.config.clientInfo,\n });\n }\n\n private async listTools(): Promise<McpResponse<ListToolsResult>> {\n return this.request<ListToolsResult>('tools/list', {});\n }\n\n private async callTool(name: string, args?: Record<string, unknown>): Promise<McpResponse<CallToolResult>> {\n return this.request<CallToolResult>('tools/call', {\n name,\n arguments: args ?? {},\n });\n }\n\n private async listResources(): Promise<McpResponse<ListResourcesResult>> {\n return this.request<ListResourcesResult>('resources/list', {});\n }\n\n private async listResourceTemplates(): Promise<McpResponse<ListResourceTemplatesResult>> {\n return this.request<ListResourceTemplatesResult>('resources/templates/list', {});\n }\n\n private async readResource(uri: string): Promise<McpResponse<ReadResourceResult>> {\n return this.request<ReadResourceResult>('resources/read', { uri });\n }\n\n private async listPrompts(): Promise<McpResponse<ListPromptsResult>> {\n return this.request<ListPromptsResult>('prompts/list', {});\n }\n\n private async getPrompt(name: string, args?: Record<string, string>): Promise<McpResponse<GetPromptResult>> {\n return this.request<GetPromptResult>('prompts/get', {\n name,\n arguments: args ?? {},\n });\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: TRANSPORT & REQUEST HELPERS\n // ═══════════════════════════════════════════════════════════════════\n\n private createTransport(): McpTransport {\n switch (this.config.transport) {\n case 'streamable-http':\n return new StreamableHttpTransport({\n baseUrl: this.config.baseUrl,\n timeout: this.config.timeout,\n auth: this.config.auth,\n publicMode: this.config.publicMode,\n debug: this.config.debug,\n interceptors: this._interceptors,\n clientInfo: this.config.clientInfo,\n });\n case 'sse':\n // TODO: Implement SSE transport\n throw new Error('SSE transport not yet implemented');\n default:\n throw new Error(`Unknown transport type: ${this.config.transport}`);\n }\n }\n\n private async request<T>(method: string, params: Record<string, unknown>): Promise<McpResponse<T>> {\n this.ensureConnected();\n\n const id = ++this.requestIdCounter;\n this._lastRequestId = id;\n const start = Date.now();\n\n try {\n const response = await this.transport!.request<T>({\n jsonrpc: '2.0',\n id,\n method,\n params,\n });\n\n const durationMs = Date.now() - start;\n this.updateSessionActivity();\n\n if ('error' in response && response.error) {\n const error = response.error as McpErrorInfo;\n this.traceRequest(method, params, id, response, durationMs);\n return {\n success: false,\n error,\n durationMs,\n requestId: id,\n };\n }\n\n this.traceRequest(method, params, id, response, durationMs);\n return {\n success: true,\n data: response.result as T,\n durationMs,\n requestId: id,\n };\n } catch (err) {\n const durationMs = Date.now() - start;\n const error: McpErrorInfo = {\n code: -32603,\n message: err instanceof Error ? err.message : 'Unknown error',\n };\n return {\n success: false,\n error,\n durationMs,\n requestId: id,\n };\n }\n }\n\n private ensureConnected(): void {\n if (!this.transport?.isConnected()) {\n throw new Error('Not connected to MCP server. Call connect() first.');\n }\n }\n\n private updateSessionActivity(): void {\n if (this._sessionInfo) {\n this._sessionInfo.lastActivityAt = new Date();\n this._sessionInfo.requestCount++;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: RESULT WRAPPERS\n // ═══════════════════════════════════════════════════════════════════\n\n private wrapToolResult(response: McpResponse<CallToolResult>): ToolResultWrapper {\n const raw = response.data ?? { content: [] };\n const isError = !response.success || raw.isError === true;\n\n // Check for Tool UI response - has UI metadata in _meta\n // Platform-specific HTML keys:\n // - OpenAI: openai/html\n // - ext-apps: ui/html\n // - Others: frontmcp/html (+ ui/html for compatibility)\n const meta = raw._meta as Record<string, unknown> | undefined;\n const hasUI =\n meta?.['ui/html'] !== undefined ||\n meta?.['ui/component'] !== undefined ||\n meta?.['openai/html'] !== undefined ||\n meta?.['frontmcp/html'] !== undefined;\n const structuredContent = (raw as Record<string, unknown>)['structuredContent'];\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n json<T>(): T {\n // For Tool UI responses, return structuredContent (the typed output)\n if (hasUI && structuredContent !== undefined) {\n return structuredContent as T;\n }\n // For regular responses, parse text content as JSON\n const textContent = raw.content?.find((c) => c.type === 'text');\n if (textContent && 'text' in textContent) {\n return JSON.parse(textContent.text) as T;\n }\n throw new Error('No text content to parse as JSON');\n },\n text(): string | undefined {\n const textContent = raw.content?.find((c) => c.type === 'text');\n if (textContent && 'text' in textContent) {\n return textContent.text;\n }\n return undefined;\n },\n hasTextContent(): boolean {\n return raw.content?.some((c) => c.type === 'text') ?? false;\n },\n hasImageContent(): boolean {\n return raw.content?.some((c) => c.type === 'image') ?? false;\n },\n hasResourceContent(): boolean {\n return raw.content?.some((c) => c.type === 'resource') ?? false;\n },\n hasToolUI(): boolean {\n return hasUI;\n },\n };\n }\n\n private wrapResourceContent(response: McpResponse<ReadResourceResult>): ResourceContentWrapper {\n const raw = response.data ?? { contents: [] };\n const isError = !response.success;\n const firstContent = raw.contents?.[0];\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n json<T>(): T {\n if (firstContent && 'text' in firstContent) {\n return JSON.parse(firstContent.text) as T;\n }\n throw new Error('No text content to parse as JSON');\n },\n text(): string | undefined {\n if (firstContent && 'text' in firstContent) {\n return firstContent.text;\n }\n return undefined;\n },\n mimeType(): string | undefined {\n return firstContent?.mimeType;\n },\n hasMimeType(type: string): boolean {\n return firstContent?.mimeType === type;\n },\n };\n }\n\n private wrapPromptResult(response: McpResponse<GetPromptResult>): PromptResultWrapper {\n const raw = response.data ?? { messages: [] };\n const isError = !response.success;\n\n return {\n raw,\n isSuccess: !isError,\n isError,\n error: response.error,\n durationMs: response.durationMs,\n messages: raw.messages ?? [],\n description: raw.description,\n };\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: LOGGING & TRACING\n // ═══════════════════════════════════════════════════════════════════\n\n private log(level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: unknown): void {\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date(),\n data,\n };\n this._logs.push(entry);\n\n if (this.config.debug) {\n console.log(`[${level.toUpperCase()}] ${message}`, data ?? '');\n }\n }\n\n private traceRequest(\n method: string,\n params: unknown,\n id: string | number,\n response: JSONRPCResponse,\n durationMs: number,\n ): void {\n this._traces.push({\n request: { method, params, id },\n response: {\n result: 'result' in response ? response.result : undefined,\n error: 'error' in response ? (response.error as McpErrorInfo) : undefined,\n },\n durationMs,\n timestamp: new Date(),\n });\n }\n\n // ═══════════════════════════════════════════════════════════════════\n // PRIVATE: TOKEN PARSING\n // ═══════════════════════════════════════════════════════════════════\n\n private parseScopesFromToken(token: string): string[] {\n try {\n const payload = this.decodeJwtPayload(token);\n if (!payload) return [];\n const scope = payload['scope'];\n const scopes = payload['scopes'];\n if (typeof scope === 'string') {\n return scope.split(' ');\n }\n if (Array.isArray(scopes)) {\n return scopes as string[];\n }\n return [];\n } catch {\n return [];\n }\n }\n\n private parseUserFromToken(token: string): { sub: string; email?: string; name?: string } | undefined {\n try {\n const payload = this.decodeJwtPayload(token);\n const sub = payload?.['sub'];\n if (!sub || typeof sub !== 'string') return undefined;\n return {\n sub,\n email: payload['email'] as string | undefined,\n name: payload['name'] as string | undefined,\n };\n } catch {\n return undefined;\n }\n }\n\n private decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n const payload = Buffer.from(parts[1], 'base64url').toString('utf-8');\n return JSON.parse(payload);\n } catch {\n return null;\n }\n }\n}\n\n// ═══════════════════════════════════════════════════════════════════\n// NOTIFICATION COLLECTORS\n// ═══════════════════════════════════════════════════════════════════\n\nclass NotificationCollector {\n constructor(private readonly notifications: NotificationEntry[]) {}\n\n get received(): NotificationEntry[] {\n return [...this.notifications];\n }\n\n has(method: string): boolean {\n return this.notifications.some((n) => n.method === method);\n }\n\n async waitFor(method: string, timeoutMs: number): Promise<NotificationEntry> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const found = this.notifications.find((n) => n.method === method);\n if (found) return found;\n await new Promise((r) => setTimeout(r, 50));\n }\n throw new Error(`Timeout waiting for notification: ${method}`);\n }\n}\n\nclass ProgressCollector {\n constructor(private readonly updates: ProgressUpdate[]) {}\n\n get all(): ProgressUpdate[] {\n return [...this.updates];\n }\n\n async waitForComplete(timeoutMs: number): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const last = this.updates[this.updates.length - 1];\n if (last && last.total !== undefined && last.progress >= last.total) {\n return;\n }\n await new Promise((r) => setTimeout(r, 50));\n }\n throw new Error('Timeout waiting for progress to complete');\n }\n}\n"]}