@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/mcp/response.ts","../../src/assertions/validators/utils.ts","../../src/assertions/validators/response.ts","../../src/assertions/matchers/toMatchToolResponse.ts","../../src/assertions/validators/schema.ts","../../src/assertions/matchers/toMatchToolSchema.ts","../../src/assertions/validators/text.ts","../../src/assertions/matchers/toContainToolText.ts","../../src/assertions/validators/pattern.ts","../../src/assertions/matchers/toMatchToolPattern.ts","../../src/assertions/matchers/toMatchToolSnapshot.ts","../../src/assertions/validators/error.ts","../../src/assertions/matchers/toBeToolError.ts","../../src/judge/claudeAgentJudge.ts","../../src/judge/judgeClient.ts","../../src/assertions/matchers/toPassToolJudge.ts","../../src/assertions/validators/size.ts","../../src/assertions/matchers/toHaveToolResponseSize.ts","../../src/assertions/matchers/toSatisfyToolPredicate.ts","../../src/assertions/matchers/index.ts","../../src/config/mcpConfig.ts","../../src/debug.ts","../../src/mcp/clientFactory.ts","../../src/mcp/fixtures/mcpFixture.ts","../../src/auth/oauthClientProvider.ts","../../src/auth/oauthFlow.ts","../../src/auth/discovery.ts","../../src/auth/storage.ts","../../src/auth/cli.ts","../../src/fixtures/mcp.ts"],"names":["extractText","path","truncateForDisplay","baseExpect","fs","oauth2","createDebug","base"],"mappings":"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","file":"mcp.js","sourcesContent":["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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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","/**\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 { 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 * 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","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 { 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 * 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","/**\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 * 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 * 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 { 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"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as playwright_test from 'playwright/test';
|
|
2
|
+
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
3
|
+
export { expect } from '@playwright/test';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test-scoped auth fixtures interface
|
|
7
|
+
*/
|
|
8
|
+
interface MCPAuthFixtures {
|
|
9
|
+
/**
|
|
10
|
+
* OAuth client provider for MCP authentication
|
|
11
|
+
*/
|
|
12
|
+
mcpAuthProvider: OAuthClientProvider | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extended Playwright test with MCP auth fixtures
|
|
16
|
+
*
|
|
17
|
+
* Use this when you need OAuth authentication for MCP server testing.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // test.ts
|
|
22
|
+
* import { test } from '@gleanwork/mcp-server-tester/fixtures/mcpAuth';
|
|
23
|
+
*
|
|
24
|
+
* test('authenticated MCP call', async ({ mcpAuthProvider }) => {
|
|
25
|
+
* // mcpAuthProvider can be passed to createMCPClientForConfig
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare const test: playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & MCPAuthFixtures, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
|
|
30
|
+
|
|
31
|
+
export { type MCPAuthFixtures, test };
|