@astral-mcp/projection 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -22
- package/dist/index.d.mts +696 -269
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3260 -1831
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CallToolResult, ContentBlock, ElicitRequestFormParams, HandlerResultTypeMap, Implementation, InputRequest, InputRequests, InputRequiredResult, InputResponse, InputResponseView, InputResponses, InputResponses as InputResponses$1, McpServer, McpServerFactory, ProtocolEra, ProtocolEra as ProtocolEra$1, acceptedContent, inputRequired, inputResponse, isInputRequiredResult } from "@modelcontextprotocol/server";
|
|
2
1
|
import "@sebastianwessel/quickjs";
|
|
2
|
+
import { CallToolResult, ContentBlock, ElicitRequestFormParams, HandlerResultTypeMap, Implementation, InputRequest, InputRequests, InputRequiredResult, InputResponse, InputResponseView, InputResponses, InputResponses as InputResponses$1, McpServer, McpServerFactory, ProtocolEra, ProtocolEra as ProtocolEra$1, acceptedContent, inputRequired, inputResponse, isInputRequiredResult } from "@modelcontextprotocol/server";
|
|
3
3
|
import { Client } from "@modelcontextprotocol/client";
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
/**
|
|
@@ -11,16 +11,16 @@ import { Client } from "@modelcontextprotocol/client";
|
|
|
11
11
|
* nothing inside the package.
|
|
12
12
|
*/
|
|
13
13
|
/** Alias identifying a wrapped server. v1 instantiates exactly one. */
|
|
14
|
-
type ServerAlias = string;
|
|
15
|
-
declare const DEFAULT_SERVER_ALIAS: ServerAlias;
|
|
14
|
+
export type ServerAlias = string;
|
|
15
|
+
export declare const DEFAULT_SERVER_ALIAS: ServerAlias;
|
|
16
16
|
/** MCP tool annotations we care about (untrusted hints — S5). */
|
|
17
|
-
interface ToolAnnotations {
|
|
17
|
+
export interface ToolAnnotations {
|
|
18
18
|
readOnlyHint?: boolean;
|
|
19
19
|
destructiveHint?: boolean;
|
|
20
20
|
idempotentHint?: boolean;
|
|
21
21
|
title?: string;
|
|
22
22
|
}
|
|
23
|
-
interface ToolCatalogEntry {
|
|
23
|
+
export interface ToolCatalogEntry {
|
|
24
24
|
/** Tool name as declared by the wrapped server. */
|
|
25
25
|
name: string;
|
|
26
26
|
description?: string;
|
|
@@ -30,11 +30,11 @@ interface ToolCatalogEntry {
|
|
|
30
30
|
outputSchema?: Record<string, unknown>;
|
|
31
31
|
annotations?: ToolAnnotations;
|
|
32
32
|
}
|
|
33
|
-
interface ToolCatalog {
|
|
33
|
+
export interface ToolCatalog {
|
|
34
34
|
/** Keyed by server alias (R30). v1 has exactly one entry. */
|
|
35
35
|
servers: Map<ServerAlias, ServerCatalog>;
|
|
36
36
|
}
|
|
37
|
-
interface ServerCatalog {
|
|
37
|
+
export interface ServerCatalog {
|
|
38
38
|
alias: ServerAlias;
|
|
39
39
|
/** Stable identity string recorded into blobs (R30). */
|
|
40
40
|
identity: string;
|
|
@@ -46,18 +46,26 @@ interface ServerCatalog {
|
|
|
46
46
|
* Look up a tool by name in a catalog, O(1) after the first call.
|
|
47
47
|
*
|
|
48
48
|
* Duplicate names resolve to the FIRST occurrence, matching `Array#find` and
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* {@link dedupeTools} (S5): a hostile server declaring the same name twice
|
|
50
|
+
* must not be able to make the policy gate see a different entry (e.g. a
|
|
51
|
+
* later `readOnlyHint: true` copy) than the one typegen exposed.
|
|
52
|
+
*/
|
|
53
|
+
export declare function findTool(catalog: ServerCatalog, name: string): ToolCatalogEntry | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Drop tools whose name repeats an earlier one; the first occurrence wins.
|
|
56
|
+
*
|
|
57
|
+
* The single dedupe rule for every consumer of the catalog (typegen, the
|
|
58
|
+
* catalog projection), so they all agree with {@link findTool} on which
|
|
59
|
+
* entry a name denotes (S5).
|
|
52
60
|
*/
|
|
53
|
-
declare function
|
|
61
|
+
export declare function dedupeTools(tools: ToolCatalogEntry[]): ToolCatalogEntry[];
|
|
54
62
|
/** Narrow to a non-null, non-array object. */
|
|
55
|
-
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
63
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
56
64
|
/** Executes a tool call against the wrapped server. Implemented by the introspector. */
|
|
57
|
-
interface ToolExecutor {
|
|
65
|
+
export interface ToolExecutor {
|
|
58
66
|
callTool(alias: ServerAlias, name: string, args: Record<string, unknown>): Promise<ToolCallOutcome>;
|
|
59
67
|
}
|
|
60
|
-
type ToolCallOutcome = {
|
|
68
|
+
export type ToolCallOutcome = {
|
|
61
69
|
ok: true;
|
|
62
70
|
result: unknown;
|
|
63
71
|
} | {
|
|
@@ -67,13 +75,13 @@ type ToolCallOutcome = {
|
|
|
67
75
|
detail?: unknown;
|
|
68
76
|
};
|
|
69
77
|
};
|
|
70
|
-
type PolicyDecision = 'auto' | 'ask' | 'deny';
|
|
71
|
-
interface PolicyOverrides {
|
|
78
|
+
export type PolicyDecision = 'auto' | 'ask' | 'deny';
|
|
79
|
+
export interface PolicyOverrides {
|
|
72
80
|
/** Per-tool decision override, keyed by tool name (v1: single server). */
|
|
73
81
|
[toolName: string]: PolicyDecision;
|
|
74
82
|
}
|
|
75
83
|
/** A tool call requested by the machine via the `toolCall` action creator. */
|
|
76
|
-
interface PendingToolCall {
|
|
84
|
+
export interface PendingToolCall {
|
|
77
85
|
/** Unique id for this call within the workflow (also the inputRequest key). */
|
|
78
86
|
id: string;
|
|
79
87
|
name: string;
|
|
@@ -82,7 +90,7 @@ interface PendingToolCall {
|
|
|
82
90
|
stateName: string;
|
|
83
91
|
}
|
|
84
92
|
/** Events the host injects into the machine. The machine never performs I/O itself. */
|
|
85
|
-
type HostEvent = {
|
|
93
|
+
export type HostEvent = {
|
|
86
94
|
type: 'TOOL_RESULT';
|
|
87
95
|
callId: string;
|
|
88
96
|
result: unknown;
|
|
@@ -98,14 +106,16 @@ type HostEvent = {
|
|
|
98
106
|
callId: string;
|
|
99
107
|
reason?: string;
|
|
100
108
|
};
|
|
101
|
-
type ErrorPhase = 'transpile' | 'validate' | 'runtime' | 'cap_exceeded' | 'blob_verification' | 'protocol' |
|
|
102
|
-
|
|
109
|
+
export type ErrorPhase = 'transpile' | 'validate' | 'runtime' | 'cap_exceeded' | 'blob_verification' | 'protocol' |
|
|
110
|
+
/** An `isError` result or transport failure from the wrapped tool, surfaced by `call_tool` (R25). */
|
|
111
|
+
'upstream' | 'terminal';
|
|
112
|
+
export interface Diagnostic {
|
|
103
113
|
message: string;
|
|
104
114
|
/** Optional source location within the submitted code. */
|
|
105
115
|
line?: number;
|
|
106
116
|
column?: number;
|
|
107
117
|
}
|
|
108
|
-
interface StructuredError {
|
|
118
|
+
export interface StructuredError {
|
|
109
119
|
phase: ErrorPhase;
|
|
110
120
|
message: string;
|
|
111
121
|
diagnostics: Diagnostic[];
|
|
@@ -113,8 +123,8 @@ interface StructuredError {
|
|
|
113
123
|
hint: string;
|
|
114
124
|
logs: LogEntry[];
|
|
115
125
|
}
|
|
116
|
-
type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
117
|
-
interface LogEntry {
|
|
126
|
+
export type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
127
|
+
export interface LogEntry {
|
|
118
128
|
level: LogLevel;
|
|
119
129
|
message: string;
|
|
120
130
|
/** Milliseconds since segment start. */
|
|
@@ -122,7 +132,7 @@ interface LogEntry {
|
|
|
122
132
|
/** Zero-based MRTR segment index this entry was captured in. */
|
|
123
133
|
segment: number;
|
|
124
134
|
}
|
|
125
|
-
interface ResourceCaps {
|
|
135
|
+
export interface ResourceCaps {
|
|
126
136
|
/** Wall-clock per execution segment, ms. */
|
|
127
137
|
segmentWallClockMs: number;
|
|
128
138
|
/** WASM memory, bytes. */
|
|
@@ -144,19 +154,27 @@ interface ResourceCaps {
|
|
|
144
154
|
/** Captured console output per segment, bytes. */
|
|
145
155
|
maxConsoleBytes: number;
|
|
146
156
|
}
|
|
147
|
-
declare const DEFAULT_CAPS: ResourceCaps;
|
|
148
|
-
declare const MAX_CAPS: ResourceCaps;
|
|
157
|
+
export declare const DEFAULT_CAPS: ResourceCaps;
|
|
158
|
+
export declare const MAX_CAPS: ResourceCaps;
|
|
149
159
|
/** Clamp requested caps into [MIN_CAPS, MAX_CAPS] (R12). */
|
|
150
|
-
declare function clampCaps(requested: Partial<ResourceCaps>): ResourceCaps;
|
|
151
|
-
declare const BLOB_SCHEMA_VERSION = 1;
|
|
152
|
-
|
|
160
|
+
export declare function clampCaps(requested: Partial<ResourceCaps>): ResourceCaps;
|
|
161
|
+
export declare const BLOB_SCHEMA_VERSION = 1;
|
|
162
|
+
/** Which tool minted a blob (R36): a blob opened by the other tool is rejected. */
|
|
163
|
+
export type BlobKind = 'machine' | 'call';
|
|
164
|
+
export interface BlobPayload {
|
|
153
165
|
/** Blob schema version; unknown versions are rejected. */
|
|
154
166
|
v: number;
|
|
167
|
+
/** Minting tool (R36). */
|
|
168
|
+
kind: BlobKind;
|
|
155
169
|
/** Library version that produced the snapshot. */
|
|
156
170
|
libv: string;
|
|
157
171
|
/** Exact XState version that produced the snapshot. */
|
|
158
172
|
xstatev: string;
|
|
159
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* Binding hash (S4): SHA-256 (hex) of the original `code` for `machine`
|
|
175
|
+
* blobs, of the canonical `{ kind: "call", name, args }` request for
|
|
176
|
+
* `call` blobs (R36).
|
|
177
|
+
*/
|
|
160
178
|
codeHash: string;
|
|
161
179
|
/** Server identity the blob was minted against (R30). */
|
|
162
180
|
serverIdentity: string;
|
|
@@ -181,25 +199,52 @@ interface BlobPayload {
|
|
|
181
199
|
/** Expiry, Unix ms (default TTL 15 min). */
|
|
182
200
|
exp: number;
|
|
183
201
|
}
|
|
184
|
-
interface BlobSealerConfig {
|
|
202
|
+
export interface BlobSealerConfig {
|
|
185
203
|
/** Current encryption key (32 bytes). */
|
|
186
204
|
key: Uint8Array;
|
|
187
205
|
/** Previous keys accepted for decryption during rotation (R22). */
|
|
188
206
|
previousKeys?: Uint8Array[];
|
|
189
|
-
/** Blob TTL in ms. Default 15 minutes. */
|
|
207
|
+
/** Blob TTL in ms for `machine` blobs. Default 15 minutes. */
|
|
190
208
|
ttlMs?: number;
|
|
209
|
+
/**
|
|
210
|
+
* Blob TTL in ms for `call` blobs (R38). Default 5 minutes: an approved
|
|
211
|
+
* `call` blob has no forward step, so it is a standing capability until
|
|
212
|
+
* it expires (D4, D9).
|
|
213
|
+
*/
|
|
214
|
+
callTtlMs?: number;
|
|
191
215
|
/** Sealed+compressed size ceiling in bytes. Default 128 KB (R23). */
|
|
192
216
|
maxBlobBytes?: number;
|
|
193
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Optional shared replay cache (R38). When configured, the adapter consults
|
|
220
|
+
* it after blob verification and before executing any gated call, for both
|
|
221
|
+
* blob kinds. No default ships: an in-memory one would silently break
|
|
222
|
+
* horizontal scaling (G4), so the integrator supplies a shared store.
|
|
223
|
+
*/
|
|
224
|
+
export interface ReplayCache {
|
|
225
|
+
/**
|
|
226
|
+
* Record `nonce` until `exp` (Unix ms) and resolve `true` when it had
|
|
227
|
+
* already been recorded — i.e. this approval is being replayed.
|
|
228
|
+
*
|
|
229
|
+
* Contract: this MUST be an atomic test-and-set across every instance that
|
|
230
|
+
* can serve a retry (a SETNX-style primitive, not a read followed by a
|
|
231
|
+
* write), or two concurrent replays of one approval both execute. The
|
|
232
|
+
* nonce is recorded on FIRST SIGHT, before the verdict is read and
|
|
233
|
+
* regardless of what follows — a decline, a policy denial, an upstream
|
|
234
|
+
* failure — so a blob is single-use whatever happens to the call it
|
|
235
|
+
* carried. A retry that fails verification never reaches this method.
|
|
236
|
+
*/
|
|
237
|
+
seen(nonce: string, exp: number): Promise<boolean>;
|
|
238
|
+
}
|
|
194
239
|
/** Verdict delivered on retry for a pending gated call. */
|
|
195
|
-
type ApprovalVerdict = {
|
|
240
|
+
export type ApprovalVerdict = {
|
|
196
241
|
kind: 'approved';
|
|
197
242
|
} | {
|
|
198
243
|
kind: 'declined';
|
|
199
244
|
reason?: string;
|
|
200
245
|
};
|
|
201
246
|
/** Outcome of running one execution segment. */
|
|
202
|
-
type SegmentOutcome = {
|
|
247
|
+
export type SegmentOutcome = {
|
|
203
248
|
status: 'completed';
|
|
204
249
|
/** Final machine output/context to return to the client. */
|
|
205
250
|
output: unknown;
|
|
@@ -219,21 +264,21 @@ type SegmentOutcome = {
|
|
|
219
264
|
status: 'error';
|
|
220
265
|
error: StructuredError;
|
|
221
266
|
};
|
|
222
|
-
interface AuditEntry {
|
|
267
|
+
export interface AuditEntry {
|
|
223
268
|
callId: string;
|
|
224
269
|
tool: string;
|
|
225
270
|
args: Record<string, unknown>;
|
|
226
271
|
decision: 'auto' | 'approved' | 'declined' | 'denied_by_policy' | 'error';
|
|
227
272
|
reason?: string;
|
|
228
273
|
}
|
|
229
|
-
interface RedactionHook {
|
|
274
|
+
export interface RedactionHook {
|
|
230
275
|
/**
|
|
231
276
|
* Mask sensitive argument fields before they appear in elicitation copy
|
|
232
277
|
* (R16). Receives the tool name and resolved args; returns args to display.
|
|
233
278
|
*/
|
|
234
279
|
(toolName: string, args: Record<string, unknown>): Record<string, unknown>;
|
|
235
280
|
}
|
|
236
|
-
interface ProjectionConfig {
|
|
281
|
+
export interface ProjectionConfig {
|
|
237
282
|
/** Resource cap overrides, clamped at maxima (R12). */
|
|
238
283
|
caps?: Partial<ResourceCaps>;
|
|
239
284
|
/** Per-tool policy overrides (R14). */
|
|
@@ -242,21 +287,34 @@ interface ProjectionConfig {
|
|
|
242
287
|
blob: BlobSealerConfig;
|
|
243
288
|
/** Redaction hook for elicitation copy (R16). */
|
|
244
289
|
redact?: RedactionHook;
|
|
245
|
-
/**
|
|
290
|
+
/**
|
|
291
|
+
* Replaces the whole R29 preamble appended to `instructions`, whichever
|
|
292
|
+
* projections are on (code mode, catalog, or the routing copy for both).
|
|
293
|
+
*/
|
|
246
294
|
codeModePreamble?: string;
|
|
247
295
|
}
|
|
248
296
|
//#endregion
|
|
249
297
|
//#region src/blob/sealer.d.ts
|
|
250
298
|
/** Envelope format version prefix. Bump (proj2, …) on any wire-format change. */
|
|
251
|
-
declare const ENVELOPE_PREFIX = "proj1";
|
|
252
|
-
/** Default blob TTL: 15 minutes (R20). */
|
|
253
|
-
declare const DEFAULT_TTL_MS: number;
|
|
299
|
+
export declare const ENVELOPE_PREFIX = "proj1";
|
|
300
|
+
/** Default blob TTL for `machine` blobs: 15 minutes (R20). */
|
|
301
|
+
export declare const DEFAULT_TTL_MS: number;
|
|
302
|
+
/**
|
|
303
|
+
* Default TTL for `call` blobs: 5 minutes (R38). An approved `call` blob has
|
|
304
|
+
* no forward step, so it is a standing capability until it expires (D4, D9).
|
|
305
|
+
*/
|
|
306
|
+
export declare const DEFAULT_CALL_TTL_MS: number;
|
|
254
307
|
/** Default sealed-blob size ceiling: 128 KB (R23). */
|
|
255
|
-
declare const DEFAULT_MAX_BLOB_BYTES: number;
|
|
308
|
+
export declare const DEFAULT_MAX_BLOB_BYTES: number;
|
|
256
309
|
/** SHA-256 hex digest of a code argument (S4 binding — R20 `codeHash`). */
|
|
257
|
-
declare function hashCode(code: string): string;
|
|
310
|
+
export declare function hashCode(code: string): string;
|
|
258
311
|
interface BuildBlobPayloadInput {
|
|
259
|
-
/**
|
|
312
|
+
/** Minting tool (R36). Default `machine`. */
|
|
313
|
+
kind?: BlobKind | undefined;
|
|
314
|
+
/**
|
|
315
|
+
* The text the blob is bound to (S4): the original `code` argument for a
|
|
316
|
+
* `machine` blob, the canonical request for a `call` blob (R36).
|
|
317
|
+
*/
|
|
260
318
|
code: string;
|
|
261
319
|
/** Identity of the wrapped server this blob is minted against (R30). */
|
|
262
320
|
serverIdentity: string;
|
|
@@ -277,7 +335,7 @@ interface BuildBlobPayloadInput {
|
|
|
277
335
|
* Construct a fully populated {@link BlobPayload}: stamps the schema and
|
|
278
336
|
* library/XState versions, hashes the code, and fills nonce/iat/exp.
|
|
279
337
|
*/
|
|
280
|
-
declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
338
|
+
export declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
281
339
|
/**
|
|
282
340
|
* Seal a payload into an opaque `proj1.` envelope string (R19, R23).
|
|
283
341
|
*
|
|
@@ -286,9 +344,14 @@ declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
|
286
344
|
* the sealed envelope exceeds `maxBlobBytes` (default 128 KB) or the config
|
|
287
345
|
* keys are malformed.
|
|
288
346
|
*/
|
|
289
|
-
declare function sealBlob(payload: BlobPayload, config: BlobSealerConfig): string;
|
|
347
|
+
export declare function sealBlob(payload: BlobPayload, config: BlobSealerConfig): string;
|
|
290
348
|
interface OpenBlobOptions {
|
|
291
|
-
/** The
|
|
349
|
+
/** The tool opening the blob (R36). Default `machine`. */
|
|
350
|
+
expectedKind?: BlobKind | undefined;
|
|
351
|
+
/**
|
|
352
|
+
* The text re-sent with the retry (S4): the `code` argument for
|
|
353
|
+
* `execute_machine`, the canonical request for `call_tool`.
|
|
354
|
+
*/
|
|
292
355
|
code: string;
|
|
293
356
|
/** Identity of the wrapped server handling the retry (R30). */
|
|
294
357
|
serverIdentity: string;
|
|
@@ -311,7 +374,7 @@ interface OpenBlobOptions {
|
|
|
311
374
|
* failed check (never key material or plaintext). A payload is only
|
|
312
375
|
* returned once every check has passed.
|
|
313
376
|
*/
|
|
314
|
-
declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
377
|
+
export declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
315
378
|
//#endregion
|
|
316
379
|
//#region src/blob/versions.d.ts
|
|
317
380
|
/**
|
|
@@ -326,9 +389,9 @@ declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
|
326
389
|
* CI instead of silently minting blobs with a stale version stamp.
|
|
327
390
|
*/
|
|
328
391
|
/** `@astral-mcp/projection` package version (must match packages/projection/package.json). */
|
|
329
|
-
declare const LIB_VERSION = "0.
|
|
392
|
+
export declare const LIB_VERSION = "0.8.0";
|
|
330
393
|
/** Pinned XState version (must match the exact pin in package.json — D2). */
|
|
331
|
-
declare const XSTATE_VERSION = "5.32.5";
|
|
394
|
+
export declare const XSTATE_VERSION = "5.32.5";
|
|
332
395
|
//#endregion
|
|
333
396
|
//#region src/mrtr/protocol.d.ts
|
|
334
397
|
/**
|
|
@@ -364,7 +427,7 @@ interface RetryEnvelope {
|
|
|
364
427
|
* an approval prompt whose only payload is an optional decline reason is our
|
|
365
428
|
* product decision (R16/R17), not a protocol shape.
|
|
366
429
|
*/
|
|
367
|
-
declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
430
|
+
export declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
368
431
|
/**
|
|
369
432
|
* Protocol revision that introduced MRTR.
|
|
370
433
|
*
|
|
@@ -375,7 +438,7 @@ declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
|
375
438
|
* `'modern'` rather than as a version string. We keep the literal purely so
|
|
376
439
|
* error copy can name the revision a client must speak (R28).
|
|
377
440
|
*/
|
|
378
|
-
declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
441
|
+
export declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
379
442
|
/**
|
|
380
443
|
* Whether the era a request is being served on can carry MRTR (R28).
|
|
381
444
|
*
|
|
@@ -386,9 +449,20 @@ declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
|
386
449
|
* no `extra.protocolVersion` to read, and reading one was the bug this
|
|
387
450
|
* migration fixes (docs/DECISIONS.md D1).
|
|
388
451
|
*/
|
|
389
|
-
declare function supportsMrtr(era: ProtocolEra$1 | undefined): boolean;
|
|
452
|
+
export declare function supportsMrtr(era: ProtocolEra$1 | undefined): boolean;
|
|
390
453
|
//#endregion
|
|
391
454
|
//#region src/mrtr/adapter.d.ts
|
|
455
|
+
/**
|
|
456
|
+
* `execute_machine` arguments plus the MRTR retry envelope.
|
|
457
|
+
*
|
|
458
|
+
* **Security (S2):** `requestState` and `inputResponses` are the retry
|
|
459
|
+
* envelope — siblings of `arguments` in a `tools/call` that the SDK lifts off
|
|
460
|
+
* the request params onto the handler context. They are NOT tool arguments.
|
|
461
|
+
* A direct caller of `executeMachine` MUST populate them only from the
|
|
462
|
+
* transport's retry fields, never from model-authored tool arguments: a
|
|
463
|
+
* model that has seen a `requestState` could otherwise echo it back with a
|
|
464
|
+
* fabricated `accept` and approve its own gated call.
|
|
465
|
+
*/
|
|
392
466
|
interface ExecuteMachineArgs extends RetryEnvelope {
|
|
393
467
|
/** The authored module source (R2). */
|
|
394
468
|
code: string;
|
|
@@ -396,9 +470,14 @@ interface ExecuteMachineArgs extends RetryEnvelope {
|
|
|
396
470
|
/** Passed to the machine as its input. */
|
|
397
471
|
input?: unknown;
|
|
398
472
|
}
|
|
399
|
-
|
|
473
|
+
/**
|
|
474
|
+
* What every gated entry point needs: the catalog and executor of the wrapped
|
|
475
|
+
* server, the blob sealer, and the per-facade policy, redaction, caps,
|
|
476
|
+
* protocol-era and replay settings. `execute_machine` adds the sandbox
|
|
477
|
+
* bridge; `call_tool` needs nothing more (R35, R38).
|
|
478
|
+
*/
|
|
479
|
+
interface ApprovalGateDeps {
|
|
400
480
|
catalog: ServerCatalog;
|
|
401
|
-
bridgeSource: string;
|
|
402
481
|
executor: ToolExecutor;
|
|
403
482
|
blob: BlobSealerConfig;
|
|
404
483
|
caps?: Partial<ResourceCaps>;
|
|
@@ -431,6 +510,12 @@ interface ExecuteMachineDeps {
|
|
|
431
510
|
* not know) leaves the shim to decide.
|
|
432
511
|
*/
|
|
433
512
|
clientCanElicit?: boolean;
|
|
513
|
+
/** Optional shared replay cache (R38); consulted after verification, before execution. */
|
|
514
|
+
replayCache?: ReplayCache;
|
|
515
|
+
}
|
|
516
|
+
interface ExecuteMachineDeps extends ApprovalGateDeps {
|
|
517
|
+
/** The `@astral-mcp/tools` bridge module source the sandbox loads (R2). */
|
|
518
|
+
bridgeSource: string;
|
|
434
519
|
}
|
|
435
520
|
/**
|
|
436
521
|
* Run `execute_machine` for one `tools/call`, whether it is a first attempt
|
|
@@ -439,11 +524,460 @@ interface ExecuteMachineDeps {
|
|
|
439
524
|
* Statelessness (R27): everything needed to resume rides in `requestState`,
|
|
440
525
|
* so any instance can serve any retry. Nothing is held between calls.
|
|
441
526
|
*/
|
|
442
|
-
declare function executeMachine(args: ExecuteMachineArgs, deps: ExecuteMachineDeps): Promise<ToolCallResult>;
|
|
527
|
+
export declare function executeMachine(args: ExecuteMachineArgs, deps: ExecuteMachineDeps): Promise<ToolCallResult>;
|
|
528
|
+
/** Every failure is a normal result with `isError: true` and a structured body (R25). */
|
|
529
|
+
export declare function errorResult(error: StructuredError): CallToolResult;
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/catalog/call.d.ts
|
|
532
|
+
/**
|
|
533
|
+
* `call_tool` arguments plus the MRTR retry envelope.
|
|
534
|
+
*
|
|
535
|
+
* **Security (S2):** `requestState` and `inputResponses` are the retry
|
|
536
|
+
* envelope — siblings of `arguments` in a `tools/call` that the SDK lifts off
|
|
537
|
+
* the request params onto the handler context. They are NOT tool arguments.
|
|
538
|
+
* A direct caller of `callTool` MUST populate them only from the transport's
|
|
539
|
+
* retry fields, never from model-authored tool arguments: a model that has
|
|
540
|
+
* seen a `requestState` could otherwise echo it back with a fabricated
|
|
541
|
+
* `accept` and approve its own write.
|
|
542
|
+
*/
|
|
543
|
+
interface CallToolArgs extends RetryEnvelope {
|
|
544
|
+
/** Tool name as listed by `search_tools`. */
|
|
545
|
+
name: string;
|
|
546
|
+
/** Arguments for the tool; absent means `{}`. */
|
|
547
|
+
args?: unknown;
|
|
548
|
+
}
|
|
549
|
+
/** `call_tool` needs exactly the dependencies every gated tool shares (R35, R38). */
|
|
550
|
+
type CallToolDeps = ApprovalGateDeps;
|
|
551
|
+
/** `structuredContent` of a completed `call_tool` (R35.5). */
|
|
552
|
+
type CallToolOutcome = {
|
|
553
|
+
status: 'ok';
|
|
554
|
+
tool: string;
|
|
555
|
+
/**
|
|
556
|
+
* The wrapped tool's result — or, when its JSON exceeded
|
|
557
|
+
* `caps.maxResultBytes`, a string preview of that JSON. The call ran
|
|
558
|
+
* either way; see `truncated`.
|
|
559
|
+
*/
|
|
560
|
+
output: unknown;
|
|
561
|
+
/** Present and `true` when `output` is a preview, not the full result. */
|
|
562
|
+
truncated?: true;
|
|
563
|
+
/** Byte length of the full result's JSON, when truncated. */
|
|
564
|
+
outputBytes?: number;
|
|
565
|
+
} | {
|
|
566
|
+
status: 'declined';
|
|
567
|
+
tool: string;
|
|
568
|
+
reason?: string;
|
|
569
|
+
} | {
|
|
570
|
+
status: 'denied_by_policy';
|
|
571
|
+
tool: string;
|
|
572
|
+
reason: string;
|
|
573
|
+
};
|
|
574
|
+
/** The single inputRequest / pending key of a `call` blob (R36). */
|
|
575
|
+
export declare const CALL_KEY = "call";
|
|
576
|
+
/** Run `call_tool` for one `tools/call`, first attempt or MRTR retry. */
|
|
577
|
+
export declare function callTool(args: CallToolArgs, deps: CallToolDeps): Promise<ToolCallResult>;
|
|
578
|
+
//#endregion
|
|
579
|
+
//#region src/catalog/canonical.d.ts
|
|
580
|
+
/**
|
|
581
|
+
* Canonical JSON for the `call_tool` binding hash (PRD R36).
|
|
582
|
+
*
|
|
583
|
+
* A `call` blob is bound to the request that produced it by hashing the
|
|
584
|
+
* canonical text of `{ kind: "call", name, args }`: object keys sorted by
|
|
585
|
+
* UTF-16 code unit order (JavaScript's default sort), array order kept,
|
|
586
|
+
* no whitespace. Both sides canonicalize the *parsed* request, so `1` and
|
|
587
|
+
* `1.0`, `-0` and `0`, escaped and literal characters, and duplicate keys
|
|
588
|
+
* (last wins at parse time) all canonicalize identically. No Unicode
|
|
589
|
+
* normalization is applied — NFC and NFD differ, deliberately failing
|
|
590
|
+
* closed. Values JSON cannot represent (`undefined`, functions, symbols,
|
|
591
|
+
* bigint, non-finite numbers) throw a `validate` error rather than being
|
|
592
|
+
* dropped: the facade is callable outside the SDK (R27), so they can occur.
|
|
593
|
+
* Non-plain objects (`Date`, `Map`, class instances) canonicalize by their
|
|
594
|
+
* own enumerable keys, i.e. typically to `{}` — JSON over the wire never
|
|
595
|
+
* produces them, so this too is reachable only by a direct caller.
|
|
596
|
+
*
|
|
597
|
+
* The hash is a coherence check, not the approval binding — S2 is carried
|
|
598
|
+
* by the blob's `pending` entry alone (R36, D9).
|
|
599
|
+
*/
|
|
600
|
+
/** Canonical JSON text of a plain JSON value. Throws `validate` on non-JSON. */
|
|
601
|
+
export declare function canonicalJson(value: unknown): string;
|
|
602
|
+
/** The text a `call` blob is bound to (R36): `{ kind: "call", name, args }`. */
|
|
603
|
+
export declare function canonicalRequest(name: string, args: Record<string, unknown>): string;
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/catalog/validate-args.d.ts
|
|
606
|
+
/**
|
|
607
|
+
* Structural argument validation for `call_tool` (PRD R35.1).
|
|
608
|
+
*
|
|
609
|
+
* Deliberately shallow: required properties present, top-level property
|
|
610
|
+
* types match, enum membership for top-level primitives, and no unknown
|
|
611
|
+
* top-level properties when the schema forbids them. It exists so a human
|
|
612
|
+
* is never asked to approve a call the wrapped server would reject on
|
|
613
|
+
* shape, and so the model gets a `validate` hint naming the property. Full
|
|
614
|
+
* JSON Schema validation would run twice — the wrapped server is the
|
|
615
|
+
* authority — for nothing but a nicer error message (D9).
|
|
616
|
+
*
|
|
617
|
+
* Own-property semantics throughout: `__proto__` or `constructor` as an
|
|
618
|
+
* argument name is ordinary data (S5/S6).
|
|
619
|
+
*/
|
|
620
|
+
/** Throws a `validate`-phase {@link ProjectionError} naming the offending property. */
|
|
621
|
+
export declare function validateArgsShape(toolName: string, args: Record<string, unknown>, schema: Record<string, unknown>): void;
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/errors.d.ts
|
|
624
|
+
/**
|
|
625
|
+
* Error carrying the structured `isError` body every failure returns (R25).
|
|
626
|
+
*/
|
|
627
|
+
export declare class ProjectionError extends Error {
|
|
628
|
+
readonly phase: ErrorPhase;
|
|
629
|
+
readonly diagnostics: Diagnostic[];
|
|
630
|
+
readonly hint: string;
|
|
631
|
+
logs: LogEntry[];
|
|
632
|
+
constructor(phase: ErrorPhase, message: string, options?: {
|
|
633
|
+
diagnostics?: Diagnostic[];
|
|
634
|
+
hint?: string;
|
|
635
|
+
logs?: LogEntry[];
|
|
636
|
+
cause?: unknown;
|
|
637
|
+
});
|
|
638
|
+
toStructured(): StructuredError;
|
|
639
|
+
}
|
|
640
|
+
/** Convert any thrown value into a StructuredError, defaulting to `runtime` phase. */
|
|
641
|
+
export declare function toStructuredError(err: unknown, logs?: LogEntry[]): StructuredError;
|
|
642
|
+
//#endregion
|
|
643
|
+
//#region src/policy/decision.d.ts
|
|
644
|
+
/**
|
|
645
|
+
* Decide the policy for a catalog tool (R14).
|
|
646
|
+
*
|
|
647
|
+
* - A developer override (`auto` | `ask` | `deny`) always wins.
|
|
648
|
+
* - With no override, `annotations.readOnlyHint === true` yields `auto`;
|
|
649
|
+
* an absent or `false` hint yields `ask` (S5: unannotated defaults to ask).
|
|
650
|
+
* - An override entry with an unrecognized value (possible when the config
|
|
651
|
+
* arrives untyped) fails safe to `ask` — it never grants `auto`.
|
|
652
|
+
*
|
|
653
|
+
* Only own properties of `overrides` are consulted, so tools named like
|
|
654
|
+
* `Object.prototype` members (`toString`, `constructor`, ...) cannot pick up
|
|
655
|
+
* inherited junk as a decision.
|
|
656
|
+
*/
|
|
657
|
+
export declare function decidePolicy(entry: ToolCatalogEntry, overrides?: PolicyOverrides): PolicyDecision;
|
|
658
|
+
/** The three normative posture strings (R33) — models match on these. */
|
|
659
|
+
type ToolPosture = 'runs immediately' | 'asks for approval' | 'blocked by policy';
|
|
660
|
+
/** Map a policy decision to its plain-words posture (R33). Shared by every surface that names one. */
|
|
661
|
+
export declare function postureOf(decision: PolicyDecision): ToolPosture;
|
|
662
|
+
/** Result of resolving a pending call against a server catalog. */
|
|
663
|
+
type ResolvedCallPolicy = {
|
|
664
|
+
ok: true;
|
|
665
|
+
decision: PolicyDecision;
|
|
666
|
+
entry: ToolCatalogEntry;
|
|
667
|
+
} | {
|
|
668
|
+
ok: false;
|
|
669
|
+
error: ProjectionError;
|
|
670
|
+
};
|
|
671
|
+
/**
|
|
672
|
+
* Resolve a machine-requested tool call against the server catalog and
|
|
673
|
+
* decide its policy.
|
|
674
|
+
*
|
|
675
|
+
* Returns the decision together with the matching catalog entry (the entry
|
|
676
|
+
* is what elicitation copy must be built from — S6), or a structured
|
|
677
|
+
* `validate`-phase {@link ProjectionError} when the machine names a tool the
|
|
678
|
+
* wrapped server does not declare.
|
|
679
|
+
*/
|
|
680
|
+
export declare function resolveCallPolicy(call: PendingToolCall, catalog: ServerCatalog, overrides?: PolicyOverrides): ResolvedCallPolicy;
|
|
681
|
+
/**
|
|
682
|
+
* Canonical TOOL_DENIED reason for calls blocked by a `deny` policy
|
|
683
|
+
* decision. A `deny` decision never produces an elicitation — the machine
|
|
684
|
+
* host injects `TOOL_DENIED` with this reason instead.
|
|
685
|
+
*/
|
|
686
|
+
export declare const POLICY_DENIED_REASON = "denied by server policy";
|
|
687
|
+
/**
|
|
688
|
+
* Build the TOOL_DENIED reason string for a policy-denied call. With a tool
|
|
689
|
+
* name it names the denied tool so the machine (and audit trail) can tell
|
|
690
|
+
* which call was blocked.
|
|
691
|
+
*/
|
|
692
|
+
export declare function policyDeniedReason(toolName?: string): string;
|
|
693
|
+
//#endregion
|
|
694
|
+
//#region src/policy/elicitation.d.ts
|
|
695
|
+
/** Structured approval copy for one gated call (input to the MRTR adapter). */
|
|
696
|
+
interface ElicitationCopy {
|
|
697
|
+
/** Short action title, e.g. `Approve: delete file`. */
|
|
698
|
+
title: string;
|
|
699
|
+
/** Full human-readable summary (plain text with an indented JSON block). */
|
|
700
|
+
message: string;
|
|
701
|
+
/** Tool name, taken from the catalog entry. */
|
|
702
|
+
toolName: string;
|
|
703
|
+
/** Machine state path that requested the call (raw; render with care). */
|
|
704
|
+
stateName: string;
|
|
705
|
+
/** The redacted arguments as rendered in `message` (JSON text, possibly truncated). */
|
|
706
|
+
args: string;
|
|
707
|
+
/** True when the catalog entry carries `destructiveHint: true`. */
|
|
708
|
+
destructive: boolean;
|
|
709
|
+
}
|
|
710
|
+
interface ElicitationCopyOptions {
|
|
711
|
+
/** Redaction hook applied to args before any rendering (R16). */
|
|
712
|
+
redact?: RedactionHook;
|
|
713
|
+
/**
|
|
714
|
+
* Who asked: a machine state (default) or a direct `call_tool` request
|
|
715
|
+
* (R35). Selects the footer; nothing else differs.
|
|
716
|
+
*/
|
|
717
|
+
origin?: 'machine' | 'direct';
|
|
718
|
+
/**
|
|
719
|
+
* Backstop cap on the whole rendered args JSON, in characters. Default
|
|
720
|
+
* 4096. Each string leaf is independently capped at 512 characters first.
|
|
721
|
+
*/
|
|
722
|
+
maxArgsChars?: number;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Build the approval summary for a gated call.
|
|
726
|
+
*
|
|
727
|
+
* `entry` MUST be the catalog entry the call was resolved against (use
|
|
728
|
+
* `resolveCallPolicy`); the copy takes the tool name, title and description
|
|
729
|
+
* from it, never from the pending call or its arguments.
|
|
730
|
+
*/
|
|
731
|
+
export declare function buildElicitationCopy(call: PendingToolCall, entry: ToolCatalogEntry, options?: ElicitationCopyOptions): ElicitationCopy;
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/text-safety.d.ts
|
|
734
|
+
/**
|
|
735
|
+
* Rendering untrusted strings inertly (S5, S6).
|
|
736
|
+
*
|
|
737
|
+
* Tool names, descriptions, the wrapped server's identity, and machine state
|
|
738
|
+
* names all flow from a possibly third-party server or a model-authored
|
|
739
|
+
* machine. Wherever they are rendered into human-facing prompt copy or into
|
|
740
|
+
* generated source, they must not be able to forge structure with control
|
|
741
|
+
* characters (newlines, ESC for ANSI sequences) or reorder text with Unicode
|
|
742
|
+
* bidi overrides. Centralizing the character class here keeps every call site
|
|
743
|
+
* on the same, complete definition — an earlier divergence let generated
|
|
744
|
+
* `.d.ts`/bridge comments miss the directional-isolate range that the
|
|
745
|
+
* elicitation copy already stripped.
|
|
746
|
+
*/
|
|
747
|
+
/**
|
|
748
|
+
* Replace control and bidi characters with the replacement character.
|
|
749
|
+
* `allowNewline` keeps `\n` (for multi-line blocks whose formatting newlines
|
|
750
|
+
* are part of the rendering, e.g. a pretty-printed JSON block).
|
|
751
|
+
*/
|
|
752
|
+
export declare function neutralizeControlChars(text: string, options?: {
|
|
753
|
+
allowNewline?: boolean;
|
|
754
|
+
}): string;
|
|
755
|
+
/** Truncate to `maxChars`, appending an ellipsis when shortened. */
|
|
756
|
+
export declare function capLength(text: string, maxChars: number): string;
|
|
757
|
+
/**
|
|
758
|
+
* The one-line human purpose: the first sentence of the server's
|
|
759
|
+
* description, neutralized and capped. Runs of replacement characters
|
|
760
|
+
* (neutralized control bytes) are collapsed so a hostile or malformed
|
|
761
|
+
* description does not render as a wall of `�`. Undefined when the server
|
|
762
|
+
* gave no usable description.
|
|
763
|
+
*
|
|
764
|
+
* One rule, three consumers — the approval copy (R16), the `discover_apis`
|
|
765
|
+
* overview and `search_tools` (R33) — so every projection describes a tool
|
|
766
|
+
* identically.
|
|
767
|
+
*/
|
|
768
|
+
export declare function purposeSentence(description: string | undefined): string | undefined;
|
|
769
|
+
//#endregion
|
|
770
|
+
//#region src/typegen/generate.d.ts
|
|
771
|
+
/**
|
|
772
|
+
* Module specifier authored machines import the tools surface from (R4).
|
|
773
|
+
* The sandbox component mounts {@link GeneratedToolTypes.bridgeSource} here.
|
|
774
|
+
*/
|
|
775
|
+
export declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
776
|
+
/**
|
|
777
|
+
* Name of the global the sandbox host MUST inject before authored code runs.
|
|
778
|
+
*
|
|
779
|
+
* Contract (for the sandbox / machine-host components):
|
|
780
|
+
*
|
|
781
|
+
* ```js
|
|
782
|
+
* globalThis.__projection_toolcall = (name, args) => <host-defined value>
|
|
783
|
+
* ```
|
|
784
|
+
*
|
|
785
|
+
* - `name` is the wrapped server's tool name exactly as catalogued.
|
|
786
|
+
* - `args` is a plain JSON-serializable object (never `undefined`; the
|
|
787
|
+
* bridge substitutes `{}` for a missing argument).
|
|
788
|
+
* - The bridge performs no I/O itself and returns the hook's value
|
|
789
|
+
* verbatim. Per R7, authored machines never consume that value as a
|
|
790
|
+
* promise inside invoked actors — the library-supplied `toolCall` action
|
|
791
|
+
* is the intended caller, and results come back as TOOL_RESULT /
|
|
792
|
+
* TOOL_ERROR / TOOL_DENIED events injected by the host.
|
|
793
|
+
* - If the hook is missing, every tool function throws, keeping the bridge
|
|
794
|
+
* inert outside a properly initialized sandbox (S1).
|
|
795
|
+
*/
|
|
796
|
+
export declare const TOOL_CALL_HOST_GLOBAL = "__projection_toolcall";
|
|
797
|
+
/** Output of {@link generateToolTypes}. */
|
|
798
|
+
interface GeneratedToolTypes {
|
|
799
|
+
/** `.d.ts` text for the `@astral-mcp/tools` surface (serve via discover_apis, R3). */
|
|
800
|
+
dts: string;
|
|
801
|
+
/** ESM source of the runtime bridge to mount at `@astral-mcp/tools` in the sandbox. */
|
|
802
|
+
bridgeSource: string;
|
|
803
|
+
/** Compact per-tool overview block for inline embedding by discover_apis (R3). */
|
|
804
|
+
overview: string;
|
|
805
|
+
/**
|
|
806
|
+
* Per-tool slice of `dts`, keyed by tool name (R34): the alias
|
|
807
|
+
* declarations and the `tools.<name>` member signature exactly as they
|
|
808
|
+
* appear in the full file, so `describe_tool` output type-checks against
|
|
809
|
+
* the `projection://types/tools.d.ts` resource.
|
|
810
|
+
*/
|
|
811
|
+
toolTypes: Map<string, ToolTypeText>;
|
|
812
|
+
}
|
|
813
|
+
/** The generated types for one tool, as served by `describe_tool` (R34). */
|
|
814
|
+
interface ToolTypeText {
|
|
815
|
+
/** `<Pascal>Input` alias name, unique within the `.d.ts`. */
|
|
816
|
+
inputAlias: string;
|
|
817
|
+
/** `<Pascal>Output` alias name, when the tool declares an `outputSchema`. */
|
|
818
|
+
outputAlias?: string;
|
|
819
|
+
/**
|
|
820
|
+
* The alias declarations verbatim from the `.d.ts`, then the member
|
|
821
|
+
* signature verbatim modulo indentation: the `tools` member is re-indented
|
|
822
|
+
* to column 0 under a `// Member of the \`tools\` surface:` line.
|
|
823
|
+
*/
|
|
824
|
+
dts: string;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Generate the `@astral-mcp/tools` artifacts for a wrapped server.
|
|
828
|
+
*
|
|
829
|
+
* Accepts either the full aliased {@link ToolCatalog} (which must contain
|
|
830
|
+
* exactly one server in v1, per R30's single-instance instantiation) or a
|
|
831
|
+
* {@link ServerCatalog} directly.
|
|
832
|
+
*/
|
|
833
|
+
export declare function generateToolTypes(catalog: ToolCatalog | ServerCatalog, options?: GenerateToolTypesOptions): GeneratedToolTypes;
|
|
834
|
+
interface GenerateToolTypesOptions {
|
|
835
|
+
/** Per-tool policy overrides (R14): decide the posture wording in docs and overview. */
|
|
836
|
+
policy?: PolicyOverrides | undefined;
|
|
837
|
+
}
|
|
838
|
+
//#endregion
|
|
839
|
+
//#region src/typegen/json-schema.d.ts
|
|
840
|
+
/**
|
|
841
|
+
* Convert a JSON Schema into TypeScript type text.
|
|
842
|
+
*
|
|
843
|
+
* @param schema - The schema (also used as the $ref resolution root).
|
|
844
|
+
* @param indent - Indentation prefix of the line the type is emitted on;
|
|
845
|
+
* nested object literals indent relative to it.
|
|
846
|
+
*/
|
|
847
|
+
export declare function schemaToTsType(schema: unknown, indent?: string): string;
|
|
848
|
+
/**
|
|
849
|
+
* True when the schema requires at least one argument property — used to
|
|
850
|
+
* decide whether the generated tool function's `args` parameter is optional.
|
|
851
|
+
*/
|
|
852
|
+
export declare function schemaRequiresArgs(schema: unknown): boolean;
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region src/catalog/describe.d.ts
|
|
855
|
+
interface DescribeToolArgs {
|
|
856
|
+
name: string;
|
|
857
|
+
/**
|
|
858
|
+
* Include the generated TypeScript for the tool (R34). Off by default:
|
|
859
|
+
* the JSON Schema already carries the shape, and the types double the
|
|
860
|
+
* payload — ask for them when authoring a machine.
|
|
861
|
+
*/
|
|
862
|
+
types?: boolean;
|
|
863
|
+
}
|
|
864
|
+
interface DescribeToolOptions {
|
|
865
|
+
/** Per-tool policy overrides (R14); decides the rendered posture. */
|
|
866
|
+
policy?: PolicyOverrides;
|
|
867
|
+
/** Per-tool generated types from typegen (R34). */
|
|
868
|
+
toolTypes?: ReadonlyMap<string, ToolTypeText>;
|
|
869
|
+
}
|
|
870
|
+
/** `structuredContent` of a `describe_tool` result (R34). */
|
|
871
|
+
interface ToolDescription {
|
|
872
|
+
name: string;
|
|
873
|
+
/** Neutralized, capped description; `undefined` when the server gave none. */
|
|
874
|
+
description?: string;
|
|
875
|
+
posture: ToolPosture;
|
|
876
|
+
destructive: boolean;
|
|
877
|
+
/** The server's annotations, as untrusted hints (S5); `title` neutralized. */
|
|
878
|
+
annotations: ToolAnnotations;
|
|
879
|
+
inputSchema: Record<string, unknown>;
|
|
880
|
+
outputSchema?: Record<string, unknown>;
|
|
881
|
+
/** True when either schema had to be reduced to fit the R34 cap. */
|
|
882
|
+
schemaTruncated: boolean;
|
|
883
|
+
/** Generated TypeScript for this tool, as in `projection://types/tools.d.ts`. */
|
|
884
|
+
types?: string;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Run `describe_tool`. Throws a `validate`-phase {@link ProjectionError}
|
|
888
|
+
* when the wrapped server declares no such tool (R34).
|
|
889
|
+
*/
|
|
890
|
+
export declare function describeTool(catalog: ServerCatalog, args: DescribeToolArgs, options?: DescribeToolOptions): CallToolResult;
|
|
891
|
+
//#endregion
|
|
892
|
+
//#region src/catalog/schema-safety.d.ts
|
|
893
|
+
/**
|
|
894
|
+
* JSON Schema sanitizer for `describe_tool` (PRD R34, S5).
|
|
895
|
+
*
|
|
896
|
+
* The wrapped server's schemas are the injection surface of the catalog
|
|
897
|
+
* projection: beyond `description`, a server controls free text in
|
|
898
|
+
* `title`, nested descriptions, `examples`, `default`, `$comment`, `x-*`
|
|
899
|
+
* vendor keys, `enum` members and `pattern`. Before a schema reaches the
|
|
900
|
+
* model it passes through:
|
|
901
|
+
*
|
|
902
|
+
* 1. a key allowlist — only the keywords a model needs to build arguments
|
|
903
|
+
* survive; everything else (examples, defaults, comments, vendor keys)
|
|
904
|
+
* is dropped;
|
|
905
|
+
* 2. string neutralization — every string VALUE has control and bidi
|
|
906
|
+
* characters replaced and is length-capped. Property NAMES and
|
|
907
|
+
* `required` entries are kept verbatim: they are the keys the model must
|
|
908
|
+
* send back, and `JSON.stringify` already renders them inert. A name
|
|
909
|
+
* longer than the string cap is dropped outright (with its `required`
|
|
910
|
+
* entry) — unusable as a key, and otherwise a way around the size cap;
|
|
911
|
+
* 3. a size cap — the rendered schema is bounded per tool, degrading in
|
|
912
|
+
* deterministic stages (drop prose → prune deep subtrees → keep the
|
|
913
|
+
* top-level shape → the marker alone) and flagging truncation explicitly
|
|
914
|
+
* so the model knows the wrapped server enforces more than it can see.
|
|
915
|
+
*
|
|
916
|
+
* Pure and total: never throws, never returns anything but plain JSON.
|
|
917
|
+
*/
|
|
918
|
+
/** Keywords that survive sanitization (R34). */
|
|
919
|
+
export declare const SCHEMA_KEY_ALLOWLIST: ReadonlySet<string>;
|
|
920
|
+
/** Rendered-schema cap per tool, in characters of its JSON text (R34). */
|
|
921
|
+
export declare const MAX_SCHEMA_CHARS: number;
|
|
922
|
+
interface SanitizedSchema {
|
|
923
|
+
/** The sanitized schema, always a plain JSON object. */
|
|
924
|
+
schema: Record<string, unknown>;
|
|
925
|
+
/** True when anything the server declared was cut: by the size cap, the depth cap or the name cap (R34). */
|
|
926
|
+
truncated: boolean;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Sanitize a tool schema for the model (R34).
|
|
930
|
+
*
|
|
931
|
+
* Non-object input (a server declaring `inputSchema: true`, or garbage)
|
|
932
|
+
* sanitizes to `{}`.
|
|
933
|
+
*/
|
|
934
|
+
export declare function sanitizeSchema(schema: unknown, maxChars?: number): SanitizedSchema;
|
|
935
|
+
//#endregion
|
|
936
|
+
//#region src/catalog/search.d.ts
|
|
937
|
+
interface SearchToolsArgs {
|
|
938
|
+
/**
|
|
939
|
+
* Words to match against tool names, titles and descriptions; any word
|
|
940
|
+
* matches, name hits weigh more (case-insensitive).
|
|
941
|
+
*/
|
|
942
|
+
query?: string;
|
|
943
|
+
/** Opaque cursor from a previous page's `nextCursor`. */
|
|
944
|
+
cursor?: string;
|
|
945
|
+
}
|
|
946
|
+
interface SearchToolsOptions {
|
|
947
|
+
/** Per-tool policy overrides (R14); decides the rendered posture. */
|
|
948
|
+
policy?: PolicyOverrides;
|
|
949
|
+
/** Tools per page. Default {@link DEFAULT_SEARCH_PAGE_SIZE}, clamped to [1, 200]. */
|
|
950
|
+
pageSize?: number;
|
|
951
|
+
}
|
|
952
|
+
/** Page size — a transport bound, independent of the R37 inline threshold. */
|
|
953
|
+
export declare const DEFAULT_SEARCH_PAGE_SIZE = 50;
|
|
954
|
+
/** `query` is capped (R33): its words are matched as plain substrings, never a regex. */
|
|
955
|
+
export declare const MAX_QUERY_CHARS = 200;
|
|
956
|
+
/** One entry of a `search_tools` page (R33). */
|
|
957
|
+
interface ToolSummary {
|
|
958
|
+
name: string;
|
|
959
|
+
purpose: string;
|
|
960
|
+
posture: ToolPosture;
|
|
961
|
+
destructive: boolean;
|
|
962
|
+
}
|
|
963
|
+
interface SearchToolsPage {
|
|
964
|
+
tools: ToolSummary[];
|
|
965
|
+
/** Matching tools across all pages. */
|
|
966
|
+
total: number;
|
|
967
|
+
nextCursor?: string;
|
|
968
|
+
}
|
|
969
|
+
/** Summarize one catalog entry (R33). */
|
|
970
|
+
export declare function summarizeTool(entry: ToolCatalogEntry, policy?: PolicyOverrides): ToolSummary;
|
|
971
|
+
/**
|
|
972
|
+
* Run `search_tools`. Throws a `validate`-phase {@link ProjectionError} for a
|
|
973
|
+
* malformed cursor, one issued for a different query, or one pointing past
|
|
974
|
+
* the end of the results (R33).
|
|
975
|
+
*/
|
|
976
|
+
export declare function searchTools(catalog: ServerCatalog, args: SearchToolsArgs, options?: SearchToolsOptions): CallToolResult;
|
|
443
977
|
//#endregion
|
|
444
978
|
//#region src/mrtr/discover.d.ts
|
|
445
979
|
/** Stable URIs the server serves via `resources/read` (R3). */
|
|
446
|
-
declare const RESOURCE_URIS: {
|
|
980
|
+
export declare const RESOURCE_URIS: {
|
|
447
981
|
readonly toolTypes: "projection://types/tools.d.ts";
|
|
448
982
|
readonly contract: "projection://docs/authoring-contract.md";
|
|
449
983
|
readonly happyPath: "projection://examples/happy-path.ts";
|
|
@@ -459,21 +993,50 @@ interface ProjectionResource {
|
|
|
459
993
|
/** Resource-level metadata (e.g. the MCP Apps `ui` object). */
|
|
460
994
|
_meta?: Record<string, unknown>;
|
|
461
995
|
}
|
|
462
|
-
declare const EXAMPLE_HAPPY_PATH = "import { setup, assign } from 'xstate';\nimport { toolCall } from '@astral-mcp/tools';\n\n// Read a file and return the tool's result. Read-only calls run immediately,\n// so this whole machine completes in one round trip.\n//\n// Run it with input: { path } — paths are server-specific, so take them\n// from the input or from an earlier read-only listing call, never guess.\nexport default setup({}).createMachine({\n id: 'readOne',\n context: ({ input }) => ({ path: input.path, result: null, error: null }),\n initial: 'reading',\n states: {\n reading: {\n entry: toolCall('read_file', ({ context }) => ({ path: context.path })),\n on: {\n TOOL_RESULT: {\n target: 'done',\n // event.result is the tool's structuredContent when the server\n // returns one (see its Output type in tools.d.ts); otherwise the\n // text of its single text block, null when empty, or the raw\n // content array. isError results arrive as TOOL_ERROR instead.\n actions: assign({ result: ({ event }) => event.result }),\n },\n TOOL_ERROR: {\n target: 'failed',\n actions: assign({ error: ({ event }) => event.error.message }),\n },\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ result: context.result, error: context.error }),\n});\n";
|
|
463
|
-
declare const EXAMPLE_DENIAL_FALLBACK = "import { setup, assign } from 'xstate';\nimport { toolCall } from '@astral-mcp/tools';\n\n// Write a file, but keep going if the user declines. TOOL_DENIED is an\n// ordinary transition — denial is never an automatic abort.\n//\n// Run it with input: { path, dir } — both are server-specific.\nexport default setup({}).createMachine({\n id: 'writeWithFallback',\n context: ({ input }) => ({ path: input.path, dir: input.dir, status: 'pending', note: null }),\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', ({ context }) => ({ path: context.path, content: 'hello' })),\n on: {\n TOOL_RESULT: {\n target: 'summarizing',\n actions: assign({ status: 'written' }),\n },\n TOOL_DENIED: {\n // The user said no: record it and carry on with the read-only\n // part of the work instead of failing the whole workflow.\n target: 'summarizing',\n actions: assign({\n status: 'skipped',\n note: ({ event }) => event.reason ?? 'declined by user',\n }),\n },\n TOOL_ERROR: {\n target: 'summarizing',\n actions: assign({ status: 'failed' }),\n },\n },\n },\n summarizing: {\n entry: toolCall('list_dir', ({ context }) => ({ path: context.dir })),\n on: {\n TOOL_RESULT: { target: 'done' },\n TOOL_ERROR: { target: 'done' },\n },\n },\n done: { type: 'final' },\n },\n output: ({ context }) => ({ status: context.status, note: context.note }),\n});\n";
|
|
996
|
+
export declare const EXAMPLE_HAPPY_PATH = "import { setup, assign } from 'xstate';\nimport { toolCall } from '@astral-mcp/tools';\n\n// Read a file and return the tool's result. Read-only calls run immediately,\n// so this whole machine completes in one round trip.\n//\n// Run it with input: { path } — paths are server-specific, so take them\n// from the input or from an earlier read-only listing call, never guess.\nexport default setup({}).createMachine({\n id: 'readOne',\n context: ({ input }) => ({ path: input.path, result: null, error: null }),\n initial: 'reading',\n states: {\n reading: {\n entry: toolCall('read_file', ({ context }) => ({ path: context.path })),\n on: {\n TOOL_RESULT: {\n target: 'done',\n // event.result is the tool's structuredContent when the server\n // returns one (see its Output type in tools.d.ts); otherwise the\n // text of its single text block, null when empty, or the raw\n // content array. isError results arrive as TOOL_ERROR instead.\n actions: assign({ result: ({ event }) => event.result }),\n },\n TOOL_ERROR: {\n target: 'failed',\n actions: assign({ error: ({ event }) => event.error.message }),\n },\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ result: context.result, error: context.error }),\n});\n";
|
|
997
|
+
export declare const EXAMPLE_DENIAL_FALLBACK = "import { setup, assign } from 'xstate';\nimport { toolCall } from '@astral-mcp/tools';\n\n// Write a file, but keep going if the user declines. TOOL_DENIED is an\n// ordinary transition — denial is never an automatic abort.\n//\n// Run it with input: { path, dir } — both are server-specific.\nexport default setup({}).createMachine({\n id: 'writeWithFallback',\n context: ({ input }) => ({ path: input.path, dir: input.dir, status: 'pending', note: null }),\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', ({ context }) => ({ path: context.path, content: 'hello' })),\n on: {\n TOOL_RESULT: {\n target: 'summarizing',\n actions: assign({ status: 'written' }),\n },\n TOOL_DENIED: {\n // The user said no: record it and carry on with the read-only\n // part of the work instead of failing the whole workflow.\n target: 'summarizing',\n actions: assign({\n status: 'skipped',\n note: ({ event }) => event.reason ?? 'declined by user',\n }),\n },\n TOOL_ERROR: {\n target: 'summarizing',\n actions: assign({ status: 'failed' }),\n },\n },\n },\n summarizing: {\n entry: toolCall('list_dir', ({ context }) => ({ path: context.dir })),\n on: {\n TOOL_RESULT: { target: 'done' },\n TOOL_ERROR: { target: 'done' },\n },\n },\n done: { type: 'final' },\n },\n output: ({ context }) => ({ status: context.status, note: context.note }),\n});\n";
|
|
464
998
|
/** Build the resources Projection serves for a wrapped server (R3). */
|
|
465
|
-
declare function buildResources(catalog: ServerCatalog, dts: string): ProjectionResource[];
|
|
999
|
+
export declare function buildResources(catalog: ServerCatalog, dts: string): ProjectionResource[];
|
|
1000
|
+
/** R37: above this many tools, `discover_apis` defers the per-tool list to the catalog tools. */
|
|
1001
|
+
export declare const DEFAULT_INLINE_TOOL_THRESHOLD = 40;
|
|
1002
|
+
interface DiscoverApisOptions {
|
|
1003
|
+
/** Whether the catalog projection (`search_tools` / `describe_tool`) is served (R37). */
|
|
1004
|
+
catalog?: boolean;
|
|
1005
|
+
/**
|
|
1006
|
+
* Tool count above which the inline per-tool list is omitted. Default
|
|
1007
|
+
* {@link DEFAULT_INLINE_TOOL_THRESHOLD}; a finite value is floored and
|
|
1008
|
+
* clamped at 0, anything else falls back to the default.
|
|
1009
|
+
*/
|
|
1010
|
+
inlineThreshold?: number;
|
|
1011
|
+
}
|
|
466
1012
|
/**
|
|
467
1013
|
* The `discover_apis` result: an inline overview sufficient to author a
|
|
468
1014
|
* simple machine unaided, plus resource links for the full artifacts.
|
|
1015
|
+
*
|
|
1016
|
+
* R37: when the catalog projection is on and the catalog is large, the
|
|
1017
|
+
* per-tool overview is replaced by the tool count and a pointer to
|
|
1018
|
+
* `search_tools` / `describe_tool` — the `.d.ts` resource stays complete.
|
|
469
1019
|
*/
|
|
470
|
-
declare function discoverApis(catalog: ServerCatalog, overview: string): CallToolResult;
|
|
1020
|
+
export declare function discoverApis(catalog: ServerCatalog, overview: string, options?: DiscoverApisOptions): CallToolResult;
|
|
1021
|
+
/** Which projections a facade serves (R1, R32). */
|
|
1022
|
+
interface ProjectionSelection {
|
|
1023
|
+
codeMode: boolean;
|
|
1024
|
+
catalog: boolean;
|
|
1025
|
+
}
|
|
471
1026
|
/**
|
|
472
|
-
* The wrapped server's `instructions`, followed by the
|
|
473
|
-
* (R29). The preamble is library copy the
|
|
1027
|
+
* The wrapped server's `instructions`, followed by the preamble for the
|
|
1028
|
+
* projections in service (R29). The preamble is library copy the
|
|
1029
|
+
* integrating developer can replace wholesale.
|
|
474
1030
|
*/
|
|
475
|
-
declare
|
|
476
|
-
|
|
1031
|
+
export declare function buildInstructions(catalog: ServerCatalog, preamble?: string, projections?: ProjectionSelection): string;
|
|
1032
|
+
/** Preamble when only code mode is on (R29). */
|
|
1033
|
+
export declare const DEFAULT_CODE_MODE_PREAMBLE = "This server runs in code mode: instead of calling its tools directly, author an XState v5 state machine and run it with execute_machine, which orchestrates the tool calls for you. Any tool that is not read-only pauses the machine and asks the user to approve that specific action before it runs. Call discover_apis first for the tool types, the authoring contract, and worked examples.";
|
|
1034
|
+
/** Preamble when only the catalog projection is on (R29, R32). */
|
|
1035
|
+
export declare const DEFAULT_CATALOG_PREAMBLE = "This server exposes its tools through a catalog: call search_tools to find a tool, describe_tool to see its arguments, then call_tool to run it. Any tool that is not read-only pauses and asks the user to approve that specific action before it runs.";
|
|
1036
|
+
/** Preamble when both projections are on: the routing rule (R29). */
|
|
1037
|
+
export declare const DEFAULT_ROUTING_PREAMBLE = "This server offers two ways to use its tools. For a single action, call search_tools to find the tool, describe_tool to see its arguments, then call_tool to run it. For several steps, branching on results, or a workflow worth saving, author an XState v5 state machine and run it with execute_machine (call discover_apis first for the tool types, the authoring contract, and worked examples). Either way, any action that is not read-only pauses and asks the user to approve that specific action before it runs.";
|
|
1038
|
+
/** The R29 preamble variant for a projection selection. */
|
|
1039
|
+
export declare function defaultPreamble(projections: ProjectionSelection): string;
|
|
477
1040
|
//#endregion
|
|
478
1041
|
//#region src/wrap.d.ts
|
|
479
1042
|
interface WrapOptions {
|
|
@@ -481,11 +1044,17 @@ interface WrapOptions {
|
|
|
481
1044
|
blob: BlobSealerConfig;
|
|
482
1045
|
/** Resource cap overrides, clamped at the hard maxima (R12). */
|
|
483
1046
|
caps?: Partial<ResourceCaps>;
|
|
484
|
-
/**
|
|
1047
|
+
/**
|
|
1048
|
+
* Per-tool policy overrides (R14). Read once, at wrap time: the facade
|
|
1049
|
+
* keeps its own frozen copy, so later changes to this object are not seen.
|
|
1050
|
+
*/
|
|
485
1051
|
policy?: PolicyOverrides;
|
|
486
1052
|
/** Masks sensitive argument fields before they reach an approval prompt (R16). */
|
|
487
1053
|
redact?: RedactionHook;
|
|
488
|
-
/**
|
|
1054
|
+
/**
|
|
1055
|
+
* Replaces the whole R29 preamble, whichever projections are on (the
|
|
1056
|
+
* code-mode, catalog or routing copy).
|
|
1057
|
+
*/
|
|
489
1058
|
codeModePreamble?: string;
|
|
490
1059
|
/** Compatibility switches for pre-2026-07-28 clients. */
|
|
491
1060
|
compat?: {
|
|
@@ -500,8 +1069,32 @@ interface WrapOptions {
|
|
|
500
1069
|
};
|
|
501
1070
|
/** Identity the servers built by `createServer` advertise. */
|
|
502
1071
|
serverInfo?: Implementation;
|
|
1072
|
+
/**
|
|
1073
|
+
* R37: above this many tools, `discover_apis` omits the per-tool list and
|
|
1074
|
+
* points at `search_tools` / `describe_tool` (only when the catalog
|
|
1075
|
+
* projection is on). Default 40.
|
|
1076
|
+
*/
|
|
1077
|
+
catalogInlineThreshold?: number;
|
|
1078
|
+
/**
|
|
1079
|
+
* Shared replay cache (R38). Consulted after blob verification and before
|
|
1080
|
+
* any gated execution, for both `execute_machine` and `call_tool`. None
|
|
1081
|
+
* ships by default; supply a store shared across instances.
|
|
1082
|
+
*/
|
|
1083
|
+
replayCache?: ReplayCache;
|
|
1084
|
+
/**
|
|
1085
|
+
* Which projections the facade serves (R1, R32): code mode
|
|
1086
|
+
* (`execute_machine`, `discover_apis`) and the catalog projection
|
|
1087
|
+
* (`search_tools`, `describe_tool`, `call_tool`). Both default on;
|
|
1088
|
+
* disabling both is an error at wrap time.
|
|
1089
|
+
*/
|
|
1090
|
+
projections?: ProjectionsOptions;
|
|
503
1091
|
}
|
|
504
|
-
/**
|
|
1092
|
+
/** Per-projection on/off switches (R1, R32). */
|
|
1093
|
+
interface ProjectionsOptions {
|
|
1094
|
+
codeMode?: boolean;
|
|
1095
|
+
catalog?: boolean;
|
|
1096
|
+
}
|
|
1097
|
+
/** Options for registering the projections on a server the caller built. */
|
|
505
1098
|
interface RegisterOptions {
|
|
506
1099
|
/**
|
|
507
1100
|
* The protocol era this server instance serves (R28). Omitted means
|
|
@@ -521,8 +1114,8 @@ interface ProjectionFacade {
|
|
|
521
1114
|
readonly resources: ProjectionResource[];
|
|
522
1115
|
/**
|
|
523
1116
|
* Server factory to hand to `createMcpHandler` or `serveStdio` (R28, R29).
|
|
524
|
-
* Every instance it builds carries the
|
|
525
|
-
*
|
|
1117
|
+
* Every instance it builds carries the `instructions` and knows the era it
|
|
1118
|
+
* is serving.
|
|
526
1119
|
*/
|
|
527
1120
|
readonly serverFactory: McpServerFactory;
|
|
528
1121
|
/**
|
|
@@ -533,18 +1126,35 @@ interface ProjectionFacade {
|
|
|
533
1126
|
executeMachine(args: ExecuteMachineArgs, era?: ProtocolEra, clientCanElicit?: boolean): Promise<ToolCallResult>;
|
|
534
1127
|
/** Run `discover_apis`. */
|
|
535
1128
|
discoverApis(): CallToolResult;
|
|
536
|
-
/**
|
|
1129
|
+
/** Run `search_tools` (R33). Failures come back as R25 structured error results. */
|
|
1130
|
+
searchTools(args: {
|
|
1131
|
+
query?: string;
|
|
1132
|
+
cursor?: string;
|
|
1133
|
+
}): CallToolResult;
|
|
1134
|
+
/** Run `describe_tool` (R34). Failures come back as R25 structured error results. */
|
|
1135
|
+
describeTool(args: {
|
|
1136
|
+
name: string;
|
|
1137
|
+
types?: boolean;
|
|
1138
|
+
}): CallToolResult;
|
|
1139
|
+
/**
|
|
1140
|
+
* Run `call_tool` (R35) for one `tools/call`, first attempt or retry.
|
|
1141
|
+
* `era` / `clientCanElicit` as for `executeMachine`.
|
|
1142
|
+
*/
|
|
1143
|
+
callTool(args: CallToolArgs, era?: ProtocolEra, clientCanElicit?: boolean): Promise<ToolCallResult>;
|
|
1144
|
+
/** The projections this facade serves (R32). Frozen: fixed at wrap time. */
|
|
1145
|
+
readonly projections: Readonly<ProjectionSelection>;
|
|
1146
|
+
/** Build an `McpServer` carrying the instructions, the enabled projections' tools and the resources. */
|
|
537
1147
|
createServer(ctx?: RegisterOptions): McpServer;
|
|
538
|
-
/** Register
|
|
1148
|
+
/** Register the enabled projections' tools and the resources on an `McpServer` the caller built. */
|
|
539
1149
|
registerOn(server: McpServer, options?: RegisterOptions): void;
|
|
540
1150
|
/** Close the connection to the wrapped server. */
|
|
541
1151
|
close(): Promise<void>;
|
|
542
1152
|
}
|
|
543
1153
|
/**
|
|
544
1154
|
* Wrap an MCP server (an in-process instance or a connected client) into a
|
|
545
|
-
*
|
|
1155
|
+
* Projection facade.
|
|
546
1156
|
*/
|
|
547
|
-
declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
1157
|
+
export declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
548
1158
|
//#endregion
|
|
549
1159
|
//#region src/apps/dashboard.d.ts
|
|
550
1160
|
/**
|
|
@@ -575,10 +1185,10 @@ declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions)
|
|
|
575
1185
|
* `{ phase, message, hint, logs }`.
|
|
576
1186
|
*/
|
|
577
1187
|
/** URI the dashboard is served under. MCP Apps mandates the ui:// scheme. */
|
|
578
|
-
declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
1188
|
+
export declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
579
1189
|
/** MIME type the MCP Apps spec mandates for app HTML resources. */
|
|
580
|
-
declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
581
|
-
declare const DASHBOARD_HTML = "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>Projection workflow dashboard</title>\n<style>\n :root {\n color-scheme: light dark;\n --bg: #ffffff; --fg: #1a1a2e; --muted: #6b7280; --line: #e5e7eb;\n --ok: #047857; --ok-bg: #ecfdf5; --err: #b91c1c; --err-bg: #fef2f2;\n --chip: #eef2ff; --mono: ui-monospace, SFMono-Regular, Menlo, monospace;\n }\n @media (prefers-color-scheme: dark) {\n :root {\n --bg: #111318; --fg: #e5e7eb; --muted: #9ca3af; --line: #2a2f3a;\n --ok: #34d399; --ok-bg: #06281f; --err: #f87171; --err-bg: #2d1215;\n --chip: #1e2433;\n }\n }\n html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg);\n font: 14px/1.5 system-ui, sans-serif; }\n main { padding: 16px; max-width: 720px; }\n h1 { font-size: 15px; margin: 0 0 12px; display: flex; gap: 8px; align-items: center; }\n .chip { font-size: 12px; padding: 2px 10px; border-radius: 999px; background: var(--chip); }\n .chip.ok { color: var(--ok); background: var(--ok-bg); }\n .chip.err { color: var(--err); background: var(--err-bg); }\n section { margin: 14px 0; }\n section > h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--muted); margin: 0 0 6px; }\n pre { margin: 0; padding: 10px; background: var(--chip); border-radius: 8px;\n font-family: var(--mono); font-size: 12px; overflow-x: auto; white-space: pre-wrap; }\n table { border-collapse: collapse; width: 100%; font-size: 13px; }\n th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line);\n vertical-align: top; }\n th { color: var(--muted); font-weight: 500; }\n td.args { font-family: var(--mono); font-size: 12px; }\n .log { font-family: var(--mono); font-size: 12px; padding: 2px 0; }\n .log .level { color: var(--muted); margin-right: 6px; }\n .hint { color: var(--muted); font-size: 13px; margin-top: 6px; }\n .hidden { display: none; }\n #waiting { color: var(--muted); }\n</style>\n</head>\n<body>\n<main>\n <h1>Projection workflow <span id=\"status\" class=\"chip\">waiting…</span></h1>\n <p id=\"waiting\">Waiting for the workflow result from the host…</p>\n <section id=\"output-section\" class=\"hidden\"><h2>Output</h2><pre id=\"output\"></pre></section>\n <section id=\"error-section\" class=\"hidden\"><h2>Error</h2>\n <pre id=\"error\"></pre><p id=\"error-hint\" class=\"hint\"></p></section>\n <section id=\"approvals-section\" class=\"hidden\"><h2>Approval audit trail</h2>\n <table><thead><tr><th>Tool</th><th>Decision</th><th>Arguments</th></tr></thead>\n <tbody id=\"approvals\"></tbody></table></section>\n <section id=\"logs-section\" class=\"hidden\"><h2>Console</h2><div id=\"logs\"></div></section>\n</main>\n<script>\n'use strict';\n(function () {\n var nextId = 1;\n var pending = new Map();\n\n function post(message) { window.parent.postMessage(message, '*'); }\n function request(method, params) {\n return new Promise(function (resolve, reject) {\n var id = nextId++;\n pending.set(id, { resolve: resolve, reject: reject });\n post({ jsonrpc: '2.0', id: id, method: method, params: params });\n });\n }\n function notify(method, params) {\n var message = { jsonrpc: '2.0', method: method };\n if (params !== undefined) message.params = params;\n post(message);\n }\n\n function byId(id) { return document.getElementById(id); }\n function show(id) { byId(id).classList.remove('hidden'); }\n function setStatus(text, cls) {\n var chip = byId('status');\n chip.textContent = text;\n chip.className = 'chip' + (cls ? ' ' + cls : '');\n byId('waiting').classList.add('hidden');\n }\n function pretty(value) {\n try { return JSON.stringify(value, null, 2); } catch (e) { return String(value); }\n }\n\n // All model-controlled data enters the DOM via textContent only.\n function renderResult(result) {\n var structured = (result && result.structuredContent) || {};\n if (result && result.isError) {\n setStatus('failed: ' + String(structured.phase || 'error'), 'err');\n byId('error').textContent =\n String(structured.message || 'unknown error');\n byId('error-hint').textContent = String(structured.hint || '');\n show('error-section');\n } else {\n setStatus('completed', 'ok');\n byId('output').textContent = pretty(\n structured.output === undefined ? null : structured.output,\n );\n show('output-section');\n }\n var approvals = Array.isArray(structured.approvals) ? structured.approvals : [];\n if (approvals.length > 0) {\n var tbody = byId('approvals');\n approvals.forEach(function (entry) {\n var row = document.createElement('tr');\n var tool = document.createElement('td');\n tool.textContent = String(entry.tool || '');\n var decision = document.createElement('td');\n decision.textContent = String(entry.decision || '');\n var args = document.createElement('td');\n args.className = 'args';\n args.textContent = pretty(entry.args || {});\n row.appendChild(tool); row.appendChild(decision); row.appendChild(args);\n tbody.appendChild(row);\n });\n show('approvals-section');\n }\n var logs = Array.isArray(structured.logs) ? structured.logs : [];\n if (logs.length > 0) {\n var list = byId('logs');\n logs.forEach(function (entry) {\n var line = document.createElement('div');\n line.className = 'log';\n var level = document.createElement('span');\n level.className = 'level';\n level.textContent = '[' + String(entry.level || 'log') + ']';\n line.appendChild(level);\n line.appendChild(document.createTextNode(String(entry.message || '')));\n list.appendChild(line);\n });\n show('logs-section');\n }\n }\n\n window.addEventListener('message', function (event) {\n // Only the embedding host may speak: forged tool-results from a hostile\n // embedder could otherwise spoof the displayed audit trail.\n if (event.source !== window.parent) return;\n var message = event.data;\n if (!message || message.jsonrpc !== '2.0') return;\n if (message.id !== undefined && message.method === undefined) {\n var waiter = pending.get(message.id);\n if (waiter) {\n pending.delete(message.id);\n if (message.error) waiter.reject(message.error);\n else waiter.resolve(message.result);\n }\n return;\n }\n if (message.method === 'ui/notifications/tool-input') {\n setStatus('running…');\n return;\n }\n if (message.method === 'ui/notifications/tool-result') {\n renderResult(message.params);\n return;\n }\n if (message.method === 'ui/notifications/tool-cancelled') {\n var reason = message.params && message.params.reason;\n setStatus('cancelled', 'err');\n byId('error').textContent = String(reason || 'cancelled by the host');\n show('error-section');\n return;\n }\n // Host -> app REQUESTS (id + method) get an empty result: answers ping\n // and ui/resource-teardown so hosts don't stall on their SHOULD-wait.\n if (message.id !== undefined && message.method !== undefined) {\n post({ jsonrpc: '2.0', id: message.id, result: {} });\n }\n });\n\n // Handshake: initialize, then signal readiness. The host MUST NOT push\n // tool data before ui/notifications/initialized.\n request('ui/initialize', { appCapabilities: {} }).then(function () {\n notify('ui/notifications/initialized');\n });\n})();\n</script>\n</body>\n</html>\n";
|
|
1190
|
+
export declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
1191
|
+
export declare const DASHBOARD_HTML = "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>Projection workflow dashboard</title>\n<style>\n :root {\n color-scheme: light dark;\n --bg: #ffffff; --fg: #1a1a2e; --muted: #6b7280; --line: #e5e7eb;\n --ok: #047857; --ok-bg: #ecfdf5; --err: #b91c1c; --err-bg: #fef2f2;\n --chip: #eef2ff; --mono: ui-monospace, SFMono-Regular, Menlo, monospace;\n }\n @media (prefers-color-scheme: dark) {\n :root {\n --bg: #111318; --fg: #e5e7eb; --muted: #9ca3af; --line: #2a2f3a;\n --ok: #34d399; --ok-bg: #06281f; --err: #f87171; --err-bg: #2d1215;\n --chip: #1e2433;\n }\n }\n html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg);\n font: 14px/1.5 system-ui, sans-serif; }\n main { padding: 16px; max-width: 720px; }\n h1 { font-size: 15px; margin: 0 0 12px; display: flex; gap: 8px; align-items: center; }\n .chip { font-size: 12px; padding: 2px 10px; border-radius: 999px; background: var(--chip); }\n .chip.ok { color: var(--ok); background: var(--ok-bg); }\n .chip.err { color: var(--err); background: var(--err-bg); }\n section { margin: 14px 0; }\n section > h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--muted); margin: 0 0 6px; }\n pre { margin: 0; padding: 10px; background: var(--chip); border-radius: 8px;\n font-family: var(--mono); font-size: 12px; overflow-x: auto; white-space: pre-wrap; }\n table { border-collapse: collapse; width: 100%; font-size: 13px; }\n th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line);\n vertical-align: top; }\n th { color: var(--muted); font-weight: 500; }\n td.args { font-family: var(--mono); font-size: 12px; }\n .log { font-family: var(--mono); font-size: 12px; padding: 2px 0; }\n .log .level { color: var(--muted); margin-right: 6px; }\n .hint { color: var(--muted); font-size: 13px; margin-top: 6px; }\n .hidden { display: none; }\n #waiting { color: var(--muted); }\n</style>\n</head>\n<body>\n<main>\n <h1>Projection workflow <span id=\"status\" class=\"chip\">waiting…</span></h1>\n <p id=\"waiting\">Waiting for the workflow result from the host…</p>\n <section id=\"output-section\" class=\"hidden\"><h2>Output</h2><pre id=\"output\"></pre></section>\n <section id=\"error-section\" class=\"hidden\"><h2>Error</h2>\n <pre id=\"error\"></pre><p id=\"error-hint\" class=\"hint\"></p></section>\n <section id=\"approvals-section\" class=\"hidden\"><h2>Approval audit trail</h2>\n <table><thead><tr><th>Tool</th><th>Decision</th><th>Arguments</th></tr></thead>\n <tbody id=\"approvals\"></tbody></table></section>\n <section id=\"logs-section\" class=\"hidden\"><h2>Console</h2><div id=\"logs\"></div></section>\n</main>\n<script>\n'use strict';\n(function () {\n var nextId = 1;\n var pending = new Map();\n\n function post(message) { window.parent.postMessage(message, '*'); }\n function request(method, params) {\n return new Promise(function (resolve, reject) {\n var id = nextId++;\n pending.set(id, { resolve: resolve, reject: reject });\n post({ jsonrpc: '2.0', id: id, method: method, params: params });\n });\n }\n function notify(method, params) {\n var message = { jsonrpc: '2.0', method: method };\n if (params !== undefined) message.params = params;\n post(message);\n }\n\n function byId(id) { return document.getElementById(id); }\n function show(id) { byId(id).classList.remove('hidden'); }\n function setStatus(text, cls) {\n var chip = byId('status');\n chip.textContent = text;\n chip.className = 'chip' + (cls ? ' ' + cls : '');\n byId('waiting').classList.add('hidden');\n }\n function pretty(value) {\n try { return JSON.stringify(value, null, 2); } catch (e) { return String(value); }\n }\n\n // All model-controlled data enters the DOM via textContent only.\n function renderResult(result) {\n var structured = (result && result.structuredContent) || {};\n if (result && result.isError) {\n setStatus('failed: ' + String(structured.phase || 'error'), 'err');\n byId('error').textContent =\n String(structured.message || 'unknown error');\n byId('error-hint').textContent = String(structured.hint || '');\n show('error-section');\n } else {\n setStatus('completed', 'ok');\n byId('output').textContent = pretty(\n structured.output === undefined ? null : structured.output,\n );\n show('output-section');\n }\n var approvals = Array.isArray(structured.approvals) ? structured.approvals : [];\n if (approvals.length > 0) {\n var tbody = byId('approvals');\n approvals.forEach(function (entry) {\n var row = document.createElement('tr');\n var tool = document.createElement('td');\n tool.textContent = String(entry.tool || '');\n var decision = document.createElement('td');\n decision.textContent = String(entry.decision || '');\n var args = document.createElement('td');\n args.className = 'args';\n args.textContent = pretty(entry.args || {});\n row.appendChild(tool); row.appendChild(decision); row.appendChild(args);\n tbody.appendChild(row);\n });\n show('approvals-section');\n }\n var logs = Array.isArray(structured.logs) ? structured.logs : [];\n if (logs.length > 0) {\n var list = byId('logs');\n logs.forEach(function (entry) {\n var line = document.createElement('div');\n line.className = 'log';\n var level = document.createElement('span');\n level.className = 'level';\n level.textContent = '[' + String(entry.level || 'log') + ']';\n line.appendChild(level);\n line.appendChild(document.createTextNode(String(entry.message || '')));\n list.appendChild(line);\n });\n show('logs-section');\n }\n }\n\n window.addEventListener('message', function (event) {\n // Only the embedding host may speak: forged tool-results from a hostile\n // embedder could otherwise spoof the displayed audit trail.\n if (event.source !== window.parent) return;\n var message = event.data;\n if (!message || message.jsonrpc !== '2.0') return;\n if (message.id !== undefined && message.method === undefined) {\n var waiter = pending.get(message.id);\n if (waiter) {\n pending.delete(message.id);\n if (message.error) waiter.reject(message.error);\n else waiter.resolve(message.result);\n }\n return;\n }\n if (message.method === 'ui/notifications/tool-input') {\n setStatus('running…');\n return;\n }\n if (message.method === 'ui/notifications/tool-result') {\n renderResult(message.params);\n return;\n }\n if (message.method === 'ui/notifications/tool-cancelled') {\n var reason = message.params && message.params.reason;\n setStatus('cancelled', 'err');\n byId('error').textContent = String(reason || 'cancelled by the host');\n show('error-section');\n return;\n }\n // Host -> app REQUESTS (id + method) get an empty result: answers ping\n // and ui/resource-teardown so hosts don't stall on their SHOULD-wait.\n if (message.id !== undefined && message.method !== undefined) {\n post({ jsonrpc: '2.0', id: message.id, result: {} });\n }\n });\n\n // Handshake: initialize, then signal readiness. The host MUST NOT push\n // tool data before ui/notifications/initialized.\n request('ui/initialize', { appCapabilities: {} }).then(function () {\n notify('ui/notifications/initialized');\n });\n})();\n</script>\n</body>\n</html>\n";
|
|
582
1192
|
//#endregion
|
|
583
1193
|
//#region src/prompts/workflow-prompts.d.ts
|
|
584
1194
|
interface WorkflowPromptDefinition {
|
|
@@ -592,29 +1202,9 @@ interface WorkflowPromptDefinition {
|
|
|
592
1202
|
}>;
|
|
593
1203
|
build(args: Record<string, string | undefined>, catalog: ServerCatalog): string;
|
|
594
1204
|
}
|
|
595
|
-
declare const SAVE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
596
|
-
declare const VISUALIZE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
597
|
-
declare const WORKFLOW_PROMPTS: readonly WorkflowPromptDefinition[];
|
|
598
|
-
//#endregion
|
|
599
|
-
//#region src/errors.d.ts
|
|
600
|
-
/**
|
|
601
|
-
* Error carrying the structured `isError` body every failure returns (R25).
|
|
602
|
-
*/
|
|
603
|
-
declare class ProjectionError extends Error {
|
|
604
|
-
readonly phase: ErrorPhase;
|
|
605
|
-
readonly diagnostics: Diagnostic[];
|
|
606
|
-
readonly hint: string;
|
|
607
|
-
logs: LogEntry[];
|
|
608
|
-
constructor(phase: ErrorPhase, message: string, options?: {
|
|
609
|
-
diagnostics?: Diagnostic[];
|
|
610
|
-
hint?: string;
|
|
611
|
-
logs?: LogEntry[];
|
|
612
|
-
cause?: unknown;
|
|
613
|
-
});
|
|
614
|
-
toStructured(): StructuredError;
|
|
615
|
-
}
|
|
616
|
-
/** Convert any thrown value into a StructuredError, defaulting to `runtime` phase. */
|
|
617
|
-
declare function toStructuredError(err: unknown, logs?: LogEntry[]): StructuredError;
|
|
1205
|
+
export declare const SAVE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1206
|
+
export declare const VISUALIZE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1207
|
+
export declare const WORKFLOW_PROMPTS: readonly WorkflowPromptDefinition[];
|
|
618
1208
|
//#endregion
|
|
619
1209
|
//#region src/introspector/introspector.d.ts
|
|
620
1210
|
/** A wrapped-server source: an in-process instance or a connected client. */
|
|
@@ -630,7 +1220,7 @@ type IntrospectorSources = Record<ServerAlias, ServerSource>;
|
|
|
630
1220
|
* {@link ToolCatalog}, and executes tool calls (implements
|
|
631
1221
|
* {@link ToolExecutor}). Construct with {@link createIntrospector}.
|
|
632
1222
|
*/
|
|
633
|
-
declare class Introspector implements ToolExecutor {
|
|
1223
|
+
export declare class Introspector implements ToolExecutor {
|
|
634
1224
|
#private;
|
|
635
1225
|
private constructor();
|
|
636
1226
|
static create(sources: IntrospectorSources): Promise<Introspector>;
|
|
@@ -661,170 +1251,7 @@ declare class Introspector implements ToolExecutor {
|
|
|
661
1251
|
*
|
|
662
1252
|
* v1 usage: `createIntrospector({ [DEFAULT_SERVER_ALIAS]: serverOrClient })`.
|
|
663
1253
|
*/
|
|
664
|
-
declare function createIntrospector(sources: IntrospectorSources): Promise<Introspector>;
|
|
665
|
-
//#endregion
|
|
666
|
-
//#region src/typegen/generate.d.ts
|
|
667
|
-
/**
|
|
668
|
-
* Module specifier authored machines import the tools surface from (R4).
|
|
669
|
-
* The sandbox component mounts {@link GeneratedToolTypes.bridgeSource} here.
|
|
670
|
-
*/
|
|
671
|
-
declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
672
|
-
/**
|
|
673
|
-
* Name of the global the sandbox host MUST inject before authored code runs.
|
|
674
|
-
*
|
|
675
|
-
* Contract (for the sandbox / machine-host components):
|
|
676
|
-
*
|
|
677
|
-
* ```js
|
|
678
|
-
* globalThis.__projection_toolcall = (name, args) => <host-defined value>
|
|
679
|
-
* ```
|
|
680
|
-
*
|
|
681
|
-
* - `name` is the wrapped server's tool name exactly as catalogued.
|
|
682
|
-
* - `args` is a plain JSON-serializable object (never `undefined`; the
|
|
683
|
-
* bridge substitutes `{}` for a missing argument).
|
|
684
|
-
* - The bridge performs no I/O itself and returns the hook's value
|
|
685
|
-
* verbatim. Per R7, authored machines never consume that value as a
|
|
686
|
-
* promise inside invoked actors — the library-supplied `toolCall` action
|
|
687
|
-
* is the intended caller, and results come back as TOOL_RESULT /
|
|
688
|
-
* TOOL_ERROR / TOOL_DENIED events injected by the host.
|
|
689
|
-
* - If the hook is missing, every tool function throws, keeping the bridge
|
|
690
|
-
* inert outside a properly initialized sandbox (S1).
|
|
691
|
-
*/
|
|
692
|
-
declare const TOOL_CALL_HOST_GLOBAL = "__projection_toolcall";
|
|
693
|
-
/** Output of {@link generateToolTypes}. */
|
|
694
|
-
interface GeneratedToolTypes {
|
|
695
|
-
/** `.d.ts` text for the `@astral-mcp/tools` surface (serve via discover_apis, R3). */
|
|
696
|
-
dts: string;
|
|
697
|
-
/** ESM source of the runtime bridge to mount at `@astral-mcp/tools` in the sandbox. */
|
|
698
|
-
bridgeSource: string;
|
|
699
|
-
/** Compact per-tool overview block for inline embedding by discover_apis (R3). */
|
|
700
|
-
overview: string;
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Generate the `@astral-mcp/tools` artifacts for a wrapped server.
|
|
704
|
-
*
|
|
705
|
-
* Accepts either the full aliased {@link ToolCatalog} (which must contain
|
|
706
|
-
* exactly one server in v1, per R30's single-instance instantiation) or a
|
|
707
|
-
* {@link ServerCatalog} directly.
|
|
708
|
-
*/
|
|
709
|
-
declare function generateToolTypes(catalog: ToolCatalog | ServerCatalog): GeneratedToolTypes;
|
|
710
|
-
//#endregion
|
|
711
|
-
//#region src/typegen/json-schema.d.ts
|
|
712
|
-
/**
|
|
713
|
-
* Convert a JSON Schema into TypeScript type text.
|
|
714
|
-
*
|
|
715
|
-
* @param schema - The schema (also used as the $ref resolution root).
|
|
716
|
-
* @param indent - Indentation prefix of the line the type is emitted on;
|
|
717
|
-
* nested object literals indent relative to it.
|
|
718
|
-
*/
|
|
719
|
-
declare function schemaToTsType(schema: unknown, indent?: string): string;
|
|
720
|
-
/**
|
|
721
|
-
* True when the schema requires at least one argument property — used to
|
|
722
|
-
* decide whether the generated tool function's `args` parameter is optional.
|
|
723
|
-
*/
|
|
724
|
-
declare function schemaRequiresArgs(schema: unknown): boolean;
|
|
725
|
-
//#endregion
|
|
726
|
-
//#region src/text-safety.d.ts
|
|
727
|
-
/**
|
|
728
|
-
* Rendering untrusted strings inertly (S5, S6).
|
|
729
|
-
*
|
|
730
|
-
* Tool names, descriptions, the wrapped server's identity, and machine state
|
|
731
|
-
* names all flow from a possibly third-party server or a model-authored
|
|
732
|
-
* machine. Wherever they are rendered into human-facing prompt copy or into
|
|
733
|
-
* generated source, they must not be able to forge structure with control
|
|
734
|
-
* characters (newlines, ESC for ANSI sequences) or reorder text with Unicode
|
|
735
|
-
* bidi overrides. Centralizing the character class here keeps every call site
|
|
736
|
-
* on the same, complete definition — an earlier divergence let generated
|
|
737
|
-
* `.d.ts`/bridge comments miss the directional-isolate range that the
|
|
738
|
-
* elicitation copy already stripped.
|
|
739
|
-
*/
|
|
740
|
-
/**
|
|
741
|
-
* Replace control and bidi characters with the replacement character.
|
|
742
|
-
* `allowNewline` keeps `\n` (for multi-line blocks whose formatting newlines
|
|
743
|
-
* are part of the rendering, e.g. a pretty-printed JSON block).
|
|
744
|
-
*/
|
|
745
|
-
declare function neutralizeControlChars(text: string, options?: {
|
|
746
|
-
allowNewline?: boolean;
|
|
747
|
-
}): string;
|
|
748
|
-
/** Truncate to `maxChars`, appending an ellipsis when shortened. */
|
|
749
|
-
declare function capLength(text: string, maxChars: number): string;
|
|
750
|
-
//#endregion
|
|
751
|
-
//#region src/policy/decision.d.ts
|
|
752
|
-
/**
|
|
753
|
-
* Decide the policy for a catalog tool (R14).
|
|
754
|
-
*
|
|
755
|
-
* - A developer override (`auto` | `ask` | `deny`) always wins.
|
|
756
|
-
* - With no override, `annotations.readOnlyHint === true` yields `auto`;
|
|
757
|
-
* an absent or `false` hint yields `ask` (S5: unannotated defaults to ask).
|
|
758
|
-
* - An override entry with an unrecognized value (possible when the config
|
|
759
|
-
* arrives untyped) fails safe to `ask` — it never grants `auto`.
|
|
760
|
-
*
|
|
761
|
-
* Only own properties of `overrides` are consulted, so tools named like
|
|
762
|
-
* `Object.prototype` members (`toString`, `constructor`, ...) cannot pick up
|
|
763
|
-
* inherited junk as a decision.
|
|
764
|
-
*/
|
|
765
|
-
declare function decidePolicy(entry: ToolCatalogEntry, overrides?: PolicyOverrides): PolicyDecision;
|
|
766
|
-
/** Result of resolving a pending call against a server catalog. */
|
|
767
|
-
type ResolvedCallPolicy = {
|
|
768
|
-
ok: true;
|
|
769
|
-
decision: PolicyDecision;
|
|
770
|
-
entry: ToolCatalogEntry;
|
|
771
|
-
} | {
|
|
772
|
-
ok: false;
|
|
773
|
-
error: ProjectionError;
|
|
774
|
-
};
|
|
775
|
-
/**
|
|
776
|
-
* Resolve a machine-requested tool call against the server catalog and
|
|
777
|
-
* decide its policy.
|
|
778
|
-
*
|
|
779
|
-
* Returns the decision together with the matching catalog entry (the entry
|
|
780
|
-
* is what elicitation copy must be built from — S6), or a structured
|
|
781
|
-
* `validate`-phase {@link ProjectionError} when the machine names a tool the
|
|
782
|
-
* wrapped server does not declare.
|
|
783
|
-
*/
|
|
784
|
-
declare function resolveCallPolicy(call: PendingToolCall, catalog: ServerCatalog, overrides?: PolicyOverrides): ResolvedCallPolicy;
|
|
785
|
-
/**
|
|
786
|
-
* Canonical TOOL_DENIED reason for calls blocked by a `deny` policy
|
|
787
|
-
* decision. A `deny` decision never produces an elicitation — the machine
|
|
788
|
-
* host injects `TOOL_DENIED` with this reason instead.
|
|
789
|
-
*/
|
|
790
|
-
declare const POLICY_DENIED_REASON = "denied by server policy";
|
|
791
|
-
/**
|
|
792
|
-
* Build the TOOL_DENIED reason string for a policy-denied call. With a tool
|
|
793
|
-
* name it names the denied tool so the machine (and audit trail) can tell
|
|
794
|
-
* which call was blocked.
|
|
795
|
-
*/
|
|
796
|
-
declare function policyDeniedReason(toolName?: string): string;
|
|
797
|
-
//#endregion
|
|
798
|
-
//#region src/policy/elicitation.d.ts
|
|
799
|
-
/** Structured approval copy for one gated call (input to the MRTR adapter). */
|
|
800
|
-
interface ElicitationCopy {
|
|
801
|
-
/** Short action title, e.g. `Approve: delete file`. */
|
|
802
|
-
title: string;
|
|
803
|
-
/** Full human-readable summary (plain text with an indented JSON block). */
|
|
804
|
-
message: string;
|
|
805
|
-
/** Tool name, taken from the catalog entry. */
|
|
806
|
-
toolName: string;
|
|
807
|
-
/** Machine state path that requested the call (raw; render with care). */
|
|
808
|
-
stateName: string;
|
|
809
|
-
/** The redacted arguments as rendered in `message` (JSON text, possibly truncated). */
|
|
810
|
-
args: string;
|
|
811
|
-
/** True when the catalog entry carries `destructiveHint: true`. */
|
|
812
|
-
destructive: boolean;
|
|
813
|
-
}
|
|
814
|
-
interface ElicitationCopyOptions {
|
|
815
|
-
/** Redaction hook applied to args before any rendering (R16). */
|
|
816
|
-
redact?: RedactionHook;
|
|
817
|
-
/** Cap on the rendered args JSON, in characters. Default 4096. */
|
|
818
|
-
maxArgsChars?: number;
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* Build the approval summary for a gated call.
|
|
822
|
-
*
|
|
823
|
-
* `entry` MUST be the catalog entry the call was resolved against (use
|
|
824
|
-
* `resolveCallPolicy`); the copy takes the tool name, title and description
|
|
825
|
-
* from it, never from the pending call or its arguments.
|
|
826
|
-
*/
|
|
827
|
-
declare function buildElicitationCopy(call: PendingToolCall, entry: ToolCatalogEntry, options?: ElicitationCopyOptions): ElicitationCopy;
|
|
1254
|
+
export declare function createIntrospector(sources: IntrospectorSources): Promise<Introspector>;
|
|
828
1255
|
//#endregion
|
|
829
1256
|
//#region src/sandbox/session.d.ts
|
|
830
1257
|
/** A tool call surfaced from the `@astral-mcp/tools` bridge inside the VM. */
|
|
@@ -887,7 +1314,7 @@ interface SandboxSession {
|
|
|
887
1314
|
* bridge, evaluate the authored module, and return a handle for driving it.
|
|
888
1315
|
* See ./index.ts for the full boundary contract.
|
|
889
1316
|
*/
|
|
890
|
-
declare function createSandboxSession(options: SandboxSessionOptions): Promise<SandboxSession>;
|
|
1317
|
+
export declare function createSandboxSession(options: SandboxSessionOptions): Promise<SandboxSession>;
|
|
891
1318
|
//#endregion
|
|
892
1319
|
//#region src/machine-host/host.d.ts
|
|
893
1320
|
interface RunSegmentOptions {
|
|
@@ -937,14 +1364,14 @@ interface RunSegmentOptions {
|
|
|
937
1364
|
* check of its own — `executeMachine` enforces `maxInputBytes` before calling
|
|
938
1365
|
* it. Callers invoking `runSegment` directly must bound `input` themselves.
|
|
939
1366
|
*/
|
|
940
|
-
declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>;
|
|
1367
|
+
export declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>;
|
|
941
1368
|
//#endregion
|
|
942
1369
|
//#region src/machine-host/contract.d.ts
|
|
943
1370
|
/**
|
|
944
1371
|
* Human-readable authoring contract. `discover_apis` publishes this inline
|
|
945
1372
|
* (R3) so a model can author a valid machine without fetching resources.
|
|
946
1373
|
*/
|
|
947
|
-
declare const AUTHORING_CONTRACT = "Projection authoring contract (execute_machine)\n\nWrite ONE module whose only top-level statements are imports and a single\ndefault-exported XState v5 machine. The module is re-evaluated on every\napproval round trip, so top-level side effects are rejected.\n\n import { setup } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({ /* ... */ });\n\nRules:\n1. Default-export a machine built with XState v5 setup(...).createMachine(...).\n XState v4 Machine(...) is rejected.\n2. Machine context must be JSON-serializable at all times. No Map, Set, Date,\n class instances, functions, undefined, bigint or symbols in context.\n3. Request tools with the toolCall action. NEVER wrap a tool call in\n fromPromise/invoke — restored snapshots restart invoked actors, which\n would re-execute an approved write. Machines using invoke are rejected.\n4. After a toolCall, wait in a state for one of these events:\n TOOL_RESULT { callId, result } the call succeeded\n TOOL_ERROR { callId, error } the call failed\n TOOL_DENIED { callId, reason } the user declined, or policy denies it\n Denial is not an abort: handle TOOL_DENIED and continue or finish.\n IMPORTANT: if your machine has more than one call outstanding at the same\n time (parallel regions), give each toolCall an explicit id and guard every\n waiting state with whenCall(id) — events reach every region that can\n handle them, so an unguarded region will consume another call's result:\n\n import { toolCall, whenCall } from '@astral-mcp/tools';\n entry: toolCall('write_file', () => ({ path: '/a' }), { id: 'a' }),\n on: { TOOL_RESULT: { guard: whenCall('a'), target: 'done' } },\n5. Read-only tools run immediately. Every other tool pauses the machine for\n user approval; the arguments captured at that moment are the arguments\n that execute.\n6. Only 'xstate' and '@astral-mcp/tools' resolve as imports. There is no\n filesystem, no network, no fetch. All working state lives in context.\n7. Finish by reaching a final state. Use the machine's output for the result.\n8. TOOL_RESULT.result is the tool's structuredContent when the server returns\n one (see its Output type in tools.d.ts); otherwise the text of its single\n text block, null for an empty result, or the raw content array for\n anything else. A tool that returns isError arrives as TOOL_ERROR. Tools\n without an Output type are typed unknown — usually a string.\n9. Tool inputs such as paths, ids and names are server-specific. Do not guess\n them: take them from the machine's input, or discover them first with a\n read-only call (a list/search tool) and keep what you learn in context.\n\nExample — happy path with a read-only call (run with input: { path }):\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'readOne',\n context: ({ input }) => ({ path: input.path, result: null }),\n initial: 'reading',\n states: {\n reading: {\n entry: toolCall('read_file', ({ context }) => ({ path: context.path })),\n on: {\n TOOL_RESULT: { target: 'done', actions: assign({ result: ({ event }) => event.result }) },\n TOOL_ERROR: 'failed',\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ result: context.result }),\n });\n\nExample — handling a denied approval (run with input: { path }):\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'writeOne',\n context: ({ input }) => ({ path: input.path, status: 'pending' }),\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', ({ context }) => ({ path: context.path, content: 'hello' })),\n on: {\n TOOL_RESULT: { target: 'done', actions: assign({ status: 'written' }) },\n TOOL_DENIED: { target: 'done', actions: assign({ status: 'skipped' }) },\n TOOL_ERROR: { target: 'done', actions: assign({ status: 'failed' }) },\n },\n },\n done: { type: 'final' },\n },\n output: ({ context }) => ({ status: context.status }),\n });\n";
|
|
1374
|
+
export declare const AUTHORING_CONTRACT = "Projection authoring contract (execute_machine)\n\nWrite ONE module whose only top-level statements are imports and a single\ndefault-exported XState v5 machine. The module is re-evaluated on every\napproval round trip, so top-level side effects are rejected.\n\n import { setup } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({ /* ... */ });\n\nRules:\n1. Default-export a machine built with XState v5 setup(...).createMachine(...).\n XState v4 Machine(...) is rejected.\n2. Machine context must be JSON-serializable at all times. No Map, Set, Date,\n class instances, functions, undefined, bigint or symbols in context.\n3. Request tools with the toolCall action. NEVER wrap a tool call in\n fromPromise/invoke — restored snapshots restart invoked actors, which\n would re-execute an approved write. Machines using invoke are rejected.\n4. After a toolCall, wait in a state for one of these events:\n TOOL_RESULT { callId, result } the call succeeded\n TOOL_ERROR { callId, error } the call failed\n TOOL_DENIED { callId, reason } the user declined, or policy denies it\n Denial is not an abort: handle TOOL_DENIED and continue or finish.\n IMPORTANT: if your machine has more than one call outstanding at the same\n time (parallel regions), give each toolCall an explicit id and guard every\n waiting state with whenCall(id) — events reach every region that can\n handle them, so an unguarded region will consume another call's result:\n\n import { toolCall, whenCall } from '@astral-mcp/tools';\n entry: toolCall('write_file', () => ({ path: '/a' }), { id: 'a' }),\n on: { TOOL_RESULT: { guard: whenCall('a'), target: 'done' } },\n5. Read-only tools run immediately. Every other tool pauses the machine for\n user approval; the arguments captured at that moment are the arguments\n that execute.\n6. Only 'xstate' and '@astral-mcp/tools' resolve as imports. There is no\n filesystem, no network, no fetch. All working state lives in context.\n7. Finish by reaching a final state. Use the machine's output for the result.\n8. TOOL_RESULT.result is the tool's structuredContent when the server returns\n one (see its Output type in tools.d.ts); otherwise the text of its single\n text block, null for an empty result, or the raw content array for\n anything else. A tool that returns isError arrives as TOOL_ERROR. Tools\n without an Output type are typed unknown — usually a string.\n9. Tool inputs such as paths, ids and names are server-specific. Do not guess\n them: take them from the machine's input, or discover them first with a\n read-only call (a list/search tool) and keep what you learn in context.\n\nExample — happy path with a read-only call (run with input: { path }):\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'readOne',\n context: ({ input }) => ({ path: input.path, result: null }),\n initial: 'reading',\n states: {\n reading: {\n entry: toolCall('read_file', ({ context }) => ({ path: context.path })),\n on: {\n TOOL_RESULT: { target: 'done', actions: assign({ result: ({ event }) => event.result }) },\n TOOL_ERROR: 'failed',\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ result: context.result }),\n });\n\nExample — handling a denied approval (run with input: { path }):\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'writeOne',\n context: ({ input }) => ({ path: input.path, status: 'pending' }),\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', ({ context }) => ({ path: context.path, content: 'hello' })),\n on: {\n TOOL_RESULT: { target: 'done', actions: assign({ status: 'written' }) },\n TOOL_DENIED: { target: 'done', actions: assign({ status: 'skipped' }) },\n TOOL_ERROR: { target: 'done', actions: assign({ status: 'failed' }) },\n },\n },\n done: { type: 'final' },\n },\n output: ({ context }) => ({ status: context.status }),\n });\n";
|
|
948
1375
|
//#endregion
|
|
949
|
-
export {
|
|
1376
|
+
export { type ApprovalGateDeps, type CallToolArgs, type CallToolDeps, type CallToolOutcome, type CallToolResult, type ContentBlock, type DescribeToolArgs, type DescribeToolOptions, type DiscoverApisOptions, type ElicitationCopy, type ElicitationCopyOptions, type ExecuteMachineArgs, type ExecuteMachineDeps, type GeneratedToolTypes, type InputRequest, type InputRequests, type InputRequiredResult, type InputResponse, type InputResponseView, type InputResponses, type OpenBlobOptions, type ProjectionFacade, type ProjectionResource, type ProjectionSelection, type ProjectionsOptions, type ProtocolEra, type RegisterOptions, type ResolvedCallPolicy, type RetryEnvelope, type RunSegmentOptions, type SandboxSession, type SandboxSessionOptions, type SandboxToolCall, type SandboxToolCallHandler, type SanitizedSchema, type SearchToolsArgs, type SearchToolsOptions, type SearchToolsPage, type ToolCallResult, type ToolDescription, type ToolPosture, type ToolSummary, type ToolTypeText, type WorkflowPromptDefinition, type WrapOptions, acceptedContent, inputRequired, inputResponse, isInputRequiredResult };
|
|
950
1377
|
//# sourceMappingURL=index.d.mts.map
|