@gleanwork/mcp-server-tester 0.12.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.
- package/LICENSE +21 -0
- package/README.md +421 -0
- package/dist/cli/index.js +2785 -0
- package/dist/fixtures/mcp.d.ts +605 -0
- package/dist/fixtures/mcp.js +2378 -0
- package/dist/fixtures/mcp.js.map +1 -0
- package/dist/fixtures/mcpAuth.d.ts +31 -0
- package/dist/fixtures/mcpAuth.js +317 -0
- package/dist/fixtures/mcpAuth.js.map +1 -0
- package/dist/index.cjs +3658 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3857 -0
- package/dist/index.d.ts +3857 -0
- package/dist/index.js +3582 -0
- package/dist/index.js.map +1 -0
- package/dist/reporters/mcpReporter.cjs +301 -0
- package/dist/reporters/mcpReporter.cjs.map +1 -0
- package/dist/reporters/mcpReporter.d.cts +85 -0
- package/dist/reporters/mcpReporter.d.ts +85 -0
- package/dist/reporters/mcpReporter.js +297 -0
- package/dist/reporters/mcpReporter.js.map +1 -0
- package/dist/reporters/ui-dist/app.js +174 -0
- package/dist/reporters/ui-dist/index.html +28 -0
- package/dist/reporters/ui-dist/styles.css +1 -0
- package/package.json +138 -0
- package/src/reporters/ui-dist/app.js +174 -0
- package/src/reporters/ui-dist/index.html +28 -0
- package/src/reporters/ui-dist/styles.css +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/oauthClientProvider.ts","../src/config/mcpConfig.ts","../src/index.ts","../src/auth/tokenAuth.ts","../src/auth/setupOAuth.ts","../src/debug.ts","../src/auth/discovery.ts","../src/auth/storage.ts","../src/auth/oauthFlow.ts","../src/auth/cli.ts","../src/mcp/clientFactory.ts","../src/mcp/response.ts","../src/assertions/validators/utils.ts","../src/assertions/validators/response.ts","../src/assertions/validators/schema.ts","../src/assertions/validators/text.ts","../src/assertions/validators/pattern.ts","../src/assertions/validators/error.ts","../src/assertions/validators/size.ts","../src/mcp/fixtures/mcpFixture.ts","../src/assertions/matchers/toMatchToolResponse.ts","../src/assertions/matchers/toMatchToolSchema.ts","../src/assertions/matchers/toContainToolText.ts","../src/assertions/matchers/toMatchToolPattern.ts","../src/assertions/matchers/toMatchToolSnapshot.ts","../src/assertions/matchers/toBeToolError.ts","../src/judge/claudeAgentJudge.ts","../src/judge/judgeClient.ts","../src/assertions/matchers/toPassToolJudge.ts","../src/assertions/matchers/toHaveToolResponseSize.ts","../src/assertions/matchers/toSatisfyToolPredicate.ts","../src/assertions/matchers/index.ts","../src/fixtures/mcp.ts","../src/evals/datasetTypes.ts","../src/evals/datasetLoader.ts","../src/evals/llmHost/adapter.ts","../src/evals/llmHost/retry.ts","../src/evals/llmHost/orchestrator.ts","../src/evals/llmHost/adapters/openai.ts","../src/evals/llmHost/adapters/anthropic.ts","../src/evals/llmHost/llmHostSimulation.ts","../src/evals/evalRunner.ts","../src/evals/llmHost/toolCallExpectation.ts","../src/spec/conformanceChecks.ts"],"names":["path","loadOAuthState","oauth","fs2","createDebug","DEFAULT_TIMEOUT_MS","extractText","truncateForDisplay","baseExpect","base","z","readFile","extractErrorMessage","result","pass"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * OAuth client provider implementation for MCP SDK\n *\n * Implements the MCP SDK's OAuthClientProvider interface using file-based storage\n * for integration with Playwright's auth state pattern.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';\nimport type {\n OAuthClientMetadata,\n OAuthClientInformationFull,\n OAuthTokens,\n} from '@modelcontextprotocol/sdk/shared/auth.js';\nimport type { StoredOAuthState } from './types.js';\n\n/**\n * Configuration for the Playwright OAuth client provider\n */\nexport interface PlaywrightOAuthClientProviderConfig {\n /**\n * Path to the auth state file (e.g., playwright/.auth/oauth-state.json)\n */\n storagePath: string;\n\n /**\n * OAuth redirect URI for callback\n */\n redirectUri: string;\n\n /**\n * Client metadata for DCR or display\n */\n clientMetadata?: Partial<OAuthClientMetadata>;\n\n /**\n * Pre-registered client ID (if not using DCR)\n */\n clientId?: string;\n\n /**\n * Pre-registered client secret (if not using DCR)\n */\n clientSecret?: string;\n}\n\n/**\n * OAuth client provider that implements the MCP SDK's OAuthClientProvider interface\n *\n * Uses file-based storage for integration with Playwright's auth state pattern.\n * Auth state is persisted to disk so it can be reused across test runs.\n *\n * @example\n * ```typescript\n * const provider = new PlaywrightOAuthClientProvider({\n * storagePath: 'playwright/.auth/oauth-state.json',\n * redirectUri: 'http://localhost:3000/callback',\n * });\n *\n * const transport = new StreamableHTTPClientTransport(serverUrl, {\n * authProvider: provider,\n * });\n * ```\n */\nexport class PlaywrightOAuthClientProvider implements OAuthClientProvider {\n private readonly config: PlaywrightOAuthClientProviderConfig;\n private cachedState: StoredOAuthState | null = null;\n private stateParam: string | null = null;\n\n constructor(config: PlaywrightOAuthClientProviderConfig) {\n this.config = config;\n }\n\n /**\n * The URL to redirect the user agent to after authorization\n */\n get redirectUrl(): string {\n return this.config.redirectUri;\n }\n\n /**\n * Metadata about this OAuth client\n */\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.config.redirectUri],\n token_endpoint_auth_method: this.config.clientSecret\n ? 'client_secret_basic'\n : 'none',\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n client_name: '@gleanwork/mcp-server-tester',\n ...this.config.clientMetadata,\n };\n }\n\n /**\n * Returns an OAuth2 state parameter\n */\n state(): string {\n if (!this.stateParam) {\n this.stateParam = this.generateRandomString(32);\n }\n return this.stateParam;\n }\n\n /**\n * Loads information about this OAuth client\n */\n async clientInformation(): Promise<OAuthClientInformationFull | undefined> {\n // If we have a pre-registered client, return it\n if (this.config.clientId) {\n return {\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n redirect_uris: [this.config.redirectUri],\n };\n }\n\n // Otherwise, try to load from storage (DCR result)\n const state = await this.loadState();\n if (state?.clientInfo) {\n return {\n client_id: state.clientInfo.clientId,\n client_secret: state.clientInfo.clientSecret,\n client_id_issued_at: state.clientInfo.clientIdIssuedAt,\n client_secret_expires_at: state.clientInfo.clientSecretExpiresAt,\n redirect_uris: [this.config.redirectUri],\n };\n }\n\n return undefined;\n }\n\n /**\n * Saves client information from Dynamic Client Registration\n */\n async saveClientInformation(\n clientInformation: OAuthClientInformationFull\n ): Promise<void> {\n const state = (await this.loadState()) ?? this.createEmptyState();\n state.clientInfo = {\n clientId: clientInformation.client_id,\n clientSecret: clientInformation.client_secret,\n clientIdIssuedAt: clientInformation.client_id_issued_at,\n clientSecretExpiresAt: clientInformation.client_secret_expires_at,\n };\n await this.saveState(state);\n }\n\n /**\n * Loads any existing OAuth tokens for the current session\n */\n async tokens(): Promise<OAuthTokens | undefined> {\n const state = await this.loadState();\n if (state?.tokens) {\n return {\n access_token: state.tokens.accessToken,\n token_type: state.tokens.tokenType,\n refresh_token: state.tokens.refreshToken,\n expires_in: state.tokens.expiresAt\n ? Math.floor((state.tokens.expiresAt - Date.now()) / 1000)\n : undefined,\n };\n }\n return undefined;\n }\n\n /**\n * Stores new OAuth tokens for the current session\n */\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n const state = (await this.loadState()) ?? this.createEmptyState();\n state.tokens = {\n accessToken: tokens.access_token,\n tokenType: tokens.token_type,\n refreshToken: tokens.refresh_token,\n expiresAt: tokens.expires_in\n ? Date.now() + tokens.expires_in * 1000\n : undefined,\n };\n await this.saveState(state);\n }\n\n /**\n * Invoked to redirect the user agent to the given URL\n *\n * In a testing context, this is typically handled by Playwright automation.\n * This implementation throws an error to signal that the caller needs to\n * handle the redirect externally.\n */\n async redirectToAuthorization(authorizationUrl: URL): Promise<void> {\n // In a test context, the authorization flow should be handled externally\n // by Playwright automation (e.g., in globalSetup)\n throw new Error(\n `OAuth authorization required. Redirect to: ${authorizationUrl.toString()}\\n` +\n 'In a testing context, use performOAuthSetup() in your Playwright globalSetup ' +\n 'to complete the OAuth flow before running tests.'\n );\n }\n\n /**\n * Saves a PKCE code verifier for the current session\n */\n async saveCodeVerifier(codeVerifier: string): Promise<void> {\n const state = (await this.loadState()) ?? this.createEmptyState();\n state.codeVerifier = codeVerifier;\n await this.saveState(state);\n }\n\n /**\n * Loads the PKCE code verifier for the current session\n */\n async codeVerifier(): Promise<string> {\n const state = await this.loadState();\n if (!state?.codeVerifier) {\n throw new Error('No code verifier found in auth state');\n }\n return state.codeVerifier;\n }\n\n /**\n * Invalidates the specified credentials\n */\n async invalidateCredentials(\n scope: 'all' | 'client' | 'tokens' | 'verifier'\n ): Promise<void> {\n const state = await this.loadState();\n if (!state) {\n return;\n }\n\n switch (scope) {\n case 'all':\n await this.deleteState();\n break;\n case 'client':\n delete state.clientInfo;\n await this.saveState(state);\n break;\n case 'tokens':\n delete state.tokens;\n await this.saveState(state);\n break;\n case 'verifier':\n delete state.codeVerifier;\n await this.saveState(state);\n break;\n }\n }\n\n // ---- Private helper methods ----\n\n private async loadState(): Promise<StoredOAuthState | null> {\n if (this.cachedState) {\n return this.cachedState;\n }\n\n try {\n const content = await fs.readFile(this.config.storagePath, 'utf-8');\n this.cachedState = JSON.parse(content) as StoredOAuthState;\n return this.cachedState;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n }\n\n private async saveState(state: StoredOAuthState): Promise<void> {\n state.savedAt = Date.now();\n this.cachedState = state;\n\n // Ensure directory exists\n const dir = path.dirname(this.config.storagePath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(\n this.config.storagePath,\n JSON.stringify(state, null, 2),\n 'utf-8'\n );\n }\n\n private async deleteState(): Promise<void> {\n this.cachedState = null;\n try {\n await fs.unlink(this.config.storagePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n private createEmptyState(): StoredOAuthState {\n return {\n savedAt: Date.now(),\n };\n }\n\n private generateRandomString(length: number): string {\n const chars =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = '';\n const randomValues = new Uint8Array(length);\n crypto.getRandomValues(randomValues);\n for (let i = 0; i < length; i++) {\n const randomValue = randomValues[i] ?? 0;\n result += chars[randomValue % chars.length];\n }\n return result;\n }\n}\n\n/**\n * Loads OAuth state from a single file (Playwright auth pattern)\n *\n * This function reads from Playwright's single-file auth state format,\n * typically created by `performOAuthSetup` in globalSetup.\n *\n * **Note:** This does NOT work with tokens stored by the CLI (`mcp-server-tester login`).\n * For CLI-stored tokens, use `loadTokens(serverUrl)` instead.\n *\n * @param storagePath - Path to the auth state file (e.g., 'playwright/.auth/oauth-state.json')\n * @returns The stored OAuth state, or null if not found\n *\n * @example\n * ```typescript\n * // Load Playwright auth state\n * const state = await loadOAuthState('playwright/.auth/oauth-state.json');\n * ```\n */\nexport async function loadOAuthState(\n storagePath: string\n): Promise<StoredOAuthState | null> {\n try {\n const content = await fs.readFile(storagePath, 'utf-8');\n return JSON.parse(content) as StoredOAuthState;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Saves OAuth state to a single file (Playwright auth pattern)\n *\n * This function writes to Playwright's single-file auth state format.\n * Used by `performOAuthSetup` in globalSetup.\n *\n * **Note:** This does NOT work with the CLI storage format (`mcp-server-tester login`).\n * For programmatic token injection compatible with CLI, use `injectTokens(serverUrl, tokens)`.\n *\n * @param storagePath - Path to the auth state file (e.g., 'playwright/.auth/oauth-state.json')\n * @param state - The OAuth state to save\n *\n * @example\n * ```typescript\n * // Save Playwright auth state\n * await saveOAuthState('playwright/.auth/oauth-state.json', {\n * tokens: { accessToken: '...', tokenType: 'Bearer' },\n * savedAt: Date.now(),\n * });\n * ```\n */\nexport async function saveOAuthState(\n storagePath: string,\n state: StoredOAuthState\n): Promise<void> {\n state.savedAt = Date.now();\n\n // Ensure directory exists\n const dir = path.dirname(storagePath);\n await fs.mkdir(dir, { recursive: true });\n\n await fs.writeFile(storagePath, JSON.stringify(state, null, 2), 'utf-8');\n}\n","import { z } from 'zod';\n\n/**\n * OAuth configuration for MCP authentication\n */\nexport interface MCPOAuthConfig {\n /**\n * OAuth authorization server metadata URL\n * (e.g., https://auth.example.com/.well-known/oauth-authorization-server)\n */\n serverUrl: string;\n\n /**\n * Scopes to request during authorization\n */\n scopes?: Array<string>;\n\n /**\n * Resource indicator (RFC 8707, required by MCP 2025-06-18 spec)\n */\n resource?: string;\n\n /**\n * Path to Playwright auth state file\n * (e.g., playwright/.auth/oauth-state.json)\n */\n authStatePath?: string;\n\n /**\n * Client ID (if pre-registered; otherwise uses Dynamic Client Registration)\n */\n clientId?: string;\n\n /**\n * Client secret (for confidential clients)\n */\n clientSecret?: string;\n\n /**\n * Redirect URI for OAuth callback\n */\n redirectUri?: string;\n}\n\n/**\n * Authentication configuration for MCP connections\n */\nexport interface MCPAuthConfig {\n /**\n * Pre-acquired access token (simplest authentication mode)\n */\n accessToken?: string;\n\n /**\n * Full OAuth configuration for browser-based authentication\n */\n oauth?: MCPOAuthConfig;\n}\n\n/**\n * MCP host capabilities that can be registered with the server\n */\nexport interface MCPHostCapabilities {\n /**\n * Sampling capabilities (for LLM sampling)\n */\n sampling?: Record<string, unknown>;\n\n /**\n * Roots capabilities (for file system roots)\n */\n roots?: {\n /**\n * Whether the client can notify the server when roots change\n */\n listChanged: boolean;\n };\n}\n\n/**\n * Configuration for MCP client connection\n *\n * Supports both stdio (local) and HTTP (remote) transports\n */\nexport interface MCPConfig {\n /**\n * Transport type\n */\n transport: 'http' | 'stdio';\n\n /**\n * Server URL (required when transport === 'http')\n */\n serverUrl?: string;\n\n /**\n * HTTP headers (optional for http transport, e.g., Authorization)\n */\n headers?: Record<string, string>;\n\n /**\n * Command to execute (required when transport === 'stdio')\n */\n command?: string;\n\n /**\n * Command arguments (optional for stdio)\n */\n args?: Array<string>;\n\n /**\n * Working directory for the command (optional for stdio)\n */\n cwd?: string;\n\n /**\n * Host capabilities to register with the server\n */\n capabilities?: MCPHostCapabilities;\n\n /**\n * Connection timeout in milliseconds\n */\n connectTimeoutMs?: number;\n\n /**\n * Request timeout in milliseconds\n */\n requestTimeoutMs?: number;\n\n /**\n * Suppress stderr output from the server process (stdio only)\n * When true, server stderr is ignored instead of inherited\n */\n quiet?: boolean;\n\n /**\n * Authentication configuration (optional for http transport)\n */\n auth?: MCPAuthConfig;\n}\n\n/**\n * Zod schema for MCPHostCapabilities\n */\nconst MCPHostCapabilitiesSchema = z.object({\n sampling: z.record(z.unknown()).optional(),\n roots: z\n .object({\n listChanged: z.boolean(),\n })\n .optional(),\n});\n\n/**\n * Zod schema for MCPOAuthConfig\n */\nconst MCPOAuthConfigSchema = z.object({\n serverUrl: z.string().url('serverUrl must be a valid URL'),\n scopes: z.array(z.string()).optional(),\n resource: z.string().url().optional(),\n authStatePath: z.string().optional(),\n clientId: z.string().optional(),\n clientSecret: z.string().optional(),\n redirectUri: z.string().url().optional(),\n});\n\n/**\n * Zod schema for MCPAuthConfig\n */\nconst MCPAuthConfigSchema = z\n .object({\n accessToken: z.string().optional(),\n oauth: MCPOAuthConfigSchema.optional(),\n })\n .refine(\n (data) => !(data.accessToken && data.oauth),\n 'Cannot specify both accessToken and oauth configuration'\n );\n\n/**\n * Zod schema for stdio transport config\n */\nconst StdioConfigSchema = z.object({\n transport: z.literal('stdio'),\n command: z.string().min(1, 'command is required for stdio transport'),\n args: z.array(z.string()).optional(),\n cwd: z.string().optional(),\n capabilities: MCPHostCapabilitiesSchema.optional(),\n connectTimeoutMs: z.number().positive().optional(),\n requestTimeoutMs: z.number().positive().optional(),\n quiet: z.boolean().optional(),\n});\n\n/**\n * Zod schema for HTTP transport config\n */\nconst HttpConfigSchema = z.object({\n transport: z.literal('http'),\n serverUrl: z.string().url('serverUrl must be a valid URL'),\n headers: z.record(z.string()).optional(),\n capabilities: MCPHostCapabilitiesSchema.optional(),\n connectTimeoutMs: z.number().positive().optional(),\n requestTimeoutMs: z.number().positive().optional(),\n auth: MCPAuthConfigSchema.optional(),\n});\n\n/**\n * Union schema for MCPConfig (validates based on transport type)\n */\nexport const MCPConfigSchema = z.discriminatedUnion('transport', [\n StdioConfigSchema,\n HttpConfigSchema,\n]);\n\n/**\n * Validates an MCPConfig object\n *\n * @param config - The config to validate\n * @returns The validated config\n * @throws {z.ZodError} If validation fails\n */\nexport function validateMCPConfig(config: unknown): MCPConfig {\n return MCPConfigSchema.parse(config);\n}\n\n/**\n * Type guard to check if a config is for stdio transport\n */\nexport function isStdioConfig(\n config: MCPConfig\n): config is MCPConfig & { transport: 'stdio'; command: string } {\n return config.transport === 'stdio' && typeof config.command === 'string';\n}\n\n/**\n * Type guard to check if a config is for HTTP transport\n */\nexport function isHttpConfig(\n config: MCPConfig\n): config is MCPConfig & { transport: 'http'; serverUrl: string } {\n return config.transport === 'http' && typeof config.serverUrl === 'string';\n}\n","/**\n * @gleanwork/mcp-server-tester\n *\n * Playwright-based testing framework for MCP servers\n *\n * @packageDocumentation\n */\n\n// Config\nexport type {\n MCPConfig,\n MCPHostCapabilities,\n MCPAuthConfig,\n MCPOAuthConfig,\n} from './config/mcpConfig.js';\nexport {\n MCPConfigSchema,\n validateMCPConfig,\n isStdioConfig,\n isHttpConfig,\n} from './config/mcpConfig.js';\n\n// Auth\nexport type {\n StoredTokens,\n StoredClientInfo,\n StoredOAuthState,\n OAuthSetupConfig,\n TokenResult,\n} from './auth/types.js';\nexport {\n PlaywrightOAuthClientProvider,\n type PlaywrightOAuthClientProviderConfig,\n} from './auth/oauthClientProvider.js';\nexport {\n createTokenAuthHeaders,\n validateAccessToken,\n isTokenExpired,\n isTokenExpiringSoon,\n} from './auth/tokenAuth.js';\nexport {\n performOAuthSetup,\n performOAuthSetupIfNeeded,\n} from './auth/setupOAuth.js';\n\n// Discovery (RFC 9728)\nexport {\n discoverProtectedResource,\n discoverAuthorizationServer,\n DiscoveryError,\n MCP_PROTOCOL_VERSION,\n type ProtectedResourceMetadata,\n type ProtectedResourceDiscoveryResult,\n} from './auth/discovery.js';\n\n// Token Storage\nexport {\n loadTokens,\n hasValidTokens,\n injectTokens,\n loadTokensFromEnv,\n ENV_VAR_NAMES,\n type StoredServerMetadata,\n} from './auth/storage.js';\n\n// CLI OAuth\nexport {\n CLIOAuthClient,\n type CLIOAuthClientConfig,\n type CLIOAuthResult,\n} from './auth/cli.js';\n\n// MCP Client\nexport {\n createMCPClientForConfig,\n closeMCPClient,\n type CreateMCPClientOptions,\n} from './mcp/clientFactory.js';\n\n// Response Normalization\nexport type { ContentBlock, NormalizedToolResponse } from './mcp/response.js';\nexport {\n normalizeToolResponse,\n extractText,\n extractText as extractTextFromResponse,\n} from './mcp/response.js';\n\n// Assertions - Matchers (primary API)\n// The extended expect with MCP tool matchers is exported via fixtures\n// Use: import { expect } from '@gleanwork/mcp-server-tester'\n\n// Assertions - Validators (for programmatic use)\nexport {\n validateResponse,\n validateSchema,\n validateText,\n validatePattern,\n validateError,\n validateSize,\n getResponseSizeBytes,\n normalizeWhitespace,\n} from './assertions/validators/index.js';\n\nexport type {\n ValidationResult,\n TextValidatorOptions,\n SizeValidatorOptions,\n SchemaValidatorOptions,\n PatternValidatorOptions,\n SnapshotSanitizer,\n BuiltInSanitizer,\n RegexSanitizer,\n FieldRemovalSanitizer,\n SchemaRegistry,\n} from './assertions/validators/types.js';\n\nexport type {\n JudgeMatcherOptions,\n ToolPredicate,\n PredicateResult,\n} from './assertions/matchers/types.js';\n\n// Fixtures\nexport type {\n MCPFixtureApi,\n MCPFixtureOptions,\n AuthType,\n} from './mcp/fixtures/mcpFixture.js';\nexport { createMCPFixture } from './mcp/fixtures/mcpFixture.js';\nexport { test, expect } from './fixtures/mcp.js';\n\n// Canonical Types (single source of truth)\nexport type {\n ResultSource,\n ExpectationType,\n ExpectationBreakdown,\n ExpectationResultMap,\n} from './types/index.js';\n\n// Eval Dataset\nexport type {\n EvalCase,\n EvalDataset,\n EvalExpectBlock,\n SerializedEvalDataset,\n EvalMode,\n} from './evals/datasetTypes.js';\nexport {\n EvalCaseSchema,\n EvalDatasetSchema,\n validateEvalCase,\n validateEvalDataset,\n} from './evals/datasetTypes.js';\n\n// Eval Loader\nexport type { LoadDatasetOptions } from './evals/datasetLoader.js';\nexport {\n loadEvalDataset,\n loadEvalDatasetFromObject,\n} from './evals/datasetLoader.js';\n\n// Eval Runner\nexport type {\n EvalContext,\n EvalExpectationResult,\n EvalCaseResult,\n EvalRunnerResult,\n EvalRunnerOptions,\n} from './evals/evalRunner.js';\nexport { runEvalDataset, runEvalCase } from './evals/evalRunner.js';\n\n// LLM Host Simulation\nexport type {\n LLMProvider,\n LLMHostConfig,\n LLMToolCall,\n LLMHostSimulationResult,\n LLMHostSimulator,\n ExpectedToolCall,\n ToolCallValidationResult,\n ToolCallValidator,\n} from './evals/llmHost/index.js';\nexport {\n simulateLLMHost,\n isProviderAvailable,\n getMissingDependencyMessage,\n createToolCallValidator,\n} from './evals/llmHost/index.js';\n\n// Judge\nexport type {\n JudgeConfig,\n Judge,\n JudgeResult,\n UsageMetrics,\n ProviderKind,\n} from './judge/judgeTypes.js';\nexport { createJudge } from './judge/judgeClient.js';\n\n// Conformance\nexport type {\n MCPConformanceOptions,\n MCPConformanceResult,\n MCPConformanceCheck,\n MCPConformanceRaw,\n} from './spec/conformanceChecks.js';\nexport { runConformanceChecks } from './spec/conformanceChecks.js';\n\n// Reporter\nexport type {\n MCPEvalReporterConfig,\n MCPEvalRunData,\n MCPEvalHistoricalSummary,\n MCPConformanceResultData,\n MCPServerCapabilitiesData,\n MCPEvalData,\n} from './reporters/types.js';\n","/**\n * Static token authentication utilities\n *\n * Simple utilities for pre-acquired token authentication\n */\n\n/**\n * Creates HTTP headers for static token authentication\n *\n * @param accessToken - The pre-acquired access token\n * @param tokenType - The token type (default: \"Bearer\")\n * @returns HTTP headers with Authorization header\n *\n * @example\n * ```typescript\n * const headers = createTokenAuthHeaders(process.env.MCP_ACCESS_TOKEN);\n * // { Authorization: 'Bearer eyJ...' }\n * ```\n */\nexport function createTokenAuthHeaders(\n accessToken: string,\n tokenType: string = 'Bearer'\n): Record<string, string> {\n return {\n Authorization: `${tokenType} ${accessToken}`,\n };\n}\n\n/**\n * Validates that an access token is present and non-empty\n *\n * @param accessToken - The access token to validate\n * @throws Error if token is missing or empty\n */\nexport function validateAccessToken(accessToken: string | undefined): void {\n if (!accessToken) {\n throw new Error('Access token is required but was not provided');\n }\n\n if (accessToken.trim().length === 0) {\n throw new Error('Access token cannot be empty');\n }\n}\n\n/**\n * Checks if a token appears to be expired based on common JWT structure\n *\n * Note: This is a best-effort check and may not work for all token formats.\n * For reliable expiration checking, use the token's associated expiration time.\n *\n * @param accessToken - The access token to check\n * @returns true if the token appears to be expired, false otherwise\n */\nexport function isTokenExpired(accessToken: string): boolean {\n try {\n // Try to decode as JWT\n const parts = accessToken.split('.');\n if (parts.length !== 3) {\n // Not a JWT, can't determine expiration\n return false;\n }\n\n const payloadPart = parts[1];\n if (!payloadPart) {\n return false;\n }\n\n const payload = JSON.parse(\n Buffer.from(payloadPart, 'base64url').toString('utf-8')\n ) as Record<string, unknown>;\n\n if (typeof payload.exp === 'number') {\n // exp is in seconds, Date.now() is in milliseconds\n return payload.exp * 1000 < Date.now();\n }\n\n return false;\n } catch {\n // If we can't parse the token, assume it's not expired\n return false;\n }\n}\n\n/**\n * Checks if a token will expire within the specified buffer time\n *\n * @param expiresAt - Token expiration timestamp in milliseconds\n * @param bufferMs - Buffer time in milliseconds (default: 60000 = 1 minute)\n * @returns true if the token will expire within the buffer time\n */\nexport function isTokenExpiringSoon(\n expiresAt: number | undefined,\n bufferMs: number = 60000\n): boolean {\n if (expiresAt === undefined) {\n return false;\n }\n\n return expiresAt - bufferMs < Date.now();\n}\n","/**\n * OAuth setup utility for Playwright globalSetup\n *\n * Performs the browser-based OAuth flow and saves the auth state\n * for reuse across tests following Playwright's auth state pattern.\n */\n\nimport { chromium, type Page } from '@playwright/test';\nimport {\n discoverAuthorizationServerMetadata,\n startAuthorization,\n exchangeAuthorization,\n} from '@modelcontextprotocol/sdk/client/auth.js';\nimport type { OAuthSetupConfig, StoredOAuthState } from './types.js';\nimport { saveOAuthState } from './oauthClientProvider.js';\nimport { debugOAuth } from '../debug.js';\n\n/**\n * Default timeout for OAuth login flow (30 seconds)\n */\nconst DEFAULT_TIMEOUT_MS = 30000;\n\n/**\n * Default redirect URI for OAuth callback\n */\nconst DEFAULT_REDIRECT_URI = 'http://localhost:3000/oauth/callback';\n\n/**\n * Performs the OAuth authorization flow using Playwright browser automation\n *\n * This function is designed to be used in Playwright's globalSetup to\n * authenticate once before running tests. The resulting auth state is\n * saved to disk and reused across tests.\n *\n * @param config - OAuth setup configuration\n *\n * @example\n * ```typescript\n * // global-setup.ts\n * import { performOAuthSetup } from '@gleanwork/mcp-server-tester';\n *\n * export default async function globalSetup() {\n * await performOAuthSetup({\n * authServerUrl: 'https://auth.example.com',\n * scopes: ['mcp:read', 'mcp:write'],\n * loginSelectors: {\n * usernameInput: '#username',\n * passwordInput: '#password',\n * submitButton: 'button[type=\"submit\"]',\n * },\n * credentials: {\n * username: process.env.TEST_USER!,\n * password: process.env.TEST_PASSWORD!,\n * },\n * outputPath: 'playwright/.auth/oauth-state.json',\n * });\n * }\n * ```\n */\nexport async function performOAuthSetup(\n config: OAuthSetupConfig\n): Promise<void> {\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const redirectUri = config.redirectUri ?? DEFAULT_REDIRECT_URI;\n\n // 1. Discover OAuth authorization server metadata\n const metadata = await discoverAuthorizationServerMetadata(\n config.authServerUrl\n );\n\n if (!metadata) {\n throw new Error(\n `Could not discover OAuth metadata at ${config.authServerUrl}`\n );\n }\n\n // 2. Build client information\n const clientInformation = {\n client_id: config.clientId ?? 'mcp-server-tester-client',\n client_secret: config.clientSecret,\n };\n\n // 3. Start authorization flow (generates PKCE, builds auth URL)\n const { authorizationUrl, codeVerifier } = await startAuthorization(\n config.authServerUrl,\n {\n metadata,\n clientInformation,\n redirectUrl: redirectUri,\n scope: config.scopes.join(' '),\n resource: config.resource ? new URL(config.resource) : undefined,\n }\n );\n\n // 4. Launch browser and complete login flow\n const browser = await chromium.launch({\n headless: process.env.OAUTH_DEBUG !== 'true',\n });\n\n try {\n const context = await browser.newContext();\n const page = await context.newPage();\n\n // Set timeout for the entire flow\n page.setDefaultTimeout(timeoutMs);\n\n // Navigate to authorization URL\n await page.goto(authorizationUrl.toString());\n\n // Complete login form\n await completeLoginForm(page, config);\n\n // Wait for redirect with authorization code\n await page.waitForURL(\n (url) => url.href.startsWith(redirectUri) && url.searchParams.has('code'),\n { timeout: timeoutMs }\n );\n\n // Extract authorization code from callback URL\n const callbackUrl = new URL(page.url());\n const code = callbackUrl.searchParams.get('code');\n const error = callbackUrl.searchParams.get('error');\n\n if (error) {\n const errorDescription =\n callbackUrl.searchParams.get('error_description');\n throw new Error(\n `OAuth authorization failed: ${error}${errorDescription ? ` - ${errorDescription}` : ''}`\n );\n }\n\n if (!code) {\n throw new Error('No authorization code in callback URL');\n }\n\n // 5. Exchange authorization code for tokens\n const tokens = await exchangeAuthorization(config.authServerUrl, {\n metadata,\n clientInformation,\n authorizationCode: code,\n codeVerifier,\n redirectUri,\n resource: config.resource ? new URL(config.resource) : undefined,\n });\n\n // 6. Save auth state to disk\n const state: StoredOAuthState = {\n tokens: {\n accessToken: tokens.access_token,\n tokenType: tokens.token_type,\n refreshToken: tokens.refresh_token,\n expiresAt: tokens.expires_in\n ? Date.now() + tokens.expires_in * 1000\n : undefined,\n },\n clientInfo: config.clientId\n ? {\n clientId: config.clientId,\n clientSecret: config.clientSecret,\n }\n : undefined,\n codeVerifier,\n savedAt: Date.now(),\n };\n\n await saveOAuthState(config.outputPath, state);\n\n debugOAuth('Auth state saved to %s', config.outputPath);\n } finally {\n await browser.close();\n }\n}\n\n/**\n * Completes the login form using the provided selectors\n */\nasync function completeLoginForm(\n page: Page,\n config: OAuthSetupConfig\n): Promise<void> {\n const { loginSelectors, credentials } = config;\n\n // Wait for and fill username\n await page.waitForSelector(loginSelectors.usernameInput, {\n state: 'visible',\n });\n await page.fill(loginSelectors.usernameInput, credentials.username);\n\n // Wait for and fill password\n await page.waitForSelector(loginSelectors.passwordInput, {\n state: 'visible',\n });\n await page.fill(loginSelectors.passwordInput, credentials.password);\n\n // Click submit button\n await page.waitForSelector(loginSelectors.submitButton, {\n state: 'visible',\n });\n await page.click(loginSelectors.submitButton);\n\n // Handle consent button if present\n if (loginSelectors.consentButton) {\n try {\n await page.waitForSelector(loginSelectors.consentButton, {\n state: 'visible',\n timeout: 5000,\n });\n await page.click(loginSelectors.consentButton);\n } catch {\n // Consent button may not appear if already consented\n }\n }\n}\n\n/**\n * Checks if OAuth state exists and contains valid tokens (Playwright auth pattern)\n *\n * This function checks Playwright's single-file auth state format,\n * typically created by `performOAuthSetup` in globalSetup.\n *\n * **Note:** This does NOT work with tokens stored by the CLI (`mcp-server-tester login`).\n * For CLI-stored tokens, use `hasValidTokens(serverUrl)` instead.\n *\n * @param storagePath - Path to the auth state file (e.g., 'playwright/.auth/oauth-state.json')\n * @returns true if valid auth state exists\n *\n * @example\n * ```typescript\n * // Check Playwright auth state\n * if (await hasValidOAuthState('playwright/.auth/oauth-state.json')) {\n * console.log('Auth state is valid, skipping OAuth setup');\n * }\n * ```\n */\nexport async function hasValidOAuthState(\n storagePath: string\n): Promise<boolean> {\n try {\n const { loadOAuthState } = await import('./oauthClientProvider.js');\n const state = await loadOAuthState(storagePath);\n\n if (!state?.tokens?.accessToken) {\n return false;\n }\n\n // Check if token is expired (with 1 minute buffer)\n if (state.tokens.expiresAt) {\n const bufferMs = 60000;\n if (state.tokens.expiresAt - bufferMs < Date.now()) {\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Performs OAuth setup only if valid state doesn't already exist\n *\n * Use this in globalSetup to avoid re-authenticating on every test run.\n *\n * @param config - OAuth setup configuration\n *\n * @example\n * ```typescript\n * // global-setup.ts\n * export default async function globalSetup() {\n * await performOAuthSetupIfNeeded({\n * authServerUrl: 'https://auth.example.com',\n * scopes: ['mcp:read'],\n * loginSelectors: { ... },\n * credentials: { ... },\n * outputPath: 'playwright/.auth/oauth-state.json',\n * });\n * }\n * ```\n */\nexport async function performOAuthSetupIfNeeded(\n config: OAuthSetupConfig\n): Promise<void> {\n const hasValid = await hasValidOAuthState(config.outputPath);\n\n if (hasValid) {\n debugOAuth('Using existing auth state from %s', config.outputPath);\n return;\n }\n\n debugOAuth('No valid auth state found, performing OAuth flow...');\n await performOAuthSetup(config);\n}\n","/**\n * Debug logging utilities\n *\n * Uses the `debug` package for conditional logging.\n * Enable via DEBUG environment variable:\n *\n * @example\n * ```bash\n * # Enable all mcp-server-tester logs\n * DEBUG=mcp-server-tester:* npm test\n *\n * # Enable only client logs\n * DEBUG=mcp-server-tester:client npm test\n *\n * # Enable only OAuth logs\n * DEBUG=mcp-server-tester:oauth npm test\n * ```\n */\n\nimport createDebug from 'debug';\n\nconst NAMESPACE = 'mcp-server-tester';\n\n/**\n * Debug logger for MCP client operations\n */\nexport const debugClient = createDebug(`${NAMESPACE}:client`);\n\n/**\n * Debug logger for OAuth operations\n */\nexport const debugOAuth = createDebug(`${NAMESPACE}:oauth`);\n\n/**\n * Debug logger for eval operations\n */\nexport const debugEval = createDebug(`${NAMESPACE}:eval`);\n","/**\n * OAuth Protected Resource and Authorization Server discovery\n *\n * Implements RFC 9728 (OAuth Protected Resource Metadata) and\n * RFC 8414 (Authorization Server Metadata) for MCP servers.\n */\n\nimport * as oauth from 'oauth4webapi';\nimport type { AuthServerMetadata } from './oauthFlow.js';\n\n/**\n * MCP Protocol version header value\n */\nexport const MCP_PROTOCOL_VERSION = '2025-06-18';\n\n/**\n * Protected Resource Metadata (RFC 9728)\n */\nexport interface ProtectedResourceMetadata {\n /**\n * The protected resource URL\n */\n resource: string;\n\n /**\n * Array of authorization server URLs\n */\n authorization_servers?: Array<string>;\n\n /**\n * Scopes supported by the protected resource\n */\n scopes_supported?: Array<string>;\n\n /**\n * Bearer token formats supported\n */\n bearer_methods_supported?: Array<string>;\n\n /**\n * Resource documentation URL\n */\n resource_documentation?: string;\n\n /**\n * Resource signing algorithms\n */\n resource_signing_alg_values_supported?: Array<string>;\n}\n\n/**\n * Result of protected resource discovery\n */\nexport interface ProtectedResourceDiscoveryResult {\n /**\n * The discovered metadata\n */\n metadata: ProtectedResourceMetadata;\n\n /**\n * The URL where metadata was found\n */\n discoveryUrl: string;\n\n /**\n * Whether path-aware discovery was used (vs base discovery)\n */\n usedPathAwareDiscovery: boolean;\n}\n\n/**\n * Discovers protected resource metadata per RFC 9728\n *\n * Follows RFC 9728 Section 4.1 for path-aware discovery:\n * 1. First tries: {origin}/.well-known/oauth-protected-resource{pathname}\n * 2. Falls back to: {origin}/.well-known/oauth-protected-resource\n *\n * @param mcpServerUrl - The MCP server URL\n * @returns Protected resource discovery result\n * @throws Error if discovery fails completely\n *\n * @example\n * const result = await discoverProtectedResource('https://api.example.com/mcp/default');\n * console.log(result.metadata.authorization_servers);\n */\nexport async function discoverProtectedResource(\n mcpServerUrl: string\n): Promise<ProtectedResourceDiscoveryResult> {\n const url = new URL(mcpServerUrl);\n const origin = url.origin;\n const pathname = url.pathname;\n\n // Try path-aware discovery first (RFC 9728 Section 4.1)\n const pathAwareUrl = `${origin}/.well-known/oauth-protected-resource${pathname}`;\n\n try {\n const metadata = await fetchProtectedResourceMetadata(pathAwareUrl);\n return {\n metadata,\n discoveryUrl: pathAwareUrl,\n usedPathAwareDiscovery: true,\n };\n } catch (error) {\n // If path-aware fails with 404, try base discovery\n if (error instanceof DiscoveryError && error.status === 404) {\n const baseUrl = `${origin}/.well-known/oauth-protected-resource`;\n\n // This will throw if base discovery also fails\n const metadata = await fetchProtectedResourceMetadata(baseUrl);\n return {\n metadata,\n discoveryUrl: baseUrl,\n usedPathAwareDiscovery: false,\n };\n }\n\n // Non-404 error from path-aware discovery\n throw error;\n }\n}\n\n/**\n * Error thrown when discovery fails\n */\nexport class DiscoveryError extends Error {\n constructor(\n message: string,\n public readonly status?: number,\n public readonly url?: string\n ) {\n super(message);\n this.name = 'DiscoveryError';\n }\n}\n\n/**\n * Fetches protected resource metadata from a discovery URL\n */\nasync function fetchProtectedResourceMetadata(\n discoveryUrl: string\n): Promise<ProtectedResourceMetadata> {\n const response = await fetch(discoveryUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n 'MCP-Protocol-Version': MCP_PROTOCOL_VERSION,\n },\n });\n\n if (!response.ok) {\n throw new DiscoveryError(\n `Protected resource discovery failed: ${response.status} ${response.statusText}`,\n response.status,\n discoveryUrl\n );\n }\n\n const metadata = (await response.json()) as ProtectedResourceMetadata;\n\n // Validate required field\n if (!metadata.resource) {\n throw new DiscoveryError(\n 'Invalid protected resource metadata: missing required \"resource\" field',\n undefined,\n discoveryUrl\n );\n }\n\n return metadata;\n}\n\n/**\n * Discovers OAuth Authorization Server metadata per RFC 8414\n *\n * Wraps oauth4webapi's discovery with MCP-specific headers.\n *\n * @param authServerUrl - The authorization server URL\n * @returns Authorization server metadata\n * @throws Error if discovery fails\n *\n * @example\n * const authServer = await discoverAuthorizationServer('https://auth.example.com');\n * console.log(authServer.server.token_endpoint);\n */\nexport async function discoverAuthorizationServer(\n authServerUrl: string\n): Promise<AuthServerMetadata> {\n const issuer = new URL(authServerUrl);\n\n // Use oauth4webapi for discovery with custom headers\n const response = await oauth.discoveryRequest(issuer, {\n algorithm: 'oauth2',\n headers: new Headers({\n 'MCP-Protocol-Version': MCP_PROTOCOL_VERSION,\n }),\n });\n\n const metadata = await oauth.processDiscoveryResponse(issuer, response);\n\n return {\n server: metadata,\n issuer: authServerUrl,\n };\n}\n","/**\n * OAuth token storage with environment variable support for CI/CD\n *\n * Provides file-based storage for OAuth state per MCP server, with support\n * for token injection via environment variables for automated testing.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { homedir } from 'node:os';\nimport type { StoredTokens, StoredClientInfo } from './types.js';\nimport type { AuthServerMetadata } from './oauthFlow.js';\nimport type { ProtectedResourceMetadata } from './discovery.js';\n\n/**\n * Combined server metadata (auth server + protected resource)\n */\nexport interface StoredServerMetadata {\n /**\n * Authorization server metadata\n */\n authServer: AuthServerMetadata;\n\n /**\n * Protected resource metadata\n */\n protectedResource: ProtectedResourceMetadata;\n\n /**\n * Timestamp when metadata was discovered\n */\n discoveredAt: number;\n}\n\n/**\n * Interface for OAuth storage operations\n */\nexport interface OAuthStorage {\n /**\n * Load combined server metadata\n */\n loadServerMetadata(): Promise<StoredServerMetadata | null>;\n\n /**\n * Save combined server metadata\n */\n saveServerMetadata(metadata: StoredServerMetadata): Promise<void>;\n\n /**\n * Load registered client information\n */\n loadClient(): Promise<StoredClientInfo | null>;\n\n /**\n * Save registered client information\n */\n saveClient(client: StoredClientInfo): Promise<void>;\n\n /**\n * Load stored tokens\n */\n loadTokens(): Promise<StoredTokens | null>;\n\n /**\n * Save tokens\n */\n saveTokens(tokens: StoredTokens): Promise<void>;\n\n /**\n * Delete stored tokens\n */\n deleteTokens(): Promise<void>;\n\n /**\n * Check if valid (non-expired) token exists\n * @param bufferMs - Buffer time in milliseconds before expiration (default: 60000)\n */\n hasValidToken(bufferMs?: number): Promise<boolean>;\n}\n\n/**\n * Configuration for file-based OAuth storage\n */\nexport interface FileOAuthStorageConfig {\n /**\n * MCP server URL (used to generate storage key)\n */\n serverUrl: string;\n\n /**\n * Custom state directory (overrides default)\n */\n stateDir?: string;\n}\n\n/**\n * Environment variable names for CI/CD token injection\n */\nexport const ENV_VAR_NAMES = {\n accessToken: 'MCP_ACCESS_TOKEN',\n refreshToken: 'MCP_REFRESH_TOKEN',\n tokenType: 'MCP_TOKEN_TYPE',\n expiresAt: 'MCP_TOKEN_EXPIRES_AT',\n} as const;\n\n/**\n * Default buffer time before token expiration (60 seconds)\n */\nconst DEFAULT_EXPIRY_BUFFER_MS = 60_000;\n\n/**\n * Generates a filesystem-safe key from a server URL\n *\n * @param serverUrl - The MCP server URL\n * @returns A filesystem-safe key string\n *\n * @example\n * generateServerKey('https://api.example.com:8080/mcp')\n * // Returns: 'api.example.com_8080_mcp'\n */\nexport function generateServerKey(serverUrl: string): string {\n const url = new URL(serverUrl);\n\n // Start with hostname\n let key = url.hostname;\n\n // Add port if non-standard\n if (url.port) {\n key += `_${url.port}`;\n }\n\n // Add path, replacing slashes with underscores\n if (url.pathname && url.pathname !== '/') {\n const cleanPath = url.pathname\n .replace(/^\\/+|\\/+$/g, '') // Remove leading/trailing slashes\n .replace(/\\//g, '_'); // Replace remaining slashes with underscores\n if (cleanPath) {\n key += `_${cleanPath}`;\n }\n }\n\n // Make filesystem-safe: replace any remaining problematic characters\n return key.replace(/[^a-zA-Z0-9_.-]/g, '_');\n}\n\n/**\n * Gets the state directory for a server\n *\n * Default locations:\n * - Linux: $XDG_STATE_HOME/mcp-tests/{serverKey}/ or ~/.local/state/mcp-tests/{serverKey}/\n * - macOS: ~/.local/state/mcp-tests/{serverKey}/\n * - Windows: %LOCALAPPDATA%\\mcp-tests\\{serverKey}\\\n *\n * @param serverUrl - The MCP server URL\n * @param customDir - Optional custom base directory\n * @returns The state directory path\n */\nexport function getStateDir(serverUrl: string, customDir?: string): string {\n const serverKey = generateServerKey(serverUrl);\n\n if (customDir) {\n return path.join(customDir, serverKey);\n }\n\n // Platform-specific defaults\n if (process.platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA;\n if (localAppData) {\n return path.join(localAppData, 'mcp-tests', serverKey);\n }\n // Fallback for Windows\n return path.join(homedir(), 'AppData', 'Local', 'mcp-tests', serverKey);\n }\n\n // Linux: Honor XDG_STATE_HOME\n if (process.platform === 'linux' && process.env.XDG_STATE_HOME) {\n return path.join(process.env.XDG_STATE_HOME, 'mcp-tests', serverKey);\n }\n\n // Default for macOS and Linux\n return path.join(homedir(), '.local', 'state', 'mcp-tests', serverKey);\n}\n\n/**\n * Get the base directory for all MCP token storage\n */\nexport function getBaseStateDir(): string {\n if (process.platform === 'win32') {\n const localAppData = process.env.LOCALAPPDATA;\n if (localAppData) {\n return path.join(localAppData, 'mcp-tests');\n }\n return path.join(homedir(), 'AppData', 'Local', 'mcp-tests');\n }\n\n if (process.platform === 'linux' && process.env.XDG_STATE_HOME) {\n return path.join(process.env.XDG_STATE_HOME, 'mcp-tests');\n }\n\n return path.join(homedir(), '.local', 'state', 'mcp-tests');\n}\n\n/**\n * Known server info\n */\nexport interface KnownServer {\n /** The server key (directory name) */\n key: string;\n /** Reconstructed URL (best effort) */\n url: string;\n /** Whether valid tokens exist */\n hasTokens: boolean;\n}\n\n/**\n * List all known authenticated servers from the token storage directory\n *\n * @returns Array of known servers with their URLs and token status\n */\nexport async function listKnownServers(): Promise<KnownServer[]> {\n const baseDir = getBaseStateDir();\n const servers: KnownServer[] = [];\n\n try {\n const entries = await fs.readdir(baseDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const serverKey = entry.name;\n const tokensPath = path.join(baseDir, serverKey, 'tokens.json');\n\n let hasTokens = false;\n try {\n await fs.access(tokensPath);\n hasTokens = true;\n } catch {\n // No tokens file\n }\n\n // Reconstruct URL from server key (best effort)\n // Format: hostname_port_path or hostname_path\n const parts = serverKey.split('_');\n const hostname = parts[0];\n const rest = parts.slice(1).join('/');\n const url = `https://${hostname}/${rest}`;\n\n servers.push({ key: serverKey, url, hasTokens });\n }\n } catch {\n // Directory doesn't exist or not readable\n }\n\n return servers;\n}\n\n/**\n * Reads tokens from environment variables (for CI/CD)\n *\n * @returns StoredTokens if MCP_ACCESS_TOKEN is set, null otherwise\n */\nexport function loadTokensFromEnv(): StoredTokens | null {\n const accessToken = process.env[ENV_VAR_NAMES.accessToken];\n\n if (!accessToken) {\n return null;\n }\n\n const expiresAtStr = process.env[ENV_VAR_NAMES.expiresAt];\n const expiresAt = expiresAtStr ? parseInt(expiresAtStr, 10) : undefined;\n\n return {\n accessToken,\n refreshToken: process.env[ENV_VAR_NAMES.refreshToken],\n tokenType: process.env[ENV_VAR_NAMES.tokenType] ?? 'Bearer',\n expiresAt: expiresAt && !isNaN(expiresAt) ? expiresAt : undefined,\n };\n}\n\n/**\n * Programmatically inject tokens into storage (for CI/CD setup)\n *\n * @param serverUrl - The MCP server URL\n * @param tokens - The tokens to inject\n * @param stateDir - Optional custom state directory\n */\nexport async function injectTokens(\n serverUrl: string,\n tokens: StoredTokens,\n stateDir?: string\n): Promise<void> {\n const storage = createFileOAuthStorage({ serverUrl, stateDir });\n await storage.saveTokens(tokens);\n}\n\n/**\n * Load stored OAuth tokens for an MCP server\n *\n * Reads tokens from the standard storage location for the given server URL.\n * Tokens are stored by `mcp-server-tester login` or `injectTokens()`.\n *\n * @param serverUrl - The MCP server URL\n * @param stateDir - Optional custom state directory\n * @returns StoredTokens if found, null otherwise\n *\n * @example\n * ```typescript\n * // After running: npx mcp-server-tester login https://api.example.com/mcp\n * const tokens = await loadTokens('https://api.example.com/mcp');\n * if (tokens) {\n * console.log('Access token:', tokens.accessToken);\n * }\n * ```\n */\nexport async function loadTokens(\n serverUrl: string,\n stateDir?: string\n): Promise<StoredTokens | null> {\n const storage = createFileOAuthStorage({ serverUrl, stateDir });\n return storage.loadTokens();\n}\n\n/**\n * Check if valid OAuth tokens exist for an MCP server\n *\n * Returns true if tokens exist and are not expired (with buffer).\n * Use this to check if authentication is needed before making requests.\n *\n * @param serverUrl - The MCP server URL\n * @param options - Optional configuration\n * @param options.stateDir - Custom state directory\n * @param options.bufferMs - Buffer time before expiration (default: 60000ms)\n * @returns true if valid (non-expired) tokens exist\n *\n * @example\n * ```typescript\n * if (await hasValidTokens('https://api.example.com/mcp')) {\n * // Use stored tokens\n * const tokens = await loadTokens('https://api.example.com/mcp');\n * } else {\n * console.log('Run: npx mcp-server-tester login https://api.example.com/mcp');\n * }\n * ```\n */\nexport async function hasValidTokens(\n serverUrl: string,\n options?: { stateDir?: string; bufferMs?: number }\n): Promise<boolean> {\n const storage = createFileOAuthStorage({\n serverUrl,\n stateDir: options?.stateDir,\n });\n return storage.hasValidToken(options?.bufferMs);\n}\n\n/**\n * Creates a file-based OAuth storage instance\n *\n * @param config - Storage configuration\n * @returns OAuthStorage instance\n */\nexport function createFileOAuthStorage(\n config: FileOAuthStorageConfig\n): OAuthStorage {\n return new FileOAuthStorage(config);\n}\n\n/**\n * File-based OAuth storage implementation\n */\nclass FileOAuthStorage implements OAuthStorage {\n private readonly stateDir: string;\n\n constructor(config: FileOAuthStorageConfig) {\n this.stateDir = getStateDir(config.serverUrl, config.stateDir);\n }\n\n private get serverMetadataPath(): string {\n return path.join(this.stateDir, 'server.json');\n }\n\n private get clientPath(): string {\n return path.join(this.stateDir, 'client.json');\n }\n\n private get tokensPath(): string {\n return path.join(this.stateDir, 'tokens.json');\n }\n\n async loadServerMetadata(): Promise<StoredServerMetadata | null> {\n return this.loadFile<StoredServerMetadata>(this.serverMetadataPath);\n }\n\n async saveServerMetadata(metadata: StoredServerMetadata): Promise<void> {\n await this.atomicWrite(this.serverMetadataPath, metadata);\n }\n\n async loadClient(): Promise<StoredClientInfo | null> {\n return this.loadFile<StoredClientInfo>(this.clientPath);\n }\n\n async saveClient(client: StoredClientInfo): Promise<void> {\n await this.atomicWrite(this.clientPath, client);\n }\n\n async loadTokens(): Promise<StoredTokens | null> {\n return this.loadFile<StoredTokens>(this.tokensPath);\n }\n\n async saveTokens(tokens: StoredTokens): Promise<void> {\n await this.atomicWrite(this.tokensPath, tokens);\n }\n\n async deleteTokens(): Promise<void> {\n await this.deleteFile(this.tokensPath);\n }\n\n async hasValidToken(\n bufferMs: number = DEFAULT_EXPIRY_BUFFER_MS\n ): Promise<boolean> {\n const tokens = await this.loadTokens();\n\n if (!tokens?.accessToken) {\n return false;\n }\n\n // If no expiration, assume valid\n if (!tokens.expiresAt) {\n return true;\n }\n\n // Check if token is expired (with buffer)\n return tokens.expiresAt > Date.now() + bufferMs;\n }\n\n /**\n * Load a JSON file, returning null if not found\n */\n private async loadFile<T>(filePath: string): Promise<T | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as T;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Write data atomically: write to .tmp file, then rename\n * Files are created with 0o600 permissions (user read/write only)\n */\n private async atomicWrite(filePath: string, data: unknown): Promise<void> {\n // Ensure directory exists with restrictive permissions\n await fs.mkdir(this.stateDir, { recursive: true, mode: 0o700 });\n\n const tmpPath = `${filePath}.tmp`;\n const content = JSON.stringify(data, null, 2);\n\n // Write to temp file with restrictive permissions (user read/write only)\n await fs.writeFile(tmpPath, content, { encoding: 'utf-8', mode: 0o600 });\n\n // Atomic rename\n await fs.rename(tmpPath, filePath);\n }\n\n /**\n * Delete a file, ignoring errors if the file doesn't exist\n */\n private async deleteFile(filePath: string): Promise<void> {\n try {\n await fs.unlink(filePath);\n } catch (error) {\n // Ignore ENOENT (file doesn't exist)\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n}\n","/**\n * OAuth flow utilities using oauth4webapi\n *\n * Implements OAuth 2.1 with PKCE as required by MCP specification\n */\n\nimport * as oauth from 'oauth4webapi';\nimport type { TokenResult } from './types.js';\n\n/**\n * Discovered OAuth authorization server metadata\n */\nexport interface AuthServerMetadata {\n /**\n * The oauth4webapi AuthorizationServer object\n */\n server: oauth.AuthorizationServer;\n\n /**\n * Issuer URL\n */\n issuer: string;\n}\n\n/**\n * PKCE code verifier and challenge pair\n */\nexport interface PKCEPair {\n /**\n * Random code verifier string\n */\n codeVerifier: string;\n\n /**\n * S256 hashed code challenge\n */\n codeChallenge: string;\n}\n\n/**\n * Configuration for building authorization URL\n */\nexport interface AuthorizationUrlConfig {\n /**\n * Authorization server metadata\n */\n authServer: AuthServerMetadata;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Redirect URI for callback\n */\n redirectUri: string;\n\n /**\n * Requested scopes\n */\n scopes: Array<string>;\n\n /**\n * PKCE code challenge\n */\n codeChallenge: string;\n\n /**\n * OAuth state parameter for CSRF protection\n */\n state: string;\n\n /**\n * Resource indicator (RFC 8707)\n */\n resource?: string;\n}\n\n/**\n * Configuration for token exchange\n */\nexport interface TokenExchangeConfig {\n /**\n * Authorization server metadata\n */\n authServer: AuthServerMetadata;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Client secret (for confidential clients)\n */\n clientSecret?: string;\n\n /**\n * Authorization code from callback\n */\n code: string;\n\n /**\n * OAuth state parameter for CSRF validation\n */\n state: string;\n\n /**\n * PKCE code verifier\n */\n codeVerifier: string;\n\n /**\n * Redirect URI used in authorization request\n */\n redirectUri: string;\n}\n\n/**\n * Configuration for token refresh\n */\nexport interface TokenRefreshConfig {\n /**\n * Authorization server metadata\n */\n authServer: AuthServerMetadata;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Client secret (for confidential clients)\n */\n clientSecret?: string;\n\n /**\n * Refresh token\n */\n refreshToken: string;\n}\n\n/**\n * Discovers OAuth authorization server metadata from a well-known URL\n *\n * @param issuerUrl - The authorization server URL (will append /.well-known/oauth-authorization-server)\n * @returns Authorization server metadata\n */\nexport async function discoverAuthServer(\n issuerUrl: string\n): Promise<AuthServerMetadata> {\n const issuer = new URL(issuerUrl);\n const response = await oauth.discoveryRequest(issuer, {\n algorithm: 'oauth2',\n });\n\n const metadata = await oauth.processDiscoveryResponse(issuer, response);\n\n return {\n server: metadata,\n issuer: issuerUrl,\n };\n}\n\n/**\n * Generates a PKCE code verifier and challenge pair\n *\n * Uses S256 challenge method as required by OAuth 2.1 and MCP specification\n *\n * @returns PKCE code verifier and challenge\n */\nexport async function generatePKCE(): Promise<PKCEPair> {\n const codeVerifier = oauth.generateRandomCodeVerifier();\n const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);\n\n return {\n codeVerifier,\n codeChallenge,\n };\n}\n\n/**\n * Generates a random state parameter for CSRF protection\n *\n * @returns Random state string\n */\nexport function generateState(): string {\n return oauth.generateRandomState();\n}\n\n/**\n * Builds the OAuth authorization URL for browser redirect\n *\n * @param config - Authorization URL configuration\n * @returns Authorization URL to redirect the user to\n */\nexport function buildAuthorizationUrl(config: AuthorizationUrlConfig): URL {\n const authorizationEndpoint = config.authServer.server.authorization_endpoint;\n if (!authorizationEndpoint) {\n throw new Error(\n 'Authorization server does not have an authorization_endpoint'\n );\n }\n\n const authorizationUrl = new URL(authorizationEndpoint);\n\n authorizationUrl.searchParams.set('client_id', config.clientId);\n authorizationUrl.searchParams.set('redirect_uri', config.redirectUri);\n authorizationUrl.searchParams.set('response_type', 'code');\n authorizationUrl.searchParams.set('scope', config.scopes.join(' '));\n authorizationUrl.searchParams.set('code_challenge', config.codeChallenge);\n authorizationUrl.searchParams.set('code_challenge_method', 'S256');\n authorizationUrl.searchParams.set('state', config.state);\n\n if (config.resource) {\n authorizationUrl.searchParams.set('resource', config.resource);\n }\n\n return authorizationUrl;\n}\n\n/**\n * Exchanges an authorization code for tokens\n *\n * @param config - Token exchange configuration\n * @returns Token result\n */\nexport async function exchangeCodeForTokens(\n config: TokenExchangeConfig\n): Promise<TokenResult> {\n const client: oauth.Client = {\n client_id: config.clientId,\n token_endpoint_auth_method: config.clientSecret\n ? 'client_secret_basic'\n : 'none',\n };\n\n const clientAuth = config.clientSecret\n ? oauth.ClientSecretBasic(config.clientSecret)\n : oauth.None();\n\n // Build callback URL with code and state for validation\n const callbackUrl = new URL(config.redirectUri);\n callbackUrl.searchParams.set('code', config.code);\n callbackUrl.searchParams.set('state', config.state);\n\n // Validate the auth response - oauth4webapi requires this before token exchange\n // This throws on error, returns URLSearchParams on success\n const validatedParams = oauth.validateAuthResponse(\n config.authServer.server,\n client,\n callbackUrl,\n config.state\n );\n\n const response = await oauth.authorizationCodeGrantRequest(\n config.authServer.server,\n client,\n clientAuth,\n validatedParams,\n config.redirectUri,\n config.codeVerifier\n );\n\n const result = await oauth.processAuthorizationCodeResponse(\n config.authServer.server,\n client,\n response\n );\n\n return {\n accessToken: result.access_token,\n tokenType: result.token_type,\n expiresIn: result.expires_in,\n refreshToken: result.refresh_token,\n scope: result.scope,\n };\n}\n\n/**\n * Refreshes an access token using a refresh token\n *\n * @param config - Token refresh configuration\n * @returns New token result\n */\nexport async function refreshAccessToken(\n config: TokenRefreshConfig\n): Promise<TokenResult> {\n const client: oauth.Client = {\n client_id: config.clientId,\n token_endpoint_auth_method: config.clientSecret\n ? 'client_secret_basic'\n : 'none',\n };\n\n const clientAuth = config.clientSecret\n ? oauth.ClientSecretBasic(config.clientSecret)\n : oauth.None();\n\n const response = await oauth.refreshTokenGrantRequest(\n config.authServer.server,\n client,\n clientAuth,\n config.refreshToken\n );\n\n // Handle non-OK responses that may not be JSON (oauth4webapi requires application/json)\n if (!response.ok) {\n const contentType = response.headers.get('content-type') ?? '';\n let errorMessage = `Token refresh failed: ${response.status} ${response.statusText}`;\n\n try {\n if (contentType.includes('application/json')) {\n // Try to extract OAuth error from JSON response\n const errorBody = (await response.clone().json()) as {\n error?: string;\n error_description?: string;\n };\n if (errorBody.error) {\n errorMessage = `Token refresh failed: ${errorBody.error}`;\n if (errorBody.error_description) {\n errorMessage += ` - ${errorBody.error_description}`;\n }\n }\n } else {\n // Non-JSON response (e.g., text/plain) - read the body as text\n const textBody = await response.clone().text();\n if (textBody) {\n errorMessage = `Token refresh failed: ${response.status} - ${textBody}`;\n }\n }\n } catch {\n // If we can't parse the error body, use the status message\n }\n\n throw new Error(errorMessage);\n }\n\n const result = await oauth.processRefreshTokenResponse(\n config.authServer.server,\n client,\n response\n );\n\n return {\n accessToken: result.access_token,\n tokenType: result.token_type,\n expiresIn: result.expires_in,\n refreshToken: result.refresh_token,\n scope: result.scope,\n };\n}\n\n/**\n * Validates the callback URL from OAuth redirect\n *\n * @param callbackUrl - The full callback URL with query parameters\n * @param expectedState - The state parameter sent in the authorization request\n * @returns The authorization code\n * @throws Error if validation fails\n */\nexport function validateCallback(\n callbackUrl: URL,\n expectedState: string\n): string {\n const error = callbackUrl.searchParams.get('error');\n if (error) {\n const errorDescription = callbackUrl.searchParams.get('error_description');\n throw new Error(\n `OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ''}`\n );\n }\n\n const state = callbackUrl.searchParams.get('state');\n if (state !== expectedState) {\n throw new Error('OAuth state mismatch - possible CSRF attack');\n }\n\n const code = callbackUrl.searchParams.get('code');\n if (!code) {\n throw new Error('No authorization code in callback URL');\n }\n\n return code;\n}\n","/**\n * CLI OAuth client for command-line authentication flows\n *\n * Provides browser-based OAuth authentication for CLI environments,\n * with support for environment variable token injection for CI/CD.\n */\n\nimport * as http from 'node:http';\nimport type { AddressInfo, Socket } from 'node:net';\nimport createDebug from 'debug';\nimport {\n generatePKCE,\n generateState,\n buildAuthorizationUrl,\n exchangeCodeForTokens,\n refreshAccessToken,\n type AuthServerMetadata,\n} from './oauthFlow.js';\nimport {\n discoverProtectedResource,\n discoverAuthorizationServer,\n MCP_PROTOCOL_VERSION,\n type ProtectedResourceMetadata,\n} from './discovery.js';\nimport {\n createFileOAuthStorage,\n loadTokensFromEnv,\n type OAuthStorage,\n type StoredServerMetadata,\n} from './storage.js';\nimport type { StoredTokens, StoredClientInfo, TokenResult } from './types.js';\n\nconst debug = createDebug('mcp-server-tester:cli-oauth');\n\n/**\n * Configuration for CLI OAuth client\n */\nexport interface CLIOAuthClientConfig {\n /**\n * MCP server URL (for protected resource discovery)\n */\n mcpServerUrl: string;\n\n /**\n * Scopes to request (optional, uses discovered scopes if not provided)\n */\n scopes?: Array<string>;\n\n /**\n * Custom storage directory\n */\n stateDir?: string;\n\n /**\n * Pre-registered client ID (skips DCR if provided)\n */\n clientId?: string;\n\n /**\n * Pre-registered client secret\n */\n clientSecret?: string;\n\n /**\n * Preferred callback port (default: random available port)\n */\n callbackPort?: number;\n\n /**\n * Timeout for OAuth flow in milliseconds (default: 300000 = 5 min)\n */\n timeoutMs?: number;\n\n /**\n * Client name for DCR registration\n */\n clientName?: string;\n}\n\n/**\n * Result of CLI OAuth authentication\n */\nexport interface CLIOAuthResult {\n /**\n * Access token\n */\n accessToken: string;\n\n /**\n * Token type (typically \"Bearer\")\n */\n tokenType: string;\n\n /**\n * Expiration timestamp (Unix ms)\n */\n expiresAt?: number;\n\n /**\n * Whether token was refreshed vs newly acquired\n */\n refreshed: boolean;\n\n /**\n * Scopes that were requested (only set for new authentications)\n */\n requestedScopes?: string[];\n\n /**\n * Whether token came from environment variables\n */\n fromEnv: boolean;\n}\n\n/**\n * Default timeout for OAuth flow (5 minutes)\n */\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n/**\n * Default client name for DCR\n */\nconst DEFAULT_CLIENT_NAME = '@gleanwork/mcp-server-tester';\n\n/**\n * Default TTL for cached server metadata (24 hours)\n * After this time, metadata will be re-discovered\n */\nconst DEFAULT_METADATA_TTL_MS = 24 * 60 * 60 * 1000;\n\n/**\n * CLI OAuth client for command-line authentication flows\n */\nexport class CLIOAuthClient {\n private readonly config: CLIOAuthClientConfig;\n private readonly storage: OAuthStorage;\n\n constructor(config: CLIOAuthClientConfig) {\n this.config = config;\n this.storage = createFileOAuthStorage({\n serverUrl: config.mcpServerUrl,\n stateDir: config.stateDir,\n });\n }\n\n /**\n * Get a valid access token, authenticating if necessary\n *\n * Token resolution priority:\n * 1. Check environment variables (for CI/CD)\n * 2. Check file storage for cached tokens\n * 3. Try to refresh if expired but refresh token exists\n * 4. Run full OAuth flow if needed\n */\n async getAccessToken(): Promise<CLIOAuthResult> {\n // 1. Check environment variables first (CI/CD support)\n const envTokens = loadTokensFromEnv();\n if (envTokens) {\n debug('Using tokens from environment variables');\n return {\n accessToken: envTokens.accessToken,\n tokenType: envTokens.tokenType,\n expiresAt: envTokens.expiresAt,\n refreshed: false,\n fromEnv: true,\n };\n }\n\n // 2. Check file storage for cached tokens\n const storedTokens = await this.storage.loadTokens();\n\n if (storedTokens?.accessToken) {\n // Check if token is still valid\n const isValid = await this.storage.hasValidToken();\n\n if (isValid) {\n debug('Using cached tokens from storage');\n return {\n accessToken: storedTokens.accessToken,\n tokenType: storedTokens.tokenType,\n expiresAt: storedTokens.expiresAt,\n refreshed: false,\n fromEnv: false,\n };\n }\n\n // 3. Try to refresh if we have a refresh token\n if (storedTokens.refreshToken) {\n debug('Token expired, attempting refresh');\n try {\n const refreshedTokens = await this.refreshStoredToken(storedTokens);\n return {\n accessToken: refreshedTokens.accessToken,\n tokenType: refreshedTokens.tokenType,\n expiresAt: refreshedTokens.expiresAt,\n refreshed: true,\n fromEnv: false,\n };\n } catch (error) {\n debug('Token refresh failed, will re-authenticate:', error);\n // Fall through to full authentication\n }\n }\n }\n\n // 4. Run full OAuth flow\n debug('Performing full OAuth authentication');\n return this.authenticate();\n }\n\n /**\n * Try to get a valid access token without triggering browser auth\n *\n * Returns null if no valid token is available (no stored tokens,\n * expired without refresh token, or refresh failed). Unlike getAccessToken(),\n * this will NOT open a browser for authentication.\n *\n * Use this for CLI commands that should prompt the user to run `login`\n * instead of automatically starting the OAuth flow.\n */\n async tryGetAccessToken(): Promise<CLIOAuthResult | null> {\n // 1. Check environment variables first (CI/CD support)\n const envTokens = loadTokensFromEnv();\n if (envTokens) {\n debug('Using tokens from environment variables');\n return {\n accessToken: envTokens.accessToken,\n tokenType: envTokens.tokenType,\n expiresAt: envTokens.expiresAt,\n refreshed: false,\n fromEnv: true,\n };\n }\n\n // 2. Check file storage for cached tokens\n const storedTokens = await this.storage.loadTokens();\n\n if (storedTokens?.accessToken) {\n // Check if token is still valid\n const isValid = await this.storage.hasValidToken();\n\n if (isValid) {\n debug('Using cached tokens from storage');\n return {\n accessToken: storedTokens.accessToken,\n tokenType: storedTokens.tokenType,\n expiresAt: storedTokens.expiresAt,\n refreshed: false,\n fromEnv: false,\n };\n }\n\n // 3. Try to refresh if we have a refresh token\n if (storedTokens.refreshToken) {\n debug('Token expired, attempting refresh');\n try {\n const refreshedTokens = await this.refreshStoredToken(storedTokens);\n return {\n accessToken: refreshedTokens.accessToken,\n tokenType: refreshedTokens.tokenType,\n expiresAt: refreshedTokens.expiresAt,\n refreshed: true,\n fromEnv: false,\n };\n } catch (error) {\n debug('Token refresh failed:', error);\n // Return null - don't fall through to browser auth\n return null;\n }\n }\n }\n\n // No valid token available - return null instead of opening browser\n debug('No valid token available');\n return null;\n }\n\n /**\n * Force a new authentication flow\n */\n async authenticate(): Promise<CLIOAuthResult> {\n // Discover servers\n const { protectedResource, authServer } = await this.discoverServers();\n\n // Get or register client\n const client = await this.getOrRegisterClient(authServer);\n\n // Perform OAuth flow\n const { tokens, requestedScopes } = await this.performOAuthFlow(\n authServer,\n client,\n protectedResource\n );\n\n return {\n accessToken: tokens.accessToken,\n tokenType: tokens.tokenType,\n expiresAt: tokens.expiresAt,\n refreshed: false,\n fromEnv: false,\n requestedScopes,\n };\n }\n\n /**\n * Check if stored credentials exist (may be expired)\n */\n async hasStoredCredentials(): Promise<boolean> {\n const tokens = await this.storage.loadTokens();\n return tokens?.accessToken !== undefined;\n }\n\n /**\n * Clear stored credentials\n */\n async clearCredentials(): Promise<void> {\n await this.storage.deleteTokens();\n debug('Cleared stored credentials');\n }\n\n /**\n * Discover protected resource and authorization server\n */\n private async discoverServers(): Promise<{\n protectedResource: ProtectedResourceMetadata;\n authServer: AuthServerMetadata;\n }> {\n // Check cached server metadata\n const cachedMetadata = await this.storage.loadServerMetadata();\n if (cachedMetadata) {\n // Check if metadata is stale (older than TTL)\n const age = Date.now() - cachedMetadata.discoveredAt;\n if (age < DEFAULT_METADATA_TTL_MS) {\n debug('Using cached server metadata (age: %dms)', age);\n debug(\n 'Cached protected resource scopes: %O',\n cachedMetadata.protectedResource.scopes_supported\n );\n debug(\n 'Cached auth server scopes: %O',\n cachedMetadata.authServer.server.scopes_supported\n );\n return {\n protectedResource: cachedMetadata.protectedResource,\n authServer: cachedMetadata.authServer,\n };\n }\n debug('Cached server metadata is stale (age: %dms), re-discovering', age);\n }\n\n // Discover protected resource\n debug('Discovering protected resource:', this.config.mcpServerUrl);\n const prResult = await discoverProtectedResource(this.config.mcpServerUrl);\n debug('Found protected resource:', prResult.metadata.resource);\n debug(\n 'Protected resource scopes_supported: %O',\n prResult.metadata.scopes_supported\n );\n\n // Get authorization server URL\n const authServerUrl = prResult.metadata.authorization_servers?.[0];\n if (!authServerUrl) {\n throw new Error(\n 'No authorization servers found in protected resource metadata'\n );\n }\n\n // Discover authorization server\n debug('Discovering authorization server:', authServerUrl);\n const authServer = await discoverAuthorizationServer(authServerUrl);\n debug('Found authorization server:', authServer.issuer);\n debug(\n 'Auth server scopes_supported: %O',\n authServer.server.scopes_supported\n );\n\n // Cache metadata\n const metadata: StoredServerMetadata = {\n authServer,\n protectedResource: prResult.metadata,\n discoveredAt: Date.now(),\n };\n await this.storage.saveServerMetadata(metadata);\n\n return {\n protectedResource: prResult.metadata,\n authServer,\n };\n }\n\n /**\n * Get existing client or register new one via DCR\n */\n private async getOrRegisterClient(\n authServer: AuthServerMetadata\n ): Promise<StoredClientInfo> {\n // Use pre-configured client if provided\n if (this.config.clientId) {\n debug('Using pre-configured client ID');\n return {\n clientId: this.config.clientId,\n clientSecret: this.config.clientSecret,\n };\n }\n\n // Check cached client\n const cachedClient = await this.storage.loadClient();\n if (cachedClient?.clientId) {\n debug('Using cached client registration');\n return cachedClient;\n }\n\n // Register new client via DCR\n debug('Registering new client via DCR');\n const client = await this.registerClient(authServer);\n await this.storage.saveClient(client);\n\n return client;\n }\n\n /**\n * Register a new client via Dynamic Client Registration\n */\n private async registerClient(\n authServer: AuthServerMetadata\n ): Promise<StoredClientInfo> {\n const registrationEndpoint = authServer.server.registration_endpoint;\n if (!registrationEndpoint) {\n throw new Error(\n 'Authorization server does not support Dynamic Client Registration. ' +\n 'Please provide a clientId in the configuration.'\n );\n }\n\n // We'll use a placeholder redirect URI for now\n // The actual port will be determined when we start the callback server\n const redirectUri = 'http://127.0.0.1:0/callback';\n\n const response = await fetch(registrationEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'MCP-Protocol-Version': MCP_PROTOCOL_VERSION,\n },\n body: JSON.stringify({\n redirect_uris: [redirectUri],\n token_endpoint_auth_method: 'none',\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n client_name: this.config.clientName ?? DEFAULT_CLIENT_NAME,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Dynamic Client Registration failed: ${response.status} ${response.statusText}\\n${errorText}`\n );\n }\n\n const data = (await response.json()) as {\n client_id: string;\n client_secret?: string;\n client_id_issued_at?: number;\n client_secret_expires_at?: number;\n };\n\n debug('Client registered:', data.client_id);\n\n return {\n clientId: data.client_id,\n clientSecret: data.client_secret,\n clientIdIssuedAt: data.client_id_issued_at,\n clientSecretExpiresAt: data.client_secret_expires_at,\n };\n }\n\n /**\n * Perform the full OAuth authorization flow\n */\n private async performOAuthFlow(\n authServer: AuthServerMetadata,\n client: StoredClientInfo,\n protectedResource: ProtectedResourceMetadata\n ): Promise<{ tokens: StoredTokens; requestedScopes: string[] }> {\n // Generate PKCE and state\n const pkce = await generatePKCE();\n const state = generateState();\n\n // Start callback server\n const { port, codePromise, close } = await this.startCallbackServer(state);\n const redirectUri = `http://127.0.0.1:${port}/callback`;\n\n try {\n // Determine scopes: user-provided > protected resource > auth server > fallback\n // Try multiple sources since not all servers advertise scopes in the same place\n const requestedScopes = this.config.scopes ??\n protectedResource.scopes_supported ??\n authServer.server.scopes_supported ?? ['openid'];\n\n debug('Scope resolution:');\n debug(' - User config scopes: %O', this.config.scopes);\n debug(\n ' - Protected resource scopes_supported: %O',\n protectedResource.scopes_supported\n );\n debug(\n ' - Auth server scopes_supported: %O',\n authServer.server.scopes_supported\n );\n debug(' - Final requested scopes: %O', requestedScopes);\n\n const authUrl = buildAuthorizationUrl({\n authServer,\n clientId: client.clientId,\n redirectUri,\n scopes: requestedScopes,\n codeChallenge: pkce.codeChallenge,\n state,\n resource: protectedResource.resource,\n });\n\n debug('Authorization URL: %s', authUrl.toString());\n debug('Authorization URL params:');\n debug(' - client_id: %s', authUrl.searchParams.get('client_id'));\n debug(' - redirect_uri: %s', authUrl.searchParams.get('redirect_uri'));\n debug(' - scope: %s', authUrl.searchParams.get('scope'));\n debug(' - resource: %s', authUrl.searchParams.get('resource'));\n\n // Open browser or print URL\n await this.openBrowserOrPrintUrl(authUrl);\n\n // Wait for callback\n debug('Waiting for OAuth callback...');\n const code = await codePromise;\n debug('Received authorization code');\n\n // Exchange code for tokens\n const tokenResult = await exchangeCodeForTokens({\n authServer,\n clientId: client.clientId,\n clientSecret: client.clientSecret,\n code,\n state,\n codeVerifier: pkce.codeVerifier,\n redirectUri,\n });\n\n // Store tokens with the client ID used to obtain them\n const tokens = this.tokenResultToStoredTokens(\n tokenResult,\n client.clientId\n );\n await this.storage.saveTokens(tokens);\n\n return { tokens, requestedScopes };\n } finally {\n // Clean up callback server and all connections\n close();\n }\n }\n\n /**\n * Refresh an expired token\n *\n * Uses the clientId stored with the tokens (if available) to ensure\n * the refresh request uses the same client that obtained the original tokens.\n * This is important because refresh tokens are bound to the client_id.\n */\n private async refreshStoredToken(\n storedTokens: StoredTokens\n ): Promise<StoredTokens> {\n if (!storedTokens.refreshToken) {\n throw new Error('No refresh token available');\n }\n\n // Get cached server metadata\n const metadata = await this.storage.loadServerMetadata();\n if (!metadata) {\n throw new Error('No cached server metadata for refresh');\n }\n\n // Determine which client credentials to use for refresh.\n // Priority: tokens.clientId > stored client.json > error\n let clientId: string;\n let clientSecret: string | undefined;\n\n if (storedTokens.clientId) {\n // Use the client ID that was used to obtain these tokens\n debug('Using clientId from stored tokens for refresh');\n clientId = storedTokens.clientId;\n\n // Try to get the client secret from stored client info if it matches\n const storedClient = await this.storage.loadClient();\n if (storedClient?.clientId === clientId) {\n clientSecret = storedClient.clientSecret;\n }\n } else {\n // Legacy tokens without clientId - fall back to stored client\n debug(\n 'No clientId in stored tokens, falling back to stored client (legacy behavior)'\n );\n const client = await this.getOrRegisterClient(metadata.authServer);\n clientId = client.clientId;\n clientSecret = client.clientSecret;\n }\n\n // Refresh token\n const tokenResult = await refreshAccessToken({\n authServer: metadata.authServer,\n clientId,\n clientSecret,\n refreshToken: storedTokens.refreshToken,\n });\n\n // Store new tokens with the clientId that was used\n const tokens = this.tokenResultToStoredTokens(tokenResult, clientId);\n await this.storage.saveTokens(tokens);\n\n return tokens;\n }\n\n /**\n * Start local callback server\n */\n private async startCallbackServer(expectedState: string): Promise<{\n port: number;\n codePromise: Promise<string>;\n close: () => void;\n }> {\n const timeoutMs = this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n return new Promise((resolve, reject) => {\n const server = http.createServer();\n\n // Track active connections so we can force-close them\n const connections = new Set<Socket>();\n server.on('connection', (socket) => {\n connections.add(socket);\n socket.on('close', () => connections.delete(socket));\n });\n\n // Helper to force-close the server\n const forceClose = () => {\n for (const socket of connections) {\n socket.destroy();\n }\n server.close();\n };\n\n let codeResolve: (code: string) => void;\n let codeReject: (error: Error) => void;\n\n const codePromise = new Promise<string>((res, rej) => {\n codeResolve = res;\n codeReject = rej;\n });\n\n // Set up timeout\n const timeout = setTimeout(() => {\n forceClose();\n codeReject(new Error(`OAuth flow timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n // Handle incoming requests\n server.on('request', (req, res) => {\n const url = new URL(\n req.url ?? '/',\n `http://127.0.0.1:${(server.address() as AddressInfo).port}`\n );\n\n if (url.pathname !== '/callback') {\n res.writeHead(404);\n res.end('Not Found');\n return;\n }\n\n // Check for errors\n const error = url.searchParams.get('error');\n if (error) {\n const errorDescription = url.searchParams.get('error_description');\n clearTimeout(timeout);\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(this.errorHtml(error, errorDescription ?? undefined));\n codeReject(\n new Error(\n `OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ''}`\n )\n );\n return;\n }\n\n // Validate state\n const state = url.searchParams.get('state');\n if (state !== expectedState) {\n clearTimeout(timeout);\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(this.errorHtml('invalid_state', 'State parameter mismatch'));\n codeReject(new Error('OAuth state mismatch - possible CSRF attack'));\n return;\n }\n\n // Get authorization code\n const code = url.searchParams.get('code');\n if (!code) {\n clearTimeout(timeout);\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end(\n this.errorHtml('missing_code', 'No authorization code received')\n );\n codeReject(new Error('No authorization code in callback'));\n return;\n }\n\n // Success!\n clearTimeout(timeout);\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(this.successHtml());\n codeResolve(code);\n });\n\n // Listen on preferred port or random port\n const preferredPort = this.config.callbackPort ?? 0;\n\n server.listen(preferredPort, '127.0.0.1', () => {\n const address = server.address() as AddressInfo;\n debug('Callback server listening on port', address.port);\n resolve({ port: address.port, codePromise, close: forceClose });\n });\n\n server.on('error', (err) => {\n reject(err);\n });\n });\n }\n\n /**\n * Open browser or print URL for headless environments\n */\n private async openBrowserOrPrintUrl(url: URL): Promise<void> {\n if (isHeadless()) {\n console.log('\\n' + '='.repeat(60));\n console.log(\n 'Please open the following URL in your browser to authenticate:'\n );\n console.log('\\n' + url.toString() + '\\n');\n console.log('='.repeat(60) + '\\n');\n return;\n }\n\n try {\n // Dynamic import of 'open' package\n const open = await import('open');\n await open.default(url.toString());\n debug('Opened browser for authentication');\n } catch (error) {\n // If browser opening fails, fall back to printing URL\n debug('Failed to open browser:', error);\n console.log('\\nFailed to open browser automatically.');\n console.log('Please open the following URL manually:\\n');\n console.log(url.toString() + '\\n');\n }\n }\n\n /**\n * Convert TokenResult to StoredTokens\n *\n * @param result - Token result from exchange or refresh\n * @param clientId - Client ID that was used to obtain these tokens\n */\n private tokenResultToStoredTokens(\n result: TokenResult,\n clientId: string\n ): StoredTokens {\n return {\n accessToken: result.accessToken,\n tokenType: result.tokenType,\n refreshToken: result.refreshToken,\n expiresAt: result.expiresIn\n ? Date.now() + result.expiresIn * 1000\n : undefined,\n clientId,\n };\n }\n\n /**\n * HTML page for successful authentication\n */\n private successHtml(): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Authentication Successful</title>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0;\n background: #f8fafc; }\n .container { text-align: center; background: white; padding: 48px 64px; border-radius: 8px;\n border: 1px solid #e2e8f0; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n .icon { width: 48px; height: 48px; margin: 0 auto 24px; background: #dcfce7; border-radius: 50%;\n display: flex; align-items: center; justify-content: center; }\n .icon svg { width: 24px; height: 24px; color: #16a34a; }\n h1 { color: #0f172a; margin: 0 0 8px 0; font-size: 20px; font-weight: 600; }\n p { color: #64748b; margin: 0; font-size: 14px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\"/>\n </svg>\n </div>\n <h1>Authentication Successful</h1>\n <p>You can close this window and return to the terminal.</p>\n </div>\n</body>\n</html>`;\n }\n\n /**\n * HTML page for authentication error\n */\n private errorHtml(error: string, description?: string): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Authentication Failed</title>\n <style>\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0;\n background: #f8fafc; }\n .container { text-align: center; background: white; padding: 48px 64px; border-radius: 8px;\n border: 1px solid #e2e8f0; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n .icon { width: 48px; height: 48px; margin: 0 auto 24px; background: #fee2e2; border-radius: 50%;\n display: flex; align-items: center; justify-content: center; }\n .icon svg { width: 24px; height: 24px; color: #dc2626; }\n h1 { color: #0f172a; margin: 0 0 8px 0; font-size: 20px; font-weight: 600; }\n p { color: #64748b; margin: 0 0 8px 0; font-size: 14px; }\n code { background: #f1f5f9; padding: 2px 8px; border-radius: 4px; color: #dc2626; font-size: 13px; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\"/>\n </svg>\n </div>\n <h1>Authentication Failed</h1>\n <p>Error: <code>${escapeHtml(error)}</code></p>\n ${description ? `<p>${escapeHtml(description)}</p>` : ''}\n </div>\n</body>\n</html>`;\n }\n}\n\n/**\n * Detect if running in a headless environment\n */\nfunction isHeadless(): boolean {\n // CI environment\n if (process.env.CI) {\n return true;\n }\n\n // No TTY (piped input)\n if (!process.stdin.isTTY) {\n return true;\n }\n\n // Linux without DISPLAY (no X server)\n if (\n process.platform === 'linux' &&\n !process.env.DISPLAY &&\n !process.env.WAYLAND_DISPLAY\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Escape HTML special characters\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n","import { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';\nimport type { MCPConfig } from '../config/mcpConfig.js';\nimport {\n validateMCPConfig,\n isStdioConfig,\n isHttpConfig,\n} from '../config/mcpConfig.js';\nimport { debugClient } from '../debug.js';\n\n/**\n * Options for creating an MCP client\n */\nexport interface CreateMCPClientOptions {\n /**\n * Client information (name and version)\n */\n clientInfo?: {\n name?: string;\n version?: string;\n };\n\n /**\n * OAuth client provider for authentication\n *\n * When provided, the MCP SDK handles OAuth flow automatically.\n * This takes precedence over static token auth in config.auth.accessToken.\n */\n authProvider?: OAuthClientProvider;\n}\n\n/**\n * Creates and connects an MCP client based on the provided configuration\n *\n * @param config - MCP configuration (will be validated)\n * @param options - Optional client options including auth provider\n * @returns Connected MCP Client instance\n * @throws {Error} If config is invalid or connection fails\n *\n * @example\n * // Stdio transport\n * const client = await createMCPClientForConfig({\n * transport: 'stdio',\n * command: 'node',\n * args: ['server.js']\n * });\n *\n * @example\n * // HTTP transport with static token auth\n * const client = await createMCPClientForConfig({\n * transport: 'http',\n * serverUrl: 'http://localhost:3000/mcp',\n * auth: { accessToken: 'your-token' }\n * });\n *\n * @example\n * // HTTP transport with OAuth provider\n * const client = await createMCPClientForConfig(\n * { transport: 'http', serverUrl: 'http://localhost:3000/mcp' },\n * { authProvider: myOAuthProvider }\n * );\n */\nexport async function createMCPClientForConfig(\n config: MCPConfig,\n options?: CreateMCPClientOptions\n): Promise<Client> {\n // Validate config\n const validatedConfig = validateMCPConfig(config);\n\n // Create client with info\n const client = new Client(\n {\n name: options?.clientInfo?.name ?? '@gleanwork/mcp-server-tester',\n version: options?.clientInfo?.version ?? '0.1.0',\n },\n {\n capabilities: validatedConfig.capabilities ?? {},\n }\n );\n\n // Create appropriate transport and connect\n if (isStdioConfig(validatedConfig)) {\n const transport = new StdioClientTransport({\n command: validatedConfig.command,\n args: validatedConfig.args ?? [],\n ...(validatedConfig.cwd && { cwd: validatedConfig.cwd }),\n // Suppress server stderr when quiet mode is enabled\n ...(validatedConfig.quiet && { stderr: 'ignore' as const }),\n });\n\n debugClient('Connecting via stdio: %O', {\n command: validatedConfig.command,\n args: validatedConfig.args,\n cwd: validatedConfig.cwd,\n });\n\n await client.connect(transport);\n } else if (isHttpConfig(validatedConfig)) {\n // Build headers, including static token auth if configured and no authProvider\n const headers: Record<string, string> = { ...validatedConfig.headers };\n\n // If using static token auth (no authProvider), add Authorization header\n if (validatedConfig.auth?.accessToken && !options?.authProvider) {\n headers.Authorization = `Bearer ${validatedConfig.auth.accessToken}`;\n }\n\n const transport = new StreamableHTTPClientTransport(\n new URL(validatedConfig.serverUrl),\n {\n requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,\n // Pass auth provider for OAuth flow - MCP SDK handles it automatically\n authProvider: options?.authProvider,\n }\n );\n\n debugClient('Connecting via HTTP: %O', {\n serverUrl: validatedConfig.serverUrl,\n headers:\n Object.keys(headers).length > 0 ? Object.keys(headers) : undefined,\n hasAuthProvider: !!options?.authProvider,\n });\n\n await client.connect(transport);\n }\n\n debugClient('Connected successfully');\n const serverInfo = client.getServerVersion();\n if (serverInfo) {\n debugClient('Server info: %O', serverInfo);\n }\n\n return client;\n}\n\n/**\n * Safely closes an MCP client connection\n *\n * @param client - The client to close\n */\nexport async function closeMCPClient(client: Client): Promise<void> {\n try {\n await client.close();\n } catch (error) {\n console.error('[MCP] Error closing client:', error);\n throw error;\n }\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * A single content block from an MCP response\n */\nexport interface ContentBlock {\n type: string;\n text?: string;\n data?: unknown;\n mimeType?: string;\n}\n\n/**\n * Normalized representation of an MCP tool response\n *\n * This provides a consistent interface regardless of the response format\n * returned by the MCP server.\n */\nexport interface NormalizedToolResponse {\n /**\n * Extracted text content (concatenated from all text blocks)\n */\n text: string;\n\n /**\n * Original raw response from the MCP SDK\n */\n raw: CallToolResult;\n\n /**\n * Whether the tool call resulted in an error\n */\n isError: boolean;\n\n /**\n * Parsed content blocks from the response\n */\n contentBlocks: ContentBlock[];\n\n /**\n * Structured content if present (parsed JSON or raw data)\n */\n structuredContent: unknown;\n}\n\n/**\n * Normalizes an MCP CallToolResult into a consistent format\n *\n * @param result - Raw CallToolResult from the MCP SDK\n * @returns Normalized response with extracted text, content blocks, etc.\n *\n * @example\n * ```typescript\n * const result = await client.callTool({ name: 'read_file', arguments: { path: 'readme.txt' } });\n * const normalized = normalizeToolResponse(result);\n *\n * console.log(normalized.text); // \"Hello World\"\n * console.log(normalized.isError); // false\n * console.log(normalized.contentBlocks); // [{ type: 'text', text: 'Hello World' }]\n * ```\n */\nexport function normalizeToolResponse(\n result: CallToolResult\n): NormalizedToolResponse {\n const isError = result.isError ?? false;\n const contentBlocks: ContentBlock[] = [];\n const textParts: string[] = [];\n\n // Parse content array if present\n if (Array.isArray(result.content)) {\n for (const block of result.content) {\n if (block == null || typeof block !== 'object') {\n continue;\n }\n\n const b = block as Record<string, unknown>;\n const contentBlock: ContentBlock = {\n type: typeof b.type === 'string' ? b.type : 'unknown',\n };\n\n // Extract text if present\n if (typeof b.text === 'string') {\n contentBlock.text = b.text;\n textParts.push(b.text);\n }\n\n // Extract data/blob if present\n if (b.data !== undefined) {\n contentBlock.data = b.data;\n }\n\n // Extract mimeType if present\n if (typeof b.mimeType === 'string') {\n contentBlock.mimeType = b.mimeType;\n }\n\n contentBlocks.push(contentBlock);\n }\n }\n\n // Handle structuredContent\n let structuredContent: unknown = null;\n if (result.structuredContent !== undefined) {\n structuredContent = result.structuredContent;\n\n // If no text was extracted from content blocks, try to get text from structuredContent\n if (textParts.length === 0) {\n if (typeof result.structuredContent === 'string') {\n textParts.push(result.structuredContent);\n } else if (result.structuredContent != null) {\n // For objects/arrays, stringify for text representation\n textParts.push(JSON.stringify(result.structuredContent));\n }\n }\n }\n\n // Build final text by joining all parts\n const text = textParts.join('\\n');\n\n return {\n text,\n raw: result,\n isError,\n contentBlocks,\n structuredContent,\n };\n}\n\n/**\n * Extracts just the text content from a normalized or raw response\n *\n * This is a convenience function that works with both:\n * - Raw CallToolResult from the MCP SDK\n * - NormalizedToolResponse from normalizeToolResponse()\n * - Plain strings or other legacy formats\n *\n * @param response - Response in any supported format\n * @returns Extracted text content\n */\nexport function extractText(response: unknown): string {\n // Handle null/undefined\n if (response == null) {\n return '';\n }\n\n // Plain string\n if (typeof response === 'string') {\n return response;\n }\n\n // Already normalized response\n if (isNormalizedResponse(response)) {\n return response.text;\n }\n\n // Raw CallToolResult - normalize it first\n if (isCallToolResult(response)) {\n return normalizeToolResponse(response).text;\n }\n\n // Array of content blocks (direct content)\n if (Array.isArray(response)) {\n return extractTextFromContentArray(response);\n }\n\n // Generic object - try common patterns\n if (typeof response === 'object') {\n const r = response as Record<string, unknown>;\n\n // Check for content array\n if (Array.isArray(r.content)) {\n return extractTextFromContentArray(r.content);\n }\n\n // Check for content as a direct string (single content block format)\n if (typeof r.content === 'string') {\n return r.content;\n }\n\n // Check for structuredContent\n if (r.structuredContent !== undefined) {\n if (typeof r.structuredContent === 'string') {\n return r.structuredContent;\n }\n return JSON.stringify(r.structuredContent);\n }\n\n // Check for direct text field\n if (typeof r.text === 'string') {\n return r.text;\n }\n\n // Fallback to JSON\n return JSON.stringify(r);\n }\n\n // Primitives (number, boolean, bigint, symbol)\n if (\n typeof response === 'number' ||\n typeof response === 'boolean' ||\n typeof response === 'bigint'\n ) {\n return String(response);\n }\n\n // Symbol or other edge cases\n return '';\n}\n\n/**\n * Type guard for NormalizedToolResponse\n */\nfunction isNormalizedResponse(value: unknown): value is NormalizedToolResponse {\n if (value == null || typeof value !== 'object') {\n return false;\n }\n const v = value as Record<string, unknown>;\n return (\n typeof v.text === 'string' &&\n typeof v.isError === 'boolean' &&\n Array.isArray(v.contentBlocks) &&\n v.raw !== undefined\n );\n}\n\n/**\n * Type guard for CallToolResult\n */\nfunction isCallToolResult(value: unknown): value is CallToolResult {\n if (value == null || typeof value !== 'object') {\n return false;\n }\n const v = value as Record<string, unknown>;\n // CallToolResult has content array (required) or isError\n return Array.isArray(v.content) || typeof v.isError === 'boolean';\n}\n\n/**\n * Extracts text from a content block array\n */\nfunction extractTextFromContentArray(content: unknown[]): string {\n const textParts: string[] = [];\n\n for (const block of content) {\n if (block == null || typeof block !== 'object') {\n continue;\n }\n const b = block as Record<string, unknown>;\n if (b.type === 'text' && typeof b.text === 'string') {\n textParts.push(b.text);\n }\n }\n\n if (textParts.length > 0) {\n return textParts.join('\\n');\n }\n\n // No text blocks found, stringify the whole array\n return JSON.stringify(content);\n}\n","/**\n * Validator Utilities\n *\n * Shared utility functions for validation operations.\n * Re-exports core utilities from mcp/response.ts and adds validation-specific helpers.\n */\n\nimport { extractText as extractTextFromResponse } from '../../mcp/response.js';\n\n/**\n * Re-export extractText from mcp/response.ts\n * This extracts text content from any response format.\n */\nexport const extractText = extractTextFromResponse;\n\n/**\n * Gets the size of a response in bytes\n *\n * Serializes the response to JSON (with pretty printing for consistency)\n * and returns the byte length using UTF-8 encoding.\n *\n * @param response - Response in any format\n * @returns Size in bytes\n */\nexport function getResponseSizeBytes(response: unknown): number {\n if (response === null || response === undefined) {\n return 0;\n }\n\n // For strings, get direct byte length\n if (typeof response === 'string') {\n return Buffer.byteLength(response, 'utf8');\n }\n\n // For objects/arrays, serialize with formatting\n const serialized = JSON.stringify(response, null, 2);\n return Buffer.byteLength(serialized, 'utf8');\n}\n\n/**\n * Converts a response to a string for comparison\n *\n * @param response - Response in any format\n * @returns String representation\n */\nexport function stringifyResponse(response: unknown): string {\n if (response === null || response === undefined) {\n return '';\n }\n\n if (typeof response === 'string') {\n return response;\n }\n\n return JSON.stringify(response, null, 2);\n}\n\n/**\n * Checks if a response represents an error\n *\n * @param response - Response to check\n * @returns true if the response is an error\n */\nexport function isErrorResponse(response: unknown): boolean {\n if (response === null || response === undefined) {\n return false;\n }\n\n if (typeof response !== 'object') {\n return false;\n }\n\n const r = response as Record<string, unknown>;\n\n // Check isError flag directly\n if (r.isError === true) {\n return true;\n }\n\n // Check for normalized response with isError\n if ('raw' in r && typeof r.raw === 'object' && r.raw !== null) {\n const raw = r.raw as Record<string, unknown>;\n return raw.isError === true;\n }\n\n return false;\n}\n\n/**\n * Extracts error message from an error response\n *\n * @param response - Error response\n * @returns Error message or empty string if not an error\n */\nexport function extractErrorMessage(response: unknown): string {\n if (!isErrorResponse(response)) {\n return '';\n }\n\n // Extract text content which typically contains the error message\n return extractText(response);\n}\n\n/**\n * Normalizes whitespace in text for consistent comparison\n *\n * Collapses multiple whitespace characters (spaces, tabs, newlines) into single spaces\n * and trims leading/trailing whitespace.\n *\n * @param text - Text to normalize\n * @returns Normalized text with collapsed whitespace\n *\n * @example\n * ```typescript\n * normalizeWhitespace(' hello\\n\\n world ');\n * // Returns: \"hello world\"\n * ```\n */\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n","/**\n * Response Validator\n *\n * Validates that a response exactly matches an expected value.\n */\n\nimport type { ValidationResult } from './types.js';\nimport { stringifyResponse } from './utils.js';\n\n/**\n * Validates that a response exactly matches the expected value\n *\n * Performs deep equality comparison using JSON serialization.\n *\n * @param actual - The actual response\n * @param expected - The expected response\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateResponse(response, { status: 'ok', count: 42 });\n * if (!result.pass) {\n * console.log(result.message);\n * }\n * ```\n */\nexport function validateResponse(\n actual: unknown,\n expected: unknown\n): ValidationResult {\n const actualStr = stringifyResponse(actual);\n const expectedStr = stringifyResponse(expected);\n\n if (actualStr === expectedStr) {\n return {\n pass: true,\n message: 'Response matches expected value',\n };\n }\n\n return {\n pass: false,\n message: `Response does not match expected value`,\n details: {\n actual: truncateForDisplay(actualStr),\n expected: truncateForDisplay(expectedStr),\n },\n };\n}\n\n/**\n * Truncates a string for display in error messages\n */\nfunction truncateForDisplay(str: string, maxLength = 500): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + '... (truncated)';\n}\n","/**\n * Schema Validator\n *\n * Validates that a response matches a Zod schema.\n */\n\nimport type { ZodType, ZodError } from 'zod';\nimport type { ValidationResult, SchemaValidatorOptions } from './types.js';\nimport { extractText } from './utils.js';\n\n/**\n * Validates that a response matches a Zod schema\n *\n * Attempts to parse the response with the provided Zod schema.\n * If the response is a text representation of JSON, it will be parsed first.\n *\n * @param response - The response to validate\n * @param schema - The Zod schema to validate against\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * const WeatherSchema = z.object({\n * temperature: z.number(),\n * conditions: z.string(),\n * });\n *\n * const result = validateSchema(response, WeatherSchema);\n * if (!result.pass) {\n * console.log(result.message);\n * }\n * ```\n */\nexport function validateSchema(\n response: unknown,\n schema: ZodType,\n options: SchemaValidatorOptions = {}\n): ValidationResult {\n // Get the value to validate\n const valueToValidate = getValidatableValue(response);\n\n // If strict mode is enabled and we have an object schema with .strict(),\n // the schema itself should handle this - the option is for documentation\n if (options.strict && valueToValidate !== null) {\n // Strict mode is handled by the schema itself (using z.object().strict())\n // This option documents the intent but the actual strictness comes from the schema\n }\n\n try {\n // Attempt to parse with the schema\n schema.parse(valueToValidate);\n\n return {\n pass: true,\n message: 'Response matches schema',\n };\n } catch (error) {\n const zodError = error as ZodError;\n const issues = formatZodIssues(zodError);\n\n return {\n pass: false,\n message: `Response does not match schema: ${issues}`,\n details: {\n issues: zodError.issues,\n },\n };\n }\n}\n\n/**\n * Extracts a validatable value from a response\n *\n * Handles various response formats:\n * - NormalizedToolResponse: extracts structuredContent or parses text\n * - CallToolResult: extracts structuredContent or parses content\n * - Plain objects: used directly\n * - Strings: parsed as JSON\n */\nfunction getValidatableValue(response: unknown): unknown {\n if (response === null || response === undefined) {\n return null;\n }\n\n // Plain object - use directly (might be a schema-ready value)\n if (typeof response === 'object' && !Array.isArray(response)) {\n const r = response as Record<string, unknown>;\n\n // Check for structuredContent (MCP response with structured data)\n if ('structuredContent' in r && r.structuredContent !== undefined) {\n return r.structuredContent;\n }\n\n // Check for normalized response format\n if ('raw' in r && 'text' in r && 'isError' in r && 'contentBlocks' in r) {\n // It's a NormalizedToolResponse\n if (r.structuredContent !== undefined) {\n return r.structuredContent;\n }\n // Try to parse text as JSON\n const text = r.text as string;\n return tryParseJson(text) ?? response;\n }\n\n // Check for raw CallToolResult format\n if ('content' in r && Array.isArray(r.content)) {\n // Try to extract and parse text content\n const text = extractText(response);\n return tryParseJson(text) ?? response;\n }\n\n // Regular object - use as-is\n return response;\n }\n\n // String - try to parse as JSON\n if (typeof response === 'string') {\n return tryParseJson(response) ?? response;\n }\n\n // Array or primitive - use directly\n return response;\n}\n\n/**\n * Attempts to parse a string as JSON\n */\nfunction tryParseJson(text: string): unknown {\n if (!text || typeof text !== 'string') {\n return null;\n }\n\n const trimmed = text.trim();\n // Quick check for JSON-like strings\n if (\n !(trimmed.startsWith('{') || trimmed.startsWith('[')) ||\n !(trimmed.endsWith('}') || trimmed.endsWith(']'))\n ) {\n return null;\n }\n\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\n/**\n * Formats Zod issues into a human-readable string\n */\nfunction formatZodIssues(error: ZodError): string {\n const issues = error.issues.map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : 'root';\n return `${path}: ${issue.message}`;\n });\n\n return issues.join('; ');\n}\n","/**\n * Text Validator\n *\n * Validates that a response contains expected text substrings.\n */\n\nimport type { ValidationResult, TextValidatorOptions } from './types.js';\nimport { extractText } from './utils.js';\n\n/**\n * Validates that a response contains all expected text substrings\n *\n * Extracts text from the response and checks that each expected substring\n * is present. By default, matching is case-sensitive.\n *\n * @param response - The response to validate\n * @param expected - Expected substring(s) to find\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateText(response, ['temperature', 'conditions']);\n * if (!result.pass) {\n * console.log(result.message);\n * }\n *\n * // Case-insensitive matching\n * const result2 = validateText(response, 'HELLO', { caseSensitive: false });\n * ```\n */\nexport function validateText(\n response: unknown,\n expected: string | string[],\n options: TextValidatorOptions = {}\n): ValidationResult {\n const { caseSensitive = true } = options;\n\n // Normalize expected to array\n const expectedStrings = Array.isArray(expected) ? expected : [expected];\n\n // Extract text from response\n const text = extractText(response);\n\n // Apply case sensitivity\n const compareText = caseSensitive ? text : text.toLowerCase();\n\n // Check each expected substring\n const missing: string[] = [];\n for (const substring of expectedStrings) {\n const compareSubstring = caseSensitive\n ? substring\n : substring.toLowerCase();\n\n if (!compareText.includes(compareSubstring)) {\n missing.push(substring);\n }\n }\n\n if (missing.length === 0) {\n return {\n pass: true,\n message:\n expectedStrings.length === 1\n ? `Response contains expected text`\n : `Response contains all ${expectedStrings.length} expected substrings`,\n };\n }\n\n return {\n pass: false,\n message:\n missing.length === 1\n ? `Response does not contain expected text: \"${missing[0]}\"`\n : `Response is missing ${missing.length} expected substrings: ${missing.map((s) => `\"${s}\"`).join(', ')}`,\n details: {\n missing,\n textLength: text.length,\n textPreview: truncateForDisplay(text),\n },\n };\n}\n\n/**\n * Truncates a string for display in error messages\n */\nfunction truncateForDisplay(str: string, maxLength = 200): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + '... (truncated)';\n}\n","/**\n * Pattern Validator\n *\n * Validates that a response matches regex patterns.\n */\n\nimport type { ValidationResult, PatternValidatorOptions } from './types.js';\nimport { extractText } from './utils.js';\n\n/**\n * Validates that a response matches all expected regex patterns\n *\n * Extracts text from the response and checks that each pattern matches.\n * Patterns can be strings (which are compiled to RegExp) or RegExp objects.\n *\n * @param response - The response to validate\n * @param patterns - Expected pattern(s) to match\n * @param options - Validation options\n * @returns Validation result\n *\n * @example\n * ```typescript\n * // String pattern\n * const result = validatePattern(response, 'temperature: \\\\d+');\n *\n * // RegExp pattern\n * const result2 = validatePattern(response, /temperature: \\d+/);\n *\n * // Multiple patterns\n * const result3 = validatePattern(response, [\n * /temperature: \\d+/,\n * /humidity: \\d+%/,\n * ]);\n *\n * // Case-insensitive matching\n * const result4 = validatePattern(response, 'HELLO', { caseSensitive: false });\n * ```\n */\nexport function validatePattern(\n response: unknown,\n patterns: string | RegExp | (string | RegExp)[],\n options: PatternValidatorOptions = {}\n): ValidationResult {\n const { caseSensitive = true } = options;\n const caseInsensitive = !caseSensitive;\n\n // Normalize patterns to array\n const patternList = Array.isArray(patterns) ? patterns : [patterns];\n\n // Extract text from response\n const text = extractText(response);\n\n // Check each pattern\n const unmatched: string[] = [];\n for (const pattern of patternList) {\n const regex = toRegExp(pattern, caseInsensitive);\n if (!regex.test(text)) {\n unmatched.push(patternToString(pattern));\n }\n }\n\n if (unmatched.length === 0) {\n return {\n pass: true,\n message:\n patternList.length === 1\n ? `Response matches pattern`\n : `Response matches all ${patternList.length} patterns`,\n };\n }\n\n return {\n pass: false,\n message:\n unmatched.length === 1\n ? `Response does not match pattern: ${unmatched[0]}`\n : `Response does not match ${unmatched.length} patterns: ${unmatched.join(', ')}`,\n details: {\n unmatched,\n textLength: text.length,\n textPreview: truncateForDisplay(text),\n },\n };\n}\n\n/**\n * Converts a pattern to a RegExp\n */\nfunction toRegExp(pattern: string | RegExp, caseInsensitive: boolean): RegExp {\n if (pattern instanceof RegExp) {\n // If caseInsensitive option is set but regex doesn't have it, add it\n if (caseInsensitive && !pattern.flags.includes('i')) {\n return new RegExp(pattern.source, pattern.flags + 'i');\n }\n return pattern;\n }\n\n // Compile string to RegExp\n const flags = caseInsensitive ? 'i' : '';\n return new RegExp(pattern, flags);\n}\n\n/**\n * Converts a pattern to a display string\n */\nfunction patternToString(pattern: string | RegExp): string {\n if (pattern instanceof RegExp) {\n return pattern.toString();\n }\n return `/${pattern}/`;\n}\n\n/**\n * Truncates a string for display in error messages\n */\nfunction truncateForDisplay(str: string, maxLength = 200): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + '... (truncated)';\n}\n","/**\n * Error Validator\n *\n * Validates error response behavior.\n */\n\nimport type { ValidationResult } from './types.js';\nimport { isErrorResponse, extractErrorMessage, extractText } from './utils.js';\n\n/**\n * Validates that a response is (or is not) an error\n *\n * Can check for:\n * - Any error (expected = true)\n * - No error (expected = false)\n * - Error with specific message(s) (expected = string or string[])\n *\n * @param response - The response to validate\n * @param expected - What to expect (true for any error, false for no error, string for specific message)\n * @returns Validation result\n *\n * @example\n * ```typescript\n * // Expect any error\n * const result = validateError(response, true);\n *\n * // Expect no error\n * const result2 = validateError(response, false);\n *\n * // Expect error with specific message\n * const result3 = validateError(response, 'File not found');\n *\n * // Expect error containing one of several messages\n * const result4 = validateError(response, ['not found', 'does not exist']);\n * ```\n */\nexport function validateError(\n response: unknown,\n expected: boolean | string | string[] = true\n): ValidationResult {\n const actualIsError = isErrorResponse(response);\n const errorMessage = actualIsError ? extractErrorMessage(response) : '';\n\n // Handle boolean expectation\n if (typeof expected === 'boolean') {\n if (expected) {\n // Expect an error\n if (actualIsError) {\n return {\n pass: true,\n message: 'Response is an error as expected',\n };\n }\n return {\n pass: false,\n message: 'Expected an error response but got success',\n details: {\n textPreview: truncateForDisplay(extractText(response)),\n },\n };\n } else {\n // Expect no error\n if (!actualIsError) {\n return {\n pass: true,\n message: 'Response is not an error as expected',\n };\n }\n return {\n pass: false,\n message: `Expected a success response but got error: \"${truncateForDisplay(errorMessage)}\"`,\n details: {\n errorMessage,\n },\n };\n }\n }\n\n // Handle string or string[] expectation\n const expectedMessages = Array.isArray(expected) ? expected : [expected];\n\n // Must be an error first\n if (!actualIsError) {\n return {\n pass: false,\n message: `Expected an error containing \"${expectedMessages[0]}\" but got success`,\n details: {\n textPreview: truncateForDisplay(extractText(response)),\n },\n };\n }\n\n // Check if error message contains any of the expected strings\n const matched = expectedMessages.some((msg) =>\n errorMessage.toLowerCase().includes(msg.toLowerCase())\n );\n\n if (matched) {\n return {\n pass: true,\n message: 'Error message contains expected text',\n };\n }\n\n return {\n pass: false,\n message:\n expectedMessages.length === 1\n ? `Error message does not contain \"${expectedMessages[0]}\"`\n : `Error message does not contain any of: ${expectedMessages.map((m) => `\"${m}\"`).join(', ')}`,\n details: {\n actualErrorMessage: errorMessage,\n expectedToContain: expectedMessages,\n },\n };\n}\n\n/**\n * Truncates a string for display in error messages\n */\nfunction truncateForDisplay(str: string, maxLength = 200): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + '... (truncated)';\n}\n","/**\n * Size Validator\n *\n * Validates that a response meets size constraints.\n */\n\nimport type { ValidationResult, SizeValidatorOptions } from './types.js';\nimport { getResponseSizeBytes } from './utils.js';\n\n/**\n * Validates that a response meets size constraints\n *\n * Checks that the response size in bytes is within the specified bounds.\n * At least one of minBytes or maxBytes must be provided.\n *\n * @param response - The response to validate\n * @param options - Size constraints\n * @returns Validation result\n *\n * @example\n * ```typescript\n * // Maximum size check\n * const result = validateSize(response, { maxBytes: 10000 });\n *\n * // Minimum size check\n * const result2 = validateSize(response, { minBytes: 100 });\n *\n * // Both bounds\n * const result3 = validateSize(response, { minBytes: 100, maxBytes: 10000 });\n * ```\n */\nexport function validateSize(\n response: unknown,\n options: SizeValidatorOptions\n): ValidationResult {\n const { maxBytes, minBytes } = options;\n\n // Require at least one bound\n if (maxBytes === undefined && minBytes === undefined) {\n return {\n pass: false,\n message: 'Size validation requires at least one of maxBytes or minBytes',\n };\n }\n\n const actualSize = getResponseSizeBytes(response);\n const issues: string[] = [];\n\n // Check minimum\n if (minBytes !== undefined && actualSize < minBytes) {\n issues.push(\n `Response size (${formatBytes(actualSize)}) is below minimum (${formatBytes(minBytes)})`\n );\n }\n\n // Check maximum\n if (maxBytes !== undefined && actualSize > maxBytes) {\n issues.push(\n `Response size (${formatBytes(actualSize)}) exceeds maximum (${formatBytes(maxBytes)})`\n );\n }\n\n if (issues.length === 0) {\n return {\n pass: true,\n message: `Response size (${formatBytes(actualSize)}) is within bounds`,\n details: {\n actualBytes: actualSize,\n },\n };\n }\n\n return {\n pass: false,\n message: issues.join('; '),\n details: {\n actualBytes: actualSize,\n minBytes,\n maxBytes,\n },\n };\n}\n\n/**\n * Formats bytes as a human-readable string\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} bytes`;\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`;\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n","import type { TestInfo } from '@playwright/test';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type {\n Tool,\n CallToolResult,\n ListToolsResult,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type { AuthType } from '../../types/index.js';\n\n// Re-export AuthType for backwards compatibility\nexport type { AuthType } from '../../types/index.js';\n\n// Dynamic import of test for conditional step tracking\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet testStep:\n | ((name: string, fn: () => Promise<unknown>) => Promise<unknown>)\n | null = null;\n\n// Try to load test.step() dynamically\ntry {\n /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */\n const playwright = require('@playwright/test');\n if (playwright && playwright.test && playwright.test.step) {\n testStep = playwright.test.step.bind(playwright.test) as typeof testStep;\n }\n /* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */\n} catch {\n // Not in a test context, that's fine\n}\n\n/**\n * Options for creating an MCP fixture\n */\nexport interface MCPFixtureOptions {\n /**\n * Authentication type used for this test\n * - 'oauth': Interactive OAuth 2.1 with PKCE (browser-based authentication)\n * - 'api-token': Static API token (e.g., from a dashboard or environment variable)\n * - 'none': No authentication\n */\n authType?: AuthType;\n\n /**\n * Playwright project name for this test\n * Used for filtering and grouping in the reporter\n */\n project?: string;\n}\n\n/**\n * High-level API for interacting with MCP servers in tests\n *\n * This interface wraps the raw MCP Client with test-friendly methods\n */\nexport interface MCPFixtureApi {\n /**\n * The underlying MCP client (for advanced usage)\n */\n client: Client;\n\n /**\n * Authentication type used for this test session\n */\n authType: AuthType;\n\n /**\n * Playwright project name for this test session\n */\n project?: string;\n\n /**\n * Lists all available tools from the MCP server\n *\n * @returns Array of tool definitions\n */\n listTools(): Promise<Array<Tool>>;\n\n /**\n * Calls a tool on the MCP server\n *\n * @param name - Tool name\n * @param args - Tool arguments\n * @returns Tool call result\n */\n callTool<TArgs extends Record<string, unknown> = Record<string, unknown>>(\n name: string,\n args: TArgs\n ): Promise<CallToolResult>;\n\n /**\n * Gets information about the connected server\n */\n getServerInfo(): {\n name?: string;\n version?: string;\n } | null;\n}\n\n/**\n * Creates an MCP fixture wrapper around a Client\n *\n * When testInfo is provided, automatically tracks all MCP operations with test.step()\n * and creates attachments for the MCP Test Reporter.\n *\n * @param client - The MCP client to wrap\n * @param testInfo - Optional Playwright TestInfo for auto-tracking\n * @returns MCPFixtureApi instance\n *\n * @example\n * ```typescript\n * // With tracking (recommended)\n * const test = base.extend<{ mcp: MCPFixtureApi }>({\n * mcp: async ({}, use, testInfo) => {\n * const client = await createMCPClientForConfig(config);\n * const api = createMCPFixture(client, testInfo);\n * await use(api);\n * await closeMCPClient(client);\n * }\n * });\n *\n * // Without tracking\n * const api = createMCPFixture(client);\n * ```\n */\nexport function createMCPFixture(\n client: Client,\n testInfo?: TestInfo,\n options?: MCPFixtureOptions\n): MCPFixtureApi {\n const authType = options?.authType ?? 'none';\n const project = options?.project;\n // If no testInfo, return basic API without tracking\n if (!testInfo) {\n return {\n client,\n authType,\n project,\n\n async listTools(): Promise<Array<Tool>> {\n const result = (await client.listTools()) as ListToolsResult;\n return result.tools;\n },\n\n async callTool<TArgs extends Record<string, unknown>>(\n name: string,\n args: TArgs\n ): Promise<CallToolResult> {\n const result = (await client.callTool({\n name,\n arguments: args,\n })) as CallToolResult;\n return result;\n },\n\n getServerInfo() {\n const serverVersion = client.getServerVersion();\n if (!serverVersion) {\n return null;\n }\n return {\n name: serverVersion.name,\n version: serverVersion.version,\n };\n },\n };\n }\n\n // With testInfo, return tracked API\n return {\n client,\n authType,\n project,\n\n async listTools(): Promise<Array<Tool>> {\n const execute = async () => {\n const result = (await client.listTools()) as ListToolsResult;\n const tools = result.tools;\n\n // Auto-attach for reporter\n await testInfo.attach('mcp-list-tools', {\n contentType: 'application/json',\n body: JSON.stringify(\n {\n operation: 'listTools',\n toolCount: tools.length,\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n })),\n },\n null,\n 2\n ),\n });\n\n return tools;\n };\n\n // Wrap in test.step if available\n return (\n testStep ? testStep('MCP: listTools()', execute) : execute()\n ) as Promise<Array<Tool>>;\n },\n\n async callTool<TArgs extends Record<string, unknown>>(\n name: string,\n args: TArgs\n ): Promise<CallToolResult> {\n const execute = async () => {\n const startTime = Date.now();\n const result = (await client.callTool({\n name,\n arguments: args,\n })) as CallToolResult;\n const durationMs = Date.now() - startTime;\n\n // Auto-attach for reporter\n await testInfo.attach(`mcp-call-${name}`, {\n contentType: 'application/json',\n body: JSON.stringify(\n {\n operation: 'callTool',\n toolName: name,\n args,\n result,\n durationMs,\n isError: result.isError || false,\n authType,\n project,\n },\n null,\n 2\n ),\n });\n\n return result;\n };\n\n // Wrap in test.step if available\n return (\n testStep ? testStep(`MCP: callTool(\"${name}\")`, execute) : execute()\n ) as Promise<CallToolResult>;\n },\n\n getServerInfo() {\n const serverVersion = client.getServerVersion();\n const result = serverVersion\n ? {\n name: serverVersion.name,\n version: serverVersion.version,\n }\n : null;\n\n // Fire-and-forget attachment (don't block synchronous call)\n testInfo\n .attach('mcp-server-info', {\n contentType: 'application/json',\n body: JSON.stringify(\n {\n operation: 'getServerInfo',\n serverInfo: result,\n },\n null,\n 2\n ),\n })\n .catch(() => {\n // Ignore attachment errors for sync methods\n });\n\n return result;\n },\n };\n}\n","/**\n * toMatchToolResponse Matcher\n *\n * Validates that a response exactly matches an expected value.\n */\n\nimport { validateResponse } from '../validators/response.js';\n\n/**\n * Creates the toMatchToolResponse matcher function\n */\nexport function toMatchToolResponse(\n this: { isNot: boolean },\n received: unknown,\n expected: unknown\n) {\n const result = validateResponse(received, expected);\n\n return {\n pass: result.pass,\n message: () => {\n if (this.isNot) {\n return result.pass\n ? 'Expected response NOT to match, but it did'\n : result.message;\n }\n return result.message;\n },\n };\n}\n","/**\n * toMatchToolSchema Matcher\n *\n * Validates that a response matches a Zod schema.\n */\n\nimport type { ZodType } from 'zod';\nimport { validateSchema } from '../validators/schema.js';\nimport type { SchemaValidatorOptions } from '../validators/types.js';\n\n/**\n * Creates the toMatchToolSchema matcher function\n */\nexport function toMatchToolSchema(\n this: { isNot: boolean },\n received: unknown,\n schema: ZodType,\n options: SchemaValidatorOptions = {}\n) {\n const result = validateSchema(received, schema, options);\n\n return {\n pass: result.pass,\n message: () => {\n if (this.isNot) {\n return result.pass\n ? 'Expected response NOT to match schema, but it did'\n : result.message;\n }\n return result.message;\n },\n };\n}\n","/**\n * toContainToolText Matcher\n *\n * Validates that a response contains expected text substrings.\n */\n\nimport { validateText } from '../validators/text.js';\nimport type { TextValidatorOptions } from '../validators/types.js';\n\n/**\n * Creates the toContainToolText matcher function\n */\nexport function toContainToolText(\n this: { isNot: boolean },\n received: unknown,\n expected: string | string[],\n options: TextValidatorOptions = {}\n) {\n const result = validateText(received, expected, options);\n\n return {\n pass: result.pass,\n message: () => {\n if (this.isNot) {\n const expectedStr = Array.isArray(expected)\n ? expected.map((s) => `\"${s}\"`).join(', ')\n : `\"${expected}\"`;\n return result.pass\n ? `Expected response NOT to contain ${expectedStr}, but it did`\n : result.message;\n }\n return result.message;\n },\n };\n}\n","/**\n * toMatchToolPattern Matcher\n *\n * Validates that a response matches regex patterns.\n */\n\nimport { validatePattern } from '../validators/pattern.js';\nimport type { PatternValidatorOptions } from '../validators/types.js';\n\n/**\n * Creates the toMatchToolPattern matcher function\n */\nexport function toMatchToolPattern(\n this: { isNot: boolean },\n received: unknown,\n patterns: string | RegExp | (string | RegExp)[],\n options: PatternValidatorOptions = {}\n) {\n const result = validatePattern(received, patterns, options);\n\n return {\n pass: result.pass,\n message: () => {\n if (this.isNot) {\n return result.pass\n ? 'Expected response NOT to match pattern(s), but it did'\n : result.message;\n }\n return result.message;\n },\n };\n}\n","/**\n * toMatchToolSnapshot Matcher\n *\n * Validates that a response matches a saved snapshot.\n * Uses Playwright's native snapshot testing functionality.\n */\n\nimport { expect as baseExpect } from '@playwright/test';\nimport type { SnapshotSanitizer } from '../validators/types.js';\nimport { extractText } from '../validators/utils.js';\n\n/**\n * Built-in regex patterns for common variable data\n */\nconst BUILT_IN_PATTERNS: Record<\n string,\n { pattern: RegExp; replacement: string }\n> = {\n timestamp: {\n pattern: /\\b\\d{10,13}\\b/g,\n replacement: '[TIMESTAMP]',\n },\n uuid: {\n pattern:\n /\\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\\b/gi,\n replacement: '[UUID]',\n },\n 'iso-date': {\n pattern:\n /\\b\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,3})?(Z|[+-]\\d{2}:?\\d{2})?)?\\b/g,\n replacement: '[ISO_DATE]',\n },\n objectId: {\n pattern: /\\b[0-9a-f]{24}\\b/gi,\n replacement: '[OBJECT_ID]',\n },\n jwt: {\n pattern: /\\beyJ[A-Za-z0-9_-]*\\.eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]+\\b/g,\n replacement: '[JWT]',\n },\n};\n\n/**\n * Type guard for regex sanitizer\n */\nfunction isRegexSanitizer(\n sanitizer: SnapshotSanitizer\n): sanitizer is { pattern: string | RegExp; replacement?: string } {\n return (\n typeof sanitizer === 'object' &&\n sanitizer !== null &&\n 'pattern' in sanitizer\n );\n}\n\n/**\n * Type guard for field removal sanitizer\n */\nfunction isFieldRemovalSanitizer(\n sanitizer: SnapshotSanitizer\n): sanitizer is { remove: string[] } {\n return (\n typeof sanitizer === 'object' && sanitizer !== null && 'remove' in sanitizer\n );\n}\n\n/**\n * Apply sanitizers to a string value\n *\n * Handles three types of sanitizers:\n * 1. Built-in names: 'timestamp', 'uuid', 'iso-date', 'objectId', 'jwt'\n * 2. Regex sanitizers: { pattern: string | RegExp, replacement?: string }\n * 3. Field removal sanitizers: { remove: string[] } - only works on JSON strings\n */\nfunction applySanitizers(\n value: string,\n sanitizers: SnapshotSanitizer[]\n): string {\n let result = value;\n\n for (const sanitizer of sanitizers) {\n // Handle built-in sanitizer names\n if (typeof sanitizer === 'string') {\n const builtIn = BUILT_IN_PATTERNS[sanitizer];\n if (builtIn) {\n result = result.replace(builtIn.pattern, builtIn.replacement);\n }\n continue;\n }\n\n // Handle regex sanitizers\n if (isRegexSanitizer(sanitizer)) {\n const pattern =\n sanitizer.pattern instanceof RegExp\n ? sanitizer.pattern\n : new RegExp(sanitizer.pattern, 'g');\n const replacement = sanitizer.replacement ?? '[SANITIZED]';\n result = result.replace(pattern, replacement);\n continue;\n }\n\n // Handle field removal sanitizers\n if (isFieldRemovalSanitizer(sanitizer)) {\n try {\n const parsed: unknown = JSON.parse(result);\n removeFields(parsed, sanitizer.remove);\n result = JSON.stringify(parsed, null, 2);\n } catch {\n // Not valid JSON, skip field removal\n }\n }\n }\n\n return result;\n}\n\n/**\n * Remove fields from an object by dot-notation paths\n */\nfunction removeFields(obj: unknown, paths: string[]): void {\n if (typeof obj !== 'object' || obj === null) {\n return;\n }\n\n for (const path of paths) {\n const parts = path.split('.');\n if (parts.length === 0) {\n continue;\n }\n\n let current: unknown = obj;\n\n // Navigate to parent of target field\n for (let i = 0; i < parts.length - 1; i++) {\n if (typeof current !== 'object' || current === null) {\n break;\n }\n const key = parts[i];\n if (key !== undefined) {\n current = (current as Record<string, unknown>)[key];\n }\n }\n\n // Delete the target field\n if (typeof current === 'object' && current !== null) {\n const lastKey = parts[parts.length - 1];\n if (lastKey !== undefined) {\n delete (current as Record<string, unknown>)[lastKey];\n }\n }\n }\n}\n\n/**\n * Creates the toMatchToolSnapshot matcher function\n *\n * Note: This is an async matcher that uses Playwright's snapshot testing.\n */\nexport async function toMatchToolSnapshot(\n this: { isNot: boolean },\n received: unknown,\n name: string,\n sanitizers: SnapshotSanitizer[] = []\n): Promise<{ pass: boolean; message: () => string }> {\n // Extract text content from response\n let content = extractText(received);\n\n // Apply sanitizers\n if (sanitizers.length > 0) {\n content = applySanitizers(content, sanitizers);\n }\n\n // .not is not really meaningful for snapshots, but handle it gracefully\n if (this.isNot) {\n // For .not, we want to verify it does NOT match - this is unusual for snapshots\n // but we can try and check if it throws\n try {\n // eslint-disable-next-line @typescript-eslint/await-thenable\n await baseExpect(content).toMatchSnapshot(name);\n // If it didn't throw, the snapshot matched - so .not fails\n return {\n pass: false,\n message: () =>\n `Expected response NOT to match snapshot \"${name}\", but it did`,\n };\n } catch {\n // Snapshot didn't match - .not passes\n return {\n pass: true,\n message: () => `Response does not match snapshot \"${name}\" as expected`,\n };\n }\n }\n\n try {\n // Use Playwright's native snapshot testing\n // eslint-disable-next-line @typescript-eslint/await-thenable\n await baseExpect(content).toMatchSnapshot(name);\n return {\n pass: true,\n message: () => `Response matches snapshot \"${name}\"`,\n };\n } catch (error) {\n return {\n pass: false,\n message: () =>\n error instanceof Error\n ? error.message\n : `Response does not match snapshot \"${name}\"`,\n };\n }\n}\n\nexport { BUILT_IN_PATTERNS, applySanitizers };\n","/**\n * toBeToolError Matcher\n *\n * Validates that a response is (or is not) an error.\n */\n\nimport { validateError } from '../validators/error.js';\n\n/**\n * Creates the toBeToolError matcher function\n */\nexport function toBeToolError(\n this: { isNot: boolean },\n received: unknown,\n expected: boolean | string | string[] = true\n) {\n // Handle .not case specially\n const effectiveExpected = this.isNot\n ? typeof expected === 'boolean'\n ? !expected\n : false // .not with string message means \"should not be error\"\n : expected;\n\n const result = validateError(received, effectiveExpected);\n\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: () => {\n if (this.isNot) {\n // When using .not, we want the opposite behavior\n if (typeof expected === 'boolean') {\n return result.pass\n ? 'Expected response NOT to be an error, but it was'\n : 'Response is not an error as expected';\n }\n const expectedStr = Array.isArray(expected)\n ? expected.join(', ')\n : expected;\n return result.pass\n ? `Expected response NOT to be an error with \"${expectedStr}\", but it was`\n : result.message;\n }\n return result.message;\n },\n };\n}\n","import { query } from '@anthropic-ai/claude-agent-sdk';\nimport type {\n JudgeConfig,\n Judge,\n JudgeResult,\n UsageMetrics,\n} from './judgeTypes.js';\n\n/**\n * Creates a Claude Agent SDK-based LLM judge client\n *\n * Uses the Claude Agent SDK query() function for evaluation.\n * This is a response-only judge that does not use any tools.\n *\n * @param config - Judge configuration\n * @returns Claude agent judge client\n */\nexport function createClaudeAgentJudge(config: JudgeConfig): Judge {\n const model = config.model ?? 'claude-sonnet-4-20250514';\n const maxBudgetUsd = config.maxBudgetUsd ?? 0.1;\n const maxToolOutputSize = config.maxToolOutputSize;\n\n return {\n async evaluate(\n candidate: unknown,\n reference: unknown,\n rubric: string\n ): Promise<JudgeResult> {\n // Calculate candidate size for threshold check\n const candidateStr =\n typeof candidate === 'string'\n ? candidate\n : JSON.stringify(candidate, null, 2);\n const candidateSizeBytes = Buffer.byteLength(candidateStr, 'utf8');\n\n // Check maxToolOutputSize threshold before calling API (fail fast, save money)\n if (\n maxToolOutputSize !== undefined &&\n candidateSizeBytes > maxToolOutputSize\n ) {\n return {\n pass: false,\n score: 0,\n reasoning: `Tool output size (${candidateSizeBytes} bytes) exceeds maximum allowed size (${maxToolOutputSize} bytes)`,\n candidateSizeBytes,\n exceedsMaxToolOutputSize: true,\n };\n }\n\n // Build evaluation prompt\n const prompt = buildJudgePrompt(candidate, reference, rubric);\n\n try {\n // Use query() with no tools for response-only mode\n // Iterate through the generator to get the final result message\n let resultMessage:\n | {\n type: 'result';\n result?: string;\n usage?: {\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n total_cost_usd?: number;\n duration_ms?: number;\n duration_api_ms?: number;\n subtype?: string;\n errors?: string[];\n }\n | undefined;\n\n for await (const message of query({\n prompt,\n options: {\n model,\n maxBudgetUsd,\n // Use empty tools array for response-only mode\n tools: [],\n // Bypass permissions since we're not using any tools\n permissionMode: 'bypassPermissions',\n allowDangerouslySkipPermissions: true,\n // Use a custom system prompt for JSON output\n systemPrompt: buildSystemPrompt(),\n // Limit to 1 turn since this is a simple evaluation\n maxTurns: 1,\n },\n })) {\n // The final message will be the SDKResultMessage\n if (message.type === 'result') {\n resultMessage = message as unknown as typeof resultMessage;\n }\n }\n\n if (!resultMessage) {\n throw new Error('No result message received from Claude Agent SDK');\n }\n\n // Check for errors\n if (\n resultMessage.subtype !== 'success' &&\n resultMessage.errors?.length\n ) {\n throw new Error(\n `Claude Agent SDK error: ${resultMessage.errors.join(', ')}`\n );\n }\n\n // Extract text response from the result\n const responseText = resultMessage.result ?? '';\n\n // Parse the JSON response\n const parsed = parseJudgeResponse(responseText);\n\n // Build usage metrics from SDK response\n const usage: UsageMetrics = {\n inputTokens: resultMessage.usage?.input_tokens ?? 0,\n outputTokens: resultMessage.usage?.output_tokens ?? 0,\n totalCostUsd: resultMessage.total_cost_usd ?? 0,\n durationMs: resultMessage.duration_ms ?? 0,\n durationApiMs: resultMessage.duration_api_ms,\n cacheReadInputTokens: resultMessage.usage?.cache_read_input_tokens,\n cacheCreationInputTokens:\n resultMessage.usage?.cache_creation_input_tokens,\n };\n\n return {\n pass: parsed.pass ?? false,\n score: parsed.score,\n reasoning: parsed.reasoning,\n usage,\n candidateSizeBytes,\n exceedsMaxToolOutputSize: false,\n };\n } catch (error) {\n throw new Error(\n `Claude Agent judge evaluation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n };\n}\n\n/**\n * Builds the system prompt for the judge\n */\nfunction buildSystemPrompt(): string {\n return (\n 'You are an expert evaluator. Evaluate the candidate response based on the rubric provided. ' +\n 'Respond ONLY with valid JSON in this exact format: {\"pass\": boolean, \"score\": number (0-1), \"reasoning\": string}. ' +\n 'Do not include any other text, markdown formatting, or code blocks.'\n );\n}\n\n/**\n * Builds the user prompt for evaluation\n */\nfunction buildJudgePrompt(\n candidate: unknown,\n reference: unknown,\n rubric: string\n): string {\n const parts: Array<string> = [];\n\n parts.push('# Evaluation Task\\n');\n parts.push(rubric);\n parts.push('\\n\\n# Candidate Response\\n');\n parts.push(\n typeof candidate === 'string'\n ? candidate\n : JSON.stringify(candidate, null, 2)\n );\n\n if (reference !== null && reference !== undefined) {\n parts.push('\\n\\n# Reference Response\\n');\n parts.push(\n typeof reference === 'string'\n ? reference\n : JSON.stringify(reference, null, 2)\n );\n }\n\n parts.push(\n '\\n\\n# Instructions\\n' +\n 'Evaluate the candidate response based on the rubric. ' +\n (reference !== null && reference !== undefined\n ? 'Compare it against the reference response if helpful. '\n : '') +\n 'Respond with JSON containing \"pass\" (boolean), \"score\" (0-1), and \"reasoning\" (string).'\n );\n\n return parts.join('');\n}\n\n/**\n * Parses the JSON response from the judge, handling markdown code blocks\n */\nfunction parseJudgeResponse(text: string): {\n pass?: boolean;\n score?: number;\n reasoning?: string;\n} {\n let jsonText = text.trim();\n\n // Strip markdown code blocks if present\n if (jsonText.startsWith('```json')) {\n jsonText = jsonText.slice(7);\n }\n if (jsonText.startsWith('```')) {\n jsonText = jsonText.slice(3);\n }\n if (jsonText.endsWith('```')) {\n jsonText = jsonText.slice(0, -3);\n }\n jsonText = jsonText.trim();\n\n try {\n return JSON.parse(jsonText) as {\n pass?: boolean;\n score?: number;\n reasoning?: string;\n };\n } catch {\n // If JSON parsing fails, try to extract from the text\n // Sometimes the model adds extra text before/after JSON\n const jsonMatch = jsonText.match(/\\{[\\s\\S]*\"pass\"[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]) as {\n pass?: boolean;\n score?: number;\n reasoning?: string;\n };\n }\n throw new Error(`Failed to parse judge response as JSON: ${text}`);\n }\n}\n","import type { Judge, JudgeConfig, ProviderKind } from './judgeTypes.js';\nimport { createClaudeAgentJudge } from './claudeAgentJudge.js';\n\n/**\n * Creates an LLM judge for evaluating tool responses\n *\n * Uses Claude Agent SDK for evaluation with usage metrics tracking.\n *\n * @param config - Judge configuration\n * @returns Judge instance\n * @throws {Error} If provider is unsupported or configuration is invalid\n *\n * @example\n * // Default Claude judge\n * const judge = createJudge();\n *\n * @example\n * // With configuration\n * const judge = createJudge({\n * model: 'claude-sonnet-4-20250514',\n * maxToolOutputSize: 50000, // Fail if response > 50KB\n * maxBudgetUsd: 0.05,\n * });\n *\n * // Evaluate a response\n * const result = await judge.evaluate(\n * candidateResponse,\n * referenceResponse,\n * 'Evaluate for accuracy and completeness'\n * );\n *\n * // Access usage metrics\n * console.log('Cost:', result.usage?.totalCostUsd);\n * console.log('Tokens:', result.usage?.inputTokens, result.usage?.outputTokens);\n */\nexport function createJudge(config: JudgeConfig = {}): Judge {\n const provider: ProviderKind = config.provider ?? 'claude';\n\n switch (provider) {\n case 'claude':\n case 'anthropic':\n // Both 'claude' and 'anthropic' use Claude Agent SDK\n return createClaudeAgentJudge(config);\n\n case 'openai':\n throw new Error(\n 'OpenAI provider is no longer supported. ' +\n 'Please use createJudge() without specifying provider, or use provider: \"claude\". ' +\n 'See migration guide at https://github.com/gleanwork/mcp-server-tester/blob/main/docs/migration-v0.11.md'\n );\n\n case 'custom-http':\n throw new Error(\n 'custom-http provider is no longer supported. ' +\n 'Please use createJudge() without specifying provider.'\n );\n\n default:\n throw new Error(`Unsupported LLM provider: ${String(provider)}`);\n }\n}\n","/**\n * toPassToolJudge Matcher\n *\n * Validates that a response passes LLM-as-judge evaluation.\n */\n\nimport { createJudge } from '../../judge/judgeClient.js';\nimport type { JudgeConfig } from '../../judge/judgeTypes.js';\nimport type { JudgeMatcherOptions } from './types.js';\n\n// Default passing threshold\nconst DEFAULT_PASSING_THRESHOLD = 0.7;\n\n// Default judge configuration\nconst DEFAULT_JUDGE_CONFIG: JudgeConfig = {};\n\n/**\n * Creates the toPassToolJudge matcher function\n *\n * Note: This is an async matcher that calls an LLM for evaluation.\n */\nexport async function toPassToolJudge(\n this: { isNot: boolean },\n received: unknown,\n rubric: string,\n options: JudgeMatcherOptions = {}\n): Promise<{ pass: boolean; message: () => string }> {\n const {\n reference = null,\n passingThreshold = DEFAULT_PASSING_THRESHOLD,\n judgeConfig = DEFAULT_JUDGE_CONFIG,\n } = options;\n\n // Create judge client\n const judge = createJudge(judgeConfig);\n\n try {\n // Evaluate the response\n const result = await judge.evaluate(received, reference, rubric);\n\n // Determine pass/fail based on threshold\n const score = result.score ?? (result.pass ? 1.0 : 0.0);\n const passes = score >= passingThreshold;\n\n if (this.isNot) {\n // For .not, we expect the evaluation to fail\n return {\n pass: !passes,\n message: () =>\n passes\n ? `Expected judge evaluation to fail, but it passed with score ${score.toFixed(2)}`\n : `Judge evaluation failed as expected with score ${score.toFixed(2)}`,\n };\n }\n\n if (passes) {\n return {\n pass: true,\n message: () =>\n `Judge evaluation passed with score ${score.toFixed(2)} (threshold: ${passingThreshold})`,\n };\n }\n\n return {\n pass: false,\n message: () =>\n `Judge evaluation failed with score ${score.toFixed(2)} (threshold: ${passingThreshold}). ` +\n `Reasoning: ${result.reasoning ?? 'No reasoning provided'}`,\n };\n } catch (error) {\n return {\n pass: false,\n message: () =>\n `Judge evaluation failed with error: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n","/**\n * toHaveToolResponseSize Matcher\n *\n * Validates that a response meets size constraints.\n */\n\nimport { validateSize } from '../validators/size.js';\nimport type { SizeValidatorOptions } from '../validators/types.js';\n\n/**\n * Creates the toHaveToolResponseSize matcher function\n */\nexport function toHaveToolResponseSize(\n this: { isNot: boolean },\n received: unknown,\n options: SizeValidatorOptions\n) {\n const result = validateSize(received, options);\n\n return {\n pass: result.pass,\n message: () => {\n if (this.isNot) {\n return result.pass\n ? 'Expected response size NOT to be within bounds, but it was'\n : result.message;\n }\n return result.message;\n },\n };\n}\n","/**\n * toSatisfyToolPredicate Matcher\n *\n * Validates that a response satisfies a custom predicate function.\n * This is an escape hatch for custom validation logic when built-in\n * matchers don't cover the use case.\n */\n\nimport { extractText } from '../validators/utils.js';\nimport type { PredicateResult, ToolPredicate } from './types.js';\n\n/**\n * Normalizes predicate result to PredicateResult object\n */\nfunction normalizeResult(result: boolean | PredicateResult): PredicateResult {\n if (typeof result === 'boolean') {\n return {\n pass: result,\n message: result ? 'Predicate passed' : 'Predicate returned false',\n };\n }\n return result;\n}\n\n/**\n * Creates the toSatisfyToolPredicate matcher function\n *\n * This matcher allows custom validation logic via a predicate function.\n * The predicate receives both the raw response and extracted text.\n *\n * @example\n * ```typescript\n * // Simple boolean predicate\n * expect(result).toSatisfyToolPredicate((response) => {\n * return response.data?.length > 0;\n * });\n *\n * // Predicate with custom message\n * expect(result).toSatisfyToolPredicate((response, text) => {\n * const hasTemperature = text.includes('temperature');\n * return {\n * pass: hasTemperature,\n * message: hasTemperature\n * ? 'Found temperature in response'\n * : 'Expected response to contain temperature',\n * };\n * });\n *\n * // Async predicate\n * expect(result).toSatisfyToolPredicate(async (response) => {\n * const isValid = await validateWithExternalService(response);\n * return isValid;\n * });\n * ```\n */\nexport async function toSatisfyToolPredicate(\n this: { isNot: boolean },\n received: unknown,\n predicate: ToolPredicate,\n description?: string\n): Promise<{ pass: boolean; message: () => string }> {\n const predicateDescription = description ?? 'custom predicate';\n\n try {\n // Extract text for convenience\n const text = extractText(received);\n\n // Run the predicate\n const rawResult = await predicate(received, text);\n const result = normalizeResult(rawResult);\n\n // Handle .not\n if (this.isNot) {\n return {\n pass: !result.pass,\n message: () =>\n result.pass\n ? `Expected response NOT to satisfy ${predicateDescription}`\n : `Response does not satisfy ${predicateDescription} as expected`,\n };\n }\n\n return {\n pass: result.pass,\n message: () =>\n result.pass\n ? (result.message ?? `Response satisfies ${predicateDescription}`)\n : (result.message ??\n `Expected response to satisfy ${predicateDescription}`),\n };\n } catch (error) {\n // Predicate threw an error\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n return {\n pass: this.isNot, // If using .not, an error means the predicate didn't pass\n message: () => `Predicate threw error: ${errorMessage}`,\n };\n }\n}\n","/**\n * Matchers Module\n *\n * Custom Playwright matchers for MCP tool response validation.\n * These matchers use the validators internally and provide a clean\n * assertion API for Playwright tests.\n */\n\nimport { expect as baseExpect } from '@playwright/test';\n\n// Import matcher functions\nimport { toMatchToolResponse } from './toMatchToolResponse.js';\nimport { toMatchToolSchema } from './toMatchToolSchema.js';\nimport { toContainToolText } from './toContainToolText.js';\nimport { toMatchToolPattern } from './toMatchToolPattern.js';\nimport { toMatchToolSnapshot } from './toMatchToolSnapshot.js';\nimport { toBeToolError } from './toBeToolError.js';\nimport { toPassToolJudge } from './toPassToolJudge.js';\nimport { toHaveToolResponseSize } from './toHaveToolResponseSize.js';\nimport { toSatisfyToolPredicate } from './toSatisfyToolPredicate.js';\n\n// Import types for global declaration\nimport './types.js';\n\n/**\n * Extended Playwright expect with MCP tool matchers\n *\n * @example\n * ```typescript\n * import { expect } from '@gleanwork/mcp-server-tester';\n *\n * test('weather tool', async ({ mcp }) => {\n * const result = await mcp.callTool('get_weather', { city: 'London' });\n *\n * expect(result).toContainToolText('temperature');\n * expect(result).toMatchToolSchema(WeatherSchema);\n * expect(result).not.toBeToolError();\n * });\n * ```\n */\nexport const expect = baseExpect.extend({\n toMatchToolResponse,\n toMatchToolSchema,\n toContainToolText,\n toMatchToolPattern,\n toMatchToolSnapshot,\n toBeToolError,\n toPassToolJudge,\n toHaveToolResponseSize,\n toSatisfyToolPredicate,\n});\n\n// Re-export types\nexport type {\n JudgeMatcherOptions,\n ToolPredicate,\n PredicateResult,\n} from './types.js';\n","import { test as base } from '@playwright/test';\nimport { expect } from '../assertions/matchers/index.js';\nimport type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';\nimport {\n createMCPClientForConfig,\n closeMCPClient,\n} from '../mcp/clientFactory.js';\nimport {\n createMCPFixture,\n type MCPFixtureApi,\n type AuthType,\n} from '../mcp/fixtures/mcpFixture.js';\nimport { PlaywrightOAuthClientProvider } from '../auth/oauthClientProvider.js';\nimport { CLIOAuthClient } from '../auth/cli.js';\nimport { isHttpConfig, type MCPConfig } from '../config/mcpConfig.js';\n\n/**\n * Internal fixture state for passing auth type between fixtures\n */\ninterface MCPFixtureState {\n /**\n * The resolved authentication type (may differ from config if CLI tokens are used)\n */\n resolvedAuthType: AuthType;\n}\n\n/**\n * Extended test fixtures for MCP testing\n */\ntype MCPFixtures = {\n /**\n * Raw MCP client instance (automatically connected and cleaned up)\n */\n mcpClient: Client;\n\n /**\n * High-level MCP API for tests\n */\n mcp: MCPFixtureApi;\n\n /**\n * Internal fixture state (not for external use)\n */\n _mcpFixtureState: MCPFixtureState;\n};\n\n/**\n * Extended Playwright test with MCP fixtures\n *\n * @example\n * import { test, expect } from '@gleanwork/mcp-server-tester';\n *\n * test('lists tools from MCP server', async ({ mcp }) => {\n * const tools = await mcp.listTools();\n * expect(tools.length).toBeGreaterThan(0);\n * });\n */\nexport const test = base.extend<MCPFixtures>({\n /**\n * Internal fixture state - tracks resolved auth type between fixtures\n */\n _mcpFixtureState: [\n // eslint-disable-next-line no-empty-pattern\n async ({}, use) => {\n // Initialize with 'none', will be updated by mcpClient fixture\n const state: MCPFixtureState = { resolvedAuthType: 'none' };\n await use(state);\n },\n { scope: 'test' },\n ],\n\n /**\n * mcpClient fixture: Creates and connects an MCP client\n *\n * The client configuration is read from the project's `use.mcpConfig`\n * setting in playwright.config.ts\n *\n * Authentication resolution order:\n * 1. Explicit authStatePath → uses PlaywrightOAuthClientProvider\n * 2. Explicit accessToken → uses static Bearer token\n * 3. HTTP transport with no auth → tries CLI-stored tokens (from `mcp-server-tester login`)\n * with automatic token refresh\n */\n mcpClient: async ({ _mcpFixtureState }, use, testInfo) => {\n // Extract mcpConfig from project use settings\n const useConfig = testInfo.project.use as { mcpConfig?: MCPConfig };\n const mcpConfig = useConfig.mcpConfig;\n\n if (!mcpConfig) {\n throw new Error(\n `Missing mcpConfig in project.use for project \"${testInfo.project.name}\". ` +\n `Please add mcpConfig to your project configuration in playwright.config.ts`\n );\n }\n\n // Track resolved auth type\n let resolvedAuthType: AuthType = 'none';\n\n // Create auth provider if OAuth authStatePath is configured\n let authProvider: OAuthClientProvider | undefined;\n if (mcpConfig.auth?.oauth?.authStatePath) {\n authProvider = new PlaywrightOAuthClientProvider({\n storagePath: mcpConfig.auth.oauth.authStatePath,\n redirectUri:\n mcpConfig.auth.oauth.redirectUri ??\n 'http://localhost:3000/oauth/callback',\n clientId: mcpConfig.auth.oauth.clientId,\n clientSecret: mcpConfig.auth.oauth.clientSecret,\n });\n resolvedAuthType = 'oauth';\n }\n\n // Build effective config - may add CLI tokens if no auth is configured\n let effectiveConfig = mcpConfig;\n\n // Check for explicit static API token\n if (mcpConfig.auth?.accessToken) {\n resolvedAuthType = 'api-token';\n }\n\n // If HTTP transport with no explicit auth, try to use CLI-stored tokens\n // This enables the simple flow: `mcp-server-tester login <url>` then run tests\n if (\n isHttpConfig(mcpConfig) &&\n !mcpConfig.auth?.accessToken &&\n !mcpConfig.auth?.oauth?.authStatePath\n ) {\n const cliClient = new CLIOAuthClient({\n mcpServerUrl: mcpConfig.serverUrl,\n });\n\n // Try to get a valid token (will refresh if expired)\n const tokenResult = await cliClient.tryGetAccessToken();\n\n if (tokenResult) {\n // Use the CLI token as static auth\n effectiveConfig = {\n ...mcpConfig,\n auth: {\n ...mcpConfig.auth,\n accessToken: tokenResult.accessToken,\n },\n };\n // CLI tokens come from OAuth flow\n resolvedAuthType = 'oauth';\n }\n }\n\n // Store resolved auth type for mcp fixture\n _mcpFixtureState.resolvedAuthType = resolvedAuthType;\n\n // Create and connect client\n const client = await createMCPClientForConfig(effectiveConfig, {\n clientInfo: {\n name: '@gleanwork/mcp-server-tester',\n version: '0.1.0',\n },\n authProvider,\n });\n\n try {\n // Provide client to test\n await use(client);\n } finally {\n // Cleanup: close the client\n await closeMCPClient(client);\n }\n },\n\n /**\n * mcp fixture: High-level test API built on mcpClient\n *\n * Depends on mcpClient fixture\n * Automatically tracks all MCP operations for the reporter\n */\n mcp: async ({ mcpClient, _mcpFixtureState }, use, testInfo) => {\n const api = createMCPFixture(mcpClient, testInfo, {\n authType: _mcpFixtureState.resolvedAuthType,\n project: testInfo.project.name,\n });\n await use(api);\n },\n});\n\n/**\n * Re-export extended expect with MCP tool matchers\n *\n * @example\n * ```typescript\n * expect(result).toContainToolText('temperature');\n * expect(result).toMatchToolSchema(WeatherSchema);\n * expect(result).not.toBeToolError();\n * ```\n */\nexport { expect };\n","import { z } from 'zod';\nimport type { LLMHostConfig } from './llmHost/llmHostTypes.js';\nimport type { SnapshotSanitizer } from '../assertions/validators/types.js';\n\n// Re-export sanitizer types from canonical source (validators/types.ts)\n// Note: For JSON datasets, the Zod schema below validates that patterns are strings.\n// The TypeScript types allow RegExp for runtime usage with Playwright matchers.\nexport type {\n BuiltInSanitizer,\n SnapshotSanitizer,\n RegexSanitizer,\n FieldRemovalSanitizer,\n} from '../assertions/validators/types.js';\n\n/**\n * Evaluation mode\n */\nexport type EvalMode = 'direct' | 'llm_host';\n\n/**\n * A single eval test case\n *\n * For 'direct' mode: toolName and args are required\n * For 'llm_host' mode: scenario and llmHostConfig are required\n */\nexport interface EvalCase {\n /**\n * Unique identifier for this test case\n */\n id: string;\n\n /**\n * Human-readable description of what this test case validates\n */\n description?: string;\n\n /**\n * Evaluation mode\n * - 'direct': Direct API calls to MCP tools (default)\n * - 'llm_host': LLM-driven tool selection via natural language\n *\n * @default 'direct'\n */\n mode?: EvalMode;\n\n /**\n * Name of the MCP tool to call (required for 'direct' mode, optional for 'llm_host' mode)\n */\n toolName?: string;\n\n /**\n * Arguments to pass to the tool (required for 'direct' mode, optional for 'llm_host' mode)\n */\n args?: Record<string, unknown>;\n\n /**\n * Natural language scenario for LLM to execute (optional, required for 'llm_host' mode)\n *\n * @example \"Get the weather for London and tell me if I need an umbrella\"\n */\n scenario?: string;\n\n /**\n * LLM host configuration (optional for 'llm_host' mode)\n *\n * If not specified, uses default configuration from test environment\n */\n llmHostConfig?: LLMHostConfig;\n\n /**\n * Additional metadata for this test case\n *\n * For 'llm_host' mode, can include 'expectedToolCalls' for validation\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Expectations to validate against the tool response\n *\n * Multiple expectations can be combined and will all be validated.\n *\n * @example\n * ```json\n * {\n * \"id\": \"weather-london\",\n * \"toolName\": \"get_weather\",\n * \"args\": { \"city\": \"London\" },\n * \"expect\": {\n * \"containsText\": [\"temperature\", \"conditions\"],\n * \"schema\": \"WeatherResponse\",\n * \"responseSize\": { \"maxBytes\": 10000 },\n * \"isError\": false\n * }\n * }\n * ```\n */\n expect?: EvalExpectBlock;\n}\n\n/**\n * Unified expectation block for eval cases\n *\n * Mirrors the Playwright matcher API for consistency.\n */\nexport interface EvalExpectBlock {\n /**\n * Exact response match (toMatchToolResponse)\n */\n response?: unknown;\n\n /**\n * Name of schema to validate against (toMatchToolSchema)\n */\n schema?: string;\n\n /**\n * Text substring(s) that must be present (toContainToolText)\n */\n containsText?: string | string[];\n\n /**\n * Regex pattern(s) that must match (toMatchToolPattern)\n */\n matchesPattern?: string | string[];\n\n /**\n * Snapshot name for comparison (toMatchToolSnapshot)\n */\n snapshot?: string;\n\n /**\n * Snapshot sanitizers to apply\n */\n snapshotSanitizers?: SnapshotSanitizer[];\n\n /**\n * Error expectation (toBeToolError)\n * - true: expects any error\n * - false: expects no error\n * - string: expects error containing this message\n */\n isError?: boolean | string | string[];\n\n /**\n * LLM-as-judge evaluation (toPassToolJudge)\n */\n passesJudge?: {\n /** Evaluation rubric/criteria */\n rubric: string;\n /** Reference response to compare against */\n reference?: unknown;\n /** Score threshold for passing (0-1, default: 0.7) */\n threshold?: number;\n /** Judge configuration ID */\n configId?: string;\n };\n\n /**\n * Response size validation (toHaveToolResponseSize)\n */\n responseSize?: {\n /** Maximum allowed size in bytes */\n maxBytes?: number;\n /** Minimum required size in bytes */\n minBytes?: number;\n };\n}\n\n/**\n * A complete eval dataset containing multiple test cases\n */\nexport interface EvalDataset {\n /**\n * Dataset name\n */\n name: string;\n\n /**\n * Dataset description\n */\n description?: string;\n\n /**\n * Test cases in this dataset\n */\n cases: Array<EvalCase>;\n\n /**\n * Optional schema definitions referenced by test cases\n */\n schemas?: Record<string, z.ZodSchema>;\n\n /**\n * Additional dataset metadata\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Zod schema for LLMHostConfig (simplified for serialization)\n */\nconst LLMHostConfigSchema = z.object({\n provider: z.enum(['openai', 'anthropic']),\n apiKeyEnvVar: z.string().optional(),\n model: z.string().optional(),\n maxTokens: z.number().optional(),\n temperature: z.number().optional(),\n maxToolCalls: z.number().optional(),\n});\n\n/**\n * Zod schema for SnapshotSanitizer\n */\nconst SnapshotSanitizerSchema = z.union([\n // Built-in sanitizers\n z.enum(['timestamp', 'uuid', 'iso-date', 'objectId', 'jwt']),\n // Custom regex sanitizer\n z.object({\n pattern: z.string(),\n replacement: z.string().optional(),\n }),\n // Field removal sanitizer\n z.object({\n remove: z.array(z.string()),\n }),\n]);\n\n/**\n * Zod schema for EvalExpectBlock\n */\nconst EvalExpectBlockSchema = z.object({\n response: z.unknown().optional(),\n schema: z.string().optional(),\n containsText: z.union([z.string(), z.array(z.string())]).optional(),\n matchesPattern: z.union([z.string(), z.array(z.string())]).optional(),\n snapshot: z.string().optional(),\n snapshotSanitizers: z.array(SnapshotSanitizerSchema).optional(),\n isError: z.union([z.boolean(), z.string(), z.array(z.string())]).optional(),\n passesJudge: z\n .object({\n rubric: z.string(),\n reference: z.unknown().optional(),\n threshold: z.number().min(0).max(1).optional(),\n configId: z.string().optional(),\n })\n .optional(),\n responseSize: z\n .object({\n maxBytes: z.number().optional(),\n minBytes: z.number().optional(),\n })\n .optional(),\n});\n\n/**\n * Zod schema for EvalCase\n *\n * toolName and args are optional for llm_host mode (which uses scenario instead)\n */\nexport const EvalCaseSchema = z.object({\n id: z.string().min(1, 'id must not be empty'),\n description: z.string().optional(),\n mode: z.enum(['direct', 'llm_host']).optional(),\n toolName: z.string().min(1, 'toolName must not be empty').optional(),\n args: z.record(z.unknown()).optional(),\n scenario: z.string().optional(),\n llmHostConfig: LLMHostConfigSchema.optional(),\n metadata: z.record(z.unknown()).optional(),\n expect: EvalExpectBlockSchema.optional(),\n});\n\n/**\n * Zod schema for EvalDataset (without schemas field, as schemas aren't serializable)\n */\nexport const EvalDatasetSchema = z.object({\n name: z.string().min(1, 'name must not be empty'),\n description: z.string().optional(),\n cases: z.array(EvalCaseSchema).min(1, 'dataset must have at least one case'),\n metadata: z.record(z.unknown()).optional(),\n});\n\n/**\n * Type for serialized eval dataset (without Zod schemas)\n */\nexport type SerializedEvalDataset = z.infer<typeof EvalDatasetSchema>;\n\n/**\n * Validates an eval case\n *\n * @param evalCase - The eval case to validate\n * @returns The validated eval case\n * @throws {z.ZodError} If validation fails\n */\nexport function validateEvalCase(evalCase: unknown): EvalCase {\n return EvalCaseSchema.parse(evalCase);\n}\n\n/**\n * Validates a serialized eval dataset\n *\n * @param dataset - The dataset to validate\n * @returns The validated dataset\n * @throws {z.ZodError} If validation fails\n */\nexport function validateEvalDataset(dataset: unknown): SerializedEvalDataset {\n return EvalDatasetSchema.parse(dataset);\n}\n","import { readFile } from 'fs/promises';\nimport { type z } from 'zod';\nimport {\n type EvalDataset,\n type SerializedEvalDataset,\n validateEvalDataset,\n} from './datasetTypes.js';\n\n/**\n * Options for loading an eval dataset\n */\nexport interface LoadDatasetOptions {\n /**\n * Optional schema definitions to attach to the dataset\n *\n * Keys should match the expectedSchemaName in eval cases\n */\n schemas?: Record<string, z.ZodSchema>;\n\n /**\n * Whether to validate the loaded dataset\n * @default true\n */\n validate?: boolean;\n}\n\n/**\n * Loads an eval dataset from a JSON file\n *\n * @param filePath - Absolute path to the JSON file\n * @param options - Load options\n * @returns The loaded and validated dataset\n * @throws {Error} If file cannot be read or JSON is invalid\n * @throws {z.ZodError} If validation fails\n *\n * @example\n * const dataset = await loadEvalDataset('./data/my-evals.json', {\n * schemas: {\n * 'weather-response': WeatherResponseSchema,\n * },\n * });\n */\nexport async function loadEvalDataset(\n filePath: string,\n options: LoadDatasetOptions = {}\n): Promise<EvalDataset> {\n const { schemas, validate = true } = options;\n\n try {\n const fileContents = await readFile(filePath, 'utf-8');\n const rawData: unknown = JSON.parse(fileContents);\n\n // Validate if requested\n const serializedDataset: SerializedEvalDataset = validate\n ? validateEvalDataset(rawData)\n : (rawData as SerializedEvalDataset);\n\n // Create full dataset with schemas\n const dataset: EvalDataset = {\n ...serializedDataset,\n schemas: schemas ?? {},\n };\n\n return dataset;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(\n `Failed to parse JSON from ${filePath}: ${error.message}`\n );\n }\n throw error;\n }\n}\n\n/**\n * Loads an eval dataset from a plain object\n *\n * Useful for programmatically creating datasets in tests\n *\n * @param data - The dataset data\n * @param options - Load options\n * @returns The loaded and validated dataset\n * @throws {z.ZodError} If validation fails\n *\n * @example\n * const dataset = loadEvalDatasetFromObject({\n * name: 'my-test-dataset',\n * cases: [\n * {\n * id: 'case-1',\n * toolName: 'get_weather',\n * args: { city: 'London' },\n * },\n * ],\n * });\n */\nexport function loadEvalDatasetFromObject(\n data: unknown,\n options: LoadDatasetOptions = {}\n): EvalDataset {\n const { schemas, validate = true } = options;\n\n // Validate if requested\n const serializedDataset: SerializedEvalDataset = validate\n ? validateEvalDataset(data)\n : (data as SerializedEvalDataset);\n\n // Create full dataset with schemas\n const dataset: EvalDataset = {\n ...serializedDataset,\n schemas: schemas ?? {},\n };\n\n return dataset;\n}\n","/**\n * LLM Adapter Interface\n *\n * Defines the contract for LLM provider adapters, enabling\n * the orchestrator to work with any LLM provider through\n * a unified interface.\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport type {\n LLMProvider,\n LLMToolCall,\n LLMHostConfig,\n} from './llmHostTypes.js';\n\n/**\n * Result from an LLM chat call\n */\nexport interface LLMChatResult {\n /**\n * Whether the LLM wants to call tools\n */\n wantsToolCalls: boolean;\n\n /**\n * Tool calls requested by the LLM (if any)\n */\n toolCalls: LLMToolCall[];\n\n /**\n * Text content from the response (final answer if no tool calls)\n */\n textContent: string | null;\n\n /**\n * Raw response from the LLM (for debugging)\n */\n rawResponse: unknown;\n}\n\n/**\n * LLM Adapter interface\n *\n * Each provider (OpenAI, Anthropic) implements this interface\n * to normalize their specific APIs into a common format.\n */\nexport interface LLMAdapter {\n /**\n * Provider identifier\n */\n readonly provider: LLMProvider;\n\n /**\n * Loads the SDK and creates a client\n *\n * @param config - LLM host configuration\n * @returns Configured client instance\n * @throws Error if SDK not installed or API key missing\n */\n createClient(config: LLMHostConfig): Promise<unknown>;\n\n /**\n * Converts MCP tools to the provider's tool format\n *\n * @param tools - MCP tool definitions\n * @returns Tools in provider-specific format\n */\n formatTools(tools: Tool[]): unknown[];\n\n /**\n * Makes a chat completion request with tool support\n *\n * @param client - Client from createClient()\n * @param messages - Conversation history in provider format\n * @param tools - Formatted tools from formatTools()\n * @param config - LLM configuration (model, temperature, etc.)\n * @returns Chat result with parsed tool calls or text response\n */\n chat(\n client: unknown,\n messages: unknown[],\n tools: unknown[],\n config: LLMHostConfig\n ): Promise<LLMChatResult>;\n\n /**\n * Creates the initial message for a scenario\n *\n * @param scenario - User's natural language prompt\n * @returns Initial message in provider format\n */\n createUserMessage(scenario: string): unknown;\n\n /**\n * Creates an assistant message with tool calls\n *\n * @param chatResult - Result from chat() that had tool calls\n * @returns Assistant message in provider format\n */\n createAssistantMessage(chatResult: LLMChatResult): unknown;\n\n /**\n * Creates tool result messages\n *\n * @param toolCall - The tool call that was executed\n * @param result - Text result from MCP tool execution\n * @returns Tool result message(s) in provider format\n */\n createToolResultMessage(toolCall: LLMToolCall, result: string): unknown;\n}\n\n/**\n * Registry of available adapters\n */\nexport type AdapterFactory = () => LLMAdapter;\n\nconst adapters = new Map<LLMProvider, AdapterFactory>();\n\n/**\n * Registers an adapter factory for a provider\n */\nexport function registerAdapter(\n provider: LLMProvider,\n factory: AdapterFactory\n): void {\n adapters.set(provider, factory);\n}\n\n/**\n * Gets an adapter for a provider\n *\n * @param provider - LLM provider\n * @returns Adapter instance\n * @throws Error if provider not registered\n */\nexport function getAdapter(provider: LLMProvider): LLMAdapter {\n const factory = adapters.get(provider);\n if (!factory) {\n throw new Error(\n `No adapter registered for provider: ${provider}. Available: ${Array.from(adapters.keys()).join(', ')}`\n );\n }\n return factory();\n}\n\n/**\n * Checks if an adapter is registered for a provider\n */\nexport function hasAdapter(provider: LLMProvider): boolean {\n return adapters.has(provider);\n}\n","/**\n * Retry utility with exponential backoff for LLM API calls\n */\n\n/**\n * Options for retry behavior\n */\nexport interface RetryOptions {\n /**\n * Maximum number of attempts (including the first)\n * @default 3\n */\n maxAttempts?: number;\n\n /**\n * Base delay in milliseconds before first retry\n * @default 1000\n */\n baseDelayMs?: number;\n\n /**\n * Maximum delay in milliseconds\n * @default 30000\n */\n maxDelayMs?: number;\n\n /**\n * Function to determine if an error is retryable\n * @default Retries on 429, 500, 502, 503, 504 HTTP errors\n */\n isRetryable?: (error: unknown) => boolean;\n\n /**\n * Callback invoked before each retry\n */\n onRetry?: (error: unknown, attempt: number, delayMs: number) => void;\n}\n\n/**\n * Default retry options\n */\nconst DEFAULT_OPTIONS: Required<Omit<RetryOptions, 'onRetry'>> & {\n onRetry?: RetryOptions['onRetry'];\n} = {\n maxAttempts: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n isRetryable: isRetryableError,\n};\n\n/**\n * Executes a function with retry logic and exponential backoff\n *\n * @param fn - Async function to execute\n * @param options - Retry options\n * @returns Result of the function\n * @throws Last error if all retries fail\n *\n * @example\n * ```typescript\n * const result = await withRetry(\n * () => openai.chat.completions.create({ ... }),\n * { maxAttempts: 3, baseDelayMs: 1000 }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = DEFAULT_OPTIONS.maxAttempts,\n baseDelayMs = DEFAULT_OPTIONS.baseDelayMs,\n maxDelayMs = DEFAULT_OPTIONS.maxDelayMs,\n isRetryable = DEFAULT_OPTIONS.isRetryable,\n onRetry,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Don't retry if it's the last attempt or error isn't retryable\n if (attempt >= maxAttempts || !isRetryable(error)) {\n throw error;\n }\n\n // Calculate delay with exponential backoff and jitter\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);\n const jitter = Math.random() * 0.1 * exponentialDelay; // 10% jitter\n const delayMs = Math.min(exponentialDelay + jitter, maxDelayMs);\n\n // Notify before retry\n if (onRetry) {\n onRetry(error, attempt, delayMs);\n }\n\n // Wait before retrying\n await sleep(delayMs);\n }\n }\n\n // Should never reach here, but TypeScript needs it\n throw lastError;\n}\n\n/**\n * Determines if an error is retryable based on HTTP status codes\n *\n * Retries on:\n * - 429 Too Many Requests (rate limit)\n * - 500 Internal Server Error\n * - 502 Bad Gateway\n * - 503 Service Unavailable\n * - 504 Gateway Timeout\n */\nexport function isRetryableError(error: unknown): boolean {\n // Check for HTTP status code in various error formats\n const statusCode = extractStatusCode(error);\n\n if (statusCode !== null) {\n return [429, 500, 502, 503, 504].includes(statusCode);\n }\n\n // Check error message for common retryable patterns\n const message = extractErrorMessage(error).toLowerCase();\n return (\n message.includes('rate limit') ||\n message.includes('429') ||\n message.includes('too many requests') ||\n message.includes('timeout') ||\n message.includes('temporarily unavailable') ||\n message.includes('service unavailable') ||\n message.includes('internal server error')\n );\n}\n\n/**\n * Extracts HTTP status code from various error formats\n */\nfunction extractStatusCode(error: unknown): number | null {\n if (error == null || typeof error !== 'object') {\n return null;\n }\n\n const e = error as Record<string, unknown>;\n\n // Direct status property\n if (typeof e.status === 'number') {\n return e.status;\n }\n\n // statusCode property\n if (typeof e.statusCode === 'number') {\n return e.statusCode;\n }\n\n // response.status (Axios-style)\n if (e.response && typeof e.response === 'object') {\n const response = e.response as Record<string, unknown>;\n if (typeof response.status === 'number') {\n return response.status;\n }\n }\n\n // code property (some SDKs use this)\n if (typeof e.code === 'number') {\n return e.code;\n }\n\n return null;\n}\n\n/**\n * Extracts error message from various error formats\n */\nfunction extractErrorMessage(error: unknown): string {\n if (error == null) {\n return '';\n }\n\n if (typeof error === 'string') {\n return error;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n if (typeof error === 'object') {\n const e = error as Record<string, unknown>;\n if (typeof e.message === 'string') {\n return e.message;\n }\n if (typeof e.error === 'string') {\n return e.error;\n }\n // Fallback to JSON for unknown object shapes\n return JSON.stringify(error);\n }\n\n // Primitives (number, boolean)\n if (typeof error === 'number' || typeof error === 'boolean') {\n return String(error);\n }\n\n return 'Unknown error';\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * LLM Host Simulation Orchestrator\n *\n * Implements the shared agentic loop logic that works with any LLM adapter.\n * This is the core of the simulation - it handles tool execution, conversation\n * management, and retry logic.\n */\n\nimport type { MCPFixtureApi } from '../../mcp/fixtures/mcpFixture.js';\nimport { extractText } from '../../mcp/response.js';\nimport type { LLMAdapter } from './adapter.js';\nimport type {\n LLMHostConfig,\n LLMHostSimulationResult,\n LLMToolCall,\n} from './llmHostTypes.js';\nimport { withRetry, type RetryOptions } from './retry.js';\n\n/**\n * Options for the simulation orchestrator\n */\nexport interface OrchestratorOptions {\n /**\n * Retry options for LLM API calls\n */\n retry?: RetryOptions;\n}\n\n/**\n * Runs an LLM host simulation using the provided adapter\n *\n * This function implements the agentic loop:\n * 1. Send scenario to LLM with available tools\n * 2. If LLM wants to call tools, execute them via MCP\n * 3. Add tool results to conversation and repeat\n * 4. When LLM gives final response, return results\n *\n * @param adapter - LLM adapter (OpenAI, Anthropic, etc.)\n * @param mcp - MCP fixture API for tool execution\n * @param scenario - Natural language prompt\n * @param config - LLM host configuration\n * @param options - Orchestrator options (retry, etc.)\n * @returns Simulation result with tool calls and response\n */\nexport async function runSimulation(\n adapter: LLMAdapter,\n mcp: MCPFixtureApi,\n scenario: string,\n config: LLMHostConfig,\n options: OrchestratorOptions = {}\n): Promise<LLMHostSimulationResult> {\n const maxIterations = config.maxToolCalls || 10;\n const retryOptions = options.retry || {};\n\n // Track all tool calls\n const allToolCalls: LLMToolCall[] = [];\n\n // Track conversation history for debugging\n const conversationHistory: Array<{\n role: 'user' | 'assistant' | 'tool';\n content: string;\n }> = [];\n\n try {\n // Create LLM client\n const client = await adapter.createClient(config);\n\n // Get tools from MCP server and format for LLM\n const mcpTools = await mcp.listTools();\n const formattedTools = adapter.formatTools(mcpTools);\n\n // Initialize conversation with user message\n const messages: unknown[] = [adapter.createUserMessage(scenario)];\n conversationHistory.push({ role: 'user', content: scenario });\n\n let finalResponse = '';\n\n // Agentic loop\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n // Call LLM with retry\n const chatResult = await withRetry(\n () => adapter.chat(client, messages, formattedTools, config),\n retryOptions\n );\n\n // Check if LLM wants to call tools\n if (chatResult.wantsToolCalls && chatResult.toolCalls.length > 0) {\n // Add assistant message to conversation\n messages.push(adapter.createAssistantMessage(chatResult));\n\n // Execute each tool call through MCP\n const toolResultMessages: unknown[] = [];\n\n for (const toolCall of chatResult.toolCalls) {\n // Track the tool call\n allToolCalls.push(toolCall);\n\n // Execute via MCP\n const mcpResult = await mcp.callTool(\n toolCall.name,\n toolCall.arguments\n );\n\n // Extract text from MCP response\n const resultText = extractText(mcpResult);\n\n // Create tool result message\n const resultMessage = adapter.createToolResultMessage(\n toolCall,\n resultText\n );\n toolResultMessages.push(resultMessage);\n\n // Track in conversation history\n conversationHistory.push({ role: 'tool', content: resultText });\n }\n\n // Add tool results to conversation\n // Note: Anthropic wraps tool results in a user message, OpenAI adds them directly\n if (adapter.provider === 'anthropic') {\n messages.push({\n role: 'user',\n content: toolResultMessages,\n });\n } else {\n // OpenAI: add each tool result as a separate message\n for (const msg of toolResultMessages) {\n messages.push(msg);\n }\n }\n } else {\n // No tool calls - we have the final response\n finalResponse = chatResult.textContent || '';\n conversationHistory.push({ role: 'assistant', content: finalResponse });\n break;\n }\n }\n\n return {\n success: true,\n toolCalls: allToolCalls,\n response: finalResponse,\n conversationHistory,\n };\n } catch (error) {\n return {\n success: false,\n toolCalls: allToolCalls,\n error: error instanceof Error ? error.message : String(error),\n conversationHistory,\n };\n }\n}\n","/**\n * OpenAI Adapter for LLM Host Simulation\n *\n * Implements the LLMAdapter interface for OpenAI's Chat Completions API.\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport type { LLMAdapter, LLMChatResult } from '../adapter.js';\nimport type { LLMHostConfig, LLMToolCall } from '../llmHostTypes.js';\n\n/**\n * OpenAI-specific types (minimal to avoid full SDK dependency at compile time)\n */\ninterface OpenAITool {\n type: 'function';\n function: {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n };\n}\n\ninterface OpenAIMessage {\n role: 'user' | 'assistant' | 'tool' | 'system';\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n tool_call_id?: string;\n}\n\n/**\n * Creates an OpenAI adapter\n */\nexport function createOpenAIAdapter(): LLMAdapter {\n return {\n provider: 'openai',\n\n async createClient(config: LLMHostConfig): Promise<unknown> {\n // Dynamic import for optional dependency\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n let OpenAI;\n try {\n // @ts-expect-error - Optional dependency, dynamically imported\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const module = await import('openai');\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n OpenAI = module.OpenAI;\n } catch {\n throw new Error(\n 'OpenAI SDK is not installed. Install it with: npm install openai'\n );\n }\n\n // Get API key\n const apiKeyEnvVar = config.apiKeyEnvVar || 'OPENAI_API_KEY';\n const apiKey = process.env[apiKeyEnvVar];\n\n if (!apiKey) {\n throw new Error(\n `OpenAI API key not found in environment variable ${apiKeyEnvVar}`\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n return new OpenAI({ apiKey });\n },\n\n formatTools(tools: Tool[]): OpenAITool[] {\n return tools.map((tool) => ({\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description || '',\n parameters: (tool.inputSchema as Record<string, unknown>) || {},\n },\n }));\n },\n\n async chat(\n client: unknown,\n messages: unknown[],\n tools: unknown[],\n config: LLMHostConfig\n ): Promise<LLMChatResult> {\n const openai = client as {\n chat: { completions: { create: (opts: unknown) => Promise<unknown> } };\n };\n\n const response = await openai.chat.completions.create({\n model: config.model || 'gpt-4o',\n messages: messages as OpenAIMessage[],\n tools: tools as OpenAITool[],\n temperature: config.temperature ?? 0.0,\n max_tokens: config.maxTokens,\n });\n\n // Parse response\n const resp = response as {\n choices: Array<{\n message: {\n content: string | null;\n tool_calls?: Array<{\n id: string;\n type: string;\n function: {\n name: string;\n arguments: string;\n };\n }>;\n };\n }>;\n };\n\n const message = resp.choices[0]?.message;\n if (!message) {\n throw new Error('No response from OpenAI');\n }\n\n // Check for tool calls\n if (message.tool_calls && message.tool_calls.length > 0) {\n const toolCalls: LLMToolCall[] = message.tool_calls.map((tc) => ({\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments) as Record<\n string,\n unknown\n >,\n id: tc.id,\n }));\n\n return {\n wantsToolCalls: true,\n toolCalls,\n textContent: message.content,\n rawResponse: response,\n };\n }\n\n // No tool calls - final response\n return {\n wantsToolCalls: false,\n toolCalls: [],\n textContent: message.content,\n rawResponse: response,\n };\n },\n\n createUserMessage(scenario: string): OpenAIMessage {\n return {\n role: 'user',\n content: scenario,\n };\n },\n\n createAssistantMessage(chatResult: LLMChatResult): OpenAIMessage {\n const rawResponse = chatResult.rawResponse as {\n choices: Array<{ message: { tool_calls?: unknown[] } }>;\n };\n\n return {\n role: 'assistant',\n content: chatResult.textContent,\n tool_calls: rawResponse.choices[0]?.message\n ?.tool_calls as OpenAIMessage['tool_calls'],\n };\n },\n\n createToolResultMessage(\n toolCall: LLMToolCall,\n result: string\n ): OpenAIMessage {\n return {\n role: 'tool',\n tool_call_id: toolCall.id,\n content: result,\n };\n },\n };\n}\n","/**\n * Anthropic Adapter for LLM Host Simulation\n *\n * Implements the LLMAdapter interface for Anthropic's Messages API.\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport type { LLMAdapter, LLMChatResult } from '../adapter.js';\nimport type { LLMHostConfig, LLMToolCall } from '../llmHostTypes.js';\n\n/**\n * Anthropic-specific types (minimal to avoid full SDK dependency at compile time)\n */\ninterface AnthropicTool {\n name: string;\n description: string;\n input_schema: Record<string, unknown>;\n}\n\ninterface AnthropicMessage {\n role: 'user' | 'assistant';\n content: string | AnthropicContentBlock[];\n}\n\ninterface AnthropicContentBlock {\n type: 'text' | 'tool_use' | 'tool_result';\n text?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n content?: string;\n}\n\n/**\n * Creates an Anthropic adapter\n */\nexport function createAnthropicAdapter(): LLMAdapter {\n return {\n provider: 'anthropic',\n\n async createClient(config: LLMHostConfig): Promise<unknown> {\n // Dynamic import for optional dependency\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n let Anthropic;\n try {\n // @ts-expect-error - Optional dependency, dynamically imported\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const module = await import('@anthropic-ai/sdk');\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n Anthropic = module.default;\n } catch {\n throw new Error(\n 'Anthropic SDK is not installed. Install it with: npm install @anthropic-ai/sdk'\n );\n }\n\n // Get API key\n const apiKeyEnvVar = config.apiKeyEnvVar || 'ANTHROPIC_API_KEY';\n const apiKey = process.env[apiKeyEnvVar];\n\n if (!apiKey) {\n throw new Error(\n `Anthropic API key not found in environment variable ${apiKeyEnvVar}`\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n return new Anthropic({ apiKey });\n },\n\n formatTools(tools: Tool[]): AnthropicTool[] {\n return tools.map((tool) => ({\n name: tool.name,\n description: tool.description || '',\n input_schema: (tool.inputSchema as Record<string, unknown>) || {},\n }));\n },\n\n async chat(\n client: unknown,\n messages: unknown[],\n tools: unknown[],\n config: LLMHostConfig\n ): Promise<LLMChatResult> {\n const anthropic = client as {\n messages: { create: (opts: unknown) => Promise<unknown> };\n };\n\n const response = await anthropic.messages.create({\n model: config.model || 'claude-3-5-sonnet-20241022',\n max_tokens: config.maxTokens || 4096,\n temperature: config.temperature ?? 0.0,\n messages: messages as AnthropicMessage[],\n tools: tools as AnthropicTool[],\n });\n\n // Parse response\n const resp = response as {\n stop_reason: string;\n content: AnthropicContentBlock[];\n };\n\n // Extract text content\n const textBlock = resp.content.find((c) => c.type === 'text');\n const textContent = textBlock?.text || null;\n\n // Check stop reason\n if (resp.stop_reason === 'tool_use') {\n // Extract tool uses\n const toolUses = resp.content.filter((c) => c.type === 'tool_use');\n const toolCalls: LLMToolCall[] = toolUses.map((tu) => ({\n name: tu.name!,\n arguments: tu.input as Record<string, unknown>,\n id: tu.id,\n }));\n\n return {\n wantsToolCalls: true,\n toolCalls,\n textContent,\n rawResponse: response,\n };\n }\n\n if (resp.stop_reason === 'max_tokens') {\n throw new Error('Response exceeded max tokens');\n }\n\n // No tool calls - final response (end_turn or other)\n return {\n wantsToolCalls: false,\n toolCalls: [],\n textContent,\n rawResponse: response,\n };\n },\n\n createUserMessage(scenario: string): AnthropicMessage {\n return {\n role: 'user',\n content: scenario,\n };\n },\n\n createAssistantMessage(chatResult: LLMChatResult): AnthropicMessage {\n const rawResponse = chatResult.rawResponse as {\n content: AnthropicContentBlock[];\n };\n\n return {\n role: 'assistant',\n content: rawResponse.content,\n };\n },\n\n createToolResultMessage(\n toolCall: LLMToolCall,\n result: string\n ): AnthropicContentBlock {\n return {\n type: 'tool_result',\n tool_use_id: toolCall.id,\n content: result,\n };\n },\n };\n}\n","/**\n * LLM Host Simulation - Main entry point\n *\n * Provides the public API for simulating LLM hosts interacting\n * with MCP servers through actual LLM providers.\n */\n\nimport type { MCPFixtureApi } from '../../mcp/fixtures/mcpFixture.js';\nimport type {\n LLMHostConfig,\n LLMHostSimulationResult,\n LLMProvider,\n} from './llmHostTypes.js';\nimport { registerAdapter, getAdapter, hasAdapter } from './adapter.js';\nimport { runSimulation } from './orchestrator.js';\nimport { createOpenAIAdapter } from './adapters/openai.js';\nimport { createAnthropicAdapter } from './adapters/anthropic.js';\n\n// Register built-in adapters\nregisterAdapter('openai', createOpenAIAdapter);\nregisterAdapter('anthropic', createAnthropicAdapter);\n\n/**\n * Simulates an LLM host interacting with an MCP server\n *\n * This function uses actual LLM providers (OpenAI or Anthropic) to test\n * MCP servers through natural language scenarios. The LLM chooses which\n * tools to call based on their descriptions, testing discoverability and\n * parameter clarity.\n *\n * @param mcp - MCP fixture API\n * @param scenario - Natural language prompt describing what to do\n * @param config - LLM host configuration\n * @returns Simulation result with tool calls and final response\n *\n * @example\n * ```typescript\n * const result = await simulateLLMHost(mcp,\n * \"Get the weather for London\",\n * {\n * provider: 'openai',\n * model: 'gpt-4o'\n * }\n * );\n *\n * expect(result.success).toBe(true);\n * expect(result.toolCalls).toContainEqual({\n * name: 'get_weather',\n * arguments: { city: 'London' }\n * });\n * ```\n */\nexport async function simulateLLMHost(\n mcp: MCPFixtureApi,\n scenario: string,\n config: LLMHostConfig\n): Promise<LLMHostSimulationResult> {\n const adapter = getAdapter(config.provider);\n\n return runSimulation(adapter, mcp, scenario, config, {\n retry: {\n maxAttempts: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n },\n });\n}\n\n/**\n * Checks if the required SDK is available for a given provider\n *\n * This performs a quick check without actually loading the SDK.\n * The actual SDK loading happens in the adapter when simulation runs.\n *\n * @param provider - LLM provider to check\n * @returns true if an adapter is registered for the provider\n */\nexport function isProviderAvailable(provider: LLMProvider): boolean {\n return hasAdapter(provider);\n}\n\n/**\n * Gets a helpful error message for missing dependencies\n *\n * @param provider - LLM provider\n * @returns Error message with installation instructions\n */\nexport function getMissingDependencyMessage(provider: LLMProvider): string {\n switch (provider) {\n case 'openai':\n return 'OpenAI SDK is not installed. Install it with: npm install openai';\n case 'anthropic':\n return 'Anthropic SDK is not installed. Install it with: npm install @anthropic-ai/sdk';\n default:\n return `Unknown provider: ${String(provider)}`;\n }\n}\n\n// Re-export adapter utilities for advanced usage\nexport { registerAdapter, getAdapter, hasAdapter } from './adapter.js';\nexport { runSimulation } from './orchestrator.js';\nexport { withRetry, isRetryableError, type RetryOptions } from './retry.js';\nexport type { LLMAdapter, LLMChatResult } from './adapter.js';\n","import type { MCPFixtureApi } from '../mcp/fixtures/mcpFixture.js';\nimport type { JudgeConfig } from '../judge/judgeTypes.js';\nimport type { EvalDataset, EvalCase, EvalExpectBlock } from './datasetTypes.js';\nimport type { TestInfo, Expect } from '@playwright/test';\nimport type { ZodType } from 'zod';\nimport { simulateLLMHost } from './llmHost/llmHostSimulation.js';\nimport type {\n AuthType,\n ResultSource,\n ExpectationType,\n EvalExpectationResult,\n} from '../types/index.js';\nimport {\n validateResponse,\n validateSchema,\n validateText,\n validatePattern,\n validateError,\n validateSize,\n} from '../assertions/validators/index.js';\nimport { createJudge } from '../judge/judgeClient.js';\n\n/**\n * Context passed to the eval runner\n */\nexport interface EvalContext {\n /**\n * MCP fixture API for interacting with the server\n */\n mcp: MCPFixtureApi;\n\n /**\n * Optional Playwright TestInfo for reporter integration\n * When provided, eval results will be attached to the test for the MCP reporter\n */\n testInfo?: TestInfo;\n\n /**\n * Optional Playwright expect function for snapshot testing\n * Required for snapshot expectations to work properly\n */\n expect?: Expect;\n}\n\nexport type { EvalExpectationResult } from '../types/index.js';\n\n/**\n * Result of a single eval case\n */\nexport interface EvalCaseResult {\n /**\n * Case ID\n */\n id: string;\n\n /**\n * Dataset name this case belongs to\n */\n datasetName: string;\n\n /**\n * MCP tool name that was called\n */\n toolName: string;\n\n /**\n * Evaluation mode (direct or llm_host)\n * @deprecated Mode is inferred from test context, not displayed in reports\n */\n mode?: 'direct' | 'llm_host';\n\n /**\n * Source of this result\n * - 'eval': From runEvalDataset() using JSON eval datasets\n * - 'test': From direct API test tracking (MCP fixture calls)\n */\n source: ResultSource;\n\n /**\n * Overall pass/fail status\n */\n pass: boolean;\n\n /**\n * Tool response\n */\n response?: unknown;\n\n /**\n * Error if tool call failed\n */\n error?: string;\n\n /**\n * Expectation results\n */\n expectations: Partial<Record<ExpectationType, EvalExpectationResult>>;\n\n /**\n * Authentication type used for this test\n */\n authType?: AuthType;\n\n /**\n * Playwright project name this test belongs to\n * Used for filtering/grouping results by project in the reporter\n */\n project?: string;\n\n /**\n * Execution time in milliseconds\n */\n durationMs: number;\n}\n\n/**\n * Overall result of running an eval dataset\n */\nexport interface EvalRunnerResult {\n /**\n * Total number of cases\n */\n total: number;\n\n /**\n * Number of passing cases\n */\n passed: number;\n\n /**\n * Number of failing cases\n */\n failed: number;\n\n /**\n * Individual case results\n */\n caseResults: Array<EvalCaseResult>;\n\n /**\n * Overall execution time in milliseconds\n */\n durationMs: number;\n}\n\n/**\n * Options for running eval dataset\n */\nexport interface EvalRunnerOptions {\n /**\n * The dataset to run\n */\n dataset: EvalDataset;\n\n /**\n * Schema registry for schema validation by name\n *\n * Maps schema names to Zod schemas for use with expect.schema\n *\n * @example\n * ```typescript\n * {\n * schemas: {\n * WeatherResponse: z.object({ temperature: z.number() }),\n * ErrorResponse: z.object({ error: z.string() }),\n * }\n * }\n * ```\n */\n schemas?: Record<string, ZodType>;\n\n /**\n * Judge configuration registry by ID\n *\n * Maps config IDs to JudgeConfig for use with expect.passesJudge.configId\n */\n judgeConfigs?: Record<string, JudgeConfig>;\n\n /**\n * Whether to stop on first failure\n * @default false\n */\n stopOnFailure?: boolean;\n\n /**\n * Optional callback called after each case\n */\n onCaseComplete?: (result: EvalCaseResult) => void | Promise<void>;\n}\n\n/**\n * Options for running a single eval case\n */\nexport interface EvalCaseOptions {\n /**\n * Dataset name for the result (defaults to 'single-case')\n */\n datasetName?: string;\n\n /**\n * Schema registry for schema validation by name\n */\n schemas?: Record<string, ZodType>;\n\n /**\n * Judge configuration registry by ID\n */\n judgeConfigs?: Record<string, JudgeConfig>;\n}\n\nasync function executeToolCall(\n evalCase: EvalCase,\n mcp: MCPFixtureApi\n): Promise<{ response: unknown; error?: string }> {\n const mode = evalCase.mode || 'direct';\n\n try {\n if (mode === 'llm_host') {\n // LLM host simulation mode\n if (!evalCase.scenario) {\n throw new Error(\n `Eval case ${evalCase.id}: scenario is required for llm_host mode`\n );\n }\n\n if (!evalCase.llmHostConfig) {\n throw new Error(\n `Eval case ${evalCase.id}: llmHostConfig is required for llm_host mode`\n );\n }\n\n const simulationResult = await simulateLLMHost(\n mcp,\n evalCase.scenario,\n evalCase.llmHostConfig\n );\n\n if (!simulationResult.success) {\n throw new Error(simulationResult.error || 'LLM host simulation failed');\n }\n\n return { response: simulationResult };\n } else {\n // Direct mode - call tool directly\n if (!evalCase.toolName) {\n throw new Error(\n `Eval case ${evalCase.id}: toolName is required for direct mode`\n );\n }\n if (!evalCase.args) {\n throw new Error(\n `Eval case ${evalCase.id}: args is required for direct mode`\n );\n }\n\n const result = await mcp.callTool(evalCase.toolName, evalCase.args);\n\n // For error expectations, return the full result so isError can be checked\n // For other expectations, return the content (backwards compatible)\n if (evalCase.expect?.isError !== undefined) {\n return { response: result };\n }\n return { response: result.structuredContent ?? result.content };\n }\n } catch (err) {\n return {\n response: undefined,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/**\n * Determines if a case passed based on error and expectation results\n */\nfunction didCasePass(\n error: string | undefined,\n expectations: EvalCaseResult['expectations']\n): boolean {\n return (\n !error &&\n Object.values(expectations).every(\n (result) => result === undefined || result.pass\n )\n );\n}\n\n/**\n * Configuration for processing expect blocks\n */\ninterface ExpectBlockConfig {\n schemas?: Record<string, ZodType>;\n judgeConfigs?: Record<string, JudgeConfig>;\n playwrightExpect?: Expect;\n}\n\n/**\n * Processes the new unified expect block using validators\n *\n * This function translates the expect block into validation results,\n * calling the appropriate validators for each field.\n */\nasync function runExpectBlockValidations(\n expectBlock: EvalExpectBlock,\n response: unknown,\n config: ExpectBlockConfig\n): Promise<EvalCaseResult['expectations']> {\n const results: EvalCaseResult['expectations'] = {};\n\n // response (toMatchToolResponse)\n if (expectBlock.response !== undefined) {\n const validation = validateResponse(response, expectBlock.response);\n results.exact = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n\n // schema (toMatchToolSchema)\n if (expectBlock.schema !== undefined) {\n const schema = config.schemas?.[expectBlock.schema];\n if (!schema) {\n results.schema = {\n pass: false,\n details: `Schema \"${expectBlock.schema}\" not found in schemas registry`,\n };\n } else {\n const validation = validateSchema(response, schema);\n results.schema = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n }\n\n // containsText (toContainToolText)\n if (expectBlock.containsText !== undefined) {\n const validation = validateText(response, expectBlock.containsText);\n results.textContains = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n\n // matchesPattern (toMatchToolPattern)\n if (expectBlock.matchesPattern !== undefined) {\n const validation = validatePattern(response, expectBlock.matchesPattern);\n results.regex = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n\n // isError (toBeToolError)\n if (expectBlock.isError !== undefined) {\n const validation = validateError(response, expectBlock.isError);\n results.error = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n\n // responseSize (toHaveToolResponseSize)\n if (expectBlock.responseSize !== undefined) {\n const validation = validateSize(response, expectBlock.responseSize);\n results.size = {\n pass: validation.pass,\n details: validation.message,\n };\n }\n\n // passesJudge (toPassToolJudge)\n if (expectBlock.passesJudge !== undefined) {\n const {\n rubric,\n reference,\n threshold = 0.7,\n configId,\n } = expectBlock.passesJudge;\n\n // Get judge config\n const judgeConfig = configId ? (config.judgeConfigs?.[configId] ?? {}) : {};\n\n try {\n const judge = createJudge(judgeConfig);\n const judgeResult = await judge.evaluate(\n response,\n reference ?? null,\n rubric\n );\n const score = judgeResult.score ?? (judgeResult.pass ? 1.0 : 0.0);\n const passed = score >= threshold;\n\n results.judge = {\n pass: passed,\n details: passed\n ? `Judge passed with score ${score.toFixed(2)}`\n : `Judge failed with score ${score.toFixed(2)} (threshold: ${threshold}). ${judgeResult.reasoning ?? ''}`,\n };\n } catch (err) {\n results.judge = {\n pass: false,\n details: `Judge evaluation error: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n }\n\n // snapshot (toMatchToolSnapshot) - requires Playwright expect with custom matcher\n if (expectBlock.snapshot !== undefined) {\n if (!config.playwrightExpect) {\n results.snapshot = {\n pass: false,\n details: 'Snapshot testing requires expect in context',\n };\n } else {\n try {\n // Use custom toMatchToolSnapshot matcher which:\n // 1. Extracts text from the response\n // 2. Applies sanitizers\n // 3. Uses Playwright's native snapshot testing\n const sanitizers = expectBlock.snapshotSanitizers ?? [];\n // eslint-disable-next-line @typescript-eslint/await-thenable, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n await (config.playwrightExpect(response) as any).toMatchToolSnapshot(\n expectBlock.snapshot,\n sanitizers\n );\n results.snapshot = {\n pass: true,\n details: `Matches snapshot \"${expectBlock.snapshot}\"`,\n };\n } catch (err) {\n results.snapshot = {\n pass: false,\n details: err instanceof Error ? err.message : String(err),\n };\n }\n }\n }\n\n return results;\n}\n\n/**\n * Runs a single eval case and returns the result\n *\n * @param evalCase - The eval case to run\n * @param context - Context containing mcp, testInfo, expect\n * @param options - Optional configuration (datasetName, schemas, judgeConfigs)\n * @returns The result of running the eval case\n *\n * @example\n * ```typescript\n * const result = await runEvalCase(\n * evalCase,\n * { mcp, testInfo, expect },\n * { schemas: { WeatherResponse: WeatherSchema } }\n * );\n *\n * expect(result.pass).toBe(true);\n * ```\n */\nexport async function runEvalCase(\n evalCase: EvalCase,\n context: EvalContext,\n options: EvalCaseOptions = {}\n): Promise<EvalCaseResult> {\n const startTime = Date.now();\n const mode = evalCase.mode || 'direct';\n\n // Execute tool call\n const { response, error } = await executeToolCall(evalCase, context.mcp);\n\n // Collect expectation results from expect block\n let expectationResults: EvalCaseResult['expectations'] = {};\n\n if (!error && evalCase.expect) {\n expectationResults = await runExpectBlockValidations(\n evalCase.expect,\n response,\n {\n schemas: options.schemas,\n judgeConfigs: options.judgeConfigs,\n playwrightExpect: context.expect,\n }\n );\n }\n\n // Build result - use test context for authType and project (Playwright is source of truth)\n return {\n id: evalCase.id,\n datasetName: options.datasetName ?? 'single-case',\n toolName: evalCase.toolName ?? evalCase.scenario ?? 'unknown',\n mode,\n source: 'eval',\n pass: didCasePass(error, expectationResults),\n response,\n error,\n expectations: expectationResults,\n authType: context.mcp.authType,\n project: context.mcp.project,\n durationMs: Date.now() - startTime,\n };\n}\n\n/**\n * Runs an eval dataset against an MCP server\n *\n * This function composes runEvalCase() for each case in the dataset,\n * adding dataset-level features like stopOnFailure and callbacks.\n *\n * @param options - Eval runner options (dataset, schemas, judgeConfigs)\n * @param context - Eval context (mcp fixture, optional testInfo, optional expect)\n * @returns Eval results\n *\n * @example\n * // Basic usage\n * const result = await runEvalDataset(\n * {\n * dataset,\n * schemas: { WeatherResponse: WeatherSchema },\n * },\n * { mcp }\n * );\n *\n * @example\n * // With MCP reporter integration\n * test('eval dataset', async ({ mcp }, testInfo) => {\n * const result = await runEvalDataset(\n * { dataset },\n * { mcp, testInfo } // testInfo enables MCP reporter\n * );\n * });\n */\nexport async function runEvalDataset(\n options: EvalRunnerOptions,\n context: EvalContext\n): Promise<EvalRunnerResult> {\n const {\n dataset,\n schemas,\n judgeConfigs,\n stopOnFailure = false,\n onCaseComplete,\n } = options;\n\n const startTime = Date.now();\n const caseResults: EvalCaseResult[] = [];\n\n // Context is used as-is (judge is handled via judgeConfigs in expect block)\n const enrichedContext = context;\n\n // Merge schemas from dataset and options\n const allSchemas = {\n ...dataset.schemas,\n ...schemas,\n };\n\n // Run each case\n for (const evalCase of dataset.cases) {\n const result = await runEvalCase(evalCase, enrichedContext, {\n datasetName: dataset.name,\n schemas: allSchemas,\n judgeConfigs,\n });\n\n caseResults.push(result);\n\n // Call onCaseComplete callback\n if (onCaseComplete) {\n await onCaseComplete(result);\n }\n\n // Stop on failure if requested\n if (stopOnFailure && !result.pass) {\n break;\n }\n }\n\n const total = caseResults.length;\n const passed = caseResults.filter((r) => r.pass).length;\n\n const result: EvalRunnerResult = {\n total,\n passed,\n failed: total - passed,\n caseResults,\n durationMs: Date.now() - startTime,\n };\n\n // Attach results for MCP reporter if testInfo is provided\n if (context.testInfo) {\n await context.testInfo.attach('mcp-test-results', {\n contentType: 'application/json',\n body: Buffer.from(JSON.stringify({ caseResults })),\n });\n }\n\n return result;\n}\n","/**\n * Tool call validator for LLM host mode\n *\n * Validates that the LLM made the expected tool calls with correct arguments\n */\n\nimport type { EvalExpectationResult } from '../../types/index.js';\nimport type { EvalCase } from '../datasetTypes.js';\nimport type { ExpectedToolCall, LLMToolCall } from './llmHostTypes.js';\n\n/**\n * Tool call validation function signature\n */\nexport type ToolCallValidator = (\n evalCase: EvalCase,\n response: unknown\n) => Promise<EvalExpectationResult>;\n\n/**\n * Checks if two argument objects match (partial match)\n *\n * @param actual - Actual arguments from LLM\n * @param expected - Expected arguments (can be partial)\n * @returns true if all expected keys match actual values\n */\nfunction argumentsMatch(\n actual: Record<string, unknown>,\n expected: Record<string, unknown>\n): boolean {\n for (const key of Object.keys(expected)) {\n if (!(key in actual)) {\n return false;\n }\n\n const actualValue = actual[key];\n const expectedValue = expected[key];\n\n // Deep equality check\n if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Finds matching tool call in actual calls\n *\n * @param expected - Expected tool call\n * @param actualCalls - Actual tool calls made by LLM\n * @returns Matching tool call or null\n */\nfunction findMatchingCall(\n expected: ExpectedToolCall,\n actualCalls: Array<LLMToolCall>\n): LLMToolCall | null {\n for (const actualCall of actualCalls) {\n if (actualCall.name !== expected.name) {\n continue;\n }\n\n if (!expected.arguments) {\n // Name match is sufficient\n return actualCall;\n }\n\n if (argumentsMatch(actualCall.arguments, expected.arguments)) {\n return actualCall;\n }\n }\n\n return null;\n}\n\n/**\n * Creates a tool call validator for LLM host mode\n *\n * Validates that the LLM made the expected tool calls with correct arguments.\n * Supports partial argument matching and optional calls.\n *\n * @returns Validator function\n *\n * @example\n * ```typescript\n * // In your eval case:\n * {\n * \"id\": \"weather-london\",\n * \"mode\": \"llm_host\",\n * \"scenario\": \"Get the weather for London\",\n * \"expectedToolCalls\": [\n * {\n * \"name\": \"get_weather\",\n * \"arguments\": { \"city\": \"London\" },\n * \"required\": true\n * }\n * ]\n * }\n * ```\n */\nexport function createToolCallValidator(): ToolCallValidator {\n return async (evalCase: EvalCase, response: unknown) => {\n // Extract expected tool calls from eval case metadata\n const expectedCalls = evalCase.metadata?.expectedToolCalls as\n | Array<ExpectedToolCall>\n | undefined;\n\n if (!expectedCalls || expectedCalls.length === 0) {\n return {\n pass: true,\n details: 'No expected tool calls specified',\n };\n }\n\n // Extract actual tool calls from response\n const responseObj = response as { toolCalls?: Array<LLMToolCall> } | null;\n const actualCalls = responseObj?.toolCalls;\n\n if (!actualCalls || actualCalls.length === 0) {\n const requiredCalls = expectedCalls.filter(\n (call) => call.required !== false\n );\n if (requiredCalls.length > 0) {\n return {\n pass: false,\n details: `Expected ${requiredCalls.length} tool call(s), but LLM made no tool calls`,\n };\n }\n return {\n pass: true,\n details: 'No tool calls expected or made',\n };\n }\n\n // Validate each expected call\n const missingCalls: Array<ExpectedToolCall> = [];\n const foundCalls: Array<{\n expected: ExpectedToolCall;\n actual: LLMToolCall;\n }> = [];\n\n for (const expectedCall of expectedCalls) {\n const matchingCall = findMatchingCall(expectedCall, actualCalls);\n\n if (!matchingCall) {\n if (expectedCall.required !== false) {\n missingCalls.push(expectedCall);\n }\n } else {\n foundCalls.push({\n expected: expectedCall,\n actual: matchingCall,\n });\n }\n }\n\n if (missingCalls.length > 0) {\n const missingDetails = missingCalls\n .map((call) => `${call.name}(${JSON.stringify(call.arguments || {})})`)\n .join(', ');\n\n return {\n pass: false,\n details: `Missing required tool call(s): ${missingDetails}. Actual calls: ${actualCalls.map((c) => c.name).join(', ')}`,\n };\n }\n\n return {\n pass: true,\n details: `All ${expectedCalls.length} expected tool call(s) were made correctly`,\n };\n };\n}\n","import type { MCPFixtureApi } from '../mcp/fixtures/mcpFixture.js';\nimport type { TestInfo } from '@playwright/test';\nimport type {\n Tool,\n Resource,\n Prompt,\n ServerCapabilities,\n Implementation,\n} from '@modelcontextprotocol/sdk/types.js';\n\n/**\n * Options for conformance checks\n */\nexport interface MCPConformanceOptions {\n /**\n * List of tools that must be present\n */\n requiredTools?: Array<string>;\n\n /**\n * Whether to validate tool schemas\n * @default true\n */\n validateSchemas?: boolean;\n\n /**\n * Whether to check server info is present\n * @default true\n */\n checkServerInfo?: boolean;\n\n /**\n * Whether to check resources capability (if declared by server)\n * @default true\n */\n checkResources?: boolean;\n\n /**\n * Whether to check prompts capability (if declared by server)\n * @default true\n */\n checkPrompts?: boolean;\n}\n\n/**\n * Individual check result\n */\nexport interface MCPConformanceCheck {\n name: string;\n pass: boolean;\n message: string;\n}\n\n/**\n * Raw MCP responses for snapshotting\n */\nexport interface MCPConformanceRaw {\n /**\n * Server info (name, version)\n * null if not available\n */\n serverInfo: Implementation | null;\n\n /**\n * Server capabilities\n * null if not available\n */\n capabilities: ServerCapabilities | null;\n\n /**\n * List of tools from the server\n */\n tools: Tool[];\n\n /**\n * List of resources from the server\n * null if server doesn't declare resources capability\n */\n resources: Resource[] | null;\n\n /**\n * List of prompts from the server\n * null if server doesn't declare prompts capability\n */\n prompts: Prompt[] | null;\n}\n\n/**\n * Result of conformance checks\n */\nexport interface MCPConformanceResult {\n /**\n * Whether all checks passed\n */\n pass: boolean;\n\n /**\n * List of check results\n */\n checks: MCPConformanceCheck[];\n\n /**\n * Raw MCP responses for snapshotting\n *\n * @example\n * ```typescript\n * const result = await runConformanceChecks(mcp);\n * expect(result.raw.tools).toMatchSnapshot();\n * expect(result.raw.capabilities).toMatchSnapshot();\n * ```\n */\n raw: MCPConformanceRaw;\n}\n\n/**\n * Runs MCP protocol conformance checks\n *\n * Validates that the MCP server conforms to expected protocol behavior.\n * Returns both assertion results and raw MCP responses for snapshotting.\n *\n * When testInfo is provided, results are automatically attached for the MCP reporter.\n *\n * @param mcp - MCP fixture API\n * @param options - Conformance check options\n * @param testInfo - Optional Playwright TestInfo for reporter integration\n * @returns Conformance check results with raw responses\n *\n * @example\n * ```typescript\n * // Basic usage\n * const result = await runConformanceChecks(mcp, {\n * requiredTools: ['get_weather', 'search_docs'],\n * validateSchemas: true,\n * });\n *\n * // Check assertions\n * expect(result.pass).toBe(true);\n *\n * // With reporter integration (recommended in Playwright tests)\n * const result = await runConformanceChecks(mcp, {\n * requiredTools: ['search'],\n * }, testInfo);\n *\n * // Snapshot raw responses\n * expect(result.raw.tools).toMatchSnapshot();\n * expect(result.raw.capabilities).toMatchSnapshot();\n * ```\n */\nexport async function runConformanceChecks(\n mcp: MCPFixtureApi,\n options: MCPConformanceOptions = {},\n testInfo?: TestInfo\n): Promise<MCPConformanceResult> {\n const {\n requiredTools = [],\n validateSchemas = true,\n checkServerInfo = true,\n checkResources = true,\n checkPrompts = true,\n } = options;\n\n const checks: MCPConformanceCheck[] = [];\n const raw: MCPConformanceRaw = {\n serverInfo: null,\n capabilities: null,\n tools: [],\n resources: null,\n prompts: null,\n };\n\n // Get server info\n const serverInfo = mcp.getServerInfo();\n if (serverInfo) {\n raw.serverInfo = serverInfo as Implementation;\n }\n\n // Check 1: Server info is present\n if (checkServerInfo) {\n checks.push({\n name: 'server_info_present',\n pass: serverInfo !== null,\n message: serverInfo\n ? `Server info: ${serverInfo.name ?? 'unknown'} v${serverInfo.version ?? 'unknown'}`\n : 'Server info is missing',\n });\n }\n\n // Get capabilities from client\n const capabilities = mcp.client.getServerCapabilities();\n if (capabilities) {\n raw.capabilities = capabilities;\n }\n\n // Check 2: Capabilities are valid\n checks.push({\n name: 'capabilities_valid',\n pass: capabilities !== undefined,\n message: capabilities\n ? `Server capabilities: ${formatCapabilities(capabilities)}`\n : 'Server capabilities not available',\n });\n\n // Check 3: List tools returns valid response\n let tools: Tool[] = [];\n try {\n tools = await mcp.listTools();\n raw.tools = tools;\n checks.push({\n name: 'list_tools_succeeds',\n pass: true,\n message: `listTools returned ${tools.length} tools`,\n });\n } catch (error) {\n checks.push({\n name: 'list_tools_succeeds',\n pass: false,\n message: `listTools failed: ${error instanceof Error ? error.message : String(error)}`,\n });\n const pass = checks.every((check) => check.pass);\n return { pass, checks, raw };\n }\n\n // Check 4: Required tools are present\n if (requiredTools.length > 0) {\n const toolNames = new Set(tools.map((t) => t.name));\n const missingTools = requiredTools.filter((name) => !toolNames.has(name));\n\n checks.push({\n name: 'required_tools_present',\n pass: missingTools.length === 0,\n message:\n missingTools.length === 0\n ? `All ${requiredTools.length} required tools are present`\n : `Missing required tools: ${missingTools.join(', ')}`,\n });\n }\n\n // Check 5: Tool schemas are valid\n if (validateSchemas && tools.length > 0) {\n const invalidTools: Array<string> = [];\n\n for (const tool of tools) {\n // Check that tool has required fields\n if (!tool.name) {\n invalidTools.push(`(unnamed tool): missing name`);\n continue;\n }\n\n if (!tool.inputSchema) {\n invalidTools.push(`${tool.name}: missing inputSchema`);\n continue;\n }\n\n // Check that inputSchema is an object schema\n if (tool.inputSchema.type !== 'object') {\n invalidTools.push(\n `${tool.name}: inputSchema.type must be \"object\", got \"${String(tool.inputSchema.type)}\"`\n );\n }\n }\n\n checks.push({\n name: 'tool_schemas_valid',\n pass: invalidTools.length === 0,\n message:\n invalidTools.length === 0\n ? `All ${tools.length} tools have valid schemas`\n : `Invalid tool schemas:\\n ${invalidTools.join('\\n ')}`,\n });\n }\n\n // Check 6: List resources (only if server declares resources capability)\n if (checkResources && capabilities?.resources) {\n try {\n const resourcesResult = await mcp.client.listResources();\n raw.resources = resourcesResult.resources;\n checks.push({\n name: 'list_resources_succeeds',\n pass: true,\n message: `listResources returned ${resourcesResult.resources.length} resources`,\n });\n } catch (error) {\n checks.push({\n name: 'list_resources_succeeds',\n pass: false,\n message: `listResources failed: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n }\n\n // Check 7: List prompts (only if server declares prompts capability)\n if (checkPrompts && capabilities?.prompts) {\n try {\n const promptsResult = await mcp.client.listPrompts();\n raw.prompts = promptsResult.prompts;\n checks.push({\n name: 'list_prompts_succeeds',\n pass: true,\n message: `listPrompts returned ${promptsResult.prompts.length} prompts`,\n });\n } catch (error) {\n checks.push({\n name: 'list_prompts_succeeds',\n pass: false,\n message: `listPrompts failed: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n }\n\n // Check 8: Calling invalid tool returns error\n try {\n const result = await mcp.callTool('__nonexistent_tool__', {});\n // MCP SDK may return isError: true instead of throwing\n const hasError = result.isError === true;\n checks.push({\n name: 'invalid_tool_returns_error',\n pass: hasError,\n message: hasError\n ? 'Nonexistent tool correctly returned an error'\n : 'Calling nonexistent tool should have returned an error',\n });\n } catch {\n // Or it may throw - both are acceptable\n checks.push({\n name: 'invalid_tool_returns_error',\n pass: true,\n message: 'Nonexistent tool correctly threw an error',\n });\n }\n\n const pass = checks.every((check) => check.pass);\n\n const result: MCPConformanceResult = { pass, checks, raw };\n\n // Attach results for MCP reporter if testInfo is provided\n if (testInfo) {\n await testInfo.attach('mcp-conformance-checks', {\n contentType: 'application/json',\n body: JSON.stringify(\n {\n operation: 'conformanceChecks',\n pass,\n checks,\n serverInfo: raw.serverInfo,\n capabilities: raw.capabilities,\n toolCount: raw.tools.length,\n authType: mcp.authType,\n project: mcp.project,\n },\n null,\n 2\n ),\n });\n }\n\n return result;\n}\n\n/**\n * Formats server capabilities for display\n */\nfunction formatCapabilities(capabilities: ServerCapabilities): string {\n const parts: string[] = [];\n if (capabilities.tools) parts.push('tools');\n if (capabilities.resources) parts.push('resources');\n if (capabilities.prompts) parts.push('prompts');\n if (capabilities.logging) parts.push('logging');\n if (capabilities.completions) parts.push('completions');\n if (capabilities.experimental) parts.push('experimental');\n return parts.length > 0 ? parts.join(', ') : 'none declared';\n}\n"]}
|