@astral-mcp/projection 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/index.d.mts +862 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2929 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,862 @@
|
|
|
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
|
+
import { Client } from "@modelcontextprotocol/client";
|
|
3
|
+
import "@sebastianwessel/quickjs";
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Shared core types for Projection.
|
|
7
|
+
*
|
|
8
|
+
* These types are the contract between the seven components (introspector,
|
|
9
|
+
* typegen, sandbox runtime, machine host, policy engine, blob sealer, MRTR
|
|
10
|
+
* adapter). Component implementations depend on this module; it depends on
|
|
11
|
+
* nothing inside the package.
|
|
12
|
+
*/
|
|
13
|
+
/** Alias identifying a wrapped server. v1 instantiates exactly one. */
|
|
14
|
+
type ServerAlias = string;
|
|
15
|
+
declare const DEFAULT_SERVER_ALIAS: ServerAlias;
|
|
16
|
+
/** MCP tool annotations we care about (untrusted hints — S5). */
|
|
17
|
+
interface ToolAnnotations {
|
|
18
|
+
readOnlyHint?: boolean;
|
|
19
|
+
destructiveHint?: boolean;
|
|
20
|
+
idempotentHint?: boolean;
|
|
21
|
+
title?: string;
|
|
22
|
+
}
|
|
23
|
+
interface ToolCatalogEntry {
|
|
24
|
+
/** Tool name as declared by the wrapped server. */
|
|
25
|
+
name: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
/** JSON Schema for the tool's input. */
|
|
28
|
+
inputSchema: Record<string, unknown>;
|
|
29
|
+
/** JSON Schema for the tool's output, when declared. */
|
|
30
|
+
outputSchema?: Record<string, unknown>;
|
|
31
|
+
annotations?: ToolAnnotations;
|
|
32
|
+
}
|
|
33
|
+
interface ToolCatalog {
|
|
34
|
+
/** Keyed by server alias (R30). v1 has exactly one entry. */
|
|
35
|
+
servers: Map<ServerAlias, ServerCatalog>;
|
|
36
|
+
}
|
|
37
|
+
interface ServerCatalog {
|
|
38
|
+
alias: ServerAlias;
|
|
39
|
+
/** Stable identity string recorded into blobs (R30). */
|
|
40
|
+
identity: string;
|
|
41
|
+
/** The wrapped server's `instructions` field, verbatim (R29). */
|
|
42
|
+
instructions?: string;
|
|
43
|
+
tools: ToolCatalogEntry[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Look up a tool by name in a catalog, O(1) after the first call.
|
|
47
|
+
*
|
|
48
|
+
* Duplicate names resolve to the FIRST occurrence, matching `Array#find` and
|
|
49
|
+
* typegen's `dedupeToolNames` (S5): a hostile server declaring the same name
|
|
50
|
+
* twice must not be able to make the policy gate see a different entry (e.g.
|
|
51
|
+
* a later `readOnlyHint: true` copy) than the one typegen exposed.
|
|
52
|
+
*/
|
|
53
|
+
declare function findTool(catalog: ServerCatalog, name: string): ToolCatalogEntry | undefined;
|
|
54
|
+
/** Narrow to a non-null, non-array object. */
|
|
55
|
+
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
56
|
+
/** Executes a tool call against the wrapped server. Implemented by the introspector. */
|
|
57
|
+
interface ToolExecutor {
|
|
58
|
+
callTool(alias: ServerAlias, name: string, args: Record<string, unknown>): Promise<ToolCallOutcome>;
|
|
59
|
+
}
|
|
60
|
+
type ToolCallOutcome = {
|
|
61
|
+
ok: true;
|
|
62
|
+
result: unknown;
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
error: {
|
|
66
|
+
message: string;
|
|
67
|
+
detail?: unknown;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
type PolicyDecision = 'auto' | 'ask' | 'deny';
|
|
71
|
+
interface PolicyOverrides {
|
|
72
|
+
/** Per-tool decision override, keyed by tool name (v1: single server). */
|
|
73
|
+
[toolName: string]: PolicyDecision;
|
|
74
|
+
}
|
|
75
|
+
/** A tool call requested by the machine via the `toolCall` action creator. */
|
|
76
|
+
interface PendingToolCall {
|
|
77
|
+
/** Unique id for this call within the workflow (also the inputRequest key). */
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
args: Record<string, unknown>;
|
|
81
|
+
/** Machine state path that requested the call (for elicitation copy — R16). */
|
|
82
|
+
stateName: string;
|
|
83
|
+
}
|
|
84
|
+
/** Events the host injects into the machine. The machine never performs I/O itself. */
|
|
85
|
+
type HostEvent = {
|
|
86
|
+
type: 'TOOL_RESULT';
|
|
87
|
+
callId: string;
|
|
88
|
+
result: unknown;
|
|
89
|
+
} | {
|
|
90
|
+
type: 'TOOL_ERROR';
|
|
91
|
+
callId: string;
|
|
92
|
+
error: {
|
|
93
|
+
message: string;
|
|
94
|
+
detail?: unknown;
|
|
95
|
+
};
|
|
96
|
+
} | {
|
|
97
|
+
type: 'TOOL_DENIED';
|
|
98
|
+
callId: string;
|
|
99
|
+
reason?: string;
|
|
100
|
+
};
|
|
101
|
+
type ErrorPhase = 'transpile' | 'validate' | 'runtime' | 'cap_exceeded' | 'blob_verification' | 'protocol' | 'terminal';
|
|
102
|
+
interface Diagnostic {
|
|
103
|
+
message: string;
|
|
104
|
+
/** Optional source location within the submitted code. */
|
|
105
|
+
line?: number;
|
|
106
|
+
column?: number;
|
|
107
|
+
}
|
|
108
|
+
interface StructuredError {
|
|
109
|
+
phase: ErrorPhase;
|
|
110
|
+
message: string;
|
|
111
|
+
diagnostics: Diagnostic[];
|
|
112
|
+
/** One-line actionable fix (R25). */
|
|
113
|
+
hint: string;
|
|
114
|
+
logs: LogEntry[];
|
|
115
|
+
}
|
|
116
|
+
type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
117
|
+
interface LogEntry {
|
|
118
|
+
level: LogLevel;
|
|
119
|
+
message: string;
|
|
120
|
+
/** Milliseconds since segment start. */
|
|
121
|
+
ts: number;
|
|
122
|
+
/** Zero-based MRTR segment index this entry was captured in. */
|
|
123
|
+
segment: number;
|
|
124
|
+
}
|
|
125
|
+
interface ResourceCaps {
|
|
126
|
+
/** Wall-clock per execution segment, ms. */
|
|
127
|
+
segmentWallClockMs: number;
|
|
128
|
+
/** WASM memory, bytes. */
|
|
129
|
+
wasmMemoryBytes: number;
|
|
130
|
+
/** Submitted code size, bytes. */
|
|
131
|
+
maxCodeBytes: number;
|
|
132
|
+
/** Submitted machine input, bytes of its JSON serialization. */
|
|
133
|
+
maxInputBytes: number;
|
|
134
|
+
/** Read-only tool calls per segment. */
|
|
135
|
+
maxReadCallsPerSegment: number;
|
|
136
|
+
/** MRTR round trips per workflow. */
|
|
137
|
+
maxRoundTrips: number;
|
|
138
|
+
/** Machine events processed per segment. */
|
|
139
|
+
maxEventsPerSegment: number;
|
|
140
|
+
/** Final result payload, bytes. */
|
|
141
|
+
maxResultBytes: number;
|
|
142
|
+
/** Machine state nodes (static count at validation). */
|
|
143
|
+
maxStateNodes: number;
|
|
144
|
+
/** Captured console output per segment, bytes. */
|
|
145
|
+
maxConsoleBytes: number;
|
|
146
|
+
}
|
|
147
|
+
declare const DEFAULT_CAPS: ResourceCaps;
|
|
148
|
+
declare const MAX_CAPS: ResourceCaps;
|
|
149
|
+
/** 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
|
+
interface BlobPayload {
|
|
153
|
+
/** Blob schema version; unknown versions are rejected. */
|
|
154
|
+
v: number;
|
|
155
|
+
/** Library version that produced the snapshot. */
|
|
156
|
+
libv: string;
|
|
157
|
+
/** Exact XState version that produced the snapshot. */
|
|
158
|
+
xstatev: string;
|
|
159
|
+
/** SHA-256 (hex) of the original `code` argument. */
|
|
160
|
+
codeHash: string;
|
|
161
|
+
/** Server identity the blob was minted against (R30). */
|
|
162
|
+
serverIdentity: string;
|
|
163
|
+
/** `getPersistedSnapshot()` output of the machine actor. */
|
|
164
|
+
snapshot: unknown;
|
|
165
|
+
/** inputRequest key -> gated tool call awaiting a verdict (S2). */
|
|
166
|
+
pending: Record<string, PendingToolCall>;
|
|
167
|
+
/**
|
|
168
|
+
* Approval audit accumulated in earlier segments (PRD §8).
|
|
169
|
+
*
|
|
170
|
+
* Carried in the blob because the library holds no cross-request state
|
|
171
|
+
* (R27): without it a completed workflow would report only the approvals
|
|
172
|
+
* of its final segment.
|
|
173
|
+
*/
|
|
174
|
+
audit: AuditEntry[];
|
|
175
|
+
/** Round-trip counter (R18). */
|
|
176
|
+
trip: number;
|
|
177
|
+
/** Random nonce for replay scoping. */
|
|
178
|
+
nonce: string;
|
|
179
|
+
/** Issued-at, Unix ms. */
|
|
180
|
+
iat: number;
|
|
181
|
+
/** Expiry, Unix ms (default TTL 15 min). */
|
|
182
|
+
exp: number;
|
|
183
|
+
}
|
|
184
|
+
interface BlobSealerConfig {
|
|
185
|
+
/** Current encryption key (32 bytes). */
|
|
186
|
+
key: Uint8Array;
|
|
187
|
+
/** Previous keys accepted for decryption during rotation (R22). */
|
|
188
|
+
previousKeys?: Uint8Array[];
|
|
189
|
+
/** Blob TTL in ms. Default 15 minutes. */
|
|
190
|
+
ttlMs?: number;
|
|
191
|
+
/** Sealed+compressed size ceiling in bytes. Default 128 KB (R23). */
|
|
192
|
+
maxBlobBytes?: number;
|
|
193
|
+
}
|
|
194
|
+
/** Verdict delivered on retry for a pending gated call. */
|
|
195
|
+
type ApprovalVerdict = {
|
|
196
|
+
kind: 'approved';
|
|
197
|
+
} | {
|
|
198
|
+
kind: 'declined';
|
|
199
|
+
reason?: string;
|
|
200
|
+
};
|
|
201
|
+
/** Outcome of running one execution segment. */
|
|
202
|
+
type SegmentOutcome = {
|
|
203
|
+
status: 'completed';
|
|
204
|
+
/** Final machine output/context to return to the client. */
|
|
205
|
+
output: unknown;
|
|
206
|
+
/** Per-call approval audit trail. */
|
|
207
|
+
audit: AuditEntry[];
|
|
208
|
+
logs: LogEntry[];
|
|
209
|
+
} | {
|
|
210
|
+
status: 'suspended';
|
|
211
|
+
/** Gated calls awaiting approval, keyed by inputRequest key. */
|
|
212
|
+
pending: Record<string, PendingToolCall>;
|
|
213
|
+
/** Actor snapshot to seal into the blob. */
|
|
214
|
+
snapshot: unknown;
|
|
215
|
+
trip: number;
|
|
216
|
+
audit: AuditEntry[];
|
|
217
|
+
logs: LogEntry[];
|
|
218
|
+
} | {
|
|
219
|
+
status: 'error';
|
|
220
|
+
error: StructuredError;
|
|
221
|
+
};
|
|
222
|
+
interface AuditEntry {
|
|
223
|
+
callId: string;
|
|
224
|
+
tool: string;
|
|
225
|
+
args: Record<string, unknown>;
|
|
226
|
+
decision: 'auto' | 'approved' | 'declined' | 'denied_by_policy' | 'error';
|
|
227
|
+
reason?: string;
|
|
228
|
+
}
|
|
229
|
+
interface RedactionHook {
|
|
230
|
+
/**
|
|
231
|
+
* Mask sensitive argument fields before they appear in elicitation copy
|
|
232
|
+
* (R16). Receives the tool name and resolved args; returns args to display.
|
|
233
|
+
*/
|
|
234
|
+
(toolName: string, args: Record<string, unknown>): Record<string, unknown>;
|
|
235
|
+
}
|
|
236
|
+
interface ProjectionConfig {
|
|
237
|
+
/** Resource cap overrides, clamped at maxima (R12). */
|
|
238
|
+
caps?: Partial<ResourceCaps>;
|
|
239
|
+
/** Per-tool policy overrides (R14). */
|
|
240
|
+
policy?: PolicyOverrides;
|
|
241
|
+
/** Blob sealing configuration (required for any gated flow). */
|
|
242
|
+
blob: BlobSealerConfig;
|
|
243
|
+
/** Redaction hook for elicitation copy (R16). */
|
|
244
|
+
redact?: RedactionHook;
|
|
245
|
+
/** Override the code-mode preamble appended to instructions (R29). */
|
|
246
|
+
codeModePreamble?: string;
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/blob/sealer.d.ts
|
|
250
|
+
/** 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;
|
|
254
|
+
/** Default sealed-blob size ceiling: 128 KB (R23). */
|
|
255
|
+
declare const DEFAULT_MAX_BLOB_BYTES: number;
|
|
256
|
+
/** SHA-256 hex digest of a code argument (S4 binding — R20 `codeHash`). */
|
|
257
|
+
declare function hashCode(code: string): string;
|
|
258
|
+
interface BuildBlobPayloadInput {
|
|
259
|
+
/** The original `code` argument; hashed into `codeHash` (S4). */
|
|
260
|
+
code: string;
|
|
261
|
+
/** Identity of the wrapped server this blob is minted against (R30). */
|
|
262
|
+
serverIdentity: string;
|
|
263
|
+
/** `getPersistedSnapshot()` output of the machine actor. */
|
|
264
|
+
snapshot: unknown;
|
|
265
|
+
/** inputRequest key -> gated tool call awaiting a verdict (S2). */
|
|
266
|
+
pending: Record<string, PendingToolCall>;
|
|
267
|
+
/** Approval audit accumulated so far in this workflow (PRD §8). */
|
|
268
|
+
audit?: AuditEntry[] | undefined;
|
|
269
|
+
/** Round-trip counter (R18). */
|
|
270
|
+
trip: number;
|
|
271
|
+
/** Blob TTL in ms. Default {@link DEFAULT_TTL_MS} (15 minutes). */
|
|
272
|
+
ttlMs?: number | undefined;
|
|
273
|
+
/** Clock override for testability, Unix ms. Default `Date.now()`. */
|
|
274
|
+
now?: number | undefined;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Construct a fully populated {@link BlobPayload}: stamps the schema and
|
|
278
|
+
* library/XState versions, hashes the code, and fills nonce/iat/exp.
|
|
279
|
+
*/
|
|
280
|
+
declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
281
|
+
/**
|
|
282
|
+
* Seal a payload into an opaque `proj1.` envelope string (R19, R23).
|
|
283
|
+
*
|
|
284
|
+
* JSON → deflateRaw → AES-256-GCM under an HKDF-SHA256 per-blob derived key,
|
|
285
|
+
* with the envelope header as AAD. Throws ProjectionError phase `terminal` if
|
|
286
|
+
* the sealed envelope exceeds `maxBlobBytes` (default 128 KB) or the config
|
|
287
|
+
* keys are malformed.
|
|
288
|
+
*/
|
|
289
|
+
declare function sealBlob(payload: BlobPayload, config: BlobSealerConfig): string;
|
|
290
|
+
interface OpenBlobOptions {
|
|
291
|
+
/** The `code` argument re-sent with the retried call (S4). */
|
|
292
|
+
code: string;
|
|
293
|
+
/** Identity of the wrapped server handling the retry (R30). */
|
|
294
|
+
serverIdentity: string;
|
|
295
|
+
config: BlobSealerConfig;
|
|
296
|
+
/** Clock override for testability, Unix ms. Default `Date.now()`. */
|
|
297
|
+
now?: number | undefined;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Verify and open a sealed blob (R21 — check order is normative):
|
|
301
|
+
*
|
|
302
|
+
* 1. parse envelope + decrypt/authenticate (current key, then each
|
|
303
|
+
* `previousKeys` — R22 rotation grace)
|
|
304
|
+
* 2. schema version, then exact `libv`/`xstatev` match (Q3: strict, no
|
|
305
|
+
* migration)
|
|
306
|
+
* 3. expiry (`exp` strictly in the future relative to `now`)
|
|
307
|
+
* 4. `codeHash` equality against the re-sent code, and `serverIdentity`
|
|
308
|
+
* match
|
|
309
|
+
*
|
|
310
|
+
* Any failure throws ProjectionError phase `blob_verification` naming the
|
|
311
|
+
* failed check (never key material or plaintext). A payload is only
|
|
312
|
+
* returned once every check has passed.
|
|
313
|
+
*/
|
|
314
|
+
declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/blob/versions.d.ts
|
|
317
|
+
/**
|
|
318
|
+
* Version constants recorded into every blob (R20) and strict-matched on
|
|
319
|
+
* open (R21, Q3: no migration — mismatches are rejected).
|
|
320
|
+
*
|
|
321
|
+
* Hardcoded rather than imported from package.json at runtime: JSON import
|
|
322
|
+
* attributes complicate the tsdown/dist story for zero benefit, and both
|
|
323
|
+
* versions are pinned exactly (DECISIONS.md D2). A test in
|
|
324
|
+
* `test/blob/versions.test.ts` asserts these constants match the installed
|
|
325
|
+
* package.json versions, so a version bump that forgets to update them fails
|
|
326
|
+
* CI instead of silently minting blobs with a stale version stamp.
|
|
327
|
+
*/
|
|
328
|
+
/** `@astral-mcp/projection` package version (must match packages/projection/package.json). */
|
|
329
|
+
declare const LIB_VERSION = "0.2.0";
|
|
330
|
+
/** Pinned XState version (must match the exact pin in package.json — D2). */
|
|
331
|
+
declare const XSTATE_VERSION = "5.32.5";
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region src/mrtr/protocol.d.ts
|
|
334
|
+
/**
|
|
335
|
+
* What a `tools/call` handler may return on the 2026-07-28 era: a finished
|
|
336
|
+
* result, or the input-required suspension. This is the SDK's own
|
|
337
|
+
* handler-return type for the method, not a shape of ours.
|
|
338
|
+
*/
|
|
339
|
+
type ToolCallResult = HandlerResultTypeMap['tools/call'];
|
|
340
|
+
/**
|
|
341
|
+
* The MRTR retry fields the client re-sends alongside the original
|
|
342
|
+
* arguments. The SDK lifts them off the params into `ctx.mcpReq`, so a
|
|
343
|
+
* handler never reads them from `args`; Projection still names them because
|
|
344
|
+
* `executeMachine` is callable outside an SDK handler (R27 — the facade is
|
|
345
|
+
* plain functions).
|
|
346
|
+
*
|
|
347
|
+
* `inputResponses` is deliberately widened the same way the SDK's own
|
|
348
|
+
* `inputResponse()` / `acceptedContent()` readers widen it: the values come
|
|
349
|
+
* from the client and are never validated by the SDK, so a caller may hand
|
|
350
|
+
* over whatever the wire carried.
|
|
351
|
+
*/
|
|
352
|
+
interface RetryEnvelope {
|
|
353
|
+
/** The `requestState` echoed back unchanged. */
|
|
354
|
+
requestState?: string;
|
|
355
|
+
/** Answers keyed by the same keys as `inputRequests`. */
|
|
356
|
+
inputResponses?: InputResponses$1 | Record<string, unknown>;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* The JSON Schema an approval elicitation asks the client to collect, typed
|
|
360
|
+
* as the SDK's restricted elicitation schema so `inputRequired.elicit()`
|
|
361
|
+
* accepts it without a cast.
|
|
362
|
+
*
|
|
363
|
+
* Projection-specific: MRTR carries whatever schema the server asks for, and
|
|
364
|
+
* an approval prompt whose only payload is an optional decline reason is our
|
|
365
|
+
* product decision (R16/R17), not a protocol shape.
|
|
366
|
+
*/
|
|
367
|
+
declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
368
|
+
/**
|
|
369
|
+
* Protocol revision that introduced MRTR.
|
|
370
|
+
*
|
|
371
|
+
* The SDK has no exported constant for it: `LATEST_PROTOCOL_VERSION` and
|
|
372
|
+
* `SUPPORTED_PROTOCOL_VERSIONS` cover the *legacy* (`initialize`-negotiated)
|
|
373
|
+
* family only — `2025-11-25` and earlier. The 2026-07-28 era is selected by
|
|
374
|
+
* `server/discover`, and the SDK models it as the `ProtocolEra` value
|
|
375
|
+
* `'modern'` rather than as a version string. We keep the literal purely so
|
|
376
|
+
* error copy can name the revision a client must speak (R28).
|
|
377
|
+
*/
|
|
378
|
+
declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
379
|
+
/**
|
|
380
|
+
* Whether the era a request is being served on can carry MRTR (R28).
|
|
381
|
+
*
|
|
382
|
+
* The SDK binds an era to the *serving instance*, not to a per-request
|
|
383
|
+
* header: `createMcpHandler` / `serveStdio` hand the era to the server
|
|
384
|
+
* factory as `McpRequestContext.era`, and a hand-connected `McpServer` is
|
|
385
|
+
* always `'legacy'`. So this takes the era, not a version string — there is
|
|
386
|
+
* no `extra.protocolVersion` to read, and reading one was the bug this
|
|
387
|
+
* migration fixes (docs/DECISIONS.md D1).
|
|
388
|
+
*/
|
|
389
|
+
declare function supportsMrtr(era: ProtocolEra$1 | undefined): boolean;
|
|
390
|
+
//#endregion
|
|
391
|
+
//#region src/mrtr/adapter.d.ts
|
|
392
|
+
interface ExecuteMachineArgs extends RetryEnvelope {
|
|
393
|
+
/** The authored module source (R2). */
|
|
394
|
+
code: string;
|
|
395
|
+
lang?: 'ts' | 'js';
|
|
396
|
+
/** Passed to the machine as its input. */
|
|
397
|
+
input?: unknown;
|
|
398
|
+
}
|
|
399
|
+
interface ExecuteMachineDeps {
|
|
400
|
+
catalog: ServerCatalog;
|
|
401
|
+
bridgeSource: string;
|
|
402
|
+
executor: ToolExecutor;
|
|
403
|
+
blob: BlobSealerConfig;
|
|
404
|
+
caps?: Partial<ResourceCaps>;
|
|
405
|
+
policy?: PolicyOverrides;
|
|
406
|
+
redact?: RedactionHook;
|
|
407
|
+
/**
|
|
408
|
+
* Protocol era this request is being served on, for down-negotiation
|
|
409
|
+
* (R28). The SDK hands it to the server factory as
|
|
410
|
+
* `McpRequestContext.era`; `undefined` is treated as legacy.
|
|
411
|
+
*/
|
|
412
|
+
protocolEra?: ProtocolEra;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Run `execute_machine` for one `tools/call`, whether it is a first attempt
|
|
416
|
+
* or an MRTR retry.
|
|
417
|
+
*
|
|
418
|
+
* Statelessness (R27): everything needed to resume rides in `requestState`,
|
|
419
|
+
* so any instance can serve any retry. Nothing is held between calls.
|
|
420
|
+
*/
|
|
421
|
+
declare function executeMachine(args: ExecuteMachineArgs, deps: ExecuteMachineDeps): Promise<ToolCallResult>;
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/mrtr/discover.d.ts
|
|
424
|
+
/** Stable URIs the server serves via `resources/read` (R3). */
|
|
425
|
+
declare const RESOURCE_URIS: {
|
|
426
|
+
readonly toolTypes: "projection://types/tools.d.ts";
|
|
427
|
+
readonly contract: "projection://docs/authoring-contract.md";
|
|
428
|
+
readonly happyPath: "projection://examples/happy-path.ts";
|
|
429
|
+
readonly denialFallback: "projection://examples/denial-fallback.ts";
|
|
430
|
+
};
|
|
431
|
+
/** One resource Projection serves, ready to register on the MCP server. */
|
|
432
|
+
interface ProjectionResource {
|
|
433
|
+
uri: string;
|
|
434
|
+
name: string;
|
|
435
|
+
description: string;
|
|
436
|
+
mimeType: string;
|
|
437
|
+
text: string;
|
|
438
|
+
}
|
|
439
|
+
declare const EXAMPLE_HAPPY_PATH = "import { setup, assign } from 'xstate';\nimport { toolCall } from '@astral-mcp/tools';\n\n// Read a file and return its contents. Read-only calls run immediately,\n// so this whole machine completes in one round trip.\nexport default setup({}).createMachine({\n id: 'readNotes',\n context: ({ input }) => ({ path: input?.path ?? '/notes.txt', text: 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 actions: assign({ text: ({ event }) => event.result }),\n },\n TOOL_ERROR: {\n target: 'failed',\n actions: assign({ text: ({ event }) => `error: ${event.error.message}` }),\n },\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ text: context.text }),\n});\n";
|
|
440
|
+
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.\nexport default setup({}).createMachine({\n id: 'writeWithFallback',\n context: { status: 'pending', note: null },\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', () => ({ path: '/notes.txt', 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', () => ({ path: '/' })),\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";
|
|
441
|
+
/** Build the resources Projection serves for a wrapped server (R3). */
|
|
442
|
+
declare function buildResources(catalog: ServerCatalog, dts: string): ProjectionResource[];
|
|
443
|
+
/**
|
|
444
|
+
* The `discover_apis` result: an inline overview sufficient to author a
|
|
445
|
+
* simple machine unaided, plus resource links for the full artifacts.
|
|
446
|
+
*/
|
|
447
|
+
declare function discoverApis(catalog: ServerCatalog, overview: string): CallToolResult;
|
|
448
|
+
/**
|
|
449
|
+
* The wrapped server's `instructions`, followed by the code-mode preamble
|
|
450
|
+
* (R29). The preamble is library copy the integrating developer can replace.
|
|
451
|
+
*/
|
|
452
|
+
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.";
|
|
453
|
+
declare function buildInstructions(catalog: ServerCatalog, preamble?: string): string;
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/wrap.d.ts
|
|
456
|
+
interface WrapOptions {
|
|
457
|
+
/** Blob sealing configuration; required for any gated flow (R22). */
|
|
458
|
+
blob: BlobSealerConfig;
|
|
459
|
+
/** Resource cap overrides, clamped at the hard maxima (R12). */
|
|
460
|
+
caps?: Partial<ResourceCaps>;
|
|
461
|
+
/** Per-tool policy overrides (R14). */
|
|
462
|
+
policy?: PolicyOverrides;
|
|
463
|
+
/** Masks sensitive argument fields before they reach an approval prompt (R16). */
|
|
464
|
+
redact?: RedactionHook;
|
|
465
|
+
/** Replaces the library's code-mode preamble (R29). */
|
|
466
|
+
codeModePreamble?: string;
|
|
467
|
+
/** Identity the servers built by `createServer` advertise. */
|
|
468
|
+
serverInfo?: Implementation;
|
|
469
|
+
}
|
|
470
|
+
/** Options for registering the code-mode surface on a server the caller built. */
|
|
471
|
+
interface RegisterOptions {
|
|
472
|
+
/**
|
|
473
|
+
* The protocol era this server instance serves (R28). Omitted means
|
|
474
|
+
* `'legacy'`: a hand-connected `McpServer` never negotiates 2026-07-28, so
|
|
475
|
+
* defaulting to legacy is the honest — and fail-safe — reading.
|
|
476
|
+
*/
|
|
477
|
+
era?: ProtocolEra;
|
|
478
|
+
}
|
|
479
|
+
interface ProjectionFacade {
|
|
480
|
+
/** Catalog of the wrapped server. */
|
|
481
|
+
readonly catalog: ServerCatalog;
|
|
482
|
+
/** Instructions to advertise: the wrapped server's, then the preamble (R29). */
|
|
483
|
+
readonly instructions: string;
|
|
484
|
+
/** Generated `.d.ts` for the wrapped server's tools. */
|
|
485
|
+
readonly dts: string;
|
|
486
|
+
/** Resources served at stable `projection://` URIs (R3). */
|
|
487
|
+
readonly resources: ProjectionResource[];
|
|
488
|
+
/**
|
|
489
|
+
* Server factory to hand to `createMcpHandler` or `serveStdio` (R28, R29).
|
|
490
|
+
* Every instance it builds carries the code-mode `instructions` and knows
|
|
491
|
+
* the era it is serving.
|
|
492
|
+
*/
|
|
493
|
+
readonly serverFactory: McpServerFactory;
|
|
494
|
+
/** Run `execute_machine` for one `tools/call`, first attempt or retry. */
|
|
495
|
+
executeMachine(args: ExecuteMachineArgs, era?: ProtocolEra): Promise<ToolCallResult>;
|
|
496
|
+
/** Run `discover_apis`. */
|
|
497
|
+
discoverApis(): CallToolResult;
|
|
498
|
+
/** Build an `McpServer` carrying the instructions, both tools and the resources. */
|
|
499
|
+
createServer(ctx?: RegisterOptions): McpServer;
|
|
500
|
+
/** Register both tools and the resources on an `McpServer` the caller built. */
|
|
501
|
+
registerOn(server: McpServer, options?: RegisterOptions): void;
|
|
502
|
+
/** Close the connection to the wrapped server. */
|
|
503
|
+
close(): Promise<void>;
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Wrap an MCP server (an in-process instance or a connected client) into a
|
|
507
|
+
* code-mode facade.
|
|
508
|
+
*/
|
|
509
|
+
declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
510
|
+
//#endregion
|
|
511
|
+
//#region src/errors.d.ts
|
|
512
|
+
/**
|
|
513
|
+
* Error carrying the structured `isError` body every failure returns (R25).
|
|
514
|
+
*/
|
|
515
|
+
declare class ProjectionError extends Error {
|
|
516
|
+
readonly phase: ErrorPhase;
|
|
517
|
+
readonly diagnostics: Diagnostic[];
|
|
518
|
+
readonly hint: string;
|
|
519
|
+
logs: LogEntry[];
|
|
520
|
+
constructor(phase: ErrorPhase, message: string, options?: {
|
|
521
|
+
diagnostics?: Diagnostic[];
|
|
522
|
+
hint?: string;
|
|
523
|
+
logs?: LogEntry[];
|
|
524
|
+
cause?: unknown;
|
|
525
|
+
});
|
|
526
|
+
toStructured(): StructuredError;
|
|
527
|
+
}
|
|
528
|
+
/** Convert any thrown value into a StructuredError, defaulting to `runtime` phase. */
|
|
529
|
+
declare function toStructuredError(err: unknown, logs?: LogEntry[]): StructuredError;
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/introspector/introspector.d.ts
|
|
532
|
+
/** A wrapped-server source: an in-process instance or a connected client. */
|
|
533
|
+
type ServerSource = McpServer | Client;
|
|
534
|
+
/**
|
|
535
|
+
* Aliased server sources (R30). v1 instantiates exactly one entry, but the
|
|
536
|
+
* interface accepts a set so the multi-server stretch goal (PRD §12.2) needs
|
|
537
|
+
* no signature break.
|
|
538
|
+
*/
|
|
539
|
+
type IntrospectorSources = Record<ServerAlias, ServerSource>;
|
|
540
|
+
/**
|
|
541
|
+
* Holds one MCP client per wrapped-server alias, exposes the aggregated
|
|
542
|
+
* {@link ToolCatalog}, and executes tool calls (implements
|
|
543
|
+
* {@link ToolExecutor}). Construct with {@link createIntrospector}.
|
|
544
|
+
*/
|
|
545
|
+
declare class Introspector implements ToolExecutor {
|
|
546
|
+
#private;
|
|
547
|
+
private constructor();
|
|
548
|
+
static create(sources: IntrospectorSources): Promise<Introspector>;
|
|
549
|
+
/** The aggregated tool catalog, keyed by server alias (R30). */
|
|
550
|
+
get catalog(): ToolCatalog;
|
|
551
|
+
/** Re-read `tools/list` from every wrapped server and rebuild the catalog. */
|
|
552
|
+
refresh(): Promise<ToolCatalog>;
|
|
553
|
+
/**
|
|
554
|
+
* Execute a tool call against the wrapped server identified by `alias`,
|
|
555
|
+
* mapping the MCP result to a {@link ToolCallOutcome}:
|
|
556
|
+
*
|
|
557
|
+
* - success → `{ ok: true, result }` where `result` is the tool's
|
|
558
|
+
* `structuredContent` when present, else a single text block's text,
|
|
559
|
+
* else the raw content array.
|
|
560
|
+
* - `isError` result or transport/protocol failure → `{ ok: false, error }`.
|
|
561
|
+
*
|
|
562
|
+
* An unknown alias is a wiring bug, not a tool failure, and throws.
|
|
563
|
+
*/
|
|
564
|
+
callTool(alias: ServerAlias, name: string, args: Record<string, unknown>): Promise<ToolCallOutcome>;
|
|
565
|
+
/**
|
|
566
|
+
* Close connections the introspector created (in-process sources).
|
|
567
|
+
* Caller-provided remote clients are left untouched.
|
|
568
|
+
*/
|
|
569
|
+
close(): Promise<void>;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Connect to the given wrapped servers and build their tool catalog.
|
|
573
|
+
*
|
|
574
|
+
* v1 usage: `createIntrospector({ [DEFAULT_SERVER_ALIAS]: serverOrClient })`.
|
|
575
|
+
*/
|
|
576
|
+
declare function createIntrospector(sources: IntrospectorSources): Promise<Introspector>;
|
|
577
|
+
//#endregion
|
|
578
|
+
//#region src/typegen/generate.d.ts
|
|
579
|
+
/**
|
|
580
|
+
* Module specifier authored machines import the tools surface from (R4).
|
|
581
|
+
* The sandbox component mounts {@link GeneratedToolTypes.bridgeSource} here.
|
|
582
|
+
*/
|
|
583
|
+
declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
584
|
+
/**
|
|
585
|
+
* Name of the global the sandbox host MUST inject before authored code runs.
|
|
586
|
+
*
|
|
587
|
+
* Contract (for the sandbox / machine-host components):
|
|
588
|
+
*
|
|
589
|
+
* ```js
|
|
590
|
+
* globalThis.__projection_toolcall = (name, args) => <host-defined value>
|
|
591
|
+
* ```
|
|
592
|
+
*
|
|
593
|
+
* - `name` is the wrapped server's tool name exactly as catalogued.
|
|
594
|
+
* - `args` is a plain JSON-serializable object (never `undefined`; the
|
|
595
|
+
* bridge substitutes `{}` for a missing argument).
|
|
596
|
+
* - The bridge performs no I/O itself and returns the hook's value
|
|
597
|
+
* verbatim. Per R7, authored machines never consume that value as a
|
|
598
|
+
* promise inside invoked actors — the library-supplied `toolCall` action
|
|
599
|
+
* is the intended caller, and results come back as TOOL_RESULT /
|
|
600
|
+
* TOOL_ERROR / TOOL_DENIED events injected by the host.
|
|
601
|
+
* - If the hook is missing, every tool function throws, keeping the bridge
|
|
602
|
+
* inert outside a properly initialized sandbox (S1).
|
|
603
|
+
*/
|
|
604
|
+
declare const TOOL_CALL_HOST_GLOBAL = "__projection_toolcall";
|
|
605
|
+
/** Output of {@link generateToolTypes}. */
|
|
606
|
+
interface GeneratedToolTypes {
|
|
607
|
+
/** `.d.ts` text for the `@astral-mcp/tools` surface (serve via discover_apis, R3). */
|
|
608
|
+
dts: string;
|
|
609
|
+
/** ESM source of the runtime bridge to mount at `@astral-mcp/tools` in the sandbox. */
|
|
610
|
+
bridgeSource: string;
|
|
611
|
+
/** Compact per-tool overview block for inline embedding by discover_apis (R3). */
|
|
612
|
+
overview: string;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Generate the `@astral-mcp/tools` artifacts for a wrapped server.
|
|
616
|
+
*
|
|
617
|
+
* Accepts either the full aliased {@link ToolCatalog} (which must contain
|
|
618
|
+
* exactly one server in v1, per R30's single-instance instantiation) or a
|
|
619
|
+
* {@link ServerCatalog} directly.
|
|
620
|
+
*/
|
|
621
|
+
declare function generateToolTypes(catalog: ToolCatalog | ServerCatalog): GeneratedToolTypes;
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/typegen/json-schema.d.ts
|
|
624
|
+
/**
|
|
625
|
+
* Convert a JSON Schema into TypeScript type text.
|
|
626
|
+
*
|
|
627
|
+
* @param schema - The schema (also used as the $ref resolution root).
|
|
628
|
+
* @param indent - Indentation prefix of the line the type is emitted on;
|
|
629
|
+
* nested object literals indent relative to it.
|
|
630
|
+
*/
|
|
631
|
+
declare function schemaToTsType(schema: unknown, indent?: string): string;
|
|
632
|
+
/**
|
|
633
|
+
* True when the schema requires at least one argument property — used to
|
|
634
|
+
* decide whether the generated tool function's `args` parameter is optional.
|
|
635
|
+
*/
|
|
636
|
+
declare function schemaRequiresArgs(schema: unknown): boolean;
|
|
637
|
+
//#endregion
|
|
638
|
+
//#region src/text-safety.d.ts
|
|
639
|
+
/**
|
|
640
|
+
* Rendering untrusted strings inertly (S5, S6).
|
|
641
|
+
*
|
|
642
|
+
* Tool names, descriptions, the wrapped server's identity, and machine state
|
|
643
|
+
* names all flow from a possibly third-party server or a model-authored
|
|
644
|
+
* machine. Wherever they are rendered into human-facing prompt copy or into
|
|
645
|
+
* generated source, they must not be able to forge structure with control
|
|
646
|
+
* characters (newlines, ESC for ANSI sequences) or reorder text with Unicode
|
|
647
|
+
* bidi overrides. Centralizing the character class here keeps every call site
|
|
648
|
+
* on the same, complete definition — an earlier divergence let generated
|
|
649
|
+
* `.d.ts`/bridge comments miss the directional-isolate range that the
|
|
650
|
+
* elicitation copy already stripped.
|
|
651
|
+
*/
|
|
652
|
+
/**
|
|
653
|
+
* Replace control and bidi characters with the replacement character.
|
|
654
|
+
* `allowNewline` keeps `\n` (for multi-line blocks whose formatting newlines
|
|
655
|
+
* are part of the rendering, e.g. a pretty-printed JSON block).
|
|
656
|
+
*/
|
|
657
|
+
declare function neutralizeControlChars(text: string, options?: {
|
|
658
|
+
allowNewline?: boolean;
|
|
659
|
+
}): string;
|
|
660
|
+
/** Truncate to `maxChars`, appending an ellipsis when shortened. */
|
|
661
|
+
declare function capLength(text: string, maxChars: number): string;
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region src/policy/decision.d.ts
|
|
664
|
+
/**
|
|
665
|
+
* Decide the policy for a catalog tool (R14).
|
|
666
|
+
*
|
|
667
|
+
* - A developer override (`auto` | `ask` | `deny`) always wins.
|
|
668
|
+
* - With no override, `annotations.readOnlyHint === true` yields `auto`;
|
|
669
|
+
* an absent or `false` hint yields `ask` (S5: unannotated defaults to ask).
|
|
670
|
+
* - An override entry with an unrecognized value (possible when the config
|
|
671
|
+
* arrives untyped) fails safe to `ask` — it never grants `auto`.
|
|
672
|
+
*
|
|
673
|
+
* Only own properties of `overrides` are consulted, so tools named like
|
|
674
|
+
* `Object.prototype` members (`toString`, `constructor`, ...) cannot pick up
|
|
675
|
+
* inherited junk as a decision.
|
|
676
|
+
*/
|
|
677
|
+
declare function decidePolicy(entry: ToolCatalogEntry, overrides?: PolicyOverrides): PolicyDecision;
|
|
678
|
+
/** Result of resolving a pending call against a server catalog. */
|
|
679
|
+
type ResolvedCallPolicy = {
|
|
680
|
+
ok: true;
|
|
681
|
+
decision: PolicyDecision;
|
|
682
|
+
entry: ToolCatalogEntry;
|
|
683
|
+
} | {
|
|
684
|
+
ok: false;
|
|
685
|
+
error: ProjectionError;
|
|
686
|
+
};
|
|
687
|
+
/**
|
|
688
|
+
* Resolve a machine-requested tool call against the server catalog and
|
|
689
|
+
* decide its policy.
|
|
690
|
+
*
|
|
691
|
+
* Returns the decision together with the matching catalog entry (the entry
|
|
692
|
+
* is what elicitation copy must be built from — S6), or a structured
|
|
693
|
+
* `validate`-phase {@link ProjectionError} when the machine names a tool the
|
|
694
|
+
* wrapped server does not declare.
|
|
695
|
+
*/
|
|
696
|
+
declare function resolveCallPolicy(call: PendingToolCall, catalog: ServerCatalog, overrides?: PolicyOverrides): ResolvedCallPolicy;
|
|
697
|
+
/**
|
|
698
|
+
* Canonical TOOL_DENIED reason for calls blocked by a `deny` policy
|
|
699
|
+
* decision. A `deny` decision never produces an elicitation — the machine
|
|
700
|
+
* host injects `TOOL_DENIED` with this reason instead.
|
|
701
|
+
*/
|
|
702
|
+
declare const POLICY_DENIED_REASON = "denied by server policy";
|
|
703
|
+
/**
|
|
704
|
+
* Build the TOOL_DENIED reason string for a policy-denied call. With a tool
|
|
705
|
+
* name it names the denied tool so the machine (and audit trail) can tell
|
|
706
|
+
* which call was blocked.
|
|
707
|
+
*/
|
|
708
|
+
declare function policyDeniedReason(toolName?: string): string;
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/policy/elicitation.d.ts
|
|
711
|
+
/** Structured approval copy for one gated call (input to the MRTR adapter). */
|
|
712
|
+
interface ElicitationCopy {
|
|
713
|
+
/** Short title, e.g. `Approval required: delete_file`. */
|
|
714
|
+
title: string;
|
|
715
|
+
/** Full human-readable summary (plain text with an indented JSON block). */
|
|
716
|
+
message: string;
|
|
717
|
+
/** Tool name, taken from the catalog entry. */
|
|
718
|
+
toolName: string;
|
|
719
|
+
/** Machine state path that requested the call (raw; render with care). */
|
|
720
|
+
stateName: string;
|
|
721
|
+
/** The redacted arguments as rendered in `message` (JSON text, possibly truncated). */
|
|
722
|
+
args: string;
|
|
723
|
+
/** True when the catalog entry carries `destructiveHint: true`. */
|
|
724
|
+
destructive: boolean;
|
|
725
|
+
}
|
|
726
|
+
interface ElicitationCopyOptions {
|
|
727
|
+
/** Redaction hook applied to args before any rendering (R16). */
|
|
728
|
+
redact?: RedactionHook;
|
|
729
|
+
/** Cap on the rendered args JSON, in characters. Default 4096. */
|
|
730
|
+
maxArgsChars?: number;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Build the approval summary for a gated call.
|
|
734
|
+
*
|
|
735
|
+
* `entry` MUST be the catalog entry the call was resolved against (use
|
|
736
|
+
* `resolveCallPolicy`); the copy takes the tool name and description from
|
|
737
|
+
* it, never from the pending call or its arguments.
|
|
738
|
+
*/
|
|
739
|
+
declare function buildElicitationCopy(call: PendingToolCall, entry: ToolCatalogEntry, options?: ElicitationCopyOptions): ElicitationCopy;
|
|
740
|
+
//#endregion
|
|
741
|
+
//#region src/sandbox/session.d.ts
|
|
742
|
+
/** A tool call surfaced from the `@astral-mcp/tools` bridge inside the VM. */
|
|
743
|
+
interface SandboxToolCall {
|
|
744
|
+
name: string;
|
|
745
|
+
args: Record<string, unknown>;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Host callback invoked for every bridge tool call made inside the VM.
|
|
749
|
+
*
|
|
750
|
+
* The returned value (or resolved promise value) is marshaled back into the
|
|
751
|
+
* VM as the bridge call's result; a thrown error / rejected promise rejects
|
|
752
|
+
* the in-VM promise. Values must be JSON-serializable. The sandbox attaches
|
|
753
|
+
* no semantics to the payload — result/error/denial encoding is the machine
|
|
754
|
+
* host's protocol.
|
|
755
|
+
*/
|
|
756
|
+
type SandboxToolCallHandler = (call: SandboxToolCall) => unknown | Promise<unknown>;
|
|
757
|
+
interface SandboxSessionOptions {
|
|
758
|
+
/** The submitted module source (R2). */
|
|
759
|
+
code: string;
|
|
760
|
+
/** Language of `code`. TypeScript is transpiled without type checking (R10). */
|
|
761
|
+
lang?: 'ts' | 'js';
|
|
762
|
+
/** Resource cap overrides; clamped at the hard maxima via `clampCaps` (R12). */
|
|
763
|
+
caps?: Partial<ResourceCaps>;
|
|
764
|
+
/**
|
|
765
|
+
* Source text of the module mounted at `@astral-mcp/tools` (R8). Generated
|
|
766
|
+
* by the typegen component. May be TypeScript or JavaScript; must be a
|
|
767
|
+
* single module (relative imports do not resolve outside the mount).
|
|
768
|
+
*/
|
|
769
|
+
bridgeSource: string;
|
|
770
|
+
/** Host callback for bridge tool calls. */
|
|
771
|
+
onToolCall: SandboxToolCallHandler;
|
|
772
|
+
/** Zero-based MRTR segment index, recorded on every log entry (R31). */
|
|
773
|
+
segment?: number;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* A live sandbox holding the evaluated authored module. One session is one
|
|
777
|
+
* execution segment: it owns a fresh wall-clock budget (R13) and a fresh log
|
|
778
|
+
* collector (R31). Sessions are single-threaded — `evaluate` calls are
|
|
779
|
+
* serialized internally.
|
|
780
|
+
*/
|
|
781
|
+
interface SandboxSession {
|
|
782
|
+
/** The effective (clamped) caps this session enforces. */
|
|
783
|
+
readonly caps: ResourceCaps;
|
|
784
|
+
/** Zero-based MRTR segment index this session was created for. */
|
|
785
|
+
readonly segment: number;
|
|
786
|
+
/**
|
|
787
|
+
* Evaluate an ESM driver module inside the VM and return its default
|
|
788
|
+
* export marshaled to the host (promises are awaited). Rejects with
|
|
789
|
+
* {@link ProjectionError} on failure. See ./index.ts for the contract.
|
|
790
|
+
*/
|
|
791
|
+
evaluate(source: string): Promise<unknown>;
|
|
792
|
+
/** Logs captured so far this segment, truncated per `maxConsoleBytes`. */
|
|
793
|
+
getLogs(): LogEntry[];
|
|
794
|
+
/** Tear down the VM. Idempotent. Pending bridge promises are rejected. */
|
|
795
|
+
dispose(): Promise<void>;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Create a sandbox session: boot a fresh QuickJS VM, mount xstate and the
|
|
799
|
+
* bridge, evaluate the authored module, and return a handle for driving it.
|
|
800
|
+
* See ./index.ts for the full boundary contract.
|
|
801
|
+
*/
|
|
802
|
+
declare function createSandboxSession(options: SandboxSessionOptions): Promise<SandboxSession>;
|
|
803
|
+
//#endregion
|
|
804
|
+
//#region src/machine-host/host.d.ts
|
|
805
|
+
interface RunSegmentOptions {
|
|
806
|
+
/** Submitted module source (R2). */
|
|
807
|
+
code: string;
|
|
808
|
+
lang?: 'ts' | 'js';
|
|
809
|
+
/** Machine input, passed as the machine's `input` on a fresh run. */
|
|
810
|
+
input?: unknown;
|
|
811
|
+
/** Catalog of the wrapped server whose tools the machine may call. */
|
|
812
|
+
catalog: ServerCatalog;
|
|
813
|
+
/** Generated `@astral-mcp/tools` bridge source (from typegen). */
|
|
814
|
+
bridgeSource: string;
|
|
815
|
+
/** Executes approved/auto tool calls against the wrapped server. */
|
|
816
|
+
executor: ToolExecutor;
|
|
817
|
+
/** Resource caps; clamped at the hard maxima (R12). */
|
|
818
|
+
caps?: Partial<ResourceCaps>;
|
|
819
|
+
/** Per-tool policy overrides (R14). */
|
|
820
|
+
policy?: PolicyOverrides;
|
|
821
|
+
/** Zero-based MRTR segment index — stamps logs (R31). */
|
|
822
|
+
segment?: number;
|
|
823
|
+
/**
|
|
824
|
+
* Resume state. Present on every segment after the first: the verified
|
|
825
|
+
* snapshot and the pending calls sealed alongside it, plus the verdicts
|
|
826
|
+
* the client returned for those calls.
|
|
827
|
+
*/
|
|
828
|
+
resume?: {
|
|
829
|
+
snapshot: unknown;
|
|
830
|
+
/** Gated calls as sealed into the blob — the approved name+args (S2). */
|
|
831
|
+
pending: Record<string, PendingToolCall>;
|
|
832
|
+
/** Verdict per pending key; a missing entry counts as declined (R17). */
|
|
833
|
+
verdicts: Record<string, ApprovalVerdict>;
|
|
834
|
+
/** Audit entries accumulated in earlier segments. */
|
|
835
|
+
audit?: AuditEntry[];
|
|
836
|
+
/** Round-trip counter carried in the blob (R18). */
|
|
837
|
+
trip: number;
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Run one execution segment to completion, suspension, or error.
|
|
842
|
+
*
|
|
843
|
+
* A segment is one MRTR round trip: fresh sandbox, fresh wall-clock budget,
|
|
844
|
+
* fresh logs. On the first segment the module is validated (R24) before the
|
|
845
|
+
* actor starts; on a resume the module is re-evaluated from the re-sent code
|
|
846
|
+
* and the actor is restored from the sealed snapshot.
|
|
847
|
+
*
|
|
848
|
+
* Note: `runSegment` interpolates `input` into driver source without a size
|
|
849
|
+
* check of its own — `executeMachine` enforces `maxInputBytes` before calling
|
|
850
|
+
* it. Callers invoking `runSegment` directly must bound `input` themselves.
|
|
851
|
+
*/
|
|
852
|
+
declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>;
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region src/machine-host/contract.d.ts
|
|
855
|
+
/**
|
|
856
|
+
* Human-readable authoring contract. `discover_apis` publishes this inline
|
|
857
|
+
* (R3) so a model can author a valid machine without fetching resources.
|
|
858
|
+
*/
|
|
859
|
+
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.\n\nExample — happy path with a read-only call:\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'readNotes',\n context: ({ input }) => ({ path: input?.path ?? '/notes.txt', text: 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({ text: ({ event }) => event.result }) },\n TOOL_ERROR: 'failed',\n },\n },\n done: { type: 'final' },\n failed: { type: 'final' },\n },\n output: ({ context }) => ({ text: context.text }),\n });\n\nExample — handling a denied approval:\n\n import { setup, assign } from 'xstate';\n import { toolCall } from '@astral-mcp/tools';\n\n export default setup({}).createMachine({\n id: 'writeNotes',\n context: { status: 'pending' },\n initial: 'writing',\n states: {\n writing: {\n entry: toolCall('write_file', () => ({ path: '/notes.txt', 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";
|
|
860
|
+
//#endregion
|
|
861
|
+
export { APPROVAL_SCHEMA, AUTHORING_CONTRACT, ApprovalVerdict, AuditEntry, BLOB_SCHEMA_VERSION, BlobPayload, BlobSealerConfig, type CallToolResult, type ContentBlock, DEFAULT_CAPS, DEFAULT_CODE_MODE_PREAMBLE, DEFAULT_MAX_BLOB_BYTES, DEFAULT_SERVER_ALIAS, DEFAULT_TTL_MS, Diagnostic, ENVELOPE_PREFIX, EXAMPLE_DENIAL_FALLBACK, EXAMPLE_HAPPY_PATH, type ElicitationCopy, type ElicitationCopyOptions, ErrorPhase, type ExecuteMachineArgs, type ExecuteMachineDeps, type GeneratedToolTypes, HostEvent, type InputRequest, type InputRequests, type InputRequiredResult, type InputResponse, type InputResponseView, type InputResponses, Introspector, LIB_VERSION, LogEntry, LogLevel, MAX_CAPS, MRTR_PROTOCOL_REVISION, type OpenBlobOptions, POLICY_DENIED_REASON, PendingToolCall, PolicyDecision, PolicyOverrides, ProjectionConfig, ProjectionError, type ProjectionFacade, type ProjectionResource, type ProtocolEra, RESOURCE_URIS, RedactionHook, type RegisterOptions, type ResolvedCallPolicy, ResourceCaps, type RetryEnvelope, type RunSegmentOptions, type SandboxSession, type SandboxSessionOptions, type SandboxToolCall, type SandboxToolCallHandler, SegmentOutcome, ServerAlias, ServerCatalog, StructuredError, TOOLS_MODULE_SPECIFIER, TOOL_CALL_HOST_GLOBAL, ToolAnnotations, ToolCallOutcome, type ToolCallResult, ToolCatalog, ToolCatalogEntry, ToolExecutor, type WrapOptions, XSTATE_VERSION, acceptedContent, buildBlobPayload, buildElicitationCopy, buildInstructions, buildResources, capLength, clampCaps, createIntrospector, createSandboxSession, decidePolicy, discoverApis, executeMachine, findTool, generateToolTypes, hashCode, inputRequired, inputResponse, isInputRequiredResult, isRecord, neutralizeControlChars, openBlob, policyDeniedReason, resolveCallPolicy, runSegment, schemaRequiresArgs, schemaToTsType, sealBlob, supportsMrtr, toStructuredError, wrapMcpServer };
|
|
862
|
+
//# sourceMappingURL=index.d.mts.map
|