@gleanwork/mcp-server-tester 1.0.1 → 1.1.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.
@@ -0,0 +1,4282 @@
1
+ import { ZodType, z } from 'zod';
2
+ import { Page, TestInfo, Expect } from '@playwright/test';
3
+ import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
4
+ import { OAuthClientMetadata, OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
5
+ import * as oauth from 'oauth4webapi';
6
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
7
+ import { Tool, CallToolResult, Implementation, ServerCapabilities, Resource, Prompt } from '@modelcontextprotocol/sdk/types.js';
8
+ import * as playwright_test from 'playwright/test';
9
+
10
+ /**
11
+ * Validator Types
12
+ *
13
+ * Core types for the unified assertion architecture.
14
+ * These types are used by both Playwright matchers and the eval runner.
15
+ */
16
+
17
+ /**
18
+ * Result of a validation operation
19
+ */
20
+ interface ValidationResult {
21
+ /** Whether the validation passed */
22
+ pass: boolean;
23
+ /** Human-readable message explaining the result */
24
+ message: string;
25
+ /** Additional structured details about the validation */
26
+ details?: Record<string, unknown>;
27
+ /**
28
+ * Optional quantitative metrics from the validation.
29
+ * Populated by validateToolCalls for precision/recall.
30
+ */
31
+ metrics?: {
32
+ precision?: number;
33
+ recall?: number;
34
+ };
35
+ }
36
+ /**
37
+ * Options for text validation
38
+ */
39
+ interface TextValidatorOptions {
40
+ /** Whether to perform case-sensitive matching (default: true) */
41
+ caseSensitive?: boolean;
42
+ }
43
+ /**
44
+ * Options for response size validation
45
+ */
46
+ interface SizeValidatorOptions {
47
+ /** Maximum allowed size in bytes */
48
+ maxBytes?: number;
49
+ /** Minimum required size in bytes */
50
+ minBytes?: number;
51
+ }
52
+ /**
53
+ * Options for schema validation
54
+ */
55
+ interface SchemaValidatorOptions {
56
+ /** Whether to use strict mode (fail on extra properties) */
57
+ strict?: boolean;
58
+ }
59
+ /**
60
+ * Options for pattern validation
61
+ */
62
+ interface PatternValidatorOptions {
63
+ /** Whether to perform case-sensitive matching (default: true) */
64
+ caseSensitive?: boolean;
65
+ }
66
+ /**
67
+ * Built-in snapshot sanitizer names for use with toMatchToolSnapshot.
68
+ * Pass these values in the sanitizers array to replace non-deterministic
69
+ * values with stable placeholders before snapshot comparison.
70
+ *
71
+ * @example
72
+ * expect(result).toMatchToolSnapshot('my-snapshot', [
73
+ * SnapshotSanitizers.UUID,
74
+ * SnapshotSanitizers.ISO_DATE,
75
+ * ]);
76
+ */
77
+ declare const SnapshotSanitizers: {
78
+ /** Replaces Unix timestamps (seconds and milliseconds) with a stable placeholder */
79
+ readonly TIMESTAMP: "timestamp";
80
+ /** Replaces UUID v1-v5 strings with a stable placeholder */
81
+ readonly UUID: "uuid";
82
+ /** Replaces ISO 8601 date/datetime strings with a stable placeholder */
83
+ readonly ISO_DATE: "iso-date";
84
+ /** Replaces MongoDB ObjectId strings with a stable placeholder */
85
+ readonly OBJECT_ID: "objectId";
86
+ /** Replaces JWT tokens with a stable placeholder */
87
+ readonly JWT: "jwt";
88
+ };
89
+ /**
90
+ * Built-in sanitizer names for common variable patterns
91
+ */
92
+ type BuiltInSanitizer = (typeof SnapshotSanitizers)[keyof typeof SnapshotSanitizers];
93
+ /**
94
+ * Custom regex-based sanitizer
95
+ */
96
+ interface RegexSanitizer {
97
+ /** Regex pattern to match */
98
+ pattern: string | RegExp;
99
+ /** Replacement string (default: "[SANITIZED]") */
100
+ replacement?: string;
101
+ }
102
+ /**
103
+ * Field removal sanitizer - removes specified fields from objects
104
+ */
105
+ interface FieldRemovalSanitizer {
106
+ /** Field paths to remove (supports dot notation for nested fields) */
107
+ remove: string[];
108
+ }
109
+ /**
110
+ * Snapshot sanitizer configuration
111
+ *
112
+ * Sanitizers transform response data before snapshot comparison,
113
+ * allowing variable content (timestamps, IDs, etc.) to be normalized.
114
+ *
115
+ * Can be:
116
+ * - A built-in sanitizer name: 'timestamp', 'uuid', 'iso-date', 'objectId', 'jwt'
117
+ * - A regex sanitizer: { pattern: /regex/, replacement: '[REPLACED]' }
118
+ * - A field removal sanitizer: { remove: ['field1', 'nested.field'] }
119
+ */
120
+ type SnapshotSanitizer = BuiltInSanitizer | RegexSanitizer | FieldRemovalSanitizer;
121
+ /**
122
+ * Schema registry for named schemas in datasets
123
+ */
124
+ type SchemaRegistry = Record<string, ZodType>;
125
+
126
+ /**
127
+ * Tool call validators for mcp_host simulation results.
128
+ *
129
+ * These validators extract the tool call trace from an MCPHostSimulationResult
130
+ * and apply assertions against expected call lists and counts.
131
+ */
132
+
133
+ interface ToolCallExpectation {
134
+ calls: Array<{
135
+ name: string;
136
+ arguments?: Record<string, unknown>;
137
+ required?: boolean;
138
+ }>;
139
+ order?: 'strict' | 'any';
140
+ exclusive?: boolean;
141
+ }
142
+ interface ToolCallCountOptions {
143
+ min?: number;
144
+ max?: number;
145
+ exact?: number;
146
+ }
147
+ /**
148
+ * Validates tool calls made during an MCP host simulation.
149
+ *
150
+ * @param response - Must be an MCPHostSimulationResult (from mcp_host mode)
151
+ * @param expectation - Expected tool call specification
152
+ */
153
+ declare function validateToolCalls(response: unknown, expectation: ToolCallExpectation): ValidationResult;
154
+ /**
155
+ * Validates the number of tool calls made during an MCP host simulation.
156
+ *
157
+ * @param response - Must be an MCPHostSimulationResult (from mcp_host mode)
158
+ * @param options - Count constraints (min, max, exact)
159
+ */
160
+ declare function validateToolCallCount(response: unknown, options: ToolCallCountOptions): ValidationResult;
161
+
162
+ /**
163
+ * Built-in judge rubrics matching Glean EvalV2's named judge types.
164
+ * Use these for consistent, standardized evaluations across teams.
165
+ *
166
+ * All built-in rubrics use a 5-point scale: 0.0 / 0.25 / 0.5 / 0.75 / 1.0
167
+ */
168
+ type BuiltInRubric = 'correctness' | 'completeness' | 'groundedness' | 'instruction-following' | 'conciseness';
169
+ declare const BUILT_IN_RUBRICS: Record<BuiltInRubric, string>;
170
+ /** A rubric specification: either a built-in named rubric or custom text. */
171
+ type RubricSpec = BuiltInRubric | {
172
+ text: string;
173
+ };
174
+ /**
175
+ * Returns true if `s` is a built-in rubric name.
176
+ */
177
+ declare function isBuiltInRubric(s: unknown): s is BuiltInRubric;
178
+ /**
179
+ * Resolves a RubricSpec to its full rubric text.
180
+ * - Built-in name → returns the expanded rubric text from BUILT_IN_RUBRICS
181
+ * - Custom object → returns rubric.text as-is
182
+ */
183
+ declare function resolveRubric(rubric: RubricSpec): string;
184
+
185
+ /**
186
+ * Usage metrics from Claude Agent SDK response
187
+ */
188
+ interface UsageMetrics {
189
+ /**
190
+ * Number of input tokens consumed
191
+ */
192
+ inputTokens: number;
193
+ /**
194
+ * Number of output tokens generated
195
+ */
196
+ outputTokens: number;
197
+ /**
198
+ * Total cost in USD
199
+ */
200
+ totalCostUsd: number;
201
+ /**
202
+ * Execution duration in milliseconds
203
+ */
204
+ durationMs: number;
205
+ /**
206
+ * API call duration in milliseconds (excluding network overhead)
207
+ */
208
+ durationApiMs?: number;
209
+ /**
210
+ * Number of tokens read from cache
211
+ */
212
+ cacheReadInputTokens?: number;
213
+ /**
214
+ * Number of tokens written to cache
215
+ */
216
+ cacheCreationInputTokens?: number;
217
+ }
218
+ /** Valid LLM judge provider kinds. */
219
+ type ProviderKind = 'anthropic' | 'vertex-anthropic' | 'anthropic-agent-sdk' | 'openai' | 'google';
220
+ /**
221
+ * Configuration for an LLM judge
222
+ */
223
+ interface JudgeConfig {
224
+ /**
225
+ * LLM provider to use
226
+ * @default 'anthropic'
227
+ */
228
+ provider?: ProviderKind;
229
+ /**
230
+ * Environment variable name containing the API key
231
+ * @default 'ANTHROPIC_API_KEY'
232
+ */
233
+ apiKeyEnvVar?: string;
234
+ /**
235
+ * Model to use for judging
236
+ * @default 'claude-sonnet-4-20250514'
237
+ */
238
+ model?: string;
239
+ /**
240
+ * Maximum tokens for response
241
+ * @default 1000
242
+ */
243
+ maxTokens?: number;
244
+ /**
245
+ * Temperature (0-1, lower is more deterministic)
246
+ * @default 0.0
247
+ */
248
+ temperature?: number;
249
+ /**
250
+ * Maximum budget in USD for the judge evaluation
251
+ * @default 0.10
252
+ */
253
+ maxBudgetUsd?: number;
254
+ /**
255
+ * Maximum size (in bytes) for tool output before failing the test
256
+ * When set, the judge will fail if the candidate response exceeds this size
257
+ */
258
+ maxToolOutputSize?: number;
259
+ }
260
+ /**
261
+ * Result from LLM judge evaluation
262
+ */
263
+ interface JudgeResult {
264
+ /**
265
+ * Whether the evaluation passed
266
+ */
267
+ pass: boolean;
268
+ /**
269
+ * Numeric score (0-1, where 1 is best)
270
+ */
271
+ score?: number;
272
+ /**
273
+ * Reasoning/explanation from the judge
274
+ */
275
+ reasoning?: string;
276
+ /**
277
+ * Usage metrics from the Claude Agent SDK
278
+ */
279
+ usage?: UsageMetrics;
280
+ /**
281
+ * Size of the candidate response in bytes (for maxToolOutputSize tracking)
282
+ */
283
+ candidateSizeBytes?: number;
284
+ /**
285
+ * Whether the candidate exceeded maxToolOutputSize
286
+ */
287
+ exceedsMaxToolOutputSize?: boolean;
288
+ /**
289
+ * Standard deviation of individual rep scores.
290
+ * Only populated when the judge was run with reps > 1.
291
+ */
292
+ scoreStdDev?: number;
293
+ /**
294
+ * True when the standard deviation across reps exceeds 0.2, indicating
295
+ * that the rubric may be ambiguous or the judge is non-deterministic.
296
+ * Only populated when the judge was run with reps > 1.
297
+ */
298
+ highVariance?: boolean;
299
+ /**
300
+ * Individual scores from each judge rep.
301
+ * Only populated when the judge was run with reps > 1.
302
+ */
303
+ scores?: number[];
304
+ }
305
+
306
+ /**
307
+ * LLM judge client interface
308
+ */
309
+ interface Judge {
310
+ /**
311
+ * Evaluates a candidate response against a reference
312
+ *
313
+ * @param candidate - The actual response to evaluate
314
+ * @param reference - The expected/reference response (or null if not applicable)
315
+ * @param rubric - The evaluation rubric/criteria
316
+ * @returns Evaluation result with usage metrics
317
+ */
318
+ evaluate(candidate: unknown, reference: unknown, rubric: string): Promise<JudgeResult>;
319
+ }
320
+
321
+ /**
322
+ * Judge Validator
323
+ *
324
+ * Validates a response using an LLM-as-a-judge evaluation.
325
+ */
326
+
327
+ /**
328
+ * Configuration for the judge validator
329
+ */
330
+ interface JudgeValidatorConfig {
331
+ /**
332
+ * The evaluation rubric: a built-in name or custom { text: string }.
333
+ * Required when no named `judge` is specified.
334
+ */
335
+ rubric?: RubricSpec;
336
+ /** Optional reference response to compare against */
337
+ reference?: unknown;
338
+ /** Minimum score required to pass (0-1, default: 0.7) */
339
+ threshold?: number;
340
+ /** Number of judge evaluations to run. Scores averaged. @default 1 */
341
+ reps?: number;
342
+ /** Judge provider. @default 'claude' */
343
+ provider?: ProviderKind;
344
+ /** Model override (e.g., 'claude-opus-4-20250514') */
345
+ model?: string;
346
+ /** Environment variable name for API key */
347
+ apiKeyEnvVar?: string;
348
+ /** Max tokens for judge response */
349
+ maxTokens?: number;
350
+ /** Temperature for judge LLM (0–1) */
351
+ temperature?: number;
352
+ /** Max budget in USD per evaluation */
353
+ maxBudgetUsd?: number;
354
+ /** Fail if response exceeds this size in bytes before judging */
355
+ maxToolOutputSize?: number;
356
+ /**
357
+ * Name of a registered custom judge executor.
358
+ * When set, the named judge handles the entire evaluation pipeline
359
+ * and returns a normalized score. The `threshold` determines pass/fail.
360
+ * Register judges with `registerJudge()` before tests run.
361
+ */
362
+ judge?: string;
363
+ }
364
+ declare function validateJudge(response: unknown, config: JudgeValidatorConfig): Promise<ValidationResult>;
365
+
366
+ /**
367
+ * Matcher Types
368
+ *
369
+ * TypeScript declarations for custom Playwright matchers.
370
+ */
371
+
372
+ /**
373
+ * Options for the LLM judge matcher
374
+ */
375
+ interface JudgeMatcherOptions {
376
+ /** Reference response to compare against */
377
+ reference?: unknown;
378
+ /** Score threshold for passing (default: 0.7) */
379
+ passingThreshold?: number;
380
+ /** Number of judge evaluations (scores averaged) */
381
+ reps?: number;
382
+ /** Override the judge provider */
383
+ provider?: ProviderKind;
384
+ /** Override the judge model */
385
+ model?: string;
386
+ /**
387
+ * Name of a registered custom judge executor.
388
+ * When set, the named judge handles the entire evaluation pipeline
389
+ * and its `pass` result is authoritative.
390
+ */
391
+ judge?: string;
392
+ }
393
+ /**
394
+ * Declaration merging for Playwright matchers
395
+ */
396
+ declare global {
397
+ namespace PlaywrightTest {
398
+ interface Matchers<R, T = unknown> {
399
+ /**
400
+ * Validates that a response exactly matches the expected value
401
+ *
402
+ * @param expected - The expected response value
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * expect(result).toMatchToolResponse({ status: 'ok', count: 42 });
407
+ * ```
408
+ */
409
+ toMatchToolResponse(expected: unknown): R;
410
+ /**
411
+ * Validates that a response matches a Zod schema
412
+ *
413
+ * @param schema - The Zod schema to validate against
414
+ * @param options - Validation options
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * const WeatherSchema = z.object({
419
+ * temperature: z.number(),
420
+ * conditions: z.string(),
421
+ * });
422
+ * expect(result).toMatchToolSchema(WeatherSchema);
423
+ * ```
424
+ */
425
+ toMatchToolSchema(schema: ZodType, options?: SchemaValidatorOptions): R;
426
+ /**
427
+ * Validates that a response contains expected text substrings
428
+ *
429
+ * @param expected - Expected substring(s) to find
430
+ * @param options - Validation options
431
+ *
432
+ * @example
433
+ * ```typescript
434
+ * expect(result).toContainToolText('temperature');
435
+ * expect(result).toContainToolText(['temperature', 'conditions']);
436
+ * expect(result).toContainToolText('HELLO', { caseSensitive: false });
437
+ * ```
438
+ */
439
+ toContainToolText(expected: string | string[], options?: TextValidatorOptions): R;
440
+ /**
441
+ * Validates that a response matches regex patterns
442
+ *
443
+ * @param patterns - Expected pattern(s) to match
444
+ * @param options - Validation options
445
+ *
446
+ * @example
447
+ * ```typescript
448
+ * expect(result).toMatchToolPattern(/temperature: \d+/);
449
+ * expect(result).toMatchToolPattern(['temp: \\d+', 'humidity: \\d+%']);
450
+ * ```
451
+ */
452
+ toMatchToolPattern(patterns: string | RegExp | (string | RegExp)[], options?: PatternValidatorOptions): R;
453
+ /**
454
+ * Validates that a response matches a saved snapshot
455
+ *
456
+ * @param name - Snapshot name
457
+ * @param sanitizers - Optional sanitizers for non-deterministic values
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * expect(result).toMatchToolSnapshot('weather-response');
462
+ * expect(result).toMatchToolSnapshot('user-data', [
463
+ * { pattern: /\d{4}-\d{2}-\d{2}/, replacement: '[DATE]' },
464
+ * ]);
465
+ * ```
466
+ */
467
+ toMatchToolSnapshot(name: string, sanitizers?: SnapshotSanitizer[]): Promise<R>;
468
+ /**
469
+ * Validates that a response is (or is not) an error
470
+ *
471
+ * @param expected - What to expect (true for error, false for success, string for specific message)
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * expect(result).toBeToolError(); // Expects any error
476
+ * expect(result).not.toBeToolError(); // Expects success
477
+ * expect(result).toBeToolError('File not found'); // Expects specific error
478
+ * ```
479
+ */
480
+ toBeToolError(expected?: boolean | string | string[]): R;
481
+ /**
482
+ * Validates that a response passes LLM-as-judge evaluation.
483
+ *
484
+ * Two call signatures:
485
+ * - With rubric: `toPassToolJudge(rubric, options?)` — built-in LLM judge
486
+ * - With named judge: `toPassToolJudge({ judge: 'name' })` — custom judge executor
487
+ *
488
+ * @example
489
+ * ```typescript
490
+ * // Built-in LLM judge with rubric
491
+ * expect(result).toPassToolJudge('Response should be helpful and accurate');
492
+ * expect(result).toPassToolJudge('correctness', {
493
+ * reference: expectedOutput,
494
+ * passingThreshold: 0.8,
495
+ * });
496
+ *
497
+ * // Named custom judge (registered via registerJudge)
498
+ * expect(result).toPassToolJudge({ judge: 'glean-completeness' });
499
+ * ```
500
+ */
501
+ toPassToolJudge(rubric: RubricSpec, options?: JudgeMatcherOptions): Promise<R>;
502
+ toPassToolJudge(options: JudgeMatcherOptions): Promise<R>;
503
+ toPassToolJudge(judges: Array<JudgeMatcherOptions & {
504
+ rubric?: RubricSpec;
505
+ }>): Promise<R>;
506
+ /**
507
+ * Validates that a response meets size constraints
508
+ *
509
+ * @param options - Size constraints (maxBytes, minBytes)
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * expect(result).toHaveToolResponseSize({ maxBytes: 10000 });
514
+ * expect(result).toHaveToolResponseSize({ minBytes: 100, maxBytes: 50000 });
515
+ * ```
516
+ */
517
+ toHaveToolResponseSize(options: SizeValidatorOptions): R;
518
+ /**
519
+ * Validates that a response satisfies a custom predicate function
520
+ *
521
+ * Use this as an escape hatch when built-in matchers don't cover your use case.
522
+ * The predicate receives both the raw response and extracted text for convenience.
523
+ *
524
+ * @param predicate - Function that validates the response
525
+ * @param description - Optional description for error messages
526
+ *
527
+ * @example
528
+ * ```typescript
529
+ * // Simple boolean predicate
530
+ * expect(result).toSatisfyToolPredicate((response) => {
531
+ * return response.data?.items?.length > 0;
532
+ * });
533
+ *
534
+ * // Predicate with custom message
535
+ * expect(result).toSatisfyToolPredicate(
536
+ * (response, text) => ({
537
+ * pass: text.includes('success'),
538
+ * message: 'Expected response to contain "success"',
539
+ * }),
540
+ * 'success check'
541
+ * );
542
+ *
543
+ * // Async predicate
544
+ * expect(result).toSatisfyToolPredicate(async (response) => {
545
+ * return await validateWithExternalService(response);
546
+ * });
547
+ * ```
548
+ */
549
+ toSatisfyToolPredicate(predicate: ToolPredicate, description?: string): Promise<R>;
550
+ /**
551
+ * Validates which tools the LLM called during a mcp_host simulation.
552
+ *
553
+ * @example
554
+ * ```typescript
555
+ * expect(simulationResult).toHaveToolCalls({
556
+ * calls: [{ name: 'search', arguments: { query: 'hello' }, required: true }],
557
+ * order: 'any',
558
+ * });
559
+ * ```
560
+ */
561
+ toHaveToolCalls(expectation: ToolCallExpectation): R;
562
+ /**
563
+ * Validates the number of tool calls made during a mcp_host simulation.
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * expect(simulationResult).toHaveToolCallCount({ min: 1, max: 3 });
568
+ * expect(simulationResult).toHaveToolCallCount({ exact: 2 });
569
+ * ```
570
+ */
571
+ toHaveToolCallCount(options: ToolCallCountOptions): R;
572
+ }
573
+ }
574
+ }
575
+ /**
576
+ * Predicate result returned by the user's predicate function
577
+ */
578
+ interface PredicateResult {
579
+ /** Whether the predicate passed */
580
+ pass: boolean;
581
+ /** Message explaining the result (shown on failure) */
582
+ message?: string;
583
+ }
584
+ /**
585
+ * A predicate function that validates a response
586
+ */
587
+ type ToolPredicate = (response: unknown, text: string) => boolean | PredicateResult | Promise<boolean | PredicateResult>;
588
+
589
+ /**
590
+ * OAuth configuration for MCP authentication
591
+ */
592
+ interface MCPOAuthConfig {
593
+ /**
594
+ * OAuth authorization server metadata URL
595
+ * (e.g., https://auth.example.com/.well-known/oauth-authorization-server)
596
+ */
597
+ serverUrl: string;
598
+ /**
599
+ * Scopes to request during authorization
600
+ */
601
+ scopes?: Array<string>;
602
+ /**
603
+ * Resource indicator (RFC 8707, required by MCP 2025-06-18 spec)
604
+ */
605
+ resource?: string;
606
+ /**
607
+ * Path to Playwright auth state file
608
+ * (e.g., playwright/.auth/oauth-state.json)
609
+ */
610
+ authStatePath?: string;
611
+ /**
612
+ * Client ID (if pre-registered; otherwise uses Dynamic Client Registration)
613
+ */
614
+ clientId?: string;
615
+ /**
616
+ * Client secret (for confidential clients)
617
+ */
618
+ clientSecret?: string;
619
+ /**
620
+ * Redirect URI for OAuth callback
621
+ */
622
+ redirectUri?: string;
623
+ }
624
+ /**
625
+ * OAuth 2.1 client credentials configuration for machine-to-machine (CI/CD) authentication.
626
+ * Credentials can be provided here or via MCP_CLIENT_ID/MCP_CLIENT_SECRET environment variables.
627
+ */
628
+ interface MCPClientCredentialsConfig {
629
+ /**
630
+ * OAuth client ID (falls back to MCP_CLIENT_ID env var)
631
+ */
632
+ clientId?: string;
633
+ /**
634
+ * OAuth client secret (falls back to MCP_CLIENT_SECRET env var)
635
+ */
636
+ clientSecret?: string;
637
+ /**
638
+ * Token endpoint URL (required)
639
+ */
640
+ tokenEndpoint?: string;
641
+ /**
642
+ * Scopes to request
643
+ */
644
+ scopes?: string[];
645
+ }
646
+ /**
647
+ * Authentication configuration for MCP connections
648
+ */
649
+ interface MCPAuthConfig {
650
+ /**
651
+ * Pre-acquired access token (simplest authentication mode)
652
+ */
653
+ accessToken?: string;
654
+ /**
655
+ * Full OAuth configuration for browser-based authentication
656
+ */
657
+ oauth?: MCPOAuthConfig;
658
+ /**
659
+ * OAuth 2.1 client credentials grant for machine-to-machine authentication
660
+ */
661
+ clientCredentials?: MCPClientCredentialsConfig;
662
+ }
663
+ /**
664
+ * MCP host capabilities that can be registered with the server
665
+ */
666
+ interface MCPHostCapabilities {
667
+ /**
668
+ * Sampling capabilities (for LLM sampling)
669
+ */
670
+ sampling?: Record<string, unknown>;
671
+ /**
672
+ * Roots capabilities (for file system roots)
673
+ */
674
+ roots?: {
675
+ /**
676
+ * Whether the client can notify the server when roots change
677
+ */
678
+ listChanged: boolean;
679
+ };
680
+ }
681
+ /**
682
+ * Configuration for MCP client connection via stdio transport (local process)
683
+ */
684
+ interface StdioMCPConfig {
685
+ /**
686
+ * Transport type discriminant
687
+ */
688
+ transport: 'stdio';
689
+ /**
690
+ * Command to execute (required for stdio transport)
691
+ */
692
+ command: string;
693
+ /**
694
+ * Command arguments
695
+ */
696
+ args?: Array<string>;
697
+ /**
698
+ * Working directory for the command
699
+ */
700
+ cwd?: string;
701
+ /**
702
+ * Environment variables to pass to the subprocess.
703
+ * Merged with the current process environment.
704
+ */
705
+ env?: Record<string, string>;
706
+ /**
707
+ * Suppress stderr output from the server process.
708
+ * When true, server stderr is ignored instead of inherited.
709
+ */
710
+ quiet?: boolean;
711
+ /**
712
+ * Host capabilities to register with the server
713
+ */
714
+ capabilities?: MCPHostCapabilities;
715
+ /**
716
+ * Connection timeout in milliseconds
717
+ */
718
+ connectTimeoutMs?: number;
719
+ /**
720
+ * Request timeout in milliseconds
721
+ */
722
+ requestTimeoutMs?: number;
723
+ /**
724
+ * Timeout in milliseconds for MCP tool/list operations. Default: 30000
725
+ */
726
+ callTimeoutMs?: number;
727
+ }
728
+ /**
729
+ * Configuration for MCP client connection via HTTP transport (remote server)
730
+ */
731
+ interface HttpMCPConfig {
732
+ /**
733
+ * Transport type discriminant
734
+ */
735
+ transport: 'http';
736
+ /**
737
+ * Server URL (required for http transport)
738
+ */
739
+ serverUrl: string;
740
+ /**
741
+ * HTTP headers (e.g., Authorization)
742
+ */
743
+ headers?: Record<string, string>;
744
+ /**
745
+ * Authentication configuration
746
+ */
747
+ auth?: MCPAuthConfig;
748
+ /**
749
+ * Host capabilities to register with the server
750
+ */
751
+ capabilities?: MCPHostCapabilities;
752
+ /**
753
+ * Connection timeout in milliseconds
754
+ */
755
+ connectTimeoutMs?: number;
756
+ /**
757
+ * Request timeout in milliseconds
758
+ */
759
+ requestTimeoutMs?: number;
760
+ /**
761
+ * Timeout in milliseconds for MCP tool/list operations. Default: 30000
762
+ */
763
+ callTimeoutMs?: number;
764
+ /**
765
+ * HTTP proxy configuration. Falls back to HTTPS_PROXY/HTTP_PROXY environment variables.
766
+ */
767
+ proxy?: {
768
+ /**
769
+ * Proxy URL. Credentials can be embedded directly if required:
770
+ * `http://user:pass@proxy.example.com:8080`
771
+ */
772
+ url: string;
773
+ };
774
+ /**
775
+ * Number of retry attempts for transient connection failures and 429 rate limit responses.
776
+ * Uses exponential backoff with Retry-After header awareness. Defaults to 0 (no retries).
777
+ */
778
+ retryAttempts?: number;
779
+ /**
780
+ * TLS/mTLS configuration for custom certificates or disabling cert validation.
781
+ * File paths should point to PEM-encoded certificate files.
782
+ */
783
+ tls?: {
784
+ /**
785
+ * Path to CA certificate PEM file (for custom/self-signed CAs)
786
+ */
787
+ ca?: string;
788
+ /**
789
+ * Path to client certificate PEM file (for mutual TLS)
790
+ */
791
+ cert?: string;
792
+ /**
793
+ * Path to client private key PEM file (for mutual TLS)
794
+ */
795
+ key?: string;
796
+ /**
797
+ * Whether to reject unauthorized certificates. Defaults to true.
798
+ * Set to false to disable certificate validation (not recommended for production).
799
+ */
800
+ rejectUnauthorized?: boolean;
801
+ };
802
+ }
803
+ /**
804
+ * Configuration for MCP client connection.
805
+ *
806
+ * This is a discriminated union — narrow with `isStdioConfig()` or `isHttpConfig()`
807
+ * before accessing transport-specific fields.
808
+ *
809
+ * Supports both stdio (local) and HTTP (remote) transports.
810
+ */
811
+ type MCPConfig = StdioMCPConfig | HttpMCPConfig;
812
+ /**
813
+ * Union schema for MCPConfig (validates based on transport type)
814
+ */
815
+ declare const MCPConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
816
+ transport: z.ZodLiteral<"stdio">;
817
+ command: z.ZodString;
818
+ args: z.ZodOptional<z.ZodArray<z.ZodString>>;
819
+ cwd: z.ZodOptional<z.ZodString>;
820
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
821
+ capabilities: z.ZodOptional<z.ZodObject<{
822
+ sampling: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
823
+ roots: z.ZodOptional<z.ZodObject<{
824
+ listChanged: z.ZodBoolean;
825
+ }, z.core.$strip>>;
826
+ }, z.core.$strip>>;
827
+ connectTimeoutMs: z.ZodOptional<z.ZodNumber>;
828
+ requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
829
+ callTimeoutMs: z.ZodOptional<z.ZodNumber>;
830
+ quiet: z.ZodOptional<z.ZodBoolean>;
831
+ }, z.core.$strip>, z.ZodObject<{
832
+ transport: z.ZodLiteral<"http">;
833
+ serverUrl: z.ZodString;
834
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
835
+ capabilities: z.ZodOptional<z.ZodObject<{
836
+ sampling: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
837
+ roots: z.ZodOptional<z.ZodObject<{
838
+ listChanged: z.ZodBoolean;
839
+ }, z.core.$strip>>;
840
+ }, z.core.$strip>>;
841
+ connectTimeoutMs: z.ZodOptional<z.ZodNumber>;
842
+ requestTimeoutMs: z.ZodOptional<z.ZodNumber>;
843
+ callTimeoutMs: z.ZodOptional<z.ZodNumber>;
844
+ auth: z.ZodOptional<z.ZodObject<{
845
+ accessToken: z.ZodOptional<z.ZodString>;
846
+ oauth: z.ZodOptional<z.ZodObject<{
847
+ serverUrl: z.ZodString;
848
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
849
+ resource: z.ZodOptional<z.ZodString>;
850
+ authStatePath: z.ZodOptional<z.ZodString>;
851
+ clientId: z.ZodOptional<z.ZodString>;
852
+ clientSecret: z.ZodOptional<z.ZodString>;
853
+ redirectUri: z.ZodOptional<z.ZodString>;
854
+ }, z.core.$strip>>;
855
+ clientCredentials: z.ZodOptional<z.ZodObject<{
856
+ clientId: z.ZodOptional<z.ZodString>;
857
+ clientSecret: z.ZodOptional<z.ZodString>;
858
+ tokenEndpoint: z.ZodOptional<z.ZodString>;
859
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
860
+ }, z.core.$strip>>;
861
+ }, z.core.$strip>>;
862
+ proxy: z.ZodOptional<z.ZodObject<{
863
+ url: z.ZodString;
864
+ }, z.core.$strip>>;
865
+ retryAttempts: z.ZodOptional<z.ZodNumber>;
866
+ tls: z.ZodOptional<z.ZodObject<{
867
+ ca: z.ZodOptional<z.ZodString>;
868
+ cert: z.ZodOptional<z.ZodString>;
869
+ key: z.ZodOptional<z.ZodString>;
870
+ rejectUnauthorized: z.ZodOptional<z.ZodBoolean>;
871
+ }, z.core.$strip>>;
872
+ }, z.core.$strip>], "transport">;
873
+ /**
874
+ * Validates an MCPConfig object
875
+ *
876
+ * @param config - The config to validate
877
+ * @returns The validated config
878
+ * @throws {z.ZodError} If validation fails
879
+ */
880
+ declare function validateMCPConfig(config: unknown): MCPConfig;
881
+ /**
882
+ * Type guard to check if a config is for stdio transport
883
+ */
884
+ declare function isStdioConfig(config: MCPConfig): config is StdioMCPConfig;
885
+ /**
886
+ * Type guard to check if a config is for HTTP transport
887
+ */
888
+ declare function isHttpConfig(config: MCPConfig): config is HttpMCPConfig;
889
+
890
+ /**
891
+ * Auth types for MCP OAuth integration
892
+ */
893
+
894
+ /**
895
+ * Stored OAuth tokens
896
+ */
897
+ interface StoredTokens {
898
+ /**
899
+ * OAuth access token
900
+ */
901
+ accessToken: string;
902
+ /**
903
+ * OAuth refresh token (if provided)
904
+ */
905
+ refreshToken?: string;
906
+ /**
907
+ * Token expiration timestamp (Unix milliseconds)
908
+ */
909
+ expiresAt?: number;
910
+ /**
911
+ * Token type (typically "Bearer")
912
+ */
913
+ tokenType: string;
914
+ /**
915
+ * Client ID that was used to obtain these tokens.
916
+ * Required for token refresh since refresh tokens are bound to the client.
917
+ */
918
+ clientId?: string;
919
+ }
920
+ /**
921
+ * Stored client information from Dynamic Client Registration
922
+ */
923
+ interface StoredClientInfo {
924
+ /**
925
+ * Client ID from DCR
926
+ */
927
+ clientId: string;
928
+ /**
929
+ * Client secret from DCR (for confidential clients)
930
+ */
931
+ clientSecret?: string;
932
+ /**
933
+ * Client ID issued at timestamp
934
+ */
935
+ clientIdIssuedAt?: number;
936
+ /**
937
+ * Client secret expiration timestamp
938
+ */
939
+ clientSecretExpiresAt?: number;
940
+ }
941
+ /**
942
+ * Complete OAuth state persisted to disk for Playwright auth state pattern
943
+ */
944
+ interface StoredOAuthState {
945
+ /**
946
+ * OAuth tokens
947
+ */
948
+ tokens?: StoredTokens;
949
+ /**
950
+ * DCR client information
951
+ */
952
+ clientInfo?: StoredClientInfo;
953
+ /**
954
+ * PKCE code verifier (used during authorization flow)
955
+ */
956
+ codeVerifier?: string;
957
+ /**
958
+ * OAuth state parameter (for CSRF protection)
959
+ */
960
+ state?: string;
961
+ /**
962
+ * Timestamp when this state was saved
963
+ */
964
+ savedAt: number;
965
+ }
966
+ /**
967
+ * Login form selectors for standard OAuth login automation
968
+ */
969
+ interface OAuthLoginSelectors {
970
+ /** Selector for username/email input field */
971
+ usernameInput: string;
972
+ /** Selector for password input field */
973
+ passwordInput: string;
974
+ /** Selector for login submit button */
975
+ submitButton: string;
976
+ /** Selector for consent/authorize button (optional) */
977
+ consentButton?: string;
978
+ }
979
+ /**
980
+ * Base configuration shared by all OAuth setup strategies
981
+ */
982
+ interface OAuthSetupBaseConfig {
983
+ /** OAuth authorization server metadata URL */
984
+ authServerUrl: string;
985
+ /** Scopes to request */
986
+ scopes: Array<string>;
987
+ /** Path to save OAuth state file */
988
+ outputPath: string;
989
+ /** Pre-registered client ID (optional, uses DCR if not provided) */
990
+ clientId?: string;
991
+ /** Pre-registered client secret (optional) */
992
+ clientSecret?: string;
993
+ /** Redirect URI for OAuth callback */
994
+ redirectUri?: string;
995
+ /** Resource indicator (RFC 8707) */
996
+ resource?: string;
997
+ /** Timeout for login flow in milliseconds (default: 30000) */
998
+ timeoutMs?: number;
999
+ }
1000
+ /**
1001
+ * Standard login strategy: automates a form with username, password, and submit button.
1002
+ * Use when the IdP presents all login fields on a single page.
1003
+ */
1004
+ interface StandardLoginConfig {
1005
+ /** Login form selectors for Playwright automation */
1006
+ loginSelectors: OAuthLoginSelectors;
1007
+ /** Test user credentials */
1008
+ credentials: {
1009
+ username: string;
1010
+ password: string;
1011
+ };
1012
+ customLoginFlow?: never;
1013
+ }
1014
+ /**
1015
+ * Custom login strategy: full control over the browser-based login flow.
1016
+ * Use for multi-step logins, MFA, custom consent screens, or any flow
1017
+ * that doesn't fit the standard username/password/submit pattern.
1018
+ *
1019
+ * The callback receives a Playwright Page already navigated to the OAuth
1020
+ * authorization URL. Complete the login so the IdP redirects to the
1021
+ * callback URL — `performOAuthSetup` handles PKCE, token exchange,
1022
+ * and state persistence automatically.
1023
+ */
1024
+ interface CustomLoginConfig {
1025
+ /**
1026
+ * Custom Playwright automation for the IdP login flow.
1027
+ *
1028
+ * @param page - Playwright Page already navigated to the OAuth authorization URL
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * customLoginFlow: async (page) => {
1033
+ * await page.fill('#username', process.env.TEST_USER!);
1034
+ * await page.click('#continue');
1035
+ * await page.fill('#password', process.env.TEST_PASS!);
1036
+ * await page.click('#submit');
1037
+ * }
1038
+ * ```
1039
+ */
1040
+ customLoginFlow: (page: Page) => Promise<void>;
1041
+ loginSelectors?: never;
1042
+ credentials?: never;
1043
+ }
1044
+ /**
1045
+ * Configuration for OAuth setup flow.
1046
+ *
1047
+ * Provide either `loginSelectors` + `credentials` for standard form-based login,
1048
+ * or `customLoginFlow` for full control over the browser automation.
1049
+ */
1050
+ type OAuthSetupConfig = OAuthSetupBaseConfig & (StandardLoginConfig | CustomLoginConfig);
1051
+ /**
1052
+ * Result of token exchange or refresh
1053
+ */
1054
+ interface TokenResult {
1055
+ /**
1056
+ * Access token
1057
+ */
1058
+ accessToken: string;
1059
+ /**
1060
+ * Token type (typically "Bearer")
1061
+ */
1062
+ tokenType: string;
1063
+ /**
1064
+ * Expires in seconds
1065
+ */
1066
+ expiresIn?: number;
1067
+ /**
1068
+ * Refresh token (if provided)
1069
+ */
1070
+ refreshToken?: string;
1071
+ /**
1072
+ * Granted scopes (space-separated)
1073
+ */
1074
+ scope?: string;
1075
+ }
1076
+
1077
+ /**
1078
+ * OAuth client provider implementation for MCP SDK
1079
+ *
1080
+ * Implements the MCP SDK's OAuthClientProvider interface using file-based storage
1081
+ * for integration with Playwright's auth state pattern.
1082
+ */
1083
+
1084
+ /**
1085
+ * Configuration for the Playwright OAuth client provider
1086
+ */
1087
+ interface PlaywrightOAuthClientProviderConfig {
1088
+ /**
1089
+ * Path to the auth state file (e.g., playwright/.auth/oauth-state.json)
1090
+ */
1091
+ storagePath: string;
1092
+ /**
1093
+ * OAuth redirect URI for callback
1094
+ */
1095
+ redirectUri: string;
1096
+ /**
1097
+ * Client metadata for DCR or display
1098
+ */
1099
+ clientMetadata?: Partial<OAuthClientMetadata>;
1100
+ /**
1101
+ * Pre-registered client ID (if not using DCR)
1102
+ */
1103
+ clientId?: string;
1104
+ /**
1105
+ * Pre-registered client secret (if not using DCR)
1106
+ */
1107
+ clientSecret?: string;
1108
+ }
1109
+ /**
1110
+ * OAuth client provider that implements the MCP SDK's OAuthClientProvider interface
1111
+ *
1112
+ * Uses file-based storage for integration with Playwright's auth state pattern.
1113
+ * Auth state is persisted to disk so it can be reused across test runs.
1114
+ *
1115
+ * @example
1116
+ * ```typescript
1117
+ * const provider = new PlaywrightOAuthClientProvider({
1118
+ * storagePath: 'playwright/.auth/oauth-state.json',
1119
+ * redirectUri: 'http://localhost:3000/callback',
1120
+ * });
1121
+ *
1122
+ * const transport = new StreamableHTTPClientTransport(serverUrl, {
1123
+ * authProvider: provider,
1124
+ * });
1125
+ * ```
1126
+ */
1127
+ declare class PlaywrightOAuthClientProvider implements OAuthClientProvider {
1128
+ private readonly config;
1129
+ private cachedState;
1130
+ private stateParam;
1131
+ constructor(config: PlaywrightOAuthClientProviderConfig);
1132
+ /**
1133
+ * The URL to redirect the user agent to after authorization
1134
+ */
1135
+ get redirectUrl(): string;
1136
+ /**
1137
+ * Metadata about this OAuth client
1138
+ */
1139
+ get clientMetadata(): OAuthClientMetadata;
1140
+ /**
1141
+ * Returns an OAuth2 state parameter
1142
+ */
1143
+ state(): string;
1144
+ /**
1145
+ * Loads information about this OAuth client
1146
+ */
1147
+ clientInformation(): Promise<OAuthClientInformationFull | undefined>;
1148
+ /**
1149
+ * Saves client information from Dynamic Client Registration
1150
+ */
1151
+ saveClientInformation(clientInformation: OAuthClientInformationFull): Promise<void>;
1152
+ /**
1153
+ * Loads any existing OAuth tokens for the current session
1154
+ */
1155
+ tokens(): Promise<OAuthTokens | undefined>;
1156
+ /**
1157
+ * Stores new OAuth tokens for the current session
1158
+ *
1159
+ * The code verifier is cleared after a successful token exchange — it is
1160
+ * single-use per PKCE spec and must not persist beyond the exchange.
1161
+ */
1162
+ saveTokens(tokens: OAuthTokens): Promise<void>;
1163
+ /**
1164
+ * Invoked to redirect the user agent to the given URL
1165
+ *
1166
+ * In a testing context, this is typically handled by Playwright automation.
1167
+ * This implementation throws an error to signal that the caller needs to
1168
+ * handle the redirect externally.
1169
+ */
1170
+ redirectToAuthorization(authorizationUrl: URL): Promise<void>;
1171
+ /**
1172
+ * Saves a PKCE code verifier for the current session
1173
+ */
1174
+ saveCodeVerifier(codeVerifier: string): Promise<void>;
1175
+ /**
1176
+ * Loads the PKCE code verifier for the current session
1177
+ */
1178
+ codeVerifier(): Promise<string>;
1179
+ /**
1180
+ * Invalidates the specified credentials
1181
+ */
1182
+ invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier'): Promise<void>;
1183
+ private loadState;
1184
+ private saveState;
1185
+ private deleteState;
1186
+ private createEmptyState;
1187
+ private generateRandomString;
1188
+ }
1189
+
1190
+ /**
1191
+ * OAuth flow utilities using oauth4webapi
1192
+ *
1193
+ * Implements OAuth 2.1 with PKCE as required by MCP specification
1194
+ */
1195
+
1196
+ /**
1197
+ * Discovered OAuth authorization server metadata
1198
+ */
1199
+ interface AuthServerMetadata {
1200
+ /**
1201
+ * The oauth4webapi AuthorizationServer object
1202
+ */
1203
+ server: oauth.AuthorizationServer;
1204
+ /**
1205
+ * Issuer URL
1206
+ */
1207
+ issuer: string;
1208
+ }
1209
+ /**
1210
+ * Configuration for token refresh
1211
+ */
1212
+ interface TokenRefreshConfig {
1213
+ /**
1214
+ * Authorization server metadata
1215
+ */
1216
+ authServer: AuthServerMetadata;
1217
+ /**
1218
+ * Client ID
1219
+ */
1220
+ clientId: string;
1221
+ /**
1222
+ * Client secret (for confidential clients)
1223
+ */
1224
+ clientSecret?: string;
1225
+ /**
1226
+ * Refresh token
1227
+ */
1228
+ refreshToken: string;
1229
+ }
1230
+ /**
1231
+ * Refreshes an access token using a refresh token
1232
+ *
1233
+ * @param config - Token refresh configuration
1234
+ * @returns New token result
1235
+ */
1236
+ declare function refreshAccessToken(config: TokenRefreshConfig): Promise<TokenResult>;
1237
+ /**
1238
+ * Configuration for client credentials grant
1239
+ */
1240
+ interface ClientCredentialsConfig {
1241
+ /**
1242
+ * Token endpoint URL
1243
+ */
1244
+ tokenEndpoint: string;
1245
+ /**
1246
+ * OAuth client ID
1247
+ */
1248
+ clientId: string;
1249
+ /**
1250
+ * OAuth client secret
1251
+ */
1252
+ clientSecret: string;
1253
+ /**
1254
+ * Scopes to request (optional)
1255
+ */
1256
+ scopes?: string[];
1257
+ }
1258
+ /**
1259
+ * Performs the OAuth 2.1 client credentials grant to obtain an access token.
1260
+ * Suitable for CI/CD machine-to-machine authentication.
1261
+ *
1262
+ * Uses oauth4webapi for spec-compliant request construction and response validation,
1263
+ * consistent with how the rest of this module handles OAuth flows.
1264
+ *
1265
+ * @param config - Client credentials configuration
1266
+ * @returns Token result
1267
+ */
1268
+ declare function performClientCredentialsFlow(config: ClientCredentialsConfig): Promise<TokenResult>;
1269
+
1270
+ /**
1271
+ * OAuth Protected Resource and Authorization Server discovery
1272
+ *
1273
+ * Implements RFC 9728 (OAuth Protected Resource Metadata) and
1274
+ * RFC 8414 (Authorization Server Metadata) for MCP servers.
1275
+ */
1276
+
1277
+ /**
1278
+ * MCP Protocol version header value
1279
+ */
1280
+ declare const MCP_PROTOCOL_VERSION = "2025-06-18";
1281
+ /**
1282
+ * Protected Resource Metadata (RFC 9728)
1283
+ */
1284
+ interface ProtectedResourceMetadata {
1285
+ /**
1286
+ * The protected resource URL
1287
+ */
1288
+ resource: string;
1289
+ /**
1290
+ * Array of authorization server URLs
1291
+ */
1292
+ authorization_servers?: Array<string>;
1293
+ /**
1294
+ * Scopes supported by the protected resource
1295
+ */
1296
+ scopes_supported?: Array<string>;
1297
+ /**
1298
+ * Bearer token formats supported
1299
+ */
1300
+ bearer_methods_supported?: Array<string>;
1301
+ /**
1302
+ * Resource documentation URL
1303
+ */
1304
+ resource_documentation?: string;
1305
+ /**
1306
+ * Resource signing algorithms
1307
+ */
1308
+ resource_signing_alg_values_supported?: Array<string>;
1309
+ }
1310
+ /**
1311
+ * Result of protected resource discovery
1312
+ */
1313
+ interface ProtectedResourceDiscoveryResult {
1314
+ /**
1315
+ * The discovered metadata
1316
+ */
1317
+ metadata: ProtectedResourceMetadata;
1318
+ /**
1319
+ * The URL where metadata was found
1320
+ */
1321
+ discoveryUrl: string;
1322
+ /**
1323
+ * Whether path-aware discovery was used (vs base discovery)
1324
+ */
1325
+ usedPathAwareDiscovery: boolean;
1326
+ }
1327
+ /**
1328
+ * Discovers protected resource metadata per RFC 9728
1329
+ *
1330
+ * Follows RFC 9728 Section 4.1 for path-aware discovery:
1331
+ * 1. First tries: {origin}/.well-known/oauth-protected-resource{pathname}
1332
+ * 2. Falls back to: {origin}/.well-known/oauth-protected-resource
1333
+ *
1334
+ * @param mcpServerUrl - The MCP server URL
1335
+ * @returns Protected resource discovery result
1336
+ * @throws Error if discovery fails completely
1337
+ *
1338
+ * @example
1339
+ * const result = await discoverProtectedResource('https://api.example.com/mcp/default');
1340
+ * console.log(result.metadata.authorization_servers);
1341
+ */
1342
+ declare function discoverProtectedResource(mcpServerUrl: string): Promise<ProtectedResourceDiscoveryResult>;
1343
+ /**
1344
+ * Error thrown when discovery fails
1345
+ */
1346
+ declare class DiscoveryError extends Error {
1347
+ readonly status?: number | undefined;
1348
+ readonly url?: string | undefined;
1349
+ constructor(message: string, status?: number | undefined, url?: string | undefined);
1350
+ }
1351
+ /**
1352
+ * Discovers OAuth Authorization Server metadata per RFC 8414
1353
+ *
1354
+ * Wraps oauth4webapi's discovery with MCP-specific headers.
1355
+ *
1356
+ * @param authServerUrl - The authorization server URL
1357
+ * @returns Authorization server metadata
1358
+ * @throws Error if discovery fails
1359
+ *
1360
+ * @example
1361
+ * const authServer = await discoverAuthorizationServer('https://auth.example.com');
1362
+ * console.log(authServer.server.token_endpoint);
1363
+ */
1364
+ declare function discoverAuthorizationServer(authServerUrl: string): Promise<AuthServerMetadata>;
1365
+
1366
+ /**
1367
+ * OAuth token storage with environment variable support for CI/CD
1368
+ *
1369
+ * Provides file-based storage for OAuth state per MCP server, with support
1370
+ * for token injection via environment variables for automated testing.
1371
+ */
1372
+
1373
+ /**
1374
+ * Combined server metadata (auth server + protected resource)
1375
+ */
1376
+ interface StoredServerMetadata {
1377
+ /**
1378
+ * Authorization server metadata
1379
+ */
1380
+ authServer: AuthServerMetadata;
1381
+ /**
1382
+ * Protected resource metadata
1383
+ */
1384
+ protectedResource: ProtectedResourceMetadata;
1385
+ /**
1386
+ * Timestamp when metadata was discovered
1387
+ */
1388
+ discoveredAt: number;
1389
+ }
1390
+ /**
1391
+ * Environment variable names for CI/CD token injection
1392
+ */
1393
+ declare const ENV_VAR_NAMES: {
1394
+ readonly accessToken: "MCP_ACCESS_TOKEN";
1395
+ readonly refreshToken: "MCP_REFRESH_TOKEN";
1396
+ readonly tokenType: "MCP_TOKEN_TYPE";
1397
+ readonly expiresAt: "MCP_TOKEN_EXPIRES_AT";
1398
+ };
1399
+ /**
1400
+ * Reads tokens from environment variables (for CI/CD)
1401
+ *
1402
+ * @returns StoredTokens if MCP_ACCESS_TOKEN is set, null otherwise
1403
+ */
1404
+ declare function loadTokensFromEnv(): StoredTokens | null;
1405
+ /**
1406
+ * Programmatically inject tokens into storage (for CI/CD setup)
1407
+ *
1408
+ * @param serverUrl - The MCP server URL
1409
+ * @param tokens - The tokens to inject
1410
+ * @param stateDir - Optional custom state directory
1411
+ */
1412
+ declare function injectTokens(serverUrl: string, tokens: StoredTokens, stateDir?: string): Promise<void>;
1413
+ /**
1414
+ * Load stored OAuth tokens for an MCP server
1415
+ *
1416
+ * Reads tokens from the standard storage location for the given server URL.
1417
+ * Tokens are stored by `mcp-server-tester login` or `injectTokens()`.
1418
+ *
1419
+ * @param serverUrl - The MCP server URL
1420
+ * @param stateDir - Optional custom state directory
1421
+ * @returns StoredTokens if found, null otherwise
1422
+ *
1423
+ * @example
1424
+ * ```typescript
1425
+ * // After running: npx mcp-server-tester login https://api.example.com/mcp
1426
+ * const tokens = await loadTokens('https://api.example.com/mcp');
1427
+ * if (tokens?.accessToken) {
1428
+ * // Use the token — never log raw token values
1429
+ * headers.Authorization = `Bearer ${tokens.accessToken}`;
1430
+ * }
1431
+ * ```
1432
+ */
1433
+ declare function loadTokens(serverUrl: string, stateDir?: string): Promise<StoredTokens | null>;
1434
+ /**
1435
+ * Check if valid OAuth tokens exist for an MCP server
1436
+ *
1437
+ * Returns true if tokens exist and are not expired (with buffer).
1438
+ * Use this to check if authentication is needed before making requests.
1439
+ *
1440
+ * @param serverUrl - The MCP server URL
1441
+ * @param options - Optional configuration
1442
+ * @param options.stateDir - Custom state directory
1443
+ * @param options.bufferMs - Buffer time before expiration (default: 60000ms)
1444
+ * @returns true if valid (non-expired) tokens exist
1445
+ *
1446
+ * @example
1447
+ * ```typescript
1448
+ * if (await hasValidTokens('https://api.example.com/mcp')) {
1449
+ * // Use stored tokens
1450
+ * const tokens = await loadTokens('https://api.example.com/mcp');
1451
+ * } else {
1452
+ * console.log('Run: npx mcp-server-tester login https://api.example.com/mcp');
1453
+ * }
1454
+ * ```
1455
+ */
1456
+ declare function hasValidTokens(serverUrl: string, options?: {
1457
+ stateDir?: string;
1458
+ bufferMs?: number;
1459
+ }): Promise<boolean>;
1460
+
1461
+ /**
1462
+ * CLI OAuth client for command-line authentication flows
1463
+ *
1464
+ * Provides browser-based OAuth authentication for CLI environments,
1465
+ * with support for environment variable token injection for CI/CD.
1466
+ */
1467
+ /**
1468
+ * Configuration for CLI OAuth client
1469
+ */
1470
+ interface CLIOAuthClientConfig {
1471
+ /**
1472
+ * MCP server URL (for protected resource discovery)
1473
+ */
1474
+ mcpServerUrl: string;
1475
+ /**
1476
+ * Scopes to request (optional, uses discovered scopes if not provided)
1477
+ */
1478
+ scopes?: Array<string>;
1479
+ /**
1480
+ * Custom storage directory
1481
+ */
1482
+ stateDir?: string;
1483
+ /**
1484
+ * Pre-registered client ID (skips DCR if provided)
1485
+ */
1486
+ clientId?: string;
1487
+ /**
1488
+ * Pre-registered client secret
1489
+ */
1490
+ clientSecret?: string;
1491
+ /**
1492
+ * Preferred callback port (default: random available port)
1493
+ */
1494
+ callbackPort?: number;
1495
+ /**
1496
+ * Timeout for OAuth flow in milliseconds (default: 300000 = 5 min)
1497
+ */
1498
+ timeoutMs?: number;
1499
+ /**
1500
+ * Client name for DCR registration
1501
+ */
1502
+ clientName?: string;
1503
+ }
1504
+ /**
1505
+ * Result of CLI OAuth authentication
1506
+ */
1507
+ interface CLIOAuthResult {
1508
+ /**
1509
+ * Access token
1510
+ */
1511
+ accessToken: string;
1512
+ /**
1513
+ * Token type (typically "Bearer")
1514
+ */
1515
+ tokenType: string;
1516
+ /**
1517
+ * Expiration timestamp (Unix ms)
1518
+ */
1519
+ expiresAt?: number;
1520
+ /**
1521
+ * Whether token was refreshed vs newly acquired
1522
+ */
1523
+ refreshed: boolean;
1524
+ /**
1525
+ * Scopes that were requested (only set for new authentications)
1526
+ */
1527
+ requestedScopes?: string[];
1528
+ /**
1529
+ * Whether token came from environment variables
1530
+ */
1531
+ fromEnv: boolean;
1532
+ }
1533
+ /**
1534
+ * CLI OAuth client for command-line authentication flows
1535
+ */
1536
+ declare class CLIOAuthClient {
1537
+ private readonly config;
1538
+ private readonly storage;
1539
+ constructor(config: CLIOAuthClientConfig);
1540
+ /**
1541
+ * Get a valid access token, authenticating if necessary
1542
+ *
1543
+ * Token resolution priority:
1544
+ * 1. Check environment variables (for CI/CD)
1545
+ * 2. Check file storage for cached tokens
1546
+ * 3. Try to refresh if expired but refresh token exists
1547
+ * 4. Run full OAuth flow if needed
1548
+ */
1549
+ getAccessToken(): Promise<CLIOAuthResult>;
1550
+ /**
1551
+ * Try to get a valid access token without triggering browser auth
1552
+ *
1553
+ * Returns null if no valid token is available (no stored tokens,
1554
+ * expired without refresh token, or refresh failed). Unlike getAccessToken(),
1555
+ * this will NOT open a browser for authentication.
1556
+ *
1557
+ * Use this for CLI commands that should prompt the user to run `login`
1558
+ * instead of automatically starting the OAuth flow.
1559
+ */
1560
+ tryGetAccessToken(): Promise<CLIOAuthResult | null>;
1561
+ /**
1562
+ * Force a new authentication flow
1563
+ */
1564
+ authenticate(): Promise<CLIOAuthResult>;
1565
+ /**
1566
+ * Check if stored credentials exist (may be expired)
1567
+ */
1568
+ hasStoredCredentials(): Promise<boolean>;
1569
+ /**
1570
+ * Clear stored credentials
1571
+ */
1572
+ clearCredentials(): Promise<void>;
1573
+ /**
1574
+ * Discover protected resource and authorization server
1575
+ */
1576
+ private discoverServers;
1577
+ /**
1578
+ * Get existing client or register new one via DCR
1579
+ */
1580
+ private getOrRegisterClient;
1581
+ /**
1582
+ * Register a new client via Dynamic Client Registration
1583
+ */
1584
+ private registerClient;
1585
+ /**
1586
+ * Perform the full OAuth authorization flow
1587
+ */
1588
+ private performOAuthFlow;
1589
+ /**
1590
+ * Refresh an expired token
1591
+ *
1592
+ * Uses the clientId stored with the tokens (if available) to ensure
1593
+ * the refresh request uses the same client that obtained the original tokens.
1594
+ * This is important because refresh tokens are bound to the client_id.
1595
+ */
1596
+ private refreshStoredToken;
1597
+ /**
1598
+ * Start local callback server
1599
+ */
1600
+ private startCallbackServer;
1601
+ /**
1602
+ * Open browser or print URL for headless environments
1603
+ */
1604
+ private openBrowserOrPrintUrl;
1605
+ /**
1606
+ * Convert TokenResult to StoredTokens
1607
+ *
1608
+ * @param result - Token result from exchange or refresh
1609
+ * @param clientId - Client ID that was used to obtain these tokens
1610
+ */
1611
+ private tokenResultToStoredTokens;
1612
+ /**
1613
+ * HTML page for successful authentication
1614
+ */
1615
+ private successHtml;
1616
+ /**
1617
+ * HTML page for authentication error
1618
+ */
1619
+ private errorHtml;
1620
+ }
1621
+
1622
+ /**
1623
+ * Options for creating an MCP fixture
1624
+ */
1625
+ interface MCPFixtureOptions {
1626
+ /**
1627
+ * Authentication type used for this test
1628
+ * - 'oauth': Interactive OAuth 2.1 with PKCE (browser-based authentication)
1629
+ * - 'api-token': Static API token (e.g., from a dashboard or environment variable)
1630
+ * - 'none': No authentication
1631
+ */
1632
+ authType?: AuthType;
1633
+ /**
1634
+ * Playwright project name for this test
1635
+ * Used for filtering and grouping in the reporter
1636
+ */
1637
+ project?: string;
1638
+ /**
1639
+ * Timeout in milliseconds for MCP tool/list operations. Default: 30000
1640
+ */
1641
+ callTimeoutMs?: number;
1642
+ }
1643
+ /**
1644
+ * High-level API for interacting with MCP servers in tests
1645
+ *
1646
+ * This interface wraps the raw MCP Client with test-friendly methods
1647
+ */
1648
+ interface MCPFixtureApi {
1649
+ /**
1650
+ * The underlying MCP client (for advanced usage)
1651
+ */
1652
+ client: Client;
1653
+ /**
1654
+ * Authentication type used for this test session
1655
+ */
1656
+ authType: AuthType;
1657
+ /**
1658
+ * Playwright project name for this test session
1659
+ */
1660
+ project?: string;
1661
+ /**
1662
+ * Lists all available tools from the MCP server
1663
+ *
1664
+ * @returns Array of tool definitions
1665
+ */
1666
+ listTools(): Promise<Array<Tool>>;
1667
+ /**
1668
+ * Calls a tool on the MCP server
1669
+ *
1670
+ * @param name - Tool name
1671
+ * @param args - Tool arguments
1672
+ * @returns Tool call result
1673
+ */
1674
+ callTool<TArgs extends Record<string, unknown> = Record<string, unknown>>(name: string, args: TArgs): Promise<CallToolResult>;
1675
+ /**
1676
+ * Gets information about the connected server
1677
+ */
1678
+ getServerInfo(): {
1679
+ name?: string;
1680
+ version?: string;
1681
+ } | null;
1682
+ }
1683
+ /**
1684
+ * Creates an MCP fixture wrapper around a Client, providing a high-level
1685
+ * {@link MCPFixtureApi} without requiring Playwright's `test.extend` pattern.
1686
+ *
1687
+ * Use this when you need to set up an MCP fixture manually — for example in
1688
+ * custom fixture hierarchies, non-Playwright test runners (e.g. Vitest,
1689
+ * Jest), or when you want to compose the fixture with other lifecycle
1690
+ * management logic that doesn't fit the standard `test.extend` model.
1691
+ *
1692
+ * For the typical Playwright use case, prefer importing `test` and `mcp`
1693
+ * directly from `@gleanwork/mcp-server-tester/fixtures/mcp`, which wires
1694
+ * this function up automatically.
1695
+ *
1696
+ * When `testInfo` is provided, all MCP operations are automatically wrapped
1697
+ * in `test.step()` calls and attachments are created for the MCP Test
1698
+ * Reporter. Omit `testInfo` for lightweight usage outside Playwright.
1699
+ *
1700
+ * @param client - The MCP client to wrap (created via `createMCPClientForConfig`)
1701
+ * @param testInfo - Optional Playwright TestInfo for auto-tracking and reporter attachments
1702
+ * @param options - Optional fixture options (authType, project)
1703
+ * @returns MCPFixtureApi instance
1704
+ *
1705
+ * @example
1706
+ * ```typescript
1707
+ * // Advanced: custom fixture setup inside test.extend
1708
+ * const test = base.extend<{ mcp: MCPFixtureApi }>({
1709
+ * mcp: async ({}, use, testInfo) => {
1710
+ * const client = await createMCPClientForConfig(config);
1711
+ * const api = createMCPFixture(client, testInfo, { authType: 'api-token' });
1712
+ * await use(api);
1713
+ * await closeMCPClient(client);
1714
+ * }
1715
+ * });
1716
+ *
1717
+ * // Non-Playwright usage (no reporter attachments)
1718
+ * const client = await createMCPClientForConfig(config);
1719
+ * const api = createMCPFixture(client);
1720
+ * const tools = await api.listTools();
1721
+ * ```
1722
+ */
1723
+ declare function createMCPFixture(client: Client, testInfo?: TestInfo, options?: MCPFixtureOptions): MCPFixtureApi;
1724
+
1725
+ /**
1726
+ * Test-scoped auth fixtures interface
1727
+ */
1728
+ interface MCPAuthFixtures {
1729
+ /**
1730
+ * OAuth client provider for MCP authentication
1731
+ */
1732
+ mcpAuthProvider: OAuthClientProvider | undefined;
1733
+ }
1734
+ /**
1735
+ * Extended Playwright test with MCP auth fixtures
1736
+ *
1737
+ * Use this when you need OAuth authentication for MCP server testing.
1738
+ *
1739
+ * @example
1740
+ * ```typescript
1741
+ * // test.ts
1742
+ * import { test } from '@gleanwork/mcp-server-tester/fixtures/mcpAuth';
1743
+ *
1744
+ * test('authenticated MCP call', async ({ mcpAuthProvider }) => {
1745
+ * // mcpAuthProvider can be passed to createMCPClientForConfig
1746
+ * });
1747
+ * ```
1748
+ */
1749
+ declare const test: playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & MCPAuthFixtures, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
1750
+
1751
+ /**
1752
+ * Options for creating an MCP client
1753
+ */
1754
+ interface CreateMCPClientOptions {
1755
+ /**
1756
+ * Client information (name and version)
1757
+ */
1758
+ clientInfo?: {
1759
+ name?: string;
1760
+ version?: string;
1761
+ };
1762
+ /**
1763
+ * OAuth client provider for authentication
1764
+ *
1765
+ * When provided, the MCP SDK handles OAuth flow automatically.
1766
+ * This takes precedence over static token auth in config.auth.accessToken.
1767
+ */
1768
+ authProvider?: OAuthClientProvider;
1769
+ /**
1770
+ * Sampling handler callback for LLM sampling requests from the server.
1771
+ *
1772
+ * When provided, the client will advertise sampling capability to the server.
1773
+ * When absent, sampling is removed from declared capabilities so the client
1774
+ * does not falsely advertise support it cannot fulfill.
1775
+ */
1776
+ samplingHandler?: (...args: unknown[]) => unknown;
1777
+ }
1778
+ /**
1779
+ * Creates and connects an MCP client based on the provided configuration
1780
+ *
1781
+ * @param config - MCP configuration (will be validated)
1782
+ * @param options - Optional client options including auth provider
1783
+ * @returns Connected MCP Client instance
1784
+ * @throws {Error} If config is invalid or connection fails
1785
+ *
1786
+ * @example
1787
+ * // Stdio transport
1788
+ * const client = await createMCPClientForConfig({
1789
+ * transport: 'stdio',
1790
+ * command: 'node',
1791
+ * args: ['server.js']
1792
+ * });
1793
+ *
1794
+ * @example
1795
+ * // HTTP transport with static token auth
1796
+ * const client = await createMCPClientForConfig({
1797
+ * transport: 'http',
1798
+ * serverUrl: 'http://localhost:3000/mcp',
1799
+ * auth: { accessToken: 'your-token' }
1800
+ * });
1801
+ *
1802
+ * @example
1803
+ * // HTTP transport with OAuth provider
1804
+ * const client = await createMCPClientForConfig(
1805
+ * { transport: 'http', serverUrl: 'http://localhost:3000/mcp' },
1806
+ * { authProvider: myOAuthProvider }
1807
+ * );
1808
+ */
1809
+ declare function createMCPClientForConfig(config: MCPConfig, options?: CreateMCPClientOptions): Promise<Client>;
1810
+ /**
1811
+ * Safely closes an MCP client connection
1812
+ *
1813
+ * @param client - The client to close
1814
+ */
1815
+ declare function closeMCPClient(client: Client): Promise<void>;
1816
+
1817
+ /**
1818
+ * A single content block from an MCP response
1819
+ */
1820
+ interface ContentBlock {
1821
+ type: string;
1822
+ text?: string;
1823
+ data?: unknown;
1824
+ mimeType?: string;
1825
+ }
1826
+ /**
1827
+ * Normalized representation of an MCP tool response
1828
+ *
1829
+ * This provides a consistent interface regardless of the response format
1830
+ * returned by the MCP server.
1831
+ */
1832
+ interface NormalizedToolResponse {
1833
+ /**
1834
+ * Extracted text content (concatenated from all text blocks)
1835
+ */
1836
+ text: string;
1837
+ /**
1838
+ * Original raw response from the MCP SDK
1839
+ */
1840
+ raw: CallToolResult;
1841
+ /**
1842
+ * Whether the tool call resulted in an error
1843
+ */
1844
+ isError: boolean;
1845
+ /**
1846
+ * Parsed content blocks from the response
1847
+ */
1848
+ contentBlocks: ContentBlock[];
1849
+ /**
1850
+ * Structured content if present (parsed JSON or raw data)
1851
+ */
1852
+ structuredContent: unknown;
1853
+ }
1854
+ /**
1855
+ * Normalizes an MCP CallToolResult into a consistent format
1856
+ *
1857
+ * @param result - Raw CallToolResult from the MCP SDK
1858
+ * @returns Normalized response with extracted text, content blocks, etc.
1859
+ *
1860
+ * @example
1861
+ * ```typescript
1862
+ * const result = await client.callTool({ name: 'read_file', arguments: { path: 'readme.txt' } });
1863
+ * const normalized = normalizeToolResponse(result);
1864
+ *
1865
+ * console.log(normalized.text); // "Hello World"
1866
+ * console.log(normalized.isError); // false
1867
+ * console.log(normalized.contentBlocks); // [{ type: 'text', text: 'Hello World' }]
1868
+ * ```
1869
+ */
1870
+ declare function normalizeToolResponse(result: CallToolResult): NormalizedToolResponse;
1871
+ /**
1872
+ * Extracts just the text content from a normalized or raw response
1873
+ *
1874
+ * This is a convenience function that works with both:
1875
+ * - Raw CallToolResult from the MCP SDK
1876
+ * - NormalizedToolResponse from normalizeToolResponse()
1877
+ * - Plain strings or other legacy formats
1878
+ *
1879
+ * @param response - Response in any supported format
1880
+ * @returns Extracted text content
1881
+ */
1882
+ declare function extractText(response: unknown): string;
1883
+
1884
+ /**
1885
+ * Types and interfaces for MCP host simulation mode
1886
+ *
1887
+ * This module provides types for testing MCP servers through MCP hosts,
1888
+ * validating tool descriptions, parameter clarity, and discoverability.
1889
+ */
1890
+
1891
+ /**
1892
+ * Host type for MCP host simulation.
1893
+ *
1894
+ * - 'sdk': Programmatic via Vercel AI SDK (default). The framework's MCP connection is reused.
1895
+ * - 'cli': CLI-based hosts (e.g., Claude Code, Codex). Spawns a process with its own MCP connection.
1896
+ * - 'browser': Web-based hosts (e.g., claude.ai). Uses Playwright/CDP. (Not yet implemented.)
1897
+ * - 'desktop': Desktop app hosts (e.g., Claude Desktop). Uses computer use. (Not yet implemented.)
1898
+ */
1899
+ type HostType = 'sdk' | 'cli' | 'browser' | 'desktop';
1900
+ /**
1901
+ * LLM provider for SDK-based host simulation.
1902
+ *
1903
+ * Each provider runs through the Vercel AI SDK (`ai` package)
1904
+ * and requires its corresponding @ai-sdk/* package:
1905
+ *
1906
+ * openai → npm install ai @ai-sdk/openai
1907
+ * anthropic → npm install ai @ai-sdk/anthropic
1908
+ * google → npm install ai @ai-sdk/google
1909
+ * azure → npm install ai @ai-sdk/azure
1910
+ * mistral → npm install ai @ai-sdk/mistral
1911
+ * deepseek → npm install ai @ai-sdk/deepseek
1912
+ * openrouter → npm install ai @openrouter/ai-sdk-provider
1913
+ * xai → npm install ai @ai-sdk/xai
1914
+ */
1915
+ type LLMProvider = 'openai' | 'anthropic' | 'azure' | 'google' | 'mistral' | 'deepseek' | 'openrouter' | 'xai'
1916
+ /**
1917
+ * Anthropic Claude via Google Vertex AI.
1918
+ * Requires @ai-sdk/google-vertex and Application Default Credentials (gcloud auth).
1919
+ * Set GOOGLE_VERTEX_PROJECT and GOOGLE_VERTEX_LOCATION env vars.
1920
+ * Use this instead of 'anthropic' in environments where api.anthropic.com is blocked.
1921
+ * @example model: 'claude-3-5-haiku@20241022'
1922
+ */
1923
+ | 'vertex-anthropic';
1924
+ /**
1925
+ * Output format for CLI host processes.
1926
+ *
1927
+ * - 'stream-json': NDJSON (one JSON object per line). Used by Claude Code (`--output-format stream-json`).
1928
+ * - 'json': Single JSON object on stdout.
1929
+ */
1930
+ type CLIOutputFormat = 'stream-json' | 'json';
1931
+ /**
1932
+ * Configuration for a CLI host process.
1933
+ *
1934
+ * The process is spawned directly (no shell) with `command` and `args`.
1935
+ * Use `{{scenario}}` in any args entry as a placeholder for the natural
1936
+ * language prompt — the framework replaces it before spawning.
1937
+ *
1938
+ * Because args are passed directly to the process (not through a shell),
1939
+ * special characters in the scenario (quotes, newlines, `$`, etc.) are
1940
+ * handled safely without escaping.
1941
+ *
1942
+ * @example Claude Code
1943
+ * ```json
1944
+ * {
1945
+ * "command": "claude",
1946
+ * "args": ["-p", "{{scenario}}", "--output-format", "stream-json",
1947
+ * "--verbose", "--mcp-config", "{...}"]
1948
+ * }
1949
+ * ```
1950
+ *
1951
+ * @example Custom CLI
1952
+ * ```json
1953
+ * {
1954
+ * "command": "my-agent",
1955
+ * "args": ["--prompt", "{{scenario}}", "--config", "./mcp.json"],
1956
+ * "outputFormat": "json"
1957
+ * }
1958
+ * ```
1959
+ */
1960
+ interface CLIConfig {
1961
+ /**
1962
+ * CLI binary to invoke.
1963
+ */
1964
+ command: string;
1965
+ /**
1966
+ * Arguments to pass. Use `{{scenario}}` as a placeholder for the prompt.
1967
+ */
1968
+ args: string[];
1969
+ /**
1970
+ * How to parse stdout.
1971
+ * @default 'stream-json'
1972
+ */
1973
+ outputFormat?: CLIOutputFormat;
1974
+ /**
1975
+ * Timeout in milliseconds.
1976
+ * @default 120000 (2 minutes)
1977
+ */
1978
+ timeout?: number;
1979
+ }
1980
+ /**
1981
+ * A cookie to inject into the browser context before running the script.
1982
+ * Matches the shape expected by Playwright's `BrowserContext.addCookies()`.
1983
+ */
1984
+ interface BrowserCookie {
1985
+ name: string;
1986
+ value: string;
1987
+ url?: string;
1988
+ domain?: string;
1989
+ path?: string;
1990
+ expires?: number;
1991
+ httpOnly?: boolean;
1992
+ secure?: boolean;
1993
+ sameSite?: 'Strict' | 'Lax' | 'None';
1994
+ partitionKey?: string;
1995
+ }
1996
+ /**
1997
+ * Configuration for a browser-based host.
1998
+ *
1999
+ * Uses Playwright to launch a Chromium instance, inject auth state,
2000
+ * and execute a user-provided script that drives a web-based MCP host
2001
+ * (e.g., claude.ai).
2002
+ */
2003
+ interface BrowserConfig {
2004
+ /**
2005
+ * Path to the browser script (resolved relative to cwd).
2006
+ * The script must default-export an async function
2007
+ * `(page: Page, scenario: string) => Promise<MCPHostSimulationResult>`.
2008
+ */
2009
+ script: string;
2010
+ /**
2011
+ * Timeout in milliseconds for the browser script.
2012
+ * @default 120000 (2 minutes)
2013
+ */
2014
+ timeout?: number;
2015
+ /**
2016
+ * Whether to launch in headless mode.
2017
+ * @default true
2018
+ */
2019
+ headless?: boolean;
2020
+ /**
2021
+ * Path to a Playwright storage state JSON file (cookies + localStorage).
2022
+ * Resolved relative to cwd.
2023
+ */
2024
+ storageState?: string;
2025
+ /**
2026
+ * Extra cookies to inject into the browser context.
2027
+ */
2028
+ cookies?: BrowserCookie[];
2029
+ }
2030
+ /**
2031
+ * Configuration for MCP host simulation
2032
+ */
2033
+ interface MCPHostConfig {
2034
+ /**
2035
+ * Host type for the simulation.
2036
+ *
2037
+ * - 'sdk': Programmatic via Vercel AI SDK (default). The framework's MCP connection is reused.
2038
+ * - 'cli': CLI-based hosts (e.g., Claude Code, Codex). Spawns a process with its own MCP connection.
2039
+ * - 'browser': Web-based hosts (not yet implemented).
2040
+ * - 'desktop': Desktop app hosts (not yet implemented).
2041
+ *
2042
+ * @default 'sdk'
2043
+ */
2044
+ hostType?: HostType;
2045
+ /**
2046
+ * LLM provider (required for 'sdk' host type, ignored for 'cli')
2047
+ */
2048
+ provider?: LLMProvider;
2049
+ /**
2050
+ * Environment variable name containing the API key
2051
+ */
2052
+ apiKeyEnvVar?: string;
2053
+ /**
2054
+ * Model to use (provider-specific default if omitted)
2055
+ */
2056
+ model?: string;
2057
+ /**
2058
+ * Maximum tokens for response
2059
+ */
2060
+ maxTokens?: number;
2061
+ /**
2062
+ * Temperature (0-1, lower is more deterministic)
2063
+ * @default 0
2064
+ */
2065
+ temperature?: number;
2066
+ /**
2067
+ * Maximum number of tool call steps to allow in a single conversation
2068
+ * @default 10
2069
+ */
2070
+ maxToolCalls?: number;
2071
+ /**
2072
+ * CLI host configuration (required for 'cli' host type).
2073
+ */
2074
+ cli?: CLIConfig;
2075
+ /**
2076
+ * Browser host configuration (required for 'browser' host type).
2077
+ */
2078
+ browser?: BrowserConfig;
2079
+ }
2080
+ /**
2081
+ * A tool call made by the LLM
2082
+ */
2083
+ interface LLMToolCall {
2084
+ /** Tool name */
2085
+ name: string;
2086
+ /** Tool arguments (as provided by LLM) */
2087
+ arguments: Record<string, unknown>;
2088
+ /** Optional tool call ID (for tracking) */
2089
+ id?: string;
2090
+ }
2091
+ /**
2092
+ * Result from an MCP host simulation
2093
+ */
2094
+ interface MCPHostSimulationResult {
2095
+ /** Whether the simulation succeeded */
2096
+ success: boolean;
2097
+ /** Tool calls made by the LLM */
2098
+ toolCalls: Array<LLMToolCall>;
2099
+ /** Final response from the LLM */
2100
+ response?: string;
2101
+ /** Error message if simulation failed */
2102
+ error?: string;
2103
+ /** The scenario prompt that was given to the LLM */
2104
+ scenario?: string;
2105
+ /** The conversation turns for attribution analysis */
2106
+ conversationHistory?: Array<{
2107
+ role: 'user' | 'assistant' | 'tool';
2108
+ content: string;
2109
+ }>;
2110
+ /**
2111
+ * Milliseconds spent waiting for LLM responses
2112
+ * (excludes MCP tool execution time)
2113
+ */
2114
+ llmDurationMs?: number;
2115
+ /**
2116
+ * Milliseconds spent executing MCP tool calls
2117
+ * (excludes LLM response time)
2118
+ */
2119
+ mcpDurationMs?: number;
2120
+ /**
2121
+ * Token usage from the LLM during simulation.
2122
+ * Populated by SDK-based hosts from the AI SDK response.
2123
+ */
2124
+ usage?: UsageMetrics;
2125
+ }
2126
+ /**
2127
+ * Interface for MCP host simulators.
2128
+ *
2129
+ * The only built-in implementation is the Vercel AI SDK orchestrator
2130
+ * (src/evals/mcpHost/adapters/vercel.ts). Custom implementations can be
2131
+ * created for specialised testing needs.
2132
+ */
2133
+ interface MCPHostSimulator {
2134
+ /**
2135
+ * Simulates an MCP host interacting with an MCP server
2136
+ *
2137
+ * @param mcp - MCP fixture API
2138
+ * @param scenario - Natural language prompt describing what the LLM should do
2139
+ * @param config - MCP host configuration
2140
+ * @returns Simulation result with tool calls and response
2141
+ */
2142
+ simulate(mcp: MCPFixtureApi, scenario: string, config: MCPHostConfig): Promise<MCPHostSimulationResult>;
2143
+ }
2144
+
2145
+ /**
2146
+ * Evaluation mode
2147
+ */
2148
+ type EvalMode = 'direct' | 'mcp_host';
2149
+ /**
2150
+ * A single eval test case
2151
+ *
2152
+ * For 'direct' mode: toolName and args are required
2153
+ * For 'mcp_host' mode: scenario and mcpHostConfig are required
2154
+ */
2155
+ interface EvalCase {
2156
+ /**
2157
+ * Unique identifier for this test case
2158
+ */
2159
+ id: string;
2160
+ /**
2161
+ * Human-readable description of what this test case validates
2162
+ */
2163
+ description?: string;
2164
+ /**
2165
+ * Evaluation mode
2166
+ * - 'direct': Direct API calls to MCP tools (default)
2167
+ * - 'mcp_host': LLM-driven tool selection via natural language
2168
+ *
2169
+ * @default 'direct'
2170
+ */
2171
+ mode?: EvalMode;
2172
+ /**
2173
+ * Name of the MCP tool to call (required for 'direct' mode, optional for 'mcp_host' mode)
2174
+ */
2175
+ toolName?: string;
2176
+ /**
2177
+ * Arguments to pass to the tool (required for 'direct' mode, optional for 'mcp_host' mode)
2178
+ */
2179
+ args?: Record<string, unknown>;
2180
+ /**
2181
+ * Natural language scenario for LLM to execute (optional, required for 'mcp_host' mode)
2182
+ *
2183
+ * @example "Get the weather for London and tell me if I need an umbrella"
2184
+ */
2185
+ scenario?: string;
2186
+ /**
2187
+ * MCP host configuration (optional for 'mcp_host' mode)
2188
+ *
2189
+ * If not specified, uses default configuration from test environment
2190
+ */
2191
+ mcpHostConfig?: MCPHostConfig;
2192
+ /**
2193
+ * Additional metadata for this test case
2194
+ *
2195
+ * For 'mcp_host' mode, can include 'expectedToolCalls' for validation
2196
+ */
2197
+ metadata?: Record<string, unknown>;
2198
+ /**
2199
+ * Number of times to run this case and compute an assertion pass rate.
2200
+ * When > 1, `EvalCaseResult.assertionPassRate` is populated and `pass` is determined
2201
+ * by `accuracyThreshold` rather than a single run.
2202
+ * @default 1
2203
+ */
2204
+ iterations?: number;
2205
+ /**
2206
+ * Minimum accuracy (0–1) required to pass when `iterations > 1`.
2207
+ * @default 1.0 (all iterations must pass)
2208
+ */
2209
+ accuracyThreshold?: number;
2210
+ /**
2211
+ * Number of times to invoke the LLM judge per `passesJudge` assertion.
2212
+ * Scores are averaged; the mean must meet the threshold to pass.
2213
+ * Reduces judge variance caused by non-determinism.
2214
+ * Per-assertion `passesJudge.reps` overrides this value.
2215
+ * @default 1
2216
+ */
2217
+ judgeReps?: number;
2218
+ /**
2219
+ * Golden/expected answer for this case.
2220
+ * When set, automatically passed as `reference` to the LLM judge
2221
+ * (unless passesJudge.reference is explicitly provided).
2222
+ * Mirrors EvalV2's `canonical_answer` field.
2223
+ */
2224
+ canonicalAnswer?: string;
2225
+ /**
2226
+ * Arbitrary string labels for this case.
2227
+ * Use for filtering eval runs with `EvalRunnerOptions.filterTags`
2228
+ * and for slicing results by category.
2229
+ *
2230
+ * @example ['tool-finding', 'multi-hop', 'search']
2231
+ */
2232
+ tags?: string[];
2233
+ /**
2234
+ * Expectations to validate against the tool response
2235
+ *
2236
+ * Multiple expectations can be combined and will all be validated.
2237
+ *
2238
+ * @example
2239
+ * ```json
2240
+ * {
2241
+ * "id": "weather-london",
2242
+ * "toolName": "get_weather",
2243
+ * "args": { "city": "London" },
2244
+ * "expect": {
2245
+ * "containsText": ["temperature", "conditions"],
2246
+ * "schema": "WeatherResponse",
2247
+ * "responseSize": { "maxBytes": 10000 },
2248
+ * "isError": false
2249
+ * }
2250
+ * }
2251
+ * ```
2252
+ */
2253
+ expect?: EvalExpectBlock;
2254
+ }
2255
+ /**
2256
+ * Configuration for a single LLM-as-judge evaluation
2257
+ */
2258
+ interface JudgeExpectConfig {
2259
+ /**
2260
+ * Name of a registered custom judge executor.
2261
+ * When set, the named judge handles evaluation and returns a normalized score.
2262
+ * The `threshold` determines pass/fail. `reps` and LLM config fields
2263
+ * (provider, model, etc.) are ignored.
2264
+ */
2265
+ judge?: string;
2266
+ /** Built-in rubric name or custom rubric object. Required when no `judge` is specified. */
2267
+ rubric?: BuiltInRubric | {
2268
+ text: string;
2269
+ };
2270
+ /** Reference response to compare against */
2271
+ reference?: unknown;
2272
+ /** Score threshold for passing (0-1, default: 0.7) */
2273
+ threshold?: number;
2274
+ /** Number of judge evaluations for this assertion. Overrides EvalCase.judgeReps. */
2275
+ reps?: number;
2276
+ /** Judge provider. @default 'anthropic' */
2277
+ provider?: 'anthropic' | 'vertex-anthropic' | 'anthropic-agent-sdk' | 'openai' | 'google';
2278
+ /** Model override (e.g., 'claude-opus-4-20250514') */
2279
+ model?: string;
2280
+ /** Environment variable name for API key */
2281
+ apiKeyEnvVar?: string;
2282
+ /** Max tokens for judge response */
2283
+ maxTokens?: number;
2284
+ /** Temperature for judge LLM (0–1) */
2285
+ temperature?: number;
2286
+ /** Max budget in USD per evaluation */
2287
+ maxBudgetUsd?: number;
2288
+ /** Fail if response exceeds this size in bytes before judging */
2289
+ maxToolOutputSize?: number;
2290
+ }
2291
+ /**
2292
+ * Unified expectation block for eval cases
2293
+ *
2294
+ * Mirrors the Playwright matcher API for consistency.
2295
+ */
2296
+ interface EvalExpectBlock {
2297
+ /**
2298
+ * Exact response match (toMatchToolResponse)
2299
+ */
2300
+ response?: unknown;
2301
+ /**
2302
+ * Name of schema to validate against (toMatchToolSchema)
2303
+ */
2304
+ schema?: string;
2305
+ /**
2306
+ * Text substring(s) that must be present (toContainToolText)
2307
+ */
2308
+ containsText?: string | string[];
2309
+ /**
2310
+ * Regex pattern(s) that must match (toMatchToolPattern)
2311
+ */
2312
+ matchesPattern?: string | string[];
2313
+ /**
2314
+ * Snapshot name for comparison (toMatchToolSnapshot)
2315
+ */
2316
+ snapshot?: string;
2317
+ /**
2318
+ * Snapshot sanitizers to apply
2319
+ */
2320
+ snapshotSanitizers?: SnapshotSanitizer[];
2321
+ /**
2322
+ * Error expectation (toBeToolError)
2323
+ * - true: expects any error
2324
+ * - false: expects no error
2325
+ * - string: expects error containing this message
2326
+ */
2327
+ isError?: boolean | string | string[];
2328
+ /**
2329
+ * LLM-as-judge evaluation (toPassToolJudge)
2330
+ *
2331
+ * Accepts a single judge config or an array for multi-judge evaluation.
2332
+ * When an array is provided, all judges must pass (AND semantics).
2333
+ */
2334
+ passesJudge?: JudgeExpectConfig | JudgeExpectConfig[];
2335
+ /**
2336
+ * Response size validation (toHaveToolResponseSize)
2337
+ */
2338
+ responseSize?: {
2339
+ /** Maximum allowed size in bytes */
2340
+ maxBytes?: number;
2341
+ /** Minimum required size in bytes */
2342
+ minBytes?: number;
2343
+ };
2344
+ /**
2345
+ * Asserts which tools the LLM called during a mcp_host simulation.
2346
+ * Only meaningful for mcp_host mode — direct mode has no tool call trace.
2347
+ */
2348
+ toolsTriggered?: {
2349
+ /** Expected tool calls */
2350
+ calls: Array<{
2351
+ /** Tool name */
2352
+ name: string;
2353
+ /** Expected arguments (partial match — extra keys are allowed) */
2354
+ arguments?: Record<string, unknown>;
2355
+ /** Whether this call MUST have been made (default: true) */
2356
+ required?: boolean;
2357
+ }>;
2358
+ /**
2359
+ * 'strict': calls must appear in the exact order listed
2360
+ * 'any': calls can appear in any order (default)
2361
+ */
2362
+ order?: 'strict' | 'any';
2363
+ /** If true, no tool calls outside the `calls` list are allowed */
2364
+ exclusive?: boolean;
2365
+ };
2366
+ /**
2367
+ * Asserts the number of tool calls made during a mcp_host simulation.
2368
+ */
2369
+ toolCallCount?: {
2370
+ /** Minimum number of tool calls */
2371
+ min?: number;
2372
+ /** Maximum number of tool calls */
2373
+ max?: number;
2374
+ /** Exact number of tool calls */
2375
+ exact?: number;
2376
+ };
2377
+ }
2378
+ /**
2379
+ * A complete eval dataset containing multiple test cases
2380
+ */
2381
+ interface EvalDataset {
2382
+ /**
2383
+ * Dataset name
2384
+ */
2385
+ name: string;
2386
+ /**
2387
+ * Dataset description
2388
+ */
2389
+ description?: string;
2390
+ /**
2391
+ * Test cases in this dataset
2392
+ */
2393
+ cases: Array<EvalCase>;
2394
+ /**
2395
+ * Optional schema definitions referenced by test cases
2396
+ */
2397
+ schemas?: Record<string, z.ZodSchema>;
2398
+ /**
2399
+ * Additional dataset metadata
2400
+ */
2401
+ metadata?: Record<string, unknown>;
2402
+ }
2403
+ /**
2404
+ * Zod schema for EvalCase
2405
+ *
2406
+ * toolName and args are optional for mcp_host mode (which uses scenario instead)
2407
+ */
2408
+ declare const EvalCaseSchema: z.ZodObject<{
2409
+ id: z.ZodString;
2410
+ description: z.ZodOptional<z.ZodString>;
2411
+ mode: z.ZodOptional<z.ZodEnum<{
2412
+ direct: "direct";
2413
+ mcp_host: "mcp_host";
2414
+ }>>;
2415
+ toolName: z.ZodOptional<z.ZodString>;
2416
+ args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2417
+ scenario: z.ZodOptional<z.ZodString>;
2418
+ mcpHostConfig: z.ZodOptional<z.ZodObject<{
2419
+ hostType: z.ZodOptional<z.ZodEnum<{
2420
+ sdk: "sdk";
2421
+ cli: "cli";
2422
+ browser: "browser";
2423
+ desktop: "desktop";
2424
+ }>>;
2425
+ provider: z.ZodOptional<z.ZodEnum<{
2426
+ openai: "openai";
2427
+ anthropic: "anthropic";
2428
+ azure: "azure";
2429
+ google: "google";
2430
+ mistral: "mistral";
2431
+ deepseek: "deepseek";
2432
+ openrouter: "openrouter";
2433
+ xai: "xai";
2434
+ "vertex-anthropic": "vertex-anthropic";
2435
+ }>>;
2436
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2437
+ model: z.ZodOptional<z.ZodString>;
2438
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2439
+ temperature: z.ZodOptional<z.ZodNumber>;
2440
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
2441
+ cli: z.ZodOptional<z.ZodObject<{
2442
+ command: z.ZodString;
2443
+ args: z.ZodArray<z.ZodString>;
2444
+ outputFormat: z.ZodOptional<z.ZodEnum<{
2445
+ "stream-json": "stream-json";
2446
+ json: "json";
2447
+ }>>;
2448
+ timeout: z.ZodOptional<z.ZodNumber>;
2449
+ }, z.core.$strip>>;
2450
+ }, z.core.$strip>>;
2451
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2452
+ iterations: z.ZodOptional<z.ZodNumber>;
2453
+ accuracyThreshold: z.ZodOptional<z.ZodNumber>;
2454
+ judgeReps: z.ZodOptional<z.ZodNumber>;
2455
+ canonicalAnswer: z.ZodOptional<z.ZodString>;
2456
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2457
+ expect: z.ZodOptional<z.ZodObject<{
2458
+ response: z.ZodOptional<z.ZodUnknown>;
2459
+ schema: z.ZodOptional<z.ZodString>;
2460
+ containsText: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
2461
+ matchesPattern: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
2462
+ snapshot: z.ZodOptional<z.ZodString>;
2463
+ snapshotSanitizers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
2464
+ timestamp: "timestamp";
2465
+ uuid: "uuid";
2466
+ "iso-date": "iso-date";
2467
+ objectId: "objectId";
2468
+ jwt: "jwt";
2469
+ }>, z.ZodObject<{
2470
+ pattern: z.ZodString;
2471
+ replacement: z.ZodOptional<z.ZodString>;
2472
+ }, z.core.$strip>, z.ZodObject<{
2473
+ remove: z.ZodArray<z.ZodString>;
2474
+ }, z.core.$strip>]>>>;
2475
+ isError: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString, z.ZodArray<z.ZodString>]>>;
2476
+ passesJudge: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
2477
+ judge: z.ZodOptional<z.ZodString>;
2478
+ rubric: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2479
+ correctness: "correctness";
2480
+ completeness: "completeness";
2481
+ groundedness: "groundedness";
2482
+ "instruction-following": "instruction-following";
2483
+ conciseness: "conciseness";
2484
+ }>, z.ZodObject<{
2485
+ text: z.ZodString;
2486
+ }, z.core.$strip>]>>;
2487
+ reference: z.ZodOptional<z.ZodUnknown>;
2488
+ threshold: z.ZodOptional<z.ZodNumber>;
2489
+ reps: z.ZodOptional<z.ZodNumber>;
2490
+ provider: z.ZodOptional<z.ZodEnum<{
2491
+ openai: "openai";
2492
+ anthropic: "anthropic";
2493
+ google: "google";
2494
+ "vertex-anthropic": "vertex-anthropic";
2495
+ "anthropic-agent-sdk": "anthropic-agent-sdk";
2496
+ }>>;
2497
+ model: z.ZodOptional<z.ZodString>;
2498
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2499
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2500
+ temperature: z.ZodOptional<z.ZodNumber>;
2501
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
2502
+ maxToolOutputSize: z.ZodOptional<z.ZodNumber>;
2503
+ }, z.core.$strip>, z.ZodArray<z.ZodObject<{
2504
+ judge: z.ZodOptional<z.ZodString>;
2505
+ rubric: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2506
+ correctness: "correctness";
2507
+ completeness: "completeness";
2508
+ groundedness: "groundedness";
2509
+ "instruction-following": "instruction-following";
2510
+ conciseness: "conciseness";
2511
+ }>, z.ZodObject<{
2512
+ text: z.ZodString;
2513
+ }, z.core.$strip>]>>;
2514
+ reference: z.ZodOptional<z.ZodUnknown>;
2515
+ threshold: z.ZodOptional<z.ZodNumber>;
2516
+ reps: z.ZodOptional<z.ZodNumber>;
2517
+ provider: z.ZodOptional<z.ZodEnum<{
2518
+ openai: "openai";
2519
+ anthropic: "anthropic";
2520
+ google: "google";
2521
+ "vertex-anthropic": "vertex-anthropic";
2522
+ "anthropic-agent-sdk": "anthropic-agent-sdk";
2523
+ }>>;
2524
+ model: z.ZodOptional<z.ZodString>;
2525
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2526
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2527
+ temperature: z.ZodOptional<z.ZodNumber>;
2528
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
2529
+ maxToolOutputSize: z.ZodOptional<z.ZodNumber>;
2530
+ }, z.core.$strip>>]>>;
2531
+ responseSize: z.ZodOptional<z.ZodObject<{
2532
+ maxBytes: z.ZodOptional<z.ZodNumber>;
2533
+ minBytes: z.ZodOptional<z.ZodNumber>;
2534
+ }, z.core.$strip>>;
2535
+ toolsTriggered: z.ZodOptional<z.ZodObject<{
2536
+ calls: z.ZodArray<z.ZodObject<{
2537
+ name: z.ZodString;
2538
+ arguments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2539
+ required: z.ZodOptional<z.ZodBoolean>;
2540
+ }, z.core.$strip>>;
2541
+ order: z.ZodOptional<z.ZodEnum<{
2542
+ strict: "strict";
2543
+ any: "any";
2544
+ }>>;
2545
+ exclusive: z.ZodOptional<z.ZodBoolean>;
2546
+ }, z.core.$strip>>;
2547
+ toolCallCount: z.ZodOptional<z.ZodObject<{
2548
+ min: z.ZodOptional<z.ZodNumber>;
2549
+ max: z.ZodOptional<z.ZodNumber>;
2550
+ exact: z.ZodOptional<z.ZodNumber>;
2551
+ }, z.core.$strip>>;
2552
+ }, z.core.$strip>>;
2553
+ }, z.core.$strip>;
2554
+ /**
2555
+ * Zod schema for EvalDataset (without schemas field, as schemas aren't serializable)
2556
+ */
2557
+ declare const EvalDatasetSchema: z.ZodObject<{
2558
+ name: z.ZodString;
2559
+ description: z.ZodOptional<z.ZodString>;
2560
+ cases: z.ZodArray<z.ZodObject<{
2561
+ id: z.ZodString;
2562
+ description: z.ZodOptional<z.ZodString>;
2563
+ mode: z.ZodOptional<z.ZodEnum<{
2564
+ direct: "direct";
2565
+ mcp_host: "mcp_host";
2566
+ }>>;
2567
+ toolName: z.ZodOptional<z.ZodString>;
2568
+ args: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2569
+ scenario: z.ZodOptional<z.ZodString>;
2570
+ mcpHostConfig: z.ZodOptional<z.ZodObject<{
2571
+ hostType: z.ZodOptional<z.ZodEnum<{
2572
+ sdk: "sdk";
2573
+ cli: "cli";
2574
+ browser: "browser";
2575
+ desktop: "desktop";
2576
+ }>>;
2577
+ provider: z.ZodOptional<z.ZodEnum<{
2578
+ openai: "openai";
2579
+ anthropic: "anthropic";
2580
+ azure: "azure";
2581
+ google: "google";
2582
+ mistral: "mistral";
2583
+ deepseek: "deepseek";
2584
+ openrouter: "openrouter";
2585
+ xai: "xai";
2586
+ "vertex-anthropic": "vertex-anthropic";
2587
+ }>>;
2588
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2589
+ model: z.ZodOptional<z.ZodString>;
2590
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2591
+ temperature: z.ZodOptional<z.ZodNumber>;
2592
+ maxToolCalls: z.ZodOptional<z.ZodNumber>;
2593
+ cli: z.ZodOptional<z.ZodObject<{
2594
+ command: z.ZodString;
2595
+ args: z.ZodArray<z.ZodString>;
2596
+ outputFormat: z.ZodOptional<z.ZodEnum<{
2597
+ "stream-json": "stream-json";
2598
+ json: "json";
2599
+ }>>;
2600
+ timeout: z.ZodOptional<z.ZodNumber>;
2601
+ }, z.core.$strip>>;
2602
+ }, z.core.$strip>>;
2603
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2604
+ iterations: z.ZodOptional<z.ZodNumber>;
2605
+ accuracyThreshold: z.ZodOptional<z.ZodNumber>;
2606
+ judgeReps: z.ZodOptional<z.ZodNumber>;
2607
+ canonicalAnswer: z.ZodOptional<z.ZodString>;
2608
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2609
+ expect: z.ZodOptional<z.ZodObject<{
2610
+ response: z.ZodOptional<z.ZodUnknown>;
2611
+ schema: z.ZodOptional<z.ZodString>;
2612
+ containsText: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
2613
+ matchesPattern: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
2614
+ snapshot: z.ZodOptional<z.ZodString>;
2615
+ snapshotSanitizers: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
2616
+ timestamp: "timestamp";
2617
+ uuid: "uuid";
2618
+ "iso-date": "iso-date";
2619
+ objectId: "objectId";
2620
+ jwt: "jwt";
2621
+ }>, z.ZodObject<{
2622
+ pattern: z.ZodString;
2623
+ replacement: z.ZodOptional<z.ZodString>;
2624
+ }, z.core.$strip>, z.ZodObject<{
2625
+ remove: z.ZodArray<z.ZodString>;
2626
+ }, z.core.$strip>]>>>;
2627
+ isError: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString, z.ZodArray<z.ZodString>]>>;
2628
+ passesJudge: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
2629
+ judge: z.ZodOptional<z.ZodString>;
2630
+ rubric: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2631
+ correctness: "correctness";
2632
+ completeness: "completeness";
2633
+ groundedness: "groundedness";
2634
+ "instruction-following": "instruction-following";
2635
+ conciseness: "conciseness";
2636
+ }>, z.ZodObject<{
2637
+ text: z.ZodString;
2638
+ }, z.core.$strip>]>>;
2639
+ reference: z.ZodOptional<z.ZodUnknown>;
2640
+ threshold: z.ZodOptional<z.ZodNumber>;
2641
+ reps: z.ZodOptional<z.ZodNumber>;
2642
+ provider: z.ZodOptional<z.ZodEnum<{
2643
+ openai: "openai";
2644
+ anthropic: "anthropic";
2645
+ google: "google";
2646
+ "vertex-anthropic": "vertex-anthropic";
2647
+ "anthropic-agent-sdk": "anthropic-agent-sdk";
2648
+ }>>;
2649
+ model: z.ZodOptional<z.ZodString>;
2650
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2651
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2652
+ temperature: z.ZodOptional<z.ZodNumber>;
2653
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
2654
+ maxToolOutputSize: z.ZodOptional<z.ZodNumber>;
2655
+ }, z.core.$strip>, z.ZodArray<z.ZodObject<{
2656
+ judge: z.ZodOptional<z.ZodString>;
2657
+ rubric: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2658
+ correctness: "correctness";
2659
+ completeness: "completeness";
2660
+ groundedness: "groundedness";
2661
+ "instruction-following": "instruction-following";
2662
+ conciseness: "conciseness";
2663
+ }>, z.ZodObject<{
2664
+ text: z.ZodString;
2665
+ }, z.core.$strip>]>>;
2666
+ reference: z.ZodOptional<z.ZodUnknown>;
2667
+ threshold: z.ZodOptional<z.ZodNumber>;
2668
+ reps: z.ZodOptional<z.ZodNumber>;
2669
+ provider: z.ZodOptional<z.ZodEnum<{
2670
+ openai: "openai";
2671
+ anthropic: "anthropic";
2672
+ google: "google";
2673
+ "vertex-anthropic": "vertex-anthropic";
2674
+ "anthropic-agent-sdk": "anthropic-agent-sdk";
2675
+ }>>;
2676
+ model: z.ZodOptional<z.ZodString>;
2677
+ apiKeyEnvVar: z.ZodOptional<z.ZodString>;
2678
+ maxTokens: z.ZodOptional<z.ZodNumber>;
2679
+ temperature: z.ZodOptional<z.ZodNumber>;
2680
+ maxBudgetUsd: z.ZodOptional<z.ZodNumber>;
2681
+ maxToolOutputSize: z.ZodOptional<z.ZodNumber>;
2682
+ }, z.core.$strip>>]>>;
2683
+ responseSize: z.ZodOptional<z.ZodObject<{
2684
+ maxBytes: z.ZodOptional<z.ZodNumber>;
2685
+ minBytes: z.ZodOptional<z.ZodNumber>;
2686
+ }, z.core.$strip>>;
2687
+ toolsTriggered: z.ZodOptional<z.ZodObject<{
2688
+ calls: z.ZodArray<z.ZodObject<{
2689
+ name: z.ZodString;
2690
+ arguments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2691
+ required: z.ZodOptional<z.ZodBoolean>;
2692
+ }, z.core.$strip>>;
2693
+ order: z.ZodOptional<z.ZodEnum<{
2694
+ strict: "strict";
2695
+ any: "any";
2696
+ }>>;
2697
+ exclusive: z.ZodOptional<z.ZodBoolean>;
2698
+ }, z.core.$strip>>;
2699
+ toolCallCount: z.ZodOptional<z.ZodObject<{
2700
+ min: z.ZodOptional<z.ZodNumber>;
2701
+ max: z.ZodOptional<z.ZodNumber>;
2702
+ exact: z.ZodOptional<z.ZodNumber>;
2703
+ }, z.core.$strip>>;
2704
+ }, z.core.$strip>>;
2705
+ }, z.core.$strip>>;
2706
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2707
+ }, z.core.$strip>;
2708
+ /**
2709
+ * Type for serialized eval dataset (without Zod schemas)
2710
+ */
2711
+ type SerializedEvalDataset = z.infer<typeof EvalDatasetSchema>;
2712
+ /**
2713
+ * Validates an eval case
2714
+ *
2715
+ * @param evalCase - The eval case to validate
2716
+ * @returns The validated eval case
2717
+ * @throws {z.ZodError} If validation fails
2718
+ */
2719
+ declare function validateEvalCase(evalCase: unknown): EvalCase;
2720
+ /**
2721
+ * Validates a serialized eval dataset
2722
+ *
2723
+ * @param dataset - The dataset to validate
2724
+ * @returns The validated dataset
2725
+ * @throws {z.ZodError} If validation fails
2726
+ */
2727
+ declare function validateEvalDataset(dataset: unknown): SerializedEvalDataset;
2728
+
2729
+ /**
2730
+ * Options for loading an eval dataset
2731
+ */
2732
+ interface LoadDatasetOptions {
2733
+ /**
2734
+ * Optional schema definitions to attach to the dataset
2735
+ *
2736
+ * Keys should match the expectedSchemaName in eval cases
2737
+ */
2738
+ schemas?: Record<string, z.ZodSchema>;
2739
+ /**
2740
+ * Whether to validate the loaded dataset
2741
+ * @default true
2742
+ */
2743
+ validate?: boolean;
2744
+ }
2745
+ /**
2746
+ * Loads an eval dataset from a JSON file
2747
+ *
2748
+ * @param filePath - Absolute path to the JSON file
2749
+ * @param options - Load options
2750
+ * @returns The loaded and validated dataset
2751
+ * @throws {Error} If file cannot be read or JSON is invalid
2752
+ * @throws {z.ZodError} If validation fails
2753
+ *
2754
+ * @example
2755
+ * const dataset = await loadEvalDataset('./data/my-evals.json', {
2756
+ * schemas: {
2757
+ * 'weather-response': WeatherResponseSchema,
2758
+ * },
2759
+ * });
2760
+ */
2761
+ declare function loadEvalDataset(filePath: string, options?: LoadDatasetOptions): Promise<EvalDataset>;
2762
+ /**
2763
+ * Loads an eval dataset from a plain object
2764
+ *
2765
+ * Useful for programmatically creating datasets in tests
2766
+ *
2767
+ * @param data - The dataset data
2768
+ * @param options - Load options
2769
+ * @returns The loaded and validated dataset
2770
+ * @throws {z.ZodError} If validation fails
2771
+ *
2772
+ * @example
2773
+ * const dataset = loadEvalDatasetFromObject({
2774
+ * name: 'my-test-dataset',
2775
+ * cases: [
2776
+ * {
2777
+ * id: 'case-1',
2778
+ * toolName: 'get_weather',
2779
+ * args: { city: 'London' },
2780
+ * },
2781
+ * ],
2782
+ * });
2783
+ */
2784
+ declare function loadEvalDatasetFromObject(data: unknown, options?: LoadDatasetOptions): EvalDataset;
2785
+
2786
+ type StoredArtifactKind = 'eval-runner-result' | 'reporter-run' | 'eval-run-comparison' | 'server-comparison';
2787
+ interface StoredEvalArtifactMetadata {
2788
+ datasetName?: string;
2789
+ gitHash?: string;
2790
+ branch?: string;
2791
+ runNumber?: string;
2792
+ trigger?: string;
2793
+ packageVersion?: string;
2794
+ toolOverrideVariantId?: string;
2795
+ mcpHostModel?: string;
2796
+ judgeModel?: string;
2797
+ labels?: Record<string, string>;
2798
+ [key: string]: unknown;
2799
+ }
2800
+ interface StoredEvalArtifact<T> {
2801
+ schemaVersion: 1;
2802
+ kind: StoredArtifactKind;
2803
+ id: string;
2804
+ createdAt: string;
2805
+ metadata: StoredEvalArtifactMetadata;
2806
+ data: T;
2807
+ }
2808
+ interface StoredArtifactSummary {
2809
+ kind: StoredArtifactKind;
2810
+ id: string;
2811
+ createdAt: string;
2812
+ metadata: StoredEvalArtifactMetadata;
2813
+ }
2814
+ interface ListStoredArtifactsOptions {
2815
+ limit?: number;
2816
+ }
2817
+ interface EvalResultStore {
2818
+ saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void>;
2819
+ loadArtifact<T>(kind: StoredArtifactKind, id: string): Promise<StoredEvalArtifact<T>>;
2820
+ loadLatestArtifact<T>(kind: StoredArtifactKind): Promise<StoredEvalArtifact<T> | null>;
2821
+ listArtifacts(kind: StoredArtifactKind, options?: ListStoredArtifactsOptions): Promise<StoredArtifactSummary[]>;
2822
+ }
2823
+ interface FileEvalResultStoreConfig {
2824
+ provider: 'file';
2825
+ dir: string;
2826
+ }
2827
+ interface GCSEvalResultStoreConfig {
2828
+ provider: 'gcs';
2829
+ bucket: string;
2830
+ prefix?: string;
2831
+ }
2832
+ type EvalResultStoreConfig = FileEvalResultStoreConfig | GCSEvalResultStoreConfig;
2833
+ type EvalResultStoreLike = EvalResultStore | EvalResultStoreConfig;
2834
+ declare function createEvalResultStore(config: EvalResultStoreConfig): EvalResultStore;
2835
+ declare function resolveEvalResultStore(store: EvalResultStoreLike): EvalResultStore;
2836
+ declare function isEvalResultStore(value: unknown): value is EvalResultStore;
2837
+ declare function createStoredEvalArtifact<T>(options: {
2838
+ kind: StoredArtifactKind;
2839
+ data: T;
2840
+ id?: string;
2841
+ metadata?: StoredEvalArtifactMetadata;
2842
+ createdAt?: string;
2843
+ }): StoredEvalArtifact<T>;
2844
+ declare function createDefaultArtifactId(timestamp?: string): string;
2845
+ declare function defaultEnvironmentMetadata(): StoredEvalArtifactMetadata;
2846
+ declare class FileEvalResultStore implements EvalResultStore {
2847
+ private readonly dir;
2848
+ constructor(config: FileEvalResultStoreConfig);
2849
+ saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void>;
2850
+ loadArtifact<T>(kind: StoredArtifactKind, id: string): Promise<StoredEvalArtifact<T>>;
2851
+ loadLatestArtifact<T>(kind: StoredArtifactKind): Promise<StoredEvalArtifact<T> | null>;
2852
+ listArtifacts(kind: StoredArtifactKind, options?: ListStoredArtifactsOptions): Promise<StoredArtifactSummary[]>;
2853
+ }
2854
+ declare class GCSEvalResultStore implements EvalResultStore {
2855
+ private readonly bucketName;
2856
+ private readonly prefix;
2857
+ private storage;
2858
+ constructor(config: GCSEvalResultStoreConfig);
2859
+ saveArtifact<T>(artifact: StoredEvalArtifact<T>): Promise<void>;
2860
+ loadArtifact<T>(kind: StoredArtifactKind, id: string): Promise<StoredEvalArtifact<T>>;
2861
+ loadLatestArtifact<T>(kind: StoredArtifactKind): Promise<StoredEvalArtifact<T> | null>;
2862
+ listArtifacts(kind: StoredArtifactKind, options?: ListStoredArtifactsOptions): Promise<StoredArtifactSummary[]>;
2863
+ private getBucket;
2864
+ private objectPath;
2865
+ }
2866
+
2867
+ /**
2868
+ * Reporter-specific type definitions
2869
+ *
2870
+ * These types are used by the MCP reporter and UI.
2871
+ *
2872
+ * @packageDocumentation
2873
+ */
2874
+
2875
+ /**
2876
+ * Configuration options for MCP Eval Reporter
2877
+ */
2878
+ interface MCPEvalReporterConfig {
2879
+ /**
2880
+ * Output directory for reports and historical data
2881
+ * @default '.mcp-test-results'
2882
+ */
2883
+ outputDir?: string;
2884
+ /**
2885
+ * Auto-open report in browser after test run
2886
+ * @default false
2887
+ */
2888
+ autoOpen?: boolean;
2889
+ /**
2890
+ * Number of historical runs to keep
2891
+ * @default 10
2892
+ */
2893
+ historyLimit?: number;
2894
+ /**
2895
+ * Suppress console output (report still generated)
2896
+ * @default false
2897
+ */
2898
+ quiet?: boolean;
2899
+ /**
2900
+ * Include auto-tracked MCP tool calls from tests without explicit eval results.
2901
+ * When true, any test using the MCP fixture will have its tool calls
2902
+ * included in the report, even without using runEvalCase/runEvalDataset.
2903
+ * When false, only tests with explicit eval results are included.
2904
+ * @default true
2905
+ */
2906
+ includeAutoTracking?: boolean;
2907
+ /**
2908
+ * Optional external result store for durable reporter run history.
2909
+ */
2910
+ resultStore?: EvalResultStoreLike;
2911
+ /**
2912
+ * Optional run ID for externally stored reporter results.
2913
+ * Defaults to a generated timestamp-based ID.
2914
+ */
2915
+ runId?: string;
2916
+ /**
2917
+ * Extra metadata to attach to externally stored reporter results.
2918
+ */
2919
+ runMetadata?: Record<string, unknown>;
2920
+ /**
2921
+ * When true, strips response payloads before storing reporter results externally.
2922
+ * Local report output is unchanged.
2923
+ * @default true
2924
+ */
2925
+ redactStoredResponses?: boolean;
2926
+ }
2927
+ /**
2928
+ * Experiment tracking metadata for an eval run
2929
+ */
2930
+ interface EvalRunMetadata {
2931
+ /** Git commit hash at time of run */
2932
+ gitHash?: string;
2933
+ /** ISO timestamp of the run */
2934
+ timestamp: string;
2935
+ /** Package version from package.json */
2936
+ packageVersion: string;
2937
+ /** Runtime tool override variant identifier, when one was used */
2938
+ toolOverrideVariantId?: string;
2939
+ /** MCP host model identifier (if mcp_host mode) */
2940
+ mcpHostModel?: string;
2941
+ /** Judge model identifier (if judge was used) */
2942
+ judgeModel?: string;
2943
+ }
2944
+ /**
2945
+ * Individual conformance check result
2946
+ */
2947
+ interface MCPConformanceCheck {
2948
+ /**
2949
+ * Check name (e.g., 'server_info_present', 'list_tools_succeeds')
2950
+ */
2951
+ name: string;
2952
+ /**
2953
+ * Whether the check passed
2954
+ */
2955
+ pass: boolean;
2956
+ /**
2957
+ * Human-readable message describing the result
2958
+ */
2959
+ message: string;
2960
+ }
2961
+ /**
2962
+ * Conformance check result as stored in reporter data
2963
+ */
2964
+ interface MCPConformanceResultData {
2965
+ /**
2966
+ * Test title where conformance check was run
2967
+ */
2968
+ testTitle: string;
2969
+ /**
2970
+ * Whether all checks passed
2971
+ */
2972
+ pass: boolean;
2973
+ /**
2974
+ * Individual check results
2975
+ */
2976
+ checks: MCPConformanceCheck[];
2977
+ /**
2978
+ * Server info if available
2979
+ */
2980
+ serverInfo?: {
2981
+ name?: string;
2982
+ version?: string;
2983
+ };
2984
+ /**
2985
+ * Number of tools discovered
2986
+ */
2987
+ toolCount: number;
2988
+ /**
2989
+ * Auth type used for this check
2990
+ */
2991
+ authType?: AuthType;
2992
+ /**
2993
+ * Project name
2994
+ */
2995
+ project?: string;
2996
+ }
2997
+ /**
2998
+ * Server capabilities data from mcp-list-tools attachment
2999
+ */
3000
+ interface MCPServerCapabilitiesData {
3001
+ /**
3002
+ * Test title where listTools was called
3003
+ */
3004
+ testTitle: string;
3005
+ /**
3006
+ * List of tools available on the server
3007
+ */
3008
+ tools: Array<{
3009
+ name: string;
3010
+ description?: string;
3011
+ }>;
3012
+ /**
3013
+ * Total number of tools
3014
+ */
3015
+ toolCount: number;
3016
+ /**
3017
+ * Auth type used for this test
3018
+ */
3019
+ authType?: AuthType;
3020
+ /**
3021
+ * Project name
3022
+ */
3023
+ project?: string;
3024
+ }
3025
+ /**
3026
+ * Result of a single iteration within a multi-iteration eval case
3027
+ */
3028
+ interface IterationResult {
3029
+ /** Whether this iteration passed */
3030
+ pass: boolean;
3031
+ /** Execution time for this iteration */
3032
+ durationMs: number;
3033
+ /** Error message if the iteration failed with an exception */
3034
+ error?: string;
3035
+ /** When true, this iteration failed due to network/infrastructure issues rather than an assertion failure */
3036
+ isInfrastructureError?: boolean;
3037
+ /**
3038
+ * Ordered trace of tool calls made by the LLM during this iteration (mcp_host mode only).
3039
+ * Captures what was actually called so you can distinguish "LLM didn't call the tool"
3040
+ * from "LLM called the wrong tool" from "tool was called but assertion failed".
3041
+ */
3042
+ mcpHostTrace?: {
3043
+ calls: Array<{
3044
+ name: string;
3045
+ arguments: Record<string, unknown>;
3046
+ status: 'expected' | 'unexpected';
3047
+ }>;
3048
+ missed: Array<{
3049
+ name: string;
3050
+ }>;
3051
+ };
3052
+ /** Token usage from mcp_host LLM simulation in this iteration */
3053
+ hostUsage?: UsageMetrics;
3054
+ }
3055
+ /**
3056
+ * Request data captured from the eval case input.
3057
+ * Preserves what was sent so results are self-contained for debugging.
3058
+ */
3059
+ interface EvalCaseRequest {
3060
+ /** Human-readable description of the case */
3061
+ description?: string;
3062
+ /** Runtime tool override variant identifier, when one was used */
3063
+ toolOverrideVariantId?: string;
3064
+ /** Tool arguments (direct mode) */
3065
+ args?: Record<string, unknown>;
3066
+ /** Natural language scenario sent to the LLM (mcp_host mode) */
3067
+ scenario?: string;
3068
+ /** LLM provider/model configuration (mcp_host mode) */
3069
+ mcpHostConfig?: {
3070
+ provider?: string;
3071
+ model?: string;
3072
+ };
3073
+ }
3074
+ /**
3075
+ * Result of a single eval case
3076
+ */
3077
+ interface EvalCaseResult {
3078
+ /**
3079
+ * Case ID
3080
+ */
3081
+ id: string;
3082
+ /**
3083
+ * Dataset name this case belongs to
3084
+ */
3085
+ datasetName: string;
3086
+ /**
3087
+ * MCP tool name that was called
3088
+ */
3089
+ toolName: string;
3090
+ /**
3091
+ * Source of this result
3092
+ */
3093
+ source: ResultSource;
3094
+ /**
3095
+ * Overall pass/fail status
3096
+ */
3097
+ pass: boolean;
3098
+ /**
3099
+ * Request data from the eval case input (tool args, scenario, LLM config).
3100
+ * Populated so results are self-contained for debugging without the original dataset.
3101
+ */
3102
+ request?: EvalCaseRequest;
3103
+ /**
3104
+ * Tool response
3105
+ */
3106
+ response?: unknown;
3107
+ /**
3108
+ * Error if tool call failed
3109
+ */
3110
+ error?: string;
3111
+ /**
3112
+ * Expectation results
3113
+ */
3114
+ expectations: Partial<Record<ExpectationType, EvalExpectationResult>>;
3115
+ /**
3116
+ * Authentication type used for this test
3117
+ */
3118
+ authType?: AuthType;
3119
+ /**
3120
+ * Playwright project name this test belongs to
3121
+ */
3122
+ project?: string;
3123
+ /**
3124
+ * Execution time in milliseconds
3125
+ */
3126
+ durationMs: number;
3127
+ /**
3128
+ * Assertion pass rate (0–1): passes divided by non-infrastructure iterations.
3129
+ * Only present when the case was run with `iterations > 1`.
3130
+ *
3131
+ * Infrastructure errors (network timeouts, rate limits, etc.) are excluded from
3132
+ * the denominator so that environment reliability does not inflate this metric.
3133
+ */
3134
+ assertionPassRate?: number;
3135
+ /**
3136
+ * 95% Wilson score confidence interval for `assertionPassRate`.
3137
+ * Only present when the case was run with `iterations > 1`.
3138
+ *
3139
+ * Interpet as: the true pass rate is likely between `lower` and `upper`.
3140
+ * Wider intervals mean fewer iterations were run; run more iterations to narrow them.
3141
+ *
3142
+ * @example { lower: 0.35, upper: 0.93 } // 7/10 passes → 70% ± wide CI
3143
+ * @example { lower: 0.57, upper: 0.80 } // 35/50 passes → 70% ± narrow CI
3144
+ */
3145
+ assertionPassRateCI?: {
3146
+ /** Lower bound of the 95% confidence interval (0–1) */
3147
+ lower: number;
3148
+ /** Upper bound of the 95% confidence interval (0–1) */
3149
+ upper: number;
3150
+ };
3151
+ /**
3152
+ * Infrastructure error rate (0–1): infra errors divided by total iterations.
3153
+ * Only present when the case was run with `iterations > 1`.
3154
+ */
3155
+ infrastructureErrorRate?: number;
3156
+ /**
3157
+ * Per-iteration pass/fail breakdown.
3158
+ * Only present when the case was run with `iterations > 1`.
3159
+ */
3160
+ iterationResults?: Array<IterationResult>;
3161
+ /**
3162
+ * Tags from the source eval case, for filtering and slicing reports.
3163
+ */
3164
+ tags?: string[];
3165
+ /**
3166
+ * Precision of tool calls made (0–1).
3167
+ * 1.0 means every tool called was expected; <1.0 means unexpected tools were called.
3168
+ * Populated whenever a `toolsTriggered` expectation is evaluated.
3169
+ */
3170
+ toolPrecision?: number;
3171
+ /**
3172
+ * Recall of required tool calls (0–1).
3173
+ * 1.0 means all required tools were called; <1.0 means some were missed.
3174
+ * Only populated when toolsTriggered expectation was evaluated.
3175
+ */
3176
+ toolRecall?: number;
3177
+ /**
3178
+ * Pass/fail status of this case in the baseline run.
3179
+ * Only present when a baseline was provided to runEvalDataset.
3180
+ */
3181
+ baselinePass?: boolean;
3182
+ /**
3183
+ * Number of iterations that failed due to infrastructure errors (network, rate limits, etc.)
3184
+ * Only present when the case was run with `iterations > 1`.
3185
+ */
3186
+ infrastructureErrorCount?: number;
3187
+ /**
3188
+ * Ordered trace of tool calls made by the LLM in mcp_host mode.
3189
+ * Only populated when the eval case uses toolsTriggered expectations.
3190
+ */
3191
+ mcpHostTrace?: {
3192
+ /** The ordered sequence of tool calls made by the LLM */
3193
+ calls: Array<{
3194
+ name: string;
3195
+ arguments: Record<string, unknown>;
3196
+ /** 'expected' = was in the expected set, 'unexpected' = was not expected */
3197
+ status: 'expected' | 'unexpected';
3198
+ }>;
3199
+ /** Tools that were required but never called */
3200
+ missed: Array<{
3201
+ name: string;
3202
+ }>;
3203
+ };
3204
+ /**
3205
+ * Aggregate token usage from mcp_host LLM simulation for this case.
3206
+ * Summed across all iterations. Only populated for mcp_host mode cases.
3207
+ */
3208
+ hostUsage?: UsageMetrics;
3209
+ }
3210
+ /**
3211
+ * Aggregated MCP eval run data
3212
+ */
3213
+ interface MCPEvalRunData {
3214
+ /**
3215
+ * Run timestamp (ISO 8601)
3216
+ */
3217
+ timestamp: string;
3218
+ /**
3219
+ * Total duration in milliseconds
3220
+ */
3221
+ durationMs: number;
3222
+ /**
3223
+ * Environment info
3224
+ */
3225
+ environment: {
3226
+ ci: boolean;
3227
+ node: string;
3228
+ platform: string;
3229
+ };
3230
+ /**
3231
+ * Aggregate metrics
3232
+ */
3233
+ metrics: {
3234
+ /**
3235
+ * Total number of eval cases
3236
+ */
3237
+ total: number;
3238
+ /**
3239
+ * Number of passed cases
3240
+ */
3241
+ passed: number;
3242
+ /**
3243
+ * Number of failed cases
3244
+ */
3245
+ failed: number;
3246
+ /**
3247
+ * Pass rate (0-1)
3248
+ */
3249
+ passRate: number;
3250
+ /**
3251
+ * Dataset breakdown: dataset name -> count
3252
+ */
3253
+ datasetBreakdown: Record<string, number>;
3254
+ /**
3255
+ * Expectation type breakdown
3256
+ */
3257
+ expectationBreakdown: ExpectationBreakdown;
3258
+ /**
3259
+ * Aggregate token usage from all mcp_host LLM simulations in this run.
3260
+ */
3261
+ totalHostUsage?: UsageMetrics;
3262
+ };
3263
+ /**
3264
+ * All eval results from this run
3265
+ */
3266
+ results: EvalCaseResult[];
3267
+ /**
3268
+ * Conformance check results (optional)
3269
+ */
3270
+ conformanceChecks?: MCPConformanceResultData[];
3271
+ /**
3272
+ * Server capabilities discovered via listTools (optional)
3273
+ */
3274
+ serverCapabilities?: MCPServerCapabilitiesData[];
3275
+ }
3276
+ /**
3277
+ * Historical summary for trend charts
3278
+ */
3279
+ interface MCPEvalHistoricalSummary {
3280
+ timestamp: string;
3281
+ total: number;
3282
+ passed: number;
3283
+ failed: number;
3284
+ passRate: number;
3285
+ durationMs: number;
3286
+ }
3287
+ /**
3288
+ * Complete data structure passed to UI
3289
+ */
3290
+ interface MCPEvalData {
3291
+ runData: MCPEvalRunData;
3292
+ historical: MCPEvalHistoricalSummary[];
3293
+ }
3294
+
3295
+ /**
3296
+ * Context passed to the eval runner
3297
+ */
3298
+ interface EvalContext {
3299
+ /**
3300
+ * MCP fixture API for interacting with the server
3301
+ */
3302
+ mcp: MCPFixtureApi;
3303
+ /**
3304
+ * Optional Playwright TestInfo for reporter integration
3305
+ * When provided, eval results will be attached to the test for the MCP reporter
3306
+ */
3307
+ testInfo?: TestInfo;
3308
+ /**
3309
+ * Optional Playwright expect function for snapshot testing
3310
+ * Required for snapshot expectations to work properly
3311
+ */
3312
+ expect?: Expect;
3313
+ }
3314
+
3315
+ /**
3316
+ * Metadata overrides for a single existing MCP tool.
3317
+ */
3318
+ interface ToolMetadataOverride {
3319
+ /**
3320
+ * Replacement tool description shown to MCP hosts.
3321
+ */
3322
+ description?: string;
3323
+ /**
3324
+ * Replacement input schema shown to MCP hosts.
3325
+ */
3326
+ inputSchema?: Record<string, unknown>;
3327
+ }
3328
+ /**
3329
+ * Runtime metadata variant for experimenting with MCP tool discoverability.
3330
+ *
3331
+ * Tool keys are canonical MCP server tool names. Overrides affect only the
3332
+ * metadata returned from listTools(); callTool() still forwards canonical tool
3333
+ * names and arguments to the original MCP server.
3334
+ */
3335
+ interface ToolOverrideVariant {
3336
+ /**
3337
+ * Stable identifier for this runtime variant.
3338
+ */
3339
+ id: string;
3340
+ /**
3341
+ * Optional human-readable explanation of what this variant is testing.
3342
+ */
3343
+ description?: string;
3344
+ /**
3345
+ * Per-tool metadata overrides keyed by canonical tool name.
3346
+ */
3347
+ tools: Record<string, ToolMetadataOverride>;
3348
+ }
3349
+ /**
3350
+ * Overall result of running an eval dataset
3351
+ */
3352
+ interface EvalRunnerResult {
3353
+ /**
3354
+ * Total number of cases
3355
+ */
3356
+ total: number;
3357
+ /**
3358
+ * Number of passing cases
3359
+ */
3360
+ passed: number;
3361
+ /**
3362
+ * Number of failing cases
3363
+ */
3364
+ failed: number;
3365
+ /**
3366
+ * Individual case results
3367
+ */
3368
+ caseResults: Array<EvalCaseResult>;
3369
+ /**
3370
+ * Overall execution time in milliseconds
3371
+ */
3372
+ durationMs: number;
3373
+ /**
3374
+ * Difference between current pass rate and baseline pass rate.
3375
+ * Positive = improvement, negative = regression.
3376
+ * Only present when `baselineResultsFrom` was provided.
3377
+ */
3378
+ deltaPassRate?: number;
3379
+ /**
3380
+ * Number of cases that regressed: passed in baseline, failed now.
3381
+ * Only present when `baselineResultsFrom` was provided.
3382
+ */
3383
+ regressions?: number;
3384
+ /**
3385
+ * Number of cases that improved: failed in baseline, passed now.
3386
+ * Only present when `baselineResultsFrom` was provided.
3387
+ */
3388
+ improvements?: number;
3389
+ /**
3390
+ * Average tool precision across all mcp_host cases that have a
3391
+ * `toolsTriggered` expectation (precision = fraction of called tools
3392
+ * that were expected). Only present when at least one such case ran.
3393
+ */
3394
+ datasetToolPrecision?: number;
3395
+ /**
3396
+ * Average tool recall across all mcp_host cases that have a
3397
+ * `toolsTriggered` expectation (recall = fraction of required tools
3398
+ * that were actually called). Only present when at least one such case ran.
3399
+ */
3400
+ datasetToolRecall?: number;
3401
+ /**
3402
+ * Harmonic mean of `datasetToolPrecision` and `datasetToolRecall`.
3403
+ * Only present when at least one case contributes precision/recall data.
3404
+ */
3405
+ datasetToolF1?: number;
3406
+ /**
3407
+ * Experiment tracking metadata captured at run time.
3408
+ */
3409
+ metadata?: EvalRunMetadata;
3410
+ /**
3411
+ * Aggregate token usage from all mcp_host LLM simulations across all cases.
3412
+ */
3413
+ totalHostUsage?: UsageMetrics;
3414
+ }
3415
+ type StoredEvalResultRef = 'latest' | {
3416
+ id: string;
3417
+ };
3418
+ interface StoredEvalResultLoadOptions {
3419
+ store: true;
3420
+ ref: StoredEvalResultRef;
3421
+ }
3422
+ interface StoredEvalResultSaveOptions {
3423
+ store: true;
3424
+ ref?: 'latest' | {
3425
+ id?: string;
3426
+ };
3427
+ }
3428
+ /**
3429
+ * Options for running eval dataset
3430
+ */
3431
+ interface EvalRunnerOptions {
3432
+ /**
3433
+ * The dataset to run
3434
+ */
3435
+ dataset: EvalDataset;
3436
+ /**
3437
+ * Schema registry for schema validation by name
3438
+ *
3439
+ * Maps schema names to Zod schemas for use with expect.schema
3440
+ *
3441
+ * @example
3442
+ * ```typescript
3443
+ * {
3444
+ * schemas: {
3445
+ * WeatherResponse: z.object({ temperature: z.number() }),
3446
+ * ErrorResponse: z.object({ error: z.string() }),
3447
+ * }
3448
+ * }
3449
+ * ```
3450
+ */
3451
+ schemas?: Record<string, ZodType>;
3452
+ /**
3453
+ * Whether to stop on first failure
3454
+ * @default false
3455
+ */
3456
+ stopOnFailure?: boolean;
3457
+ /**
3458
+ * Optional callback called after each case
3459
+ */
3460
+ onCaseComplete?: (result: EvalCaseResult) => void | Promise<void>;
3461
+ /**
3462
+ * Maximum number of eval cases to run concurrently.
3463
+ * When > 1, cases run in parallel (ignores stopOnFailure ordering).
3464
+ * @default 1 (sequential)
3465
+ */
3466
+ concurrency?: number;
3467
+ /**
3468
+ * Default iteration count for `mcp_host` mode cases that do not specify
3469
+ * `iterations` explicitly. Has no effect on `direct` mode cases (which are
3470
+ * deterministic and always default to 1 iteration).
3471
+ *
3472
+ * Set to 10 for standard runs or 20 for release gates. Individual cases can
3473
+ * still override this with their own `iterations` field.
3474
+ *
3475
+ * @default 1 (preserves historical behaviour when not set)
3476
+ *
3477
+ * @example
3478
+ * ```typescript
3479
+ * // Run all mcp_host cases 10 times each by default
3480
+ * await runEvalDataset({ dataset, defaultLlmIterations: 10 }, { mcp });
3481
+ * ```
3482
+ */
3483
+ defaultLlmIterations?: number;
3484
+ /**
3485
+ * Default number of judge evaluations for cases that do not specify
3486
+ * `judgeReps` explicitly. Applies to any case with a `passesJudge`
3487
+ * expectation. Per-case `judgeReps` overrides this.
3488
+ *
3489
+ * @default 1 (single judge run)
3490
+ */
3491
+ defaultJudgeReps?: number;
3492
+ /**
3493
+ * When set, only eval cases whose `tags` array contains at least one of
3494
+ * the specified tags are run. Cases without a `tags` field are excluded.
3495
+ * When undefined or empty, all cases run (default behavior).
3496
+ */
3497
+ filterTags?: string[];
3498
+ /**
3499
+ * If set, saves the run results to this file path after completion.
3500
+ * Use with `baselineResultsFrom` on the next run for regression detection.
3501
+ *
3502
+ * @example '.mcp-test-results/baseline.json'
3503
+ */
3504
+ saveResultsTo?: string | StoredEvalResultSaveOptions;
3505
+ /**
3506
+ * When true (default), strips the `response` field from each case result
3507
+ * before saving the baseline file. Keeps baseline files small and git-friendly —
3508
+ * the full tool response is not needed for pass/fail regression detection.
3509
+ *
3510
+ * Set to false to preserve complete responses in the saved file.
3511
+ *
3512
+ * @default true
3513
+ */
3514
+ omitResponsesFromBaseline?: boolean;
3515
+ /**
3516
+ * When true (default), strips response bodies from each case result before
3517
+ * saving to an external result store. Stored artifacts only need the pass/fail
3518
+ * shape and tool-call metadata — full response payloads are not necessary
3519
+ * for regression detection or history comparison. Set to false when you
3520
+ * specifically need stored artifacts to retain complete responses.
3521
+ *
3522
+ * Defaults to `true` to match the reporter's `redactStoredResponses` default
3523
+ * (see `MCPReporter`). Both write paths produce the same redaction shape, so
3524
+ * users with both configured don't end up with a mix of redacted and
3525
+ * non-redacted artifacts depending on which code path wrote them.
3526
+ *
3527
+ * @default true
3528
+ */
3529
+ redactStoredResponses?: boolean;
3530
+ /**
3531
+ * Optional external result store for loading/saving eval run artifacts.
3532
+ */
3533
+ resultStore?: EvalResultStoreLike;
3534
+ /**
3535
+ * If set, loads this file or stored result as the baseline and computes delta metrics vs the current run.
3536
+ * Populates `EvalRunnerResult.deltaPassRate`, `.regressions`, `.improvements`,
3537
+ * and tags each `EvalCaseResult.baselinePass`.
3538
+ */
3539
+ baselineResultsFrom?: string | StoredEvalResultLoadOptions;
3540
+ /**
3541
+ * Runtime MCP tool metadata overrides used for variant experiments.
3542
+ *
3543
+ * Overrides are applied to the tool list shown to MCP hosts without changing
3544
+ * the eval dataset or mutating the underlying MCP server. Tool keys must be
3545
+ * canonical tool names exposed by the server.
3546
+ */
3547
+ toolOverrides?: ToolOverrideVariant;
3548
+ /**
3549
+ * MCP host model identifier to record in run metadata.
3550
+ * Use this to identify which model was used when running mcp_host cases.
3551
+ *
3552
+ * @example 'claude-opus-4-20250514'
3553
+ */
3554
+ mcpHostModel?: string;
3555
+ /**
3556
+ * Judge model identifier to record in run metadata.
3557
+ * Use this to identify which model was used for judge evaluations.
3558
+ *
3559
+ * @example 'claude-sonnet-4-20250514'
3560
+ */
3561
+ judgeModel?: string;
3562
+ }
3563
+ /**
3564
+ * Options for running a single eval case
3565
+ */
3566
+ interface EvalCaseOptions {
3567
+ /**
3568
+ * Dataset name for the result (defaults to 'single-case')
3569
+ */
3570
+ datasetName?: string;
3571
+ /**
3572
+ * Schema registry for schema validation by name
3573
+ */
3574
+ schemas?: Record<string, ZodType>;
3575
+ /**
3576
+ * Runtime tool override variant id for reporter/debug metadata.
3577
+ */
3578
+ toolOverrideVariantId?: string;
3579
+ }
3580
+ /**
3581
+ * Runs a single eval case and returns the result.
3582
+ * When `evalCase.iterations > 1`, runs the case N times and returns accuracy.
3583
+ *
3584
+ * @param evalCase - The eval case to run
3585
+ * @param context - Context containing mcp, testInfo, expect
3586
+ * @param options - Optional configuration (datasetName, schemas)
3587
+ * @returns The result of running the eval case
3588
+ *
3589
+ * @example
3590
+ * ```typescript
3591
+ * const result = await runEvalCase(
3592
+ * evalCase,
3593
+ * { mcp, testInfo, expect },
3594
+ * { schemas: { WeatherResponse: WeatherSchema } }
3595
+ * );
3596
+ *
3597
+ * expect(result.pass).toBe(true);
3598
+ * ```
3599
+ */
3600
+ declare function runEvalCase(evalCase: EvalCase, context: EvalContext, options?: EvalCaseOptions): Promise<EvalCaseResult>;
3601
+ declare function runEvalDataset(options: EvalRunnerOptions, context: EvalContext): Promise<EvalRunnerResult>;
3602
+
3603
+ /** Outcome of comparing two servers on a single eval case. */
3604
+ type ComparisonOutcome = 'A_WINS' | 'B_WINS' | 'TIE' | 'BOTH_FAIL';
3605
+ /** Result of comparing a single eval case across two servers. */
3606
+ interface CaseComparisonResult {
3607
+ /** Case ID */
3608
+ id: string;
3609
+ /** Comparison outcome */
3610
+ outcome: ComparisonOutcome;
3611
+ /** Result from server A */
3612
+ serverA: EvalCaseResult;
3613
+ /** Result from server B */
3614
+ serverB: EvalCaseResult;
3615
+ }
3616
+ /** Aggregated result of running a dataset against two servers. */
3617
+ interface ServerComparisonResult {
3618
+ /** Dataset name */
3619
+ dataset: string;
3620
+ /** Total cases compared (cases present in both runs) */
3621
+ total: number;
3622
+ /** Cases where server A passed and server B failed */
3623
+ aWins: number;
3624
+ /** Cases where server B passed and server A failed */
3625
+ bWins: number;
3626
+ /** Cases where both passed */
3627
+ ties: number;
3628
+ /** Cases where both failed */
3629
+ bothFail: number;
3630
+ /** Cases with a decisive outcome (aWins + bWins + ties, excludes BOTH_FAIL) */
3631
+ decidedCases: number;
3632
+ /** Fraction of total cases where both servers failed (bothFail / total) */
3633
+ failureAlignment: number;
3634
+ /** A win rate (aWins / decidedCases, excludes BOTH_FAIL) */
3635
+ aWinRate: number;
3636
+ /** B win rate (bWins / decidedCases, excludes BOTH_FAIL) */
3637
+ bWinRate: number;
3638
+ /** Tie rate (ties / decidedCases, excludes BOTH_FAIL) */
3639
+ tieRate: number;
3640
+ /** Per-case comparison results */
3641
+ cases: CaseComparisonResult[];
3642
+ /** Full result from server A */
3643
+ serverAResult: EvalRunnerResult;
3644
+ /** Full result from server B */
3645
+ serverBResult: EvalRunnerResult;
3646
+ /** Total duration in milliseconds */
3647
+ durationMs: number;
3648
+ }
3649
+ /**
3650
+ * Options for `runServerComparison`.
3651
+ * Same as `EvalRunnerOptions` without baseline-specific fields.
3652
+ */
3653
+ type ServerComparisonOptions = Omit<EvalRunnerOptions, 'saveResultsTo' | 'baselineResultsFrom'> & {
3654
+ comparisonStore?: EvalResultStoreLike;
3655
+ comparisonId?: string;
3656
+ comparisonMetadata?: StoredEvalArtifactMetadata;
3657
+ redactStoredResponses?: boolean;
3658
+ };
3659
+ /**
3660
+ * Runs the same eval dataset against two MCP servers in parallel and
3661
+ * returns a detailed per-case comparison of results.
3662
+ *
3663
+ * Both servers receive identical cases and options. The comparison uses
3664
+ * simple pass/fail per case: A_WINS means A passed and B failed, etc.
3665
+ *
3666
+ * @param options - Eval dataset and runner options (shared between both servers)
3667
+ * @param contextA - MCP context for server A (e.g., Glean MCP)
3668
+ * @param contextB - MCP context for server B (e.g., native MCP)
3669
+ * @returns Comparison result with per-case outcomes and aggregate win rates
3670
+ *
3671
+ * @example
3672
+ * ```typescript
3673
+ * const comparison = await runServerComparison(
3674
+ * { dataset },
3675
+ * { mcp: gleanMcpFixture },
3676
+ * { mcp: nativeMcpFixture }
3677
+ * );
3678
+ * console.log(`Glean MCP wins: ${(comparison.aWinRate * 100).toFixed(1)}%`);
3679
+ * console.log(`Native MCP wins: ${(comparison.bWinRate * 100).toFixed(1)}%`);
3680
+ * ```
3681
+ */
3682
+ declare function runServerComparison(options: ServerComparisonOptions, contextA: EvalContext, contextB: EvalContext): Promise<ServerComparisonResult>;
3683
+ interface SaveServerComparisonOptions {
3684
+ store: EvalResultStoreLike;
3685
+ comparison: ServerComparisonResult;
3686
+ id?: string;
3687
+ metadata?: StoredEvalArtifactMetadata;
3688
+ redactStoredResponses?: boolean;
3689
+ }
3690
+ declare function saveServerComparison(options: SaveServerComparisonOptions): Promise<StoredEvalArtifact<ServerComparisonResult>>;
3691
+
3692
+ /** Labels used when presenting an eval run comparison. */
3693
+ interface EvalRunComparisonLabels {
3694
+ /** Label for the baseline run. Defaults to "baseline". */
3695
+ baseline?: string;
3696
+ /** Label for the candidate run. Defaults to the candidate variant id or "candidate". */
3697
+ candidate?: string;
3698
+ }
3699
+ /** Outcome of comparing one eval case across two completed eval runs. */
3700
+ type EvalCaseComparisonOutcome = 'IMPROVED' | 'REGRESSED' | 'UNCHANGED_PASS' | 'UNCHANGED_FAIL' | 'MISSING_FROM_BASELINE' | 'MISSING_FROM_CANDIDATE';
3701
+ /** Per-case comparison between a baseline run and candidate run. */
3702
+ interface EvalCaseComparison {
3703
+ /** Case ID */
3704
+ id: string;
3705
+ /** Outcome for this case */
3706
+ outcome: EvalCaseComparisonOutcome;
3707
+ /** Baseline case result, absent when the case only exists in the candidate run */
3708
+ baseline?: EvalCaseResult;
3709
+ /** Candidate case result, absent when the case only exists in the baseline run */
3710
+ candidate?: EvalCaseResult;
3711
+ }
3712
+ /** Options for comparing two completed eval runs. */
3713
+ interface CompareEvalRunsOptions {
3714
+ /** Baseline run result */
3715
+ baseline: EvalRunnerResult;
3716
+ /** Candidate run result */
3717
+ candidate: EvalRunnerResult;
3718
+ /** Optional human-readable run labels */
3719
+ labels?: EvalRunComparisonLabels;
3720
+ }
3721
+ /** Aggregated comparison between two completed eval runs. */
3722
+ interface EvalRunComparisonResult {
3723
+ /** Baseline label */
3724
+ baselineLabel: string;
3725
+ /** Candidate label */
3726
+ candidateLabel: string;
3727
+ /** Baseline pass rate (passed / total, or 0 when total is 0) */
3728
+ baselinePassRate: number;
3729
+ /** Candidate pass rate (passed / total, or 0 when total is 0) */
3730
+ candidatePassRate: number;
3731
+ /** Candidate pass rate minus baseline pass rate */
3732
+ deltaPassRate: number;
3733
+ /** Baseline dataset tool precision, when present */
3734
+ baselineToolPrecision?: number;
3735
+ /** Candidate dataset tool precision, when present */
3736
+ candidateToolPrecision?: number;
3737
+ /** Candidate precision minus baseline precision, when both are present */
3738
+ deltaToolPrecision?: number;
3739
+ /** Baseline dataset tool recall, when present */
3740
+ baselineToolRecall?: number;
3741
+ /** Candidate dataset tool recall, when present */
3742
+ candidateToolRecall?: number;
3743
+ /** Candidate recall minus baseline recall, when both are present */
3744
+ deltaToolRecall?: number;
3745
+ /** Baseline dataset tool F1, when present */
3746
+ baselineToolF1?: number;
3747
+ /** Candidate dataset tool F1, when present */
3748
+ candidateToolF1?: number;
3749
+ /** Candidate F1 minus baseline F1, when both are present */
3750
+ deltaToolF1?: number;
3751
+ /** All per-case comparison records in deterministic order */
3752
+ cases: EvalCaseComparison[];
3753
+ /** Cases that failed in baseline and passed in candidate */
3754
+ improvedCases: EvalCaseComparison[];
3755
+ /** Cases that passed in baseline and failed in candidate */
3756
+ regressedCases: EvalCaseComparison[];
3757
+ /** Cases that passed in both runs */
3758
+ unchangedPasses: EvalCaseComparison[];
3759
+ /** Cases that failed in both runs */
3760
+ unchangedFailures: EvalCaseComparison[];
3761
+ /** Cases present only in candidate */
3762
+ missingFromBaseline: EvalCaseComparison[];
3763
+ /** Cases present only in baseline */
3764
+ missingFromCandidate: EvalCaseComparison[];
3765
+ }
3766
+ type StoredEvalRunRef = 'latest' | {
3767
+ id: string;
3768
+ };
3769
+ interface SaveEvalRunComparisonOptions {
3770
+ store: EvalResultStoreLike;
3771
+ comparison: EvalRunComparisonResult;
3772
+ id?: string;
3773
+ metadata?: StoredEvalArtifactMetadata;
3774
+ redactStoredResponses?: boolean;
3775
+ }
3776
+ /**
3777
+ * Compares two completed eval runs without running any evals or reading files.
3778
+ *
3779
+ * Use this after running a baseline and candidate (for example a toolOverrides
3780
+ * variant) to compute pass-rate deltas, tool metric deltas, and per-case
3781
+ * improvement/regression buckets.
3782
+ */
3783
+ declare function compareEvalRuns(options: CompareEvalRunsOptions): EvalRunComparisonResult;
3784
+ declare function loadStoredEvalRunnerResult(storeLike: EvalResultStoreLike, ref: StoredEvalRunRef): Promise<StoredEvalArtifact<EvalRunnerResult>>;
3785
+ declare function saveEvalRunComparison(options: SaveEvalRunComparisonOptions): Promise<StoredEvalArtifact<EvalRunComparisonResult>>;
3786
+
3787
+ /**
3788
+ * Metric used to rank variant candidates and decide improvement.
3789
+ *
3790
+ * - `passRate`: passed / total across the dataset (always available).
3791
+ * - `toolF1` / `toolPrecision` / `toolRecall`: dataset-level tool-call metrics,
3792
+ * only available when the dataset has `mcp_host` cases with `toolsTriggered`
3793
+ * expectations. Choosing one of these when no such cases exist throws a clear
3794
+ * error rather than silently ranking on nothing.
3795
+ */
3796
+ type ExperimentMetric = 'passRate' | 'toolF1' | 'toolPrecision' | 'toolRecall';
3797
+ /**
3798
+ * Why a variant experiment stopped.
3799
+ *
3800
+ * - `no-variants`: no candidates were ever produced (round 0 yielded none).
3801
+ * - `no-improvement`: a round's best candidate did not beat the best-so-far by
3802
+ * at least `minImprovement`, or `proposeVariants` returned no further
3803
+ * candidates.
3804
+ * - `max-rounds`: the configured `maxRounds` budget was exhausted.
3805
+ * - `threshold-met`: reserved for future absolute-target convergence; not
3806
+ * emitted by the current delta-based logic.
3807
+ */
3808
+ type VariantExperimentReason = 'threshold-met' | 'no-improvement' | 'max-rounds' | 'no-variants';
3809
+ /** Whether a winning variant should be applied, rejected, or is inconclusive. */
3810
+ type VariantRecommendation = 'apply' | 'reject' | 'inconclusive';
3811
+ /** Result of running and scoring a single candidate variant. */
3812
+ interface VariantCandidateResult {
3813
+ /** The variant that was injected via `toolOverrides`. */
3814
+ variant: ToolOverrideVariant;
3815
+ /** The eval run produced for this variant. */
3816
+ result: EvalRunnerResult;
3817
+ /** Comparison of this candidate against the original baseline run. */
3818
+ comparison: EvalRunComparisonResult;
3819
+ /** The selected metric's value for this candidate. */
3820
+ metricValue: number;
3821
+ /** `metricValue` minus the baseline's metric value. */
3822
+ metricDelta: number;
3823
+ /**
3824
+ * True when this candidate regressed at least one case and `allowRegressions`
3825
+ * is not set. Disqualified candidates can never become the winner.
3826
+ */
3827
+ disqualified: boolean;
3828
+ }
3829
+ /** All candidates tried in a single round, plus the round's best non-disqualified pick. */
3830
+ interface VariantExperimentRound {
3831
+ /** 0-based round index. */
3832
+ round: number;
3833
+ /** Every candidate scored this round, in input order. */
3834
+ candidates: VariantCandidateResult[];
3835
+ /** Highest-scoring non-disqualified candidate this round, if any. */
3836
+ best?: VariantCandidateResult;
3837
+ }
3838
+ /** Context passed to a `proposeVariants` callback before each round. */
3839
+ interface ProposeVariantsContext {
3840
+ /** 0-based index of the round about to run. */
3841
+ round: number;
3842
+ /** The original baseline run (no overrides). */
3843
+ baseline: EvalRunnerResult;
3844
+ /** The metric the experiment is optimizing. */
3845
+ metric: ExperimentMetric;
3846
+ /** All completed rounds so far, in order. */
3847
+ history: VariantExperimentRound[];
3848
+ /** Best non-disqualified candidate across all prior rounds, if any. */
3849
+ bestSoFar?: VariantCandidateResult;
3850
+ }
3851
+ /** A structured, ready-to-act proposal derived from the best attempted candidate. */
3852
+ interface VariantImprovementProposal {
3853
+ /** `id` of the variant this proposal describes. */
3854
+ variantId: string;
3855
+ /** Metric the experiment optimized. */
3856
+ metric: ExperimentMetric;
3857
+ /** Baseline metric value. */
3858
+ baselineValue: number;
3859
+ /** Candidate metric value. */
3860
+ candidateValue: number;
3861
+ /** `candidateValue` minus `baselineValue`. */
3862
+ delta: number;
3863
+ /** Per-tool overrides this variant applied, keyed by canonical tool name. */
3864
+ toolChanges: Record<string, ToolMetadataOverride>;
3865
+ /** IDs of cases that failed in baseline and passed with this variant. */
3866
+ improvedCaseIds: string[];
3867
+ /** IDs of cases that passed in baseline and failed with this variant. */
3868
+ regressedCaseIds: string[];
3869
+ /**
3870
+ * `apply` when the variant improved the metric without disqualifying
3871
+ * regressions; `reject` when the best attempt regressed cases (and
3872
+ * regressions are not allowed); `inconclusive` when nothing beat baseline.
3873
+ */
3874
+ recommendation: VariantRecommendation;
3875
+ }
3876
+ /** Options for {@link runVariantExperiment}. */
3877
+ interface VariantExperimentOptions {
3878
+ /** The eval dataset. Treated as the stable behavioral contract; never mutated. */
3879
+ dataset: EvalDataset;
3880
+ /** Static candidates tried in round 0. */
3881
+ variants?: ToolOverrideVariant[];
3882
+ /**
3883
+ * AI hook returning the next candidates given prior-round results. Invoked for
3884
+ * rounds >= 1, and for round 0 when `variants` is omitted. Return `[]` to stop.
3885
+ */
3886
+ proposeVariants?: (context: ProposeVariantsContext) => Promise<ToolOverrideVariant[]>;
3887
+ /** Metric to optimize. @default 'passRate' */
3888
+ metric?: ExperimentMetric;
3889
+ /** Maximum number of rounds to run. @default 1 */
3890
+ maxRounds?: number;
3891
+ /**
3892
+ * Convergence threshold. Stop when a round's best metric improvement over the
3893
+ * prior best-so-far is below this value. @default 0
3894
+ */
3895
+ minImprovement?: number;
3896
+ /**
3897
+ * When false (default), any candidate that regresses a case is disqualified
3898
+ * from winning and surfaced with `recommendation: 'reject'`. When true,
3899
+ * regressions do not disqualify.
3900
+ * @default false
3901
+ */
3902
+ allowRegressions?: boolean;
3903
+ /** Default `mcp_host` iterations per case. Forwarded to `runEvalDataset`. */
3904
+ defaultLlmIterations?: number;
3905
+ /** Default judge repetitions per case. Forwarded to `runEvalDataset`. */
3906
+ defaultJudgeReps?: number;
3907
+ /** Max eval cases to run concurrently within each run. Forwarded to `runEvalDataset`. */
3908
+ concurrency?: number;
3909
+ /** Run only cases with at least one of these tags. Forwarded to `runEvalDataset`. */
3910
+ filterTags?: string[];
3911
+ /** Schema registry for `expect.schema` cases. Forwarded to `runEvalDataset`. */
3912
+ schemas?: Record<string, ZodType>;
3913
+ /** MCP host model identifier recorded in run metadata. */
3914
+ mcpHostModel?: string;
3915
+ /** Judge model identifier recorded in run metadata. */
3916
+ judgeModel?: string;
3917
+ }
3918
+ /** Aggregated result of a variant experiment. */
3919
+ interface VariantExperimentResult {
3920
+ /** Metric that was optimized. */
3921
+ metric: ExperimentMetric;
3922
+ /** The original baseline run (no overrides). */
3923
+ baseline: EvalRunnerResult;
3924
+ /** Every round that ran, in order. */
3925
+ rounds: VariantExperimentRound[];
3926
+ /** Best non-disqualified candidate across all rounds, if any. */
3927
+ winner?: VariantCandidateResult;
3928
+ /** Structured proposal derived from the best attempted candidate, if any ran. */
3929
+ proposal?: VariantImprovementProposal;
3930
+ /** True when the experiment stopped on its own terms (always true today). */
3931
+ converged: boolean;
3932
+ /** Why the experiment stopped. */
3933
+ reason: VariantExperimentReason;
3934
+ }
3935
+ /**
3936
+ * Runs a tool-metadata variant experiment: establishes a baseline, then injects
3937
+ * each candidate variant via `toolOverrides`, compares it to the baseline,
3938
+ * ranks by the chosen metric, guards against regressions, and emits a structured
3939
+ * improvement proposal.
3940
+ *
3941
+ * The library owns the experiment mechanism; the *policy* — which variant to try
3942
+ * next — is the caller's, supplied either as a static `variants` list or an
3943
+ * iterative `proposeVariants` callback. This is the programmatic spine an AI or
3944
+ * skill drives to optimize tool descriptions/schemas for better host triggering.
3945
+ *
3946
+ * Candidates are always compared against the original baseline (not the prior
3947
+ * round), so the resulting proposal is directly applicable. Multi-round
3948
+ * convergence is tracked separately via best-so-far.
3949
+ *
3950
+ * @example
3951
+ * ```typescript
3952
+ * const result = await runVariantExperiment(
3953
+ * { dataset, variants: [variantA, variantB], metric: 'passRate' },
3954
+ * { mcp, testInfo }
3955
+ * );
3956
+ * if (result.proposal?.recommendation === 'apply') {
3957
+ * console.log('Apply:', result.winner?.variant.id, '+', result.proposal.delta);
3958
+ * }
3959
+ * ```
3960
+ */
3961
+ declare function runVariantExperiment(options: VariantExperimentOptions, context: EvalContext): Promise<VariantExperimentResult>;
3962
+
3963
+ /**
3964
+ * Options for saveBaseline
3965
+ */
3966
+ interface SaveBaselineOptions {
3967
+ /**
3968
+ * When true (default), strips the `response` field from each case result
3969
+ * before saving. Keeps baseline files small and git-friendly — the baseline
3970
+ * is a pass/fail record and the full response is not needed for comparison.
3971
+ *
3972
+ * Set to false to preserve the complete response in the saved file.
3973
+ *
3974
+ * @default true
3975
+ */
3976
+ omitResponses?: boolean;
3977
+ }
3978
+ /**
3979
+ * Saves eval results to a JSON file for use as a baseline in future runs.
3980
+ *
3981
+ * @param result - The eval run result to save
3982
+ * @param filePath - Path to write the JSON file (parent dirs created automatically)
3983
+ * @param options - Save options
3984
+ */
3985
+ declare function saveBaseline(result: EvalRunnerResult, filePath: string, options?: SaveBaselineOptions): Promise<void>;
3986
+ /**
3987
+ * Loads a previously saved baseline from a JSON file.
3988
+ *
3989
+ * @param filePath - Path to the JSON file written by saveBaseline
3990
+ * @returns The saved EvalRunnerResult
3991
+ * @throws If the file cannot be read or parsed
3992
+ */
3993
+ declare function loadBaseline(filePath: string): Promise<EvalRunnerResult>;
3994
+
3995
+ /**
3996
+ * Custom Judge Registry
3997
+ *
3998
+ * Allows consumers to register named judge executors that can be referenced
3999
+ * by string ID in eval fixtures and programmatic tests. This enables
4000
+ * multi-step judge pipelines (LLM call + post-processing), custom scoring
4001
+ * logic, and reusable judge configurations without duplicating rubrics.
4002
+ */
4003
+ /**
4004
+ * Result returned by a custom judge executor.
4005
+ *
4006
+ * Custom judges must return a normalized score (0–1). The framework applies
4007
+ * the caller's `threshold` (default 0.7) to determine pass/fail. This keeps
4008
+ * judges reusable — the same judge can be used with different thresholds in
4009
+ * different tests.
4010
+ */
4011
+ interface CustomJudgeResult {
4012
+ /** Normalized score (0–1, where 1 is best) */
4013
+ score: number;
4014
+ /** Optional reasoning/explanation */
4015
+ reasoning?: string;
4016
+ }
4017
+ /**
4018
+ * A user-defined judge executor function.
4019
+ *
4020
+ * Custom executors own their entire evaluation pipeline — prompt construction,
4021
+ * LLM calls, and post-processing — but return a normalized score. The framework
4022
+ * determines pass/fail by comparing the score against the caller's threshold.
4023
+ *
4024
+ * @param candidate - The actual response to evaluate
4025
+ * @param reference - Optional reference/expected response
4026
+ * @returns Evaluation result with a normalized score and optional reasoning
4027
+ *
4028
+ * @example
4029
+ * ```typescript
4030
+ * const completenessJudge: CustomJudgeExecutor = async (candidate, reference) => {
4031
+ * // Step 1: LLM call with your own prompt and schema
4032
+ * const llmResult = await callLLM(COMPLETENESS_PROMPT, candidate);
4033
+ * const { verdict, reasoning } = JSON.parse(llmResult);
4034
+ *
4035
+ * // Step 2: Deterministic post-processing into a normalized score
4036
+ * const score = { Complete: 1.0, Incomplete: 0.5 }[verdict] ?? 0.0;
4037
+ *
4038
+ * return { score, reasoning };
4039
+ * };
4040
+ * ```
4041
+ */
4042
+ type CustomJudgeExecutor = (candidate: unknown, reference?: unknown) => Promise<CustomJudgeResult>;
4043
+ /**
4044
+ * Registers a named custom judge executor.
4045
+ *
4046
+ * Call this in your test setup (e.g., `playwright.config.ts` or a global setup file)
4047
+ * before tests run. The name can then be referenced in JSON eval fixtures via the
4048
+ * `judge` field on `passesJudge`.
4049
+ *
4050
+ * @param name - Unique identifier for the judge
4051
+ * @param executor - The judge executor function
4052
+ * @throws {Error} If a judge with the same name is already registered
4053
+ *
4054
+ * @example
4055
+ * ```typescript
4056
+ * import { registerJudge } from '@gleanwork/mcp-server-tester';
4057
+ *
4058
+ * registerJudge('glean-completeness', async (candidate, reference) => {
4059
+ * // Step 1: LLM call with your own prompt and schema
4060
+ * const llmResult = await callLLM(COMPLETENESS_PROMPT, candidate);
4061
+ * const { verdict, reasoning } = JSON.parse(llmResult);
4062
+ *
4063
+ * // Step 2: Deterministic post-processing into a normalized score
4064
+ * const score = { Complete: 1.0, Incomplete: 0.5 }[verdict] ?? 0.0;
4065
+ *
4066
+ * return { score, reasoning };
4067
+ * });
4068
+ *
4069
+ * // Then in tests — same judge, different thresholds:
4070
+ * // expect(result).toPassToolJudge({ judge: 'glean-completeness', passingThreshold: 0.8 });
4071
+ * // expect(result).toPassToolJudge({ judge: 'glean-completeness', passingThreshold: 0.5 });
4072
+ * ```
4073
+ */
4074
+ declare function registerJudge(name: string, executor: CustomJudgeExecutor): void;
4075
+ /**
4076
+ * Retrieves a registered custom judge executor by name.
4077
+ *
4078
+ * @param name - The judge name to look up
4079
+ * @returns The registered executor
4080
+ * @throws {Error} If no judge with the given name is registered
4081
+ */
4082
+ declare function getRegisteredJudge(name: string): CustomJudgeExecutor;
4083
+ /**
4084
+ * Clears all registered judges. Intended for test teardown.
4085
+ */
4086
+ declare function clearJudgeRegistry(): void;
4087
+
4088
+ /**
4089
+ * Options for conformance checks
4090
+ */
4091
+ interface MCPConformanceOptions {
4092
+ /**
4093
+ * List of tools that must be present
4094
+ */
4095
+ requiredTools?: Array<string>;
4096
+ /**
4097
+ * Whether to validate tool schemas
4098
+ * @default true
4099
+ */
4100
+ validateSchemas?: boolean;
4101
+ /**
4102
+ * Whether to check server info is present
4103
+ * @default true
4104
+ */
4105
+ checkServerInfo?: boolean;
4106
+ /**
4107
+ * Whether to check resources capability (if declared by server)
4108
+ * @default true
4109
+ */
4110
+ checkResources?: boolean;
4111
+ /**
4112
+ * Whether to check prompts capability (if declared by server)
4113
+ * @default true
4114
+ */
4115
+ checkPrompts?: boolean;
4116
+ }
4117
+ /**
4118
+ * Raw MCP responses for snapshotting
4119
+ */
4120
+ interface MCPConformanceRaw {
4121
+ /**
4122
+ * Server info (name, version)
4123
+ * null if not available
4124
+ */
4125
+ serverInfo: Implementation | null;
4126
+ /**
4127
+ * Server capabilities
4128
+ * null if not available
4129
+ */
4130
+ capabilities: ServerCapabilities | null;
4131
+ /**
4132
+ * List of tools from the server
4133
+ */
4134
+ tools: Tool[];
4135
+ /**
4136
+ * List of resources from the server
4137
+ * null if server doesn't declare resources capability
4138
+ */
4139
+ resources: Resource[] | null;
4140
+ /**
4141
+ * List of prompts from the server
4142
+ * null if server doesn't declare prompts capability
4143
+ */
4144
+ prompts: Prompt[] | null;
4145
+ }
4146
+ /**
4147
+ * Result of conformance checks
4148
+ */
4149
+ interface MCPConformanceResult {
4150
+ /**
4151
+ * Whether all checks passed
4152
+ */
4153
+ pass: boolean;
4154
+ /**
4155
+ * List of check results
4156
+ */
4157
+ checks: MCPConformanceCheck[];
4158
+ /**
4159
+ * Raw MCP responses for snapshotting
4160
+ *
4161
+ * @example
4162
+ * ```typescript
4163
+ * const result = await runConformanceChecks(mcp);
4164
+ * expect(result.raw.tools).toMatchSnapshot();
4165
+ * expect(result.raw.capabilities).toMatchSnapshot();
4166
+ * ```
4167
+ */
4168
+ raw: MCPConformanceRaw;
4169
+ }
4170
+ /**
4171
+ * Runs MCP protocol conformance checks
4172
+ *
4173
+ * Validates that the MCP server conforms to expected protocol behavior.
4174
+ * Returns both assertion results and raw MCP responses for snapshotting.
4175
+ *
4176
+ * When testInfo is provided, results are automatically attached for the MCP reporter.
4177
+ *
4178
+ * @param mcp - MCP fixture API
4179
+ * @param options - Conformance check options
4180
+ * @param testInfo - Optional Playwright TestInfo for reporter integration
4181
+ * @returns Conformance check results with raw responses
4182
+ *
4183
+ * @example
4184
+ * ```typescript
4185
+ * // Basic usage
4186
+ * const result = await runConformanceChecks(mcp, {
4187
+ * requiredTools: ['get_weather', 'search_docs'],
4188
+ * validateSchemas: true,
4189
+ * });
4190
+ *
4191
+ * // Check assertions
4192
+ * expect(result.pass).toBe(true);
4193
+ *
4194
+ * // With reporter integration (recommended in Playwright tests)
4195
+ * const result = await runConformanceChecks(mcp, {
4196
+ * requiredTools: ['search'],
4197
+ * }, testInfo);
4198
+ *
4199
+ * // Snapshot raw responses
4200
+ * expect(result.raw.tools).toMatchSnapshot();
4201
+ * expect(result.raw.capabilities).toMatchSnapshot();
4202
+ * ```
4203
+ */
4204
+ declare function runConformanceChecks(mcp: MCPFixtureApi, options?: MCPConformanceOptions, testInfo?: TestInfo): Promise<MCPConformanceResult>;
4205
+
4206
+ /**
4207
+ * Canonical type definitions for @gleanwork/mcp-server-tester
4208
+ *
4209
+ * This module is the single source of truth for shared types.
4210
+ * All other modules should import from here rather than defining their own.
4211
+ *
4212
+ * @packageDocumentation
4213
+ */
4214
+ /**
4215
+ * Authentication type for MCP connections
4216
+ *
4217
+ * - 'oauth': Interactive OAuth 2.1 with PKCE (browser-based authentication)
4218
+ * - 'api-token': Static API token (e.g., from a dashboard or environment variable)
4219
+ * - 'none': No authentication
4220
+ */
4221
+ type AuthType = 'oauth' | 'api-token' | 'none';
4222
+ /**
4223
+ * Source of test results
4224
+ *
4225
+ * - 'eval': From runEvalDataset() using JSON eval datasets
4226
+ * - 'test': From direct API test tracking (MCP fixture calls)
4227
+ */
4228
+ type ResultSource = 'eval' | 'test';
4229
+ /**
4230
+ * Known expectation types supported by the framework
4231
+ */
4232
+ type ExpectationType = 'exact' | 'schema' | 'textContains' | 'regex' | 'snapshot' | 'judge' | 'error' | 'size' | 'toolsTriggered' | 'toolCallCount';
4233
+ /**
4234
+ * Result of an expectation check
4235
+ */
4236
+ interface EvalExpectationResult {
4237
+ /**
4238
+ * Whether the expectation passed
4239
+ */
4240
+ pass: boolean;
4241
+ /**
4242
+ * Optional details about the result
4243
+ */
4244
+ details?: string;
4245
+ /**
4246
+ * Judge score (0-1). Populated for passesJudge expectations.
4247
+ */
4248
+ score?: number;
4249
+ /**
4250
+ * Judge reasoning. Populated for passesJudge expectations.
4251
+ */
4252
+ reasoning?: string;
4253
+ /**
4254
+ * Judge name — rubric name (e.g. 'correctness') or custom judge name.
4255
+ * Populated for passesJudge expectations.
4256
+ */
4257
+ judgeName?: string;
4258
+ /**
4259
+ * Judge provider used. Populated for passesJudge expectations.
4260
+ */
4261
+ judgeProvider?: string;
4262
+ /**
4263
+ * Judge model used. Populated for passesJudge expectations.
4264
+ */
4265
+ judgeModel?: string;
4266
+ /**
4267
+ * Per-judge breakdown when multiple judges are used.
4268
+ * Each entry contains the individual judge's result.
4269
+ * Only populated when passesJudge is an array with 2+ entries.
4270
+ */
4271
+ judgeResults?: EvalExpectationResult[];
4272
+ }
4273
+ /**
4274
+ * Map of expectation type to result
4275
+ */
4276
+ type ExpectationResultMap = Partial<Record<ExpectationType, EvalExpectationResult>>;
4277
+ /**
4278
+ * Breakdown of expectation types used in a run
4279
+ */
4280
+ type ExpectationBreakdown = Partial<Record<ExpectationType, number>>;
4281
+
4282
+ export { type EvalRunComparisonResult as $, type AuthType as A, BUILT_IN_RUBRICS as B, type CLIConfig as C, DiscoveryError as D, ENV_VAR_NAMES as E, type EvalCaseRequest as F, type EvalCaseResult as G, EvalCaseSchema as H, type EvalContext as I, type JudgeMatcherOptions as J, type EvalDataset as K, type LLMProvider as L, type MCPFixtureApi as M, EvalDatasetSchema as N, type OAuthSetupConfig as O, type PatternValidatorOptions as P, type EvalExpectBlock as Q, type RubricSpec as R, type SchemaValidatorOptions as S, type TextValidatorOptions as T, type EvalExpectationResult as U, type ValidationResult as V, type EvalMode as W, type EvalResultStore as X, type EvalResultStoreConfig as Y, type EvalResultStoreLike as Z, type EvalRunComparisonLabels as _, type MCPHostConfig as a, type StoredEvalArtifact as a$, type EvalRunMetadata as a0, type EvalRunnerOptions as a1, type EvalRunnerResult as a2, type ExpectationBreakdown as a3, type ExpectationResultMap as a4, type ExpectationType as a5, type ExperimentMetric as a6, type FieldRemovalSanitizer as a7, FileEvalResultStore as a8, type FileEvalResultStoreConfig as a9, type MCPHostCapabilities as aA, type MCPHostSimulator as aB, type MCPOAuthConfig as aC, type MCPServerCapabilitiesData as aD, MCP_PROTOCOL_VERSION as aE, type NormalizedToolResponse as aF, PlaywrightOAuthClientProvider as aG, type PlaywrightOAuthClientProviderConfig as aH, type PredicateResult as aI, type ProposeVariantsContext as aJ, type ProtectedResourceDiscoveryResult as aK, type ProtectedResourceMetadata as aL, type ProviderKind as aM, type RegexSanitizer as aN, type ResultSource as aO, type SaveBaselineOptions as aP, type SaveEvalRunComparisonOptions as aQ, type SaveServerComparisonOptions as aR, type SchemaRegistry as aS, type SerializedEvalDataset as aT, type ServerComparisonOptions as aU, type ServerComparisonResult as aV, SnapshotSanitizers as aW, type StdioMCPConfig as aX, type StoredArtifactKind as aY, type StoredArtifactSummary as aZ, type StoredClientInfo as a_, GCSEvalResultStore as aa, type GCSEvalResultStoreConfig as ab, type HostType as ac, type HttpMCPConfig as ad, type IterationResult as ae, type JudgeExpectConfig as af, type JudgeResult as ag, type JudgeValidatorConfig as ah, type LLMToolCall as ai, type ListStoredArtifactsOptions as aj, type LoadDatasetOptions as ak, type MCPAuthConfig as al, type MCPAuthFixtures as am, type MCPClientCredentialsConfig as an, type MCPConfig as ao, MCPConfigSchema as ap, type MCPConformanceCheck as aq, type MCPConformanceOptions as ar, type MCPConformanceRaw as as, type MCPConformanceResult as at, type MCPConformanceResultData as au, type MCPEvalData as av, type MCPEvalHistoricalSummary as aw, type MCPEvalReporterConfig as ax, type MCPEvalRunData as ay, type MCPFixtureOptions as az, type MCPHostSimulationResult as b, validateToolCallCount as b$, type StoredEvalArtifactMetadata as b0, type StoredEvalResultLoadOptions as b1, type StoredEvalResultRef as b2, type StoredEvalResultSaveOptions as b3, type StoredEvalRunRef as b4, type StoredOAuthState as b5, type StoredServerMetadata as b6, type StoredTokens as b7, type TokenResult as b8, type ToolMetadataOverride as b9, isHttpConfig as bA, isStdioConfig as bB, loadBaseline as bC, loadEvalDataset as bD, loadEvalDatasetFromObject as bE, loadStoredEvalRunnerResult as bF, loadTokens as bG, loadTokensFromEnv as bH, test as bI, normalizeToolResponse as bJ, performClientCredentialsFlow as bK, refreshAccessToken as bL, registerJudge as bM, resolveEvalResultStore as bN, resolveRubric as bO, runConformanceChecks as bP, runEvalCase as bQ, runEvalDataset as bR, runServerComparison as bS, runVariantExperiment as bT, saveBaseline as bU, saveEvalRunComparison as bV, saveServerComparison as bW, validateEvalCase as bX, validateEvalDataset as bY, validateJudge as bZ, validateMCPConfig as b_, type ToolOverrideVariant as ba, type UsageMetrics as bb, type VariantCandidateResult as bc, type VariantExperimentOptions as bd, type VariantExperimentReason as be, type VariantExperimentResult as bf, type VariantExperimentRound as bg, type VariantImprovementProposal as bh, type VariantRecommendation as bi, clearJudgeRegistry as bj, closeMCPClient as bk, compareEvalRuns as bl, createDefaultArtifactId as bm, createEvalResultStore as bn, createMCPClientForConfig as bo, createMCPFixture as bp, createStoredEvalArtifact as bq, defaultEnvironmentMetadata as br, discoverAuthorizationServer as bs, discoverProtectedResource as bt, extractText as bu, getRegisteredJudge as bv, hasValidTokens as bw, injectTokens as bx, isBuiltInRubric as by, isEvalResultStore as bz, type SizeValidatorOptions as c, validateToolCalls as c0, type SnapshotSanitizer as d, type ToolPredicate as e, type ToolCallExpectation as f, type ToolCallCountOptions as g, type JudgeConfig as h, type Judge as i, type BuiltInRubric as j, type BuiltInSanitizer as k, CLIOAuthClient as l, type CLIOAuthClientConfig as m, type CLIOAuthResult as n, type CLIOutputFormat as o, type CaseComparisonResult as p, type ClientCredentialsConfig as q, type CompareEvalRunsOptions as r, type ComparisonOutcome as s, type ContentBlock as t, type CreateMCPClientOptions as u, type CustomJudgeExecutor as v, type CustomJudgeResult as w, type EvalCase as x, type EvalCaseComparison as y, type EvalCaseComparisonOutcome as z };