@ancplua/qyl-api-schema 0.5.15 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,205 +1,1054 @@
1
+ import "@typespec/http";
1
2
  import "@typespec/openapi3";
2
3
 
4
+ import "../common/types.tsp";
5
+ import "../otel/logs.tsp";
6
+ import "../otel/metrics.tsp";
7
+ import "../otel/span.tsp";
8
+
9
+ using TypeSpec.Http;
3
10
  using TypeSpec.OpenAPI;
11
+ using Qyl.Api.Contracts.Common;
12
+ using Qyl.Api.Contracts.OTel.Logs;
13
+ using Qyl.Api.Contracts.OTel.Metrics;
14
+ using Qyl.Api.Contracts.OTel.Traces;
4
15
 
5
16
  namespace Qyl.Api.Contracts.Runner.Mcp;
6
17
 
7
- @doc("Icon metadata carried by MCP tools and resource links.")
8
- model RunnerMcpIcon {
9
- src: string;
10
- mimeType?: string;
11
- sizes?: string[];
12
- theme?: string;
18
+ @doc("Opaque identifier for one authenticated local runner session.")
19
+ @minLength(1)
20
+ @maxLength(128)
21
+ scalar RunnerMcpSessionId extends string;
22
+
23
+ @doc("Opaque identifier for one MCP workbench workspace.")
24
+ @minLength(1)
25
+ @maxLength(128)
26
+ scalar RunnerMcpWorkspaceId extends string;
27
+
28
+ @doc("Opaque identifier for one configured MCP server.")
29
+ @minLength(1)
30
+ @maxLength(128)
31
+ scalar RunnerMcpServerId extends string;
32
+
33
+ @doc("Opaque identifier for one asynchronous MCP tool execution.")
34
+ @minLength(1)
35
+ @maxLength(128)
36
+ scalar RunnerMcpExecutionId extends string;
37
+
38
+ @doc("Opaque identifier for one reusable MCP test case.")
39
+ @minLength(1)
40
+ @maxLength(128)
41
+ scalar RunnerMcpTestCaseId extends string;
42
+
43
+ @doc("Opaque identifier for one reusable MCP test suite.")
44
+ @minLength(1)
45
+ @maxLength(128)
46
+ scalar RunnerMcpSuiteId extends string;
47
+
48
+ @doc("Opaque identifier for one MCP evaluation run.")
49
+ @minLength(1)
50
+ @maxLength(128)
51
+ scalar RunnerMcpEvaluationRunId extends string;
52
+
53
+ @doc("Opaque identifier for one generated evaluation export.")
54
+ @minLength(1)
55
+ @maxLength(128)
56
+ scalar RunnerMcpEvaluationExportId extends string;
57
+
58
+ @doc("Authenticated local principal metadata. No credential or session token is represented here.")
59
+ model RunnerMcpPrincipalIdentity {
60
+ id: string;
61
+ displayName?: string;
62
+ local: true;
13
63
  }
14
64
 
15
- @doc("Task-augmentation support advertised for an MCP tool.")
16
- enum RunnerMcpToolTaskSupport {
17
- forbidden: "forbidden",
18
- optional: "optional",
19
- required: "required",
65
+ @doc("Metadata for the authenticated local workbench session. The HttpOnly session cookie is never returned in this model.")
66
+ model RunnerMcpWorkbenchSession {
67
+ id: RunnerMcpSessionId;
68
+ principal: RunnerMcpPrincipalIdentity;
69
+ workspaceIds: RunnerMcpWorkspaceId[];
70
+ activeWorkspaceId?: RunnerMcpWorkspaceId;
71
+ createdAt: utcDateTime;
72
+ expiresAt?: utcDateTime;
20
73
  }
21
74
 
22
- @doc("Execution metadata advertised for an MCP tool.")
23
- model RunnerMcpToolExecution {
24
- taskSupport?: RunnerMcpToolTaskSupport;
75
+ @doc("Loopback session bootstrap response. The cookie value is carried only in Set-Cookie and never in the JSON body.")
76
+ model RunnerMcpSessionBootstrapResponse extends RunnerMcpWorkbenchSession {
77
+ @doc("qyl-mcp-session cookie with HttpOnly, SameSite, Path, and expiry attributes; Secure is also present when served over HTTPS.")
78
+ @header("Set-Cookie")
79
+ setCookie: string;
25
80
  }
26
81
 
27
- @doc("Stable qyl projection of an MCP tool advertised by a runner resource.")
28
- model RunnerMcpTool {
82
+ @doc("One isolated MCP workbench workspace owned by the authenticated local principal.")
83
+ model RunnerMcpWorkspace {
84
+ id: RunnerMcpWorkspaceId;
85
+ ownerId: string;
29
86
  name: string;
30
- title?: string;
31
87
  description?: string;
32
- inputSchema: Record<unknown>;
33
- outputSchema?: Record<unknown>;
34
- annotations?: Record<unknown>;
35
- execution?: RunnerMcpToolExecution;
36
- icons?: RunnerMcpIcon[];
37
- @encodedName("application/json", "_meta")
38
- metadata?: Record<unknown>;
39
- }
40
-
41
- @doc("MCP tools currently advertised by a runner resource.")
42
- model RunnerMcpToolsResponse {
43
- tools: RunnerMcpTool[];
44
- nextCursor?: string;
45
- @encodedName("application/json", "_meta")
46
- metadata?: Record<unknown>;
88
+ createdAt: utcDateTime;
89
+ updatedAt: utcDateTime;
47
90
  }
48
91
 
49
- @doc("Tool call accepted by the runner's MCP projection.")
50
- model RunnerMcpToolCallRequest {
92
+ @doc("Request to create an isolated MCP workbench workspace.")
93
+ model RunnerMcpWorkspaceCreateRequest {
94
+ @minLength(1)
95
+ @maxLength(120)
51
96
  name: string;
52
- arguments?: Record<unknown>;
53
- task?: RunnerMcpTaskMetadata;
54
- @encodedName("application/json", "_meta")
55
- metadata?: Record<unknown>;
97
+
98
+ @maxLength(2000)
99
+ description?: string;
100
+ }
101
+
102
+ @doc("Request to update mutable MCP workbench workspace metadata.")
103
+ model RunnerMcpWorkspaceUpdateRequest {
104
+ @minLength(1)
105
+ @maxLength(120)
106
+ name?: string;
107
+
108
+ @maxLength(2000)
109
+ description?: string;
56
110
  }
57
111
 
58
- @doc("Task-augmentation metadata accepted on an MCP tool call. ttl is encoded as milliseconds.")
59
- model RunnerMcpTaskMetadata {
60
- ttl?: float64;
112
+ @doc("Workspaces visible to the authenticated local session.")
113
+ model RunnerMcpWorkspaceListResponse {
114
+ workspaces: RunnerMcpWorkspace[];
61
115
  }
62
116
 
63
- @doc("Metadata shared by every MCP content variant.")
64
- model RunnerMcpContentMetadata {
65
- annotations?: Record<unknown>;
66
- @encodedName("application/json", "_meta")
67
- metadata?: Record<unknown>;
117
+ @doc("Preferred tool-argument editor for one authenticated workspace.")
118
+ enum RunnerMcpToolInputMode {
119
+ form: "form",
120
+ json: "json",
68
121
  }
69
122
 
70
- @doc("Text provided to or returned by an MCP model or tool.")
71
- model RunnerMcpTextContent extends RunnerMcpContentMetadata {
72
- type: "text";
73
- text: string;
123
+ @doc("Saved presentation preferences isolated to one authenticated MCP workspace.")
124
+ model RunnerMcpWorkspacePreferences {
125
+ workspaceId: RunnerMcpWorkspaceId;
126
+ selectedServerId?: RunnerMcpServerId;
127
+
128
+ @maxLength(1024)
129
+ selectedToolName?: string;
130
+
131
+ inputMode: RunnerMcpToolInputMode;
132
+
133
+ @maxLength(128)
134
+ activePanel?: string;
135
+
136
+ compactMode: boolean;
137
+ updatedAt: utcDateTime;
138
+ }
139
+
140
+ @doc("Request to replace saved presentation preferences for one authenticated MCP workspace.")
141
+ model RunnerMcpWorkspacePreferencesUpdateRequest {
142
+ selectedServerId?: RunnerMcpServerId;
143
+
144
+ @maxLength(1024)
145
+ selectedToolName?: string;
146
+
147
+ inputMode?: RunnerMcpToolInputMode;
148
+
149
+ @maxLength(128)
150
+ activePanel?: string;
151
+
152
+ compactMode?: boolean;
74
153
  }
75
154
 
76
- @doc("Base64-encoded image content.")
77
- model RunnerMcpImageContent extends RunnerMcpContentMetadata {
78
- type: "image";
79
- data: bytes;
80
- mimeType: string;
155
+ @doc("Supported MCP server transport owned by the local runner.")
156
+ enum RunnerMcpTransportKind {
157
+ stdio: "stdio",
158
+ streamableHttp: "streamable_http",
159
+ sse: "sse",
160
+ inproc: "inproc",
161
+ builtin: "builtin",
81
162
  }
82
163
 
83
- @doc("Base64-encoded audio content.")
84
- model RunnerMcpAudioContent extends RunnerMcpContentMetadata {
85
- type: "audio";
86
- data: bytes;
87
- mimeType: string;
164
+ @doc("Reference to a secret resolved from the runner environment. The environment value is never part of this contract.")
165
+ model RunnerMcpSecretReference {
166
+ source: "environment";
167
+
168
+ @pattern("^[A-Za-z_][A-Za-z0-9_]*$")
169
+ environmentVariable: string;
170
+ }
171
+
172
+ @doc("Environment variable whose value is resolved from a secret reference at connection time.")
173
+ model RunnerMcpEnvironmentSecretReference {
174
+ @pattern("^[A-Za-z_][A-Za-z0-9_]*$")
175
+ name: string;
176
+
177
+ secret: RunnerMcpSecretReference;
178
+ }
179
+
180
+ @doc("HTTP header whose value is resolved from a secret reference at connection time.")
181
+ model RunnerMcpHeaderSecretReference {
182
+ @minLength(1)
183
+ name: string;
184
+
185
+ secret: RunnerMcpSecretReference;
186
+
187
+ @doc("Optional HTTP authentication scheme applied to the resolved secret. Omit for a raw header value.")
188
+ scheme?: RunnerMcpHeaderSecretScheme;
189
+ }
190
+
191
+ @doc("HTTP authentication scheme applied to an environment-resolved header secret.")
192
+ enum RunnerMcpHeaderSecretScheme {
193
+ bearer: "bearer",
194
+ basic: "basic",
195
+ }
196
+
197
+ @doc("Sanitized local stdio transport configuration. Arguments must not contain secrets.")
198
+ model RunnerMcpStdioServerConfiguration {
199
+ transport: "stdio";
200
+
201
+ @minLength(1)
202
+ command: string;
203
+
204
+ arguments?: string[];
205
+ workingDirectory?: string;
206
+ environment?: RunnerMcpEnvironmentSecretReference[];
207
+ }
208
+
209
+ @doc("Sanitized MCP Streamable HTTP transport configuration.")
210
+ model RunnerMcpStreamableHttpServerConfiguration {
211
+ transport: "streamable_http";
212
+ endpoint: url;
213
+ headers?: RunnerMcpHeaderSecretReference[];
214
+ }
215
+
216
+ @doc("Sanitized legacy MCP SSE transport configuration.")
217
+ model RunnerMcpSseServerConfiguration {
218
+ transport: "sse";
219
+ endpoint: url;
220
+ headers?: RunnerMcpHeaderSecretReference[];
221
+ }
222
+
223
+ @doc("Sanitized in-process MCP server configuration.")
224
+ model RunnerMcpInProcessServerConfiguration {
225
+ transport: "inproc";
226
+
227
+ @minLength(1)
228
+ implementation: string;
229
+ }
230
+
231
+ @doc("Sanitized built-in MCP server configuration.")
232
+ model RunnerMcpBuiltinServerConfiguration {
233
+ transport: "builtin";
234
+
235
+ @minLength(1)
236
+ name: string;
237
+ }
238
+
239
+ @doc("Exactly one sanitized MCP server transport configuration.")
240
+ @oneOf
241
+ union RunnerMcpServerConfiguration {
242
+ stdio: RunnerMcpStdioServerConfiguration,
243
+ streamableHttp: RunnerMcpStreamableHttpServerConfiguration,
244
+ sse: RunnerMcpSseServerConfiguration,
245
+ inproc: RunnerMcpInProcessServerConfiguration,
246
+ builtin: RunnerMcpBuiltinServerConfiguration,
247
+ }
248
+
249
+ @doc("Connection lifecycle for one configured MCP server.")
250
+ enum RunnerMcpConnectionStatus {
251
+ disconnected: "disconnected",
252
+ connecting: "connecting",
253
+ connected: "connected",
254
+ disconnecting: "disconnecting",
255
+ reconnecting: "reconnecting",
256
+ failed: "failed",
257
+ }
258
+
259
+ @doc("Stable category for a workbench, transport, protocol, or tool execution error.")
260
+ enum RunnerMcpErrorCategory {
261
+ authentication: "authentication",
262
+ transport: "transport",
263
+ protocol: "protocol",
264
+ serialization: "serialization",
265
+ schemaValidation: "schema_validation",
266
+ toolError: "tool_error",
267
+ timeout: "timeout",
268
+ cancelled: "cancelled",
269
+ internal: "internal",
270
+ }
271
+
272
+ @doc("Typed, sanitized failure captured by the MCP workbench.")
273
+ model RunnerMcpError {
274
+ category: RunnerMcpErrorCategory;
275
+ code: string;
276
+ message: string;
277
+ occurredAt: utcDateTime;
278
+ retryable: boolean;
279
+
280
+ @doc("Sanitized implementation details with credentials and secret values removed.")
281
+ details?: unknown;
282
+ }
283
+
284
+ @doc("SDK-validated MCP initialize result projected through a Qyl-owned connection snapshot.")
285
+ model RunnerMcpInitializationSnapshot {
286
+ initializedAt: utcDateTime;
287
+ protocolVersion: string;
288
+
289
+ @doc("Opaque SDK server-info entity.")
290
+ serverIdentity: unknown;
291
+
292
+ @doc("Opaque SDK server-capabilities entity.")
293
+ capabilities: unknown;
294
+
295
+ instructions?: string;
296
+
297
+ @doc("Opaque SDK session information when the transport exposes it.")
298
+ sessionInfo?: unknown;
299
+
300
+ @doc("Complete opaque SDK initialize result.")
301
+ result: unknown;
88
302
  }
89
303
 
90
- @doc("A resource embedded in MCP content.")
91
- model RunnerMcpEmbeddedResourceContent extends RunnerMcpContentMetadata {
92
- type: "resource";
93
- resource: RunnerMcpResourceContent;
304
+ @doc("Current connection state and most recent initialization evidence for one MCP server.")
305
+ model RunnerMcpConnectionSnapshot {
306
+ status: RunnerMcpConnectionStatus;
307
+ changedAt: utcDateTime;
308
+ connectedAt?: utcDateTime;
309
+ disconnectedAt?: utcDateTime;
310
+ initialization?: RunnerMcpInitializationSnapshot;
311
+ recentError?: RunnerMcpError;
94
312
  }
95
313
 
96
- @doc("A link to a resource that an MCP server can read.")
97
- model RunnerMcpResourceLinkContent extends RunnerMcpContentMetadata {
98
- type: "resource_link";
99
- uri: url;
314
+ @doc("Persisted sanitized MCP server configuration and current runtime connection state.")
315
+ model RunnerMcpServer {
316
+ id: RunnerMcpServerId;
317
+ workspaceId: RunnerMcpWorkspaceId;
100
318
  name: string;
101
- title?: string;
102
319
  description?: string;
103
- mimeType?: string;
320
+ configuration: RunnerMcpServerConfiguration;
321
+ connection: RunnerMcpConnectionSnapshot;
322
+ createdAt: utcDateTime;
323
+ updatedAt: utcDateTime;
324
+ }
325
+
326
+ @doc("Request to add an MCP server configuration to a workspace.")
327
+ model RunnerMcpServerCreateRequest {
328
+ @minLength(1)
329
+ @maxLength(120)
330
+ name: string;
331
+
332
+ @maxLength(2000)
333
+ description?: string;
334
+
335
+ configuration: RunnerMcpServerConfiguration;
336
+ autoConnect?: boolean = false;
337
+ }
338
+
339
+ @doc("Request to replace mutable MCP server metadata or its complete sanitized transport configuration.")
340
+ model RunnerMcpServerUpdateRequest {
341
+ @minLength(1)
342
+ @maxLength(120)
343
+ name?: string;
344
+
345
+ @maxLength(2000)
346
+ description?: string;
347
+
348
+ configuration?: RunnerMcpServerConfiguration;
349
+ }
350
+
351
+ @doc("Configured MCP servers in one authenticated workspace.")
352
+ model RunnerMcpServerListResponse {
353
+ servers: RunnerMcpServer[];
354
+ }
355
+
356
+ @doc("An MCP server connection action was accepted and continues asynchronously.")
357
+ model RunnerMcpServerActionAccepted {
358
+ @statusCode statusCode: 202;
359
+ server: RunnerMcpServer;
360
+ }
361
+
362
+ @doc("One discovered MCP entity collection. Every item remains the SDK-validated opaque entity.")
363
+ model RunnerMcpDiscoveryCollection {
364
+ items: unknown[];
365
+
104
366
  @minValue(0)
105
- size?: int64;
106
- icons?: RunnerMcpIcon[];
367
+ count: int32;
368
+
369
+ complete: boolean;
370
+ cursor?: string;
371
+ nextCursor?: string;
372
+ discoveredAt: utcDateTime;
107
373
  }
108
374
 
109
- @doc("An MCP sampling request to invoke a tool.")
110
- model RunnerMcpToolUseContent extends RunnerMcpContentMetadata {
111
- type: "tool_use";
375
+ @doc("Complete MCP capability discovery evidence for one server.")
376
+ model RunnerMcpDiscoverySnapshot {
377
+ serverId: RunnerMcpServerId;
378
+ startedAt: utcDateTime;
379
+ completedAt: utcDateTime;
380
+ tools: RunnerMcpDiscoveryCollection;
381
+ resources: RunnerMcpDiscoveryCollection;
382
+ resourceTemplates: RunnerMcpDiscoveryCollection;
383
+ prompts: RunnerMcpDiscoveryCollection;
384
+ }
385
+
386
+ @doc("Direction of a captured MCP protocol or transport event.")
387
+ enum RunnerMcpProtocolDirection {
388
+ clientToServer: "client_to_server",
389
+ serverToClient: "server_to_client",
390
+ local: "local",
391
+ }
392
+
393
+ @doc("Kind of captured MCP protocol or transport event.")
394
+ enum RunnerMcpProtocolEventKind {
395
+ request: "request",
396
+ response: "response",
397
+ notification: "notification",
398
+ error: "error",
399
+ transport: "transport",
400
+ }
401
+
402
+ @doc("Chronological diagnostic event carrying only a redacted opaque SDK message or local transport payload.")
403
+ model RunnerMcpProtocolEvent {
112
404
  id: string;
113
- name: string;
114
- input: unknown;
405
+ serverId: RunnerMcpServerId;
406
+ direction: RunnerMcpProtocolDirection;
407
+ kind: RunnerMcpProtocolEventKind;
408
+ method?: string;
409
+
410
+ @doc("Opaque JSON-RPC request identifier, which may be a string or number.")
411
+ requestId?: unknown;
412
+
413
+ timestamp: utcDateTime;
414
+ durationMs?: DurationMs;
415
+
416
+ @doc("Opaque SDK message or transport payload after credential and secret redaction.")
417
+ payload?: unknown;
418
+
419
+ redactionApplied: true;
420
+ executionId?: RunnerMcpExecutionId;
421
+ traceId?: TraceId;
422
+ }
423
+
424
+ @doc("Cursor page of chronological MCP protocol diagnostic events.")
425
+ model RunnerMcpProtocolEventPage {
426
+ events: RunnerMcpProtocolEvent[];
427
+ nextCursor?: string;
428
+ }
429
+
430
+ @doc("How consequential the workbench considers an MCP tool invocation.")
431
+ enum RunnerMcpExecutionEffect {
432
+ readOnly: "read_only",
433
+ consequential: "consequential",
434
+ `unknown`: "unknown",
115
435
  }
116
436
 
117
- @doc("The result of an MCP sampling tool invocation.")
118
- model RunnerMcpToolResultContent extends RunnerMcpContentMetadata {
119
- type: "tool_result";
120
- toolUseId: string;
121
- content: RunnerMcpContent[];
122
- structuredContent?: Record<unknown>;
123
- isError?: boolean;
437
+ @doc("Client acknowledgement supplied when requesting a consequential MCP tool invocation.")
438
+ model RunnerMcpExecutionConfirmationRequest {
439
+ acknowledged: true;
440
+ acknowledgement: string;
124
441
  }
125
442
 
126
- @doc("One MCP content item. The type literal selects the required variant fields.")
443
+ @doc("Server-timestamped confirmation evidence persisted for a consequential MCP tool invocation.")
444
+ model RunnerMcpExecutionConfirmationEvidence {
445
+ acknowledged: true;
446
+ acknowledgement: string;
447
+ confirmedAt: utcDateTime;
448
+ }
449
+
450
+ @doc("Request to asynchronously invoke one discovered MCP tool.")
451
+ model RunnerMcpExecutionRequest {
452
+ @minLength(1)
453
+ toolName: string;
454
+
455
+ @doc("Opaque tool arguments validated against the SDK tool schema before execution.")
456
+ arguments?: unknown;
457
+
458
+ @minValue(1)
459
+ @maxValue(3600000)
460
+ timeoutMs: int32 = 30000;
461
+
462
+ confirmation?: RunnerMcpExecutionConfirmationRequest;
463
+
464
+ @minLength(8)
465
+ @maxLength(256)
466
+ idempotencyKey: string;
467
+ }
468
+
469
+ @doc("Asynchronous MCP execution lifecycle.")
470
+ enum RunnerMcpExecutionStatus {
471
+ queued: "queued",
472
+ running: "running",
473
+ cancelling: "cancelling",
474
+ succeeded: "succeeded",
475
+ failed: "failed",
476
+ cancelled: "cancelled",
477
+ timedOut: "timed_out",
478
+ }
479
+
480
+ @doc("Token usage reported or derived for one MCP execution when available.")
481
+ model RunnerMcpExecutionTokenUsage {
482
+ inputTokens?: TokenCount;
483
+ outputTokens?: TokenCount;
484
+ totalTokens?: TokenCount;
485
+ estimated: boolean;
486
+ }
487
+
488
+ @doc("USD cost reported or estimated for one MCP execution when available.")
489
+ model RunnerMcpExecutionCost {
490
+ amountUsd: CostUsd;
491
+ estimated: boolean;
492
+ source?: string;
493
+ }
494
+
495
+ @doc("Qyl observability identifiers correlating workbench, MCP, and downstream activity.")
496
+ model RunnerMcpTelemetryCorrelation {
497
+ executionId?: RunnerMcpExecutionId;
498
+ evaluationRunId?: RunnerMcpEvaluationRunId;
499
+ testCaseId?: RunnerMcpTestCaseId;
500
+ traceIds: TraceId[];
501
+ spanIds: SpanId[];
502
+ }
503
+
504
+ @doc("Persisted asynchronous execution evidence. SDK tool results remain opaque.")
505
+ model RunnerMcpExecutionRecord {
506
+ id: RunnerMcpExecutionId;
507
+ workspaceId: RunnerMcpWorkspaceId;
508
+ serverId: RunnerMcpServerId;
509
+ request: RunnerMcpExecutionRequest;
510
+
511
+ @doc("Server-derived effect from the SDK-validated discovered Tool and its annotations.")
512
+ effect: RunnerMcpExecutionEffect;
513
+
514
+ confirmation?: RunnerMcpExecutionConfirmationEvidence;
515
+ status: RunnerMcpExecutionStatus;
516
+ createdAt: utcDateTime;
517
+ startedAt?: utcDateTime;
518
+ completedAt?: utcDateTime;
519
+ durationMs?: DurationMs;
520
+
521
+ @minValue(0)
522
+ attemptCount: int32;
523
+
524
+ @minValue(0)
525
+ retryCount: int32;
526
+
527
+ cancelRequestedAt?: utcDateTime;
528
+ cancelledAt?: utcDateTime;
529
+
530
+ @doc("Complete opaque SDK tool-call result after output sanitization.")
531
+ result?: unknown;
532
+
533
+ error?: RunnerMcpError;
534
+ tokenUsage?: RunnerMcpExecutionTokenUsage;
535
+ cost?: RunnerMcpExecutionCost;
536
+ telemetry?: RunnerMcpTelemetryCorrelation;
537
+ }
538
+
539
+ @doc("An MCP execution was accepted and continues asynchronously.")
540
+ model RunnerMcpExecutionAccepted {
541
+ @statusCode statusCode: 202;
542
+ execution: RunnerMcpExecutionRecord;
543
+ }
544
+
545
+ @doc("Request to cancel an asynchronous MCP execution where the transport permits cancellation.")
546
+ model RunnerMcpExecutionCancelRequest {
547
+ @maxLength(1000)
548
+ reason?: string;
549
+
550
+ @minLength(8)
551
+ @maxLength(256)
552
+ idempotencyKey: string;
553
+ }
554
+
555
+ @doc("Cursor page of MCP execution records.")
556
+ model RunnerMcpExecutionPage {
557
+ executions: RunnerMcpExecutionRecord[];
558
+ nextCursor?: string;
559
+ }
560
+
561
+ @doc("Whether correlated Qyl observability evidence was available.")
562
+ enum RunnerMcpTelemetryAvailability {
563
+ available: "available",
564
+ partial: "partial",
565
+ unavailable: "unavailable",
566
+ }
567
+
568
+ @doc("Availability and retained item count for one correlated Qyl telemetry signal.")
569
+ model RunnerMcpTelemetrySignalAvailability {
570
+ status: RunnerMcpTelemetryAvailability;
571
+ unavailableReason?: string;
572
+
573
+ @minValue(0)
574
+ itemCount: int32;
575
+ }
576
+
577
+ @doc("Per-signal availability for correlated workbench observability evidence.")
578
+ model RunnerMcpTelemetrySignalSummary {
579
+ traces: RunnerMcpTelemetrySignalAvailability;
580
+ logs: RunnerMcpTelemetrySignalAvailability;
581
+ metrics: RunnerMcpTelemetrySignalAvailability;
582
+ exceptions: RunnerMcpTelemetrySignalAvailability;
583
+ toolCallEvents: RunnerMcpTelemetrySignalAvailability;
584
+ }
585
+
586
+ @doc("Correlated Qyl observability evidence for one MCP execution. Signals unsupported by the connected Qyl read API are explicitly unavailable.")
587
+ model RunnerMcpExecutionTelemetryResponse {
588
+ signals: RunnerMcpTelemetrySignalSummary;
589
+ correlation: RunnerMcpTelemetryCorrelation;
590
+ traces: Trace[];
591
+ logs: LogRecord[];
592
+ metrics: MetricPoint[];
593
+ queriedAt: utcDateTime;
594
+
595
+ @doc("Confirms that workbench telemetry querying is excluded from workbench export instrumentation.")
596
+ selfExportSuppressed: true;
597
+ }
598
+
599
+ @doc("Assertion outcome reported by an evaluation.")
600
+ enum RunnerMcpAssertionStatus {
601
+ passed: "passed",
602
+ failed: "failed",
603
+ error: "error",
604
+ skipped: "skipped",
605
+ }
606
+
607
+ @doc("Execution-status assertion for an MCP test case.")
608
+ model RunnerMcpStatusAssertion {
609
+ id: string;
610
+ kind: "status";
611
+
612
+ @minItems(1)
613
+ expected: RunnerMcpExecutionStatus[];
614
+ }
615
+
616
+ @doc("Exact JSON value assertion at an optional JSON Pointer path.")
617
+ model RunnerMcpExactAssertion {
618
+ id: string;
619
+ kind: "exact";
620
+ path?: string;
621
+ expected: unknown;
622
+ }
623
+
624
+ @doc("Partial JSON object or array containment assertion at an optional JSON Pointer path.")
625
+ model RunnerMcpPartialAssertion {
626
+ id: string;
627
+ kind: "partial";
628
+ path?: string;
629
+ expected: unknown;
630
+ }
631
+
632
+ @doc("JSON Schema assertion at an optional JSON Pointer path.")
633
+ model RunnerMcpSchemaAssertion {
634
+ id: string;
635
+ kind: "schema";
636
+ path?: string;
637
+ schema: unknown;
638
+ }
639
+
640
+ @doc("Regular-expression assertion at an optional JSON Pointer path.")
641
+ model RunnerMcpPatternAssertion {
642
+ id: string;
643
+ kind: "pattern";
644
+ path?: string;
645
+ pattern: string;
646
+ flags?: string;
647
+ }
648
+
649
+ @doc("Maximum execution latency assertion.")
650
+ model RunnerMcpLatencyAssertion {
651
+ id: string;
652
+ kind: "latency";
653
+
654
+ @minValue(0)
655
+ maxDurationMs: float64;
656
+ }
657
+
658
+ @doc("Exactly one supported MCP evaluation assertion.")
127
659
  @oneOf
128
- union RunnerMcpContent {
129
- text: RunnerMcpTextContent,
130
- image: RunnerMcpImageContent,
131
- audio: RunnerMcpAudioContent,
132
- embeddedResource: RunnerMcpEmbeddedResourceContent,
133
- resourceLink: RunnerMcpResourceLinkContent,
134
- toolUse: RunnerMcpToolUseContent,
135
- toolResult: RunnerMcpToolResultContent,
136
- }
137
-
138
- @doc("Lifecycle state of an MCP task returned by a task-augmented tool call.")
139
- enum RunnerMcpTaskStatus {
140
- working: "working",
141
- inputRequired: "input_required",
660
+ union RunnerMcpTestAssertion {
661
+ status: RunnerMcpStatusAssertion,
662
+ exact: RunnerMcpExactAssertion,
663
+ partial: RunnerMcpPartialAssertion,
664
+ schema: RunnerMcpSchemaAssertion,
665
+ pattern: RunnerMcpPatternAssertion,
666
+ latency: RunnerMcpLatencyAssertion,
667
+ }
668
+
669
+ @doc("Reusable tool invocation and assertions persisted in one workspace.")
670
+ model RunnerMcpTestCase {
671
+ id: RunnerMcpTestCaseId;
672
+ workspaceId: RunnerMcpWorkspaceId;
673
+ serverId: RunnerMcpServerId;
674
+ name: string;
675
+ description?: string;
676
+ toolName: string;
677
+ arguments?: unknown;
678
+
679
+ @minValue(1)
680
+ @maxValue(3600000)
681
+ timeoutMs: int32;
682
+
683
+ assertions: RunnerMcpTestAssertion[];
684
+ tags: string[];
685
+ createdAt: utcDateTime;
686
+ updatedAt: utcDateTime;
687
+ }
688
+
689
+ @doc("Request to create a reusable MCP test case.")
690
+ model RunnerMcpTestCaseCreateRequest {
691
+ serverId: RunnerMcpServerId;
692
+
693
+ @minLength(1)
694
+ @maxLength(160)
695
+ name: string;
696
+
697
+ @maxLength(4000)
698
+ description?: string;
699
+
700
+ @minLength(1)
701
+ toolName: string;
702
+
703
+ arguments?: unknown;
704
+
705
+ @minValue(1)
706
+ @maxValue(3600000)
707
+ timeoutMs: int32 = 30000;
708
+
709
+ @minItems(1)
710
+ assertions: RunnerMcpTestAssertion[];
711
+
712
+ tags?: string[];
713
+ }
714
+
715
+ @doc("Request to update mutable MCP test-case fields.")
716
+ model RunnerMcpTestCaseUpdateRequest {
717
+ serverId?: RunnerMcpServerId;
718
+
719
+ @minLength(1)
720
+ @maxLength(160)
721
+ name?: string;
722
+
723
+ @maxLength(4000)
724
+ description?: string;
725
+
726
+ @minLength(1)
727
+ toolName?: string;
728
+
729
+ arguments?: unknown;
730
+
731
+ @minValue(1)
732
+ @maxValue(3600000)
733
+ timeoutMs?: int32;
734
+
735
+ @minItems(1)
736
+ assertions?: RunnerMcpTestAssertion[];
737
+
738
+ tags?: string[];
739
+ }
740
+
741
+ @doc("Cursor page of reusable MCP test cases.")
742
+ model RunnerMcpTestCasePage {
743
+ testCases: RunnerMcpTestCase[];
744
+ nextCursor?: string;
745
+ }
746
+
747
+ @doc("Reusable ordered group of MCP test cases.")
748
+ model RunnerMcpTestSuite {
749
+ id: RunnerMcpSuiteId;
750
+ workspaceId: RunnerMcpWorkspaceId;
751
+ name: string;
752
+ description?: string;
753
+
754
+ @minItems(1)
755
+ testCaseIds: RunnerMcpTestCaseId[];
756
+
757
+ tags: string[];
758
+ createdAt: utcDateTime;
759
+ updatedAt: utcDateTime;
760
+ }
761
+
762
+ @doc("Request to create a reusable MCP test suite.")
763
+ model RunnerMcpTestSuiteCreateRequest {
764
+ @minLength(1)
765
+ @maxLength(160)
766
+ name: string;
767
+
768
+ @maxLength(4000)
769
+ description?: string;
770
+
771
+ @minItems(1)
772
+ testCaseIds: RunnerMcpTestCaseId[];
773
+
774
+ tags?: string[];
775
+ }
776
+
777
+ @doc("Request to update mutable MCP test-suite fields.")
778
+ model RunnerMcpTestSuiteUpdateRequest {
779
+ @minLength(1)
780
+ @maxLength(160)
781
+ name?: string;
782
+
783
+ @maxLength(4000)
784
+ description?: string;
785
+
786
+ @minItems(1)
787
+ testCaseIds?: RunnerMcpTestCaseId[];
788
+
789
+ tags?: string[];
790
+ }
791
+
792
+ @doc("Cursor page of reusable MCP test suites.")
793
+ model RunnerMcpTestSuitePage {
794
+ suites: RunnerMcpTestSuite[];
795
+ nextCursor?: string;
796
+ }
797
+
798
+ @doc("Request to execute one test case or suite asynchronously.")
799
+ model RunnerMcpEvaluationRunRequest {
800
+ @minLength(8)
801
+ @maxLength(256)
802
+ idempotencyKey: string;
803
+
804
+ confirmation?: RunnerMcpExecutionConfirmationRequest;
805
+
806
+ @minValue(1)
807
+ @maxValue(50)
808
+ concurrency?: int32 = 1;
809
+
810
+ failFast?: boolean = false;
811
+ }
812
+
813
+ @doc("Request to run one persisted MCP test case asynchronously.")
814
+ model RunnerMcpTestCaseRunRequest extends RunnerMcpEvaluationRunRequest {}
815
+
816
+ @doc("Request to run a complete suite or an explicit subset of its persisted test cases asynchronously.")
817
+ model RunnerMcpSuiteRunRequest extends RunnerMcpEvaluationRunRequest {
818
+ @minItems(1)
819
+ selectedTestCaseIds?: RunnerMcpTestCaseId[];
820
+ }
821
+
822
+ @doc("Lifecycle for an MCP evaluation run.")
823
+ enum RunnerMcpEvaluationRunStatus {
824
+ queued: "queued",
825
+ running: "running",
142
826
  completed: "completed",
143
827
  failed: "failed",
144
828
  cancelled: "cancelled",
145
829
  }
146
830
 
147
- @doc("Task returned by an MCP task-augmented tool call. ttl and pollInterval are encoded as milliseconds.")
148
- model RunnerMcpTask {
149
- taskId: string;
150
- status: RunnerMcpTaskStatus;
151
- statusMessage?: string;
831
+ @doc("Outcome for one test case within an evaluation run.")
832
+ enum RunnerMcpEvaluationResultStatus {
833
+ passed: "passed",
834
+ failed: "failed",
835
+ error: "error",
836
+ skipped: "skipped",
837
+ }
838
+
839
+ @doc("Outcome of one assertion with sanitized actual evidence when useful.")
840
+ model RunnerMcpAssertionResult {
841
+ assertionId: string;
842
+ kind: string;
843
+ status: RunnerMcpAssertionStatus;
844
+ message?: string;
845
+ actual?: unknown;
846
+ }
847
+
848
+ @doc("Immutable reusable-test definition captured when an evaluation run starts.")
849
+ model RunnerMcpEvaluationTestCaseSnapshot {
850
+ id: RunnerMcpTestCaseId;
851
+ serverId: RunnerMcpServerId;
852
+ name: string;
853
+ description?: string;
854
+ toolName: string;
855
+ arguments?: unknown;
856
+ timeoutMs: int32;
857
+ assertions: RunnerMcpTestAssertion[];
858
+ tags: string[];
859
+ }
860
+
861
+ @doc("Immutable suite definition captured when an evaluation run starts.")
862
+ model RunnerMcpEvaluationSuiteSnapshot {
863
+ id: RunnerMcpSuiteId;
864
+ name: string;
865
+ description?: string;
866
+ testCaseIds: RunnerMcpTestCaseId[];
867
+ tags: string[];
868
+ }
869
+
870
+ @doc("One test-case result retained by an MCP evaluation run.")
871
+ model RunnerMcpEvaluationTestResult {
872
+ testCase: RunnerMcpEvaluationTestCaseSnapshot;
873
+ executionId?: RunnerMcpExecutionId;
874
+ status: RunnerMcpEvaluationResultStatus;
875
+ startedAt?: utcDateTime;
876
+ completedAt?: utcDateTime;
877
+ durationMs?: DurationMs;
878
+ assertions: RunnerMcpAssertionResult[];
879
+ error?: RunnerMcpError;
880
+ }
881
+
882
+ @doc("Aggregate correctness, reliability, latency, usage, and cost for an MCP evaluation run.")
883
+ model RunnerMcpEvaluationSummary {
884
+ @minValue(0)
885
+ total: int32;
886
+
887
+ @minValue(0)
888
+ passed: int32;
889
+
890
+ @minValue(0)
891
+ failed: int32;
892
+
893
+ @minValue(0)
894
+ errors: int32;
895
+
896
+ @minValue(0)
897
+ skipped: int32;
898
+
899
+ successRate: Ratio;
900
+ reliability: Ratio;
901
+ meanDurationMs?: DurationMs;
902
+ p50DurationMs?: DurationMs;
903
+ p95DurationMs?: DurationMs;
904
+ p99DurationMs?: DurationMs;
905
+ tokenUsage?: RunnerMcpExecutionTokenUsage;
906
+ cost?: RunnerMcpExecutionCost;
907
+ }
908
+
909
+ @doc("Asynchronous MCP evaluation run with retained per-test evidence.")
910
+ model RunnerMcpEvaluationRun {
911
+ id: RunnerMcpEvaluationRunId;
912
+ workspaceId: RunnerMcpWorkspaceId;
913
+ suite?: RunnerMcpEvaluationSuiteSnapshot;
914
+ testCases: RunnerMcpEvaluationTestCaseSnapshot[];
915
+ status: RunnerMcpEvaluationRunStatus;
152
916
  createdAt: utcDateTime;
153
- lastUpdatedAt: utcDateTime;
154
- ttl?: float64;
155
- pollInterval?: float64;
917
+ startedAt?: utcDateTime;
918
+ completedAt?: utcDateTime;
919
+ results: RunnerMcpEvaluationTestResult[];
920
+ summary?: RunnerMcpEvaluationSummary;
921
+ confirmation?: RunnerMcpExecutionConfirmationEvidence;
922
+ telemetry?: RunnerMcpTelemetryCorrelation;
923
+ error?: RunnerMcpError;
924
+ }
925
+
926
+ @doc("An MCP evaluation run was accepted and continues asynchronously.")
927
+ model RunnerMcpEvaluationRunAccepted {
928
+ @statusCode statusCode: 202;
929
+ run: RunnerMcpEvaluationRun;
156
930
  }
157
931
 
158
- @doc("Stable qyl projection of an MCP tool-call result.")
159
- model RunnerMcpToolCallResponse {
160
- content: RunnerMcpContent[];
161
- structuredContent?: Record<unknown>;
162
- isError: boolean;
163
- task?: RunnerMcpTask;
164
- @encodedName("application/json", "_meta")
165
- metadata?: Record<unknown>;
932
+ @doc("Cursor page of MCP evaluation runs.")
933
+ model RunnerMcpEvaluationRunPage {
934
+ runs: RunnerMcpEvaluationRun[];
935
+ nextCursor?: string;
166
936
  }
167
937
 
168
- @doc("Resource URI accepted by the runner's MCP projection.")
169
- model RunnerMcpResourceReadRequest {
170
- uri: url;
171
- @encodedName("application/json", "_meta")
172
- metadata?: Record<unknown>;
938
+ @doc("Request to compare a baseline MCP evaluation run with a candidate run.")
939
+ model RunnerMcpEvaluationComparisonRequest {
940
+ baselineRunId: RunnerMcpEvaluationRunId;
941
+ candidateRunId: RunnerMcpEvaluationRunId;
173
942
  }
174
943
 
175
- @doc("Metadata shared by MCP text and blob resources.")
176
- model RunnerMcpResourceContentMetadata {
177
- uri: url;
178
- mimeType?: string;
179
- @encodedName("application/json", "_meta")
180
- metadata?: Record<unknown>;
944
+ @doc("Regression classification for one test case across two evaluation runs.")
945
+ enum RunnerMcpRegressionStatus {
946
+ improved: "improved",
947
+ regressed: "regressed",
948
+ unchanged: "unchanged",
949
+ added: "added",
950
+ removed: "removed",
181
951
  }
182
952
 
183
- @doc("Text resource content returned by an MCP server.")
184
- model RunnerMcpTextResourceContent extends RunnerMcpResourceContentMetadata {
185
- text: string;
953
+ @doc("Per-test comparison across a baseline and candidate MCP evaluation run.")
954
+ model RunnerMcpEvaluationTestComparison {
955
+ testCaseId: RunnerMcpTestCaseId;
956
+ status: RunnerMcpRegressionStatus;
957
+ baselineStatus?: RunnerMcpEvaluationResultStatus;
958
+ candidateStatus?: RunnerMcpEvaluationResultStatus;
959
+ durationDeltaMs?: float64;
186
960
  }
187
961
 
188
- @doc("Base64-encoded resource content returned by an MCP server.")
189
- model RunnerMcpBlobResourceContent extends RunnerMcpResourceContentMetadata {
190
- blob: bytes;
962
+ @doc("Aggregate comparison of two completed MCP evaluation runs.")
963
+ model RunnerMcpEvaluationRunComparison {
964
+ baselineRunId: RunnerMcpEvaluationRunId;
965
+ candidateRunId: RunnerMcpEvaluationRunId;
966
+ baseline: RunnerMcpEvaluationSummary;
967
+ candidate: RunnerMcpEvaluationSummary;
968
+ successRateDelta: float64;
969
+ reliabilityDelta: float64;
970
+ p95DurationDeltaMs?: float64;
971
+ tokenDelta?: int64;
972
+ costDeltaUsd?: float64;
973
+ tests: RunnerMcpEvaluationTestComparison[];
974
+ comparedAt: utcDateTime;
191
975
  }
192
976
 
193
- @doc("Exactly one MCP text or blob resource variant.")
977
+ @doc("Supported evaluation export representation.")
978
+ enum RunnerMcpEvaluationExportFormat {
979
+ json: "json",
980
+ report: "report",
981
+ }
982
+
983
+ @doc("Request to generate a machine-readable or readable evaluation export.")
984
+ model RunnerMcpEvaluationExportRequest {
985
+ format: RunnerMcpEvaluationExportFormat;
986
+ includeProtocolEvents?: boolean = true;
987
+ includeTelemetry?: boolean = true;
988
+
989
+ @minLength(8)
990
+ @maxLength(256)
991
+ idempotencyKey: string;
992
+ }
993
+
994
+ @doc("Lifecycle for generation of an evaluation export artifact.")
995
+ enum RunnerMcpEvaluationExportStatus {
996
+ pending: "pending",
997
+ ready: "ready",
998
+ failed: "failed",
999
+ }
1000
+
1001
+ @doc("Metadata for one generated evaluation JSON or readable report artifact.")
1002
+ model RunnerMcpEvaluationExport {
1003
+ id: RunnerMcpEvaluationExportId;
1004
+ runId: RunnerMcpEvaluationRunId;
1005
+ format: RunnerMcpEvaluationExportFormat;
1006
+ status: RunnerMcpEvaluationExportStatus;
1007
+ requestedAt: utcDateTime;
1008
+ completedAt?: utcDateTime;
1009
+ mediaType?: string;
1010
+ fileName?: string;
1011
+ byteSize?: ByteSize;
1012
+ sha256?: Sha256Hash;
1013
+ error?: RunnerMcpError;
1014
+ }
1015
+
1016
+ @doc("Machine-readable evaluation export with retained execution, protocol, and optional telemetry evidence.")
1017
+ model RunnerMcpEvaluationJsonExportPayload {
1018
+ format: "json";
1019
+ run: RunnerMcpEvaluationRun;
1020
+ protocolEvents: RunnerMcpProtocolEvent[];
1021
+ telemetry: RunnerMcpExecutionTelemetryResponse[];
1022
+ exportedAt: utcDateTime;
1023
+ }
1024
+
1025
+ @doc("Human-readable Markdown evaluation report.")
1026
+ model RunnerMcpEvaluationReportExportPayload {
1027
+ format: "report";
1028
+ markdown: string;
1029
+ exportedAt: utcDateTime;
1030
+ }
1031
+
1032
+ @doc("Exactly one generated evaluation export representation.")
194
1033
  @oneOf
195
- union RunnerMcpResourceContent {
196
- text: RunnerMcpTextResourceContent,
197
- blob: RunnerMcpBlobResourceContent,
1034
+ union RunnerMcpEvaluationExportPayload {
1035
+ json: RunnerMcpEvaluationJsonExportPayload,
1036
+ report: RunnerMcpEvaluationReportExportPayload,
1037
+ }
1038
+
1039
+ @doc("Ready evaluation export metadata and its TypeSpec-owned content.")
1040
+ model RunnerMcpEvaluationExportArtifact {
1041
+ export: RunnerMcpEvaluationExport;
1042
+ payload: RunnerMcpEvaluationExportPayload;
1043
+ }
1044
+
1045
+ @doc("An evaluation export was accepted and continues asynchronously.")
1046
+ model RunnerMcpEvaluationExportAccepted {
1047
+ @statusCode statusCode: 202;
1048
+ export: RunnerMcpEvaluationExport;
198
1049
  }
199
1050
 
200
- @doc("Stable qyl projection of an MCP resources/read result.")
201
- model RunnerMcpResourceReadResponse {
202
- contents: RunnerMcpResourceContent[];
203
- @encodedName("application/json", "_meta")
204
- metadata?: Record<unknown>;
1051
+ @doc("Successful deletion with no response body.")
1052
+ model RunnerMcpDeleted {
1053
+ @statusCode statusCode: 204;
205
1054
  }