@astral-mcp/projection 0.7.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 +39 -19
- package/dist/index.d.mts +288 -267
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +617 -220
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -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;
|
|
@@ -50,7 +50,7 @@ interface ServerCatalog {
|
|
|
50
50
|
* must not be able to make the policy gate see a different entry (e.g. a
|
|
51
51
|
* later `readOnlyHint: true` copy) than the one typegen exposed.
|
|
52
52
|
*/
|
|
53
|
-
declare function findTool(catalog: ServerCatalog, name: string): ToolCatalogEntry | undefined;
|
|
53
|
+
export declare function findTool(catalog: ServerCatalog, name: string): ToolCatalogEntry | undefined;
|
|
54
54
|
/**
|
|
55
55
|
* Drop tools whose name repeats an earlier one; the first occurrence wins.
|
|
56
56
|
*
|
|
@@ -58,14 +58,14 @@ declare function findTool(catalog: ServerCatalog, name: string): ToolCatalogEntr
|
|
|
58
58
|
* catalog projection), so they all agree with {@link findTool} on which
|
|
59
59
|
* entry a name denotes (S5).
|
|
60
60
|
*/
|
|
61
|
-
declare function dedupeTools(tools: ToolCatalogEntry[]): ToolCatalogEntry[];
|
|
61
|
+
export declare function dedupeTools(tools: ToolCatalogEntry[]): ToolCatalogEntry[];
|
|
62
62
|
/** Narrow to a non-null, non-array object. */
|
|
63
|
-
declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
63
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
64
64
|
/** Executes a tool call against the wrapped server. Implemented by the introspector. */
|
|
65
|
-
interface ToolExecutor {
|
|
65
|
+
export interface ToolExecutor {
|
|
66
66
|
callTool(alias: ServerAlias, name: string, args: Record<string, unknown>): Promise<ToolCallOutcome>;
|
|
67
67
|
}
|
|
68
|
-
type ToolCallOutcome = {
|
|
68
|
+
export type ToolCallOutcome = {
|
|
69
69
|
ok: true;
|
|
70
70
|
result: unknown;
|
|
71
71
|
} | {
|
|
@@ -75,13 +75,13 @@ type ToolCallOutcome = {
|
|
|
75
75
|
detail?: unknown;
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
|
-
type PolicyDecision = 'auto' | 'ask' | 'deny';
|
|
79
|
-
interface PolicyOverrides {
|
|
78
|
+
export type PolicyDecision = 'auto' | 'ask' | 'deny';
|
|
79
|
+
export interface PolicyOverrides {
|
|
80
80
|
/** Per-tool decision override, keyed by tool name (v1: single server). */
|
|
81
81
|
[toolName: string]: PolicyDecision;
|
|
82
82
|
}
|
|
83
83
|
/** A tool call requested by the machine via the `toolCall` action creator. */
|
|
84
|
-
interface PendingToolCall {
|
|
84
|
+
export interface PendingToolCall {
|
|
85
85
|
/** Unique id for this call within the workflow (also the inputRequest key). */
|
|
86
86
|
id: string;
|
|
87
87
|
name: string;
|
|
@@ -90,7 +90,7 @@ interface PendingToolCall {
|
|
|
90
90
|
stateName: string;
|
|
91
91
|
}
|
|
92
92
|
/** Events the host injects into the machine. The machine never performs I/O itself. */
|
|
93
|
-
type HostEvent = {
|
|
93
|
+
export type HostEvent = {
|
|
94
94
|
type: 'TOOL_RESULT';
|
|
95
95
|
callId: string;
|
|
96
96
|
result: unknown;
|
|
@@ -106,16 +106,16 @@ type HostEvent = {
|
|
|
106
106
|
callId: string;
|
|
107
107
|
reason?: string;
|
|
108
108
|
};
|
|
109
|
-
type ErrorPhase = 'transpile' | 'validate' | 'runtime' | 'cap_exceeded' | 'blob_verification' | 'protocol' |
|
|
109
|
+
export type ErrorPhase = 'transpile' | 'validate' | 'runtime' | 'cap_exceeded' | 'blob_verification' | 'protocol' |
|
|
110
110
|
/** An `isError` result or transport failure from the wrapped tool, surfaced by `call_tool` (R25). */
|
|
111
111
|
'upstream' | 'terminal';
|
|
112
|
-
interface Diagnostic {
|
|
112
|
+
export interface Diagnostic {
|
|
113
113
|
message: string;
|
|
114
114
|
/** Optional source location within the submitted code. */
|
|
115
115
|
line?: number;
|
|
116
116
|
column?: number;
|
|
117
117
|
}
|
|
118
|
-
interface StructuredError {
|
|
118
|
+
export interface StructuredError {
|
|
119
119
|
phase: ErrorPhase;
|
|
120
120
|
message: string;
|
|
121
121
|
diagnostics: Diagnostic[];
|
|
@@ -123,8 +123,8 @@ interface StructuredError {
|
|
|
123
123
|
hint: string;
|
|
124
124
|
logs: LogEntry[];
|
|
125
125
|
}
|
|
126
|
-
type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
127
|
-
interface LogEntry {
|
|
126
|
+
export type LogLevel = 'log' | 'info' | 'warn' | 'error' | 'debug';
|
|
127
|
+
export interface LogEntry {
|
|
128
128
|
level: LogLevel;
|
|
129
129
|
message: string;
|
|
130
130
|
/** Milliseconds since segment start. */
|
|
@@ -132,7 +132,7 @@ interface LogEntry {
|
|
|
132
132
|
/** Zero-based MRTR segment index this entry was captured in. */
|
|
133
133
|
segment: number;
|
|
134
134
|
}
|
|
135
|
-
interface ResourceCaps {
|
|
135
|
+
export interface ResourceCaps {
|
|
136
136
|
/** Wall-clock per execution segment, ms. */
|
|
137
137
|
segmentWallClockMs: number;
|
|
138
138
|
/** WASM memory, bytes. */
|
|
@@ -154,14 +154,14 @@ interface ResourceCaps {
|
|
|
154
154
|
/** Captured console output per segment, bytes. */
|
|
155
155
|
maxConsoleBytes: number;
|
|
156
156
|
}
|
|
157
|
-
declare const DEFAULT_CAPS: ResourceCaps;
|
|
158
|
-
declare const MAX_CAPS: ResourceCaps;
|
|
157
|
+
export declare const DEFAULT_CAPS: ResourceCaps;
|
|
158
|
+
export declare const MAX_CAPS: ResourceCaps;
|
|
159
159
|
/** Clamp requested caps into [MIN_CAPS, MAX_CAPS] (R12). */
|
|
160
|
-
declare function clampCaps(requested: Partial<ResourceCaps>): ResourceCaps;
|
|
161
|
-
declare const BLOB_SCHEMA_VERSION = 1;
|
|
160
|
+
export declare function clampCaps(requested: Partial<ResourceCaps>): ResourceCaps;
|
|
161
|
+
export declare const BLOB_SCHEMA_VERSION = 1;
|
|
162
162
|
/** Which tool minted a blob (R36): a blob opened by the other tool is rejected. */
|
|
163
|
-
type BlobKind = 'machine' | 'call';
|
|
164
|
-
interface BlobPayload {
|
|
163
|
+
export type BlobKind = 'machine' | 'call';
|
|
164
|
+
export interface BlobPayload {
|
|
165
165
|
/** Blob schema version; unknown versions are rejected. */
|
|
166
166
|
v: number;
|
|
167
167
|
/** Minting tool (R36). */
|
|
@@ -199,7 +199,7 @@ interface BlobPayload {
|
|
|
199
199
|
/** Expiry, Unix ms (default TTL 15 min). */
|
|
200
200
|
exp: number;
|
|
201
201
|
}
|
|
202
|
-
interface BlobSealerConfig {
|
|
202
|
+
export interface BlobSealerConfig {
|
|
203
203
|
/** Current encryption key (32 bytes). */
|
|
204
204
|
key: Uint8Array;
|
|
205
205
|
/** Previous keys accepted for decryption during rotation (R22). */
|
|
@@ -221,7 +221,7 @@ interface BlobSealerConfig {
|
|
|
221
221
|
* blob kinds. No default ships: an in-memory one would silently break
|
|
222
222
|
* horizontal scaling (G4), so the integrator supplies a shared store.
|
|
223
223
|
*/
|
|
224
|
-
interface ReplayCache {
|
|
224
|
+
export interface ReplayCache {
|
|
225
225
|
/**
|
|
226
226
|
* Record `nonce` until `exp` (Unix ms) and resolve `true` when it had
|
|
227
227
|
* already been recorded — i.e. this approval is being replayed.
|
|
@@ -237,14 +237,14 @@ interface ReplayCache {
|
|
|
237
237
|
seen(nonce: string, exp: number): Promise<boolean>;
|
|
238
238
|
}
|
|
239
239
|
/** Verdict delivered on retry for a pending gated call. */
|
|
240
|
-
type ApprovalVerdict = {
|
|
240
|
+
export type ApprovalVerdict = {
|
|
241
241
|
kind: 'approved';
|
|
242
242
|
} | {
|
|
243
243
|
kind: 'declined';
|
|
244
244
|
reason?: string;
|
|
245
245
|
};
|
|
246
246
|
/** Outcome of running one execution segment. */
|
|
247
|
-
type SegmentOutcome = {
|
|
247
|
+
export type SegmentOutcome = {
|
|
248
248
|
status: 'completed';
|
|
249
249
|
/** Final machine output/context to return to the client. */
|
|
250
250
|
output: unknown;
|
|
@@ -264,21 +264,21 @@ type SegmentOutcome = {
|
|
|
264
264
|
status: 'error';
|
|
265
265
|
error: StructuredError;
|
|
266
266
|
};
|
|
267
|
-
interface AuditEntry {
|
|
267
|
+
export interface AuditEntry {
|
|
268
268
|
callId: string;
|
|
269
269
|
tool: string;
|
|
270
270
|
args: Record<string, unknown>;
|
|
271
271
|
decision: 'auto' | 'approved' | 'declined' | 'denied_by_policy' | 'error';
|
|
272
272
|
reason?: string;
|
|
273
273
|
}
|
|
274
|
-
interface RedactionHook {
|
|
274
|
+
export interface RedactionHook {
|
|
275
275
|
/**
|
|
276
276
|
* Mask sensitive argument fields before they appear in elicitation copy
|
|
277
277
|
* (R16). Receives the tool name and resolved args; returns args to display.
|
|
278
278
|
*/
|
|
279
279
|
(toolName: string, args: Record<string, unknown>): Record<string, unknown>;
|
|
280
280
|
}
|
|
281
|
-
interface ProjectionConfig {
|
|
281
|
+
export interface ProjectionConfig {
|
|
282
282
|
/** Resource cap overrides, clamped at maxima (R12). */
|
|
283
283
|
caps?: Partial<ResourceCaps>;
|
|
284
284
|
/** Per-tool policy overrides (R14). */
|
|
@@ -296,18 +296,18 @@ interface ProjectionConfig {
|
|
|
296
296
|
//#endregion
|
|
297
297
|
//#region src/blob/sealer.d.ts
|
|
298
298
|
/** Envelope format version prefix. Bump (proj2, …) on any wire-format change. */
|
|
299
|
-
declare const ENVELOPE_PREFIX = "proj1";
|
|
299
|
+
export declare const ENVELOPE_PREFIX = "proj1";
|
|
300
300
|
/** Default blob TTL for `machine` blobs: 15 minutes (R20). */
|
|
301
|
-
declare const DEFAULT_TTL_MS: number;
|
|
301
|
+
export declare const DEFAULT_TTL_MS: number;
|
|
302
302
|
/**
|
|
303
303
|
* Default TTL for `call` blobs: 5 minutes (R38). An approved `call` blob has
|
|
304
304
|
* no forward step, so it is a standing capability until it expires (D4, D9).
|
|
305
305
|
*/
|
|
306
|
-
declare const DEFAULT_CALL_TTL_MS: number;
|
|
306
|
+
export declare const DEFAULT_CALL_TTL_MS: number;
|
|
307
307
|
/** Default sealed-blob size ceiling: 128 KB (R23). */
|
|
308
|
-
declare const DEFAULT_MAX_BLOB_BYTES: number;
|
|
308
|
+
export declare const DEFAULT_MAX_BLOB_BYTES: number;
|
|
309
309
|
/** SHA-256 hex digest of a code argument (S4 binding — R20 `codeHash`). */
|
|
310
|
-
declare function hashCode(code: string): string;
|
|
310
|
+
export declare function hashCode(code: string): string;
|
|
311
311
|
interface BuildBlobPayloadInput {
|
|
312
312
|
/** Minting tool (R36). Default `machine`. */
|
|
313
313
|
kind?: BlobKind | undefined;
|
|
@@ -335,7 +335,7 @@ interface BuildBlobPayloadInput {
|
|
|
335
335
|
* Construct a fully populated {@link BlobPayload}: stamps the schema and
|
|
336
336
|
* library/XState versions, hashes the code, and fills nonce/iat/exp.
|
|
337
337
|
*/
|
|
338
|
-
declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
338
|
+
export declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
339
339
|
/**
|
|
340
340
|
* Seal a payload into an opaque `proj1.` envelope string (R19, R23).
|
|
341
341
|
*
|
|
@@ -344,7 +344,7 @@ declare function buildBlobPayload(input: BuildBlobPayloadInput): BlobPayload;
|
|
|
344
344
|
* the sealed envelope exceeds `maxBlobBytes` (default 128 KB) or the config
|
|
345
345
|
* keys are malformed.
|
|
346
346
|
*/
|
|
347
|
-
declare function sealBlob(payload: BlobPayload, config: BlobSealerConfig): string;
|
|
347
|
+
export declare function sealBlob(payload: BlobPayload, config: BlobSealerConfig): string;
|
|
348
348
|
interface OpenBlobOptions {
|
|
349
349
|
/** The tool opening the blob (R36). Default `machine`. */
|
|
350
350
|
expectedKind?: BlobKind | undefined;
|
|
@@ -374,7 +374,7 @@ interface OpenBlobOptions {
|
|
|
374
374
|
* failed check (never key material or plaintext). A payload is only
|
|
375
375
|
* returned once every check has passed.
|
|
376
376
|
*/
|
|
377
|
-
declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
377
|
+
export declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
378
378
|
//#endregion
|
|
379
379
|
//#region src/blob/versions.d.ts
|
|
380
380
|
/**
|
|
@@ -389,9 +389,9 @@ declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
|
389
389
|
* CI instead of silently minting blobs with a stale version stamp.
|
|
390
390
|
*/
|
|
391
391
|
/** `@astral-mcp/projection` package version (must match packages/projection/package.json). */
|
|
392
|
-
declare const LIB_VERSION = "0.
|
|
392
|
+
export declare const LIB_VERSION = "0.8.0";
|
|
393
393
|
/** Pinned XState version (must match the exact pin in package.json — D2). */
|
|
394
|
-
declare const XSTATE_VERSION = "5.32.5";
|
|
394
|
+
export declare const XSTATE_VERSION = "5.32.5";
|
|
395
395
|
//#endregion
|
|
396
396
|
//#region src/mrtr/protocol.d.ts
|
|
397
397
|
/**
|
|
@@ -427,7 +427,7 @@ interface RetryEnvelope {
|
|
|
427
427
|
* an approval prompt whose only payload is an optional decline reason is our
|
|
428
428
|
* product decision (R16/R17), not a protocol shape.
|
|
429
429
|
*/
|
|
430
|
-
declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
430
|
+
export declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
431
431
|
/**
|
|
432
432
|
* Protocol revision that introduced MRTR.
|
|
433
433
|
*
|
|
@@ -438,7 +438,7 @@ declare const APPROVAL_SCHEMA: ElicitRequestFormParams['requestedSchema'];
|
|
|
438
438
|
* `'modern'` rather than as a version string. We keep the literal purely so
|
|
439
439
|
* error copy can name the revision a client must speak (R28).
|
|
440
440
|
*/
|
|
441
|
-
declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
441
|
+
export declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
442
442
|
/**
|
|
443
443
|
* Whether the era a request is being served on can carry MRTR (R28).
|
|
444
444
|
*
|
|
@@ -449,7 +449,7 @@ declare const MRTR_PROTOCOL_REVISION = "2026-07-28";
|
|
|
449
449
|
* no `extra.protocolVersion` to read, and reading one was the bug this
|
|
450
450
|
* migration fixes (docs/DECISIONS.md D1).
|
|
451
451
|
*/
|
|
452
|
-
declare function supportsMrtr(era: ProtocolEra$1 | undefined): boolean;
|
|
452
|
+
export declare function supportsMrtr(era: ProtocolEra$1 | undefined): boolean;
|
|
453
453
|
//#endregion
|
|
454
454
|
//#region src/mrtr/adapter.d.ts
|
|
455
455
|
/**
|
|
@@ -524,9 +524,9 @@ interface ExecuteMachineDeps extends ApprovalGateDeps {
|
|
|
524
524
|
* Statelessness (R27): everything needed to resume rides in `requestState`,
|
|
525
525
|
* so any instance can serve any retry. Nothing is held between calls.
|
|
526
526
|
*/
|
|
527
|
-
declare function executeMachine(args: ExecuteMachineArgs, deps: ExecuteMachineDeps): Promise<ToolCallResult>;
|
|
527
|
+
export declare function executeMachine(args: ExecuteMachineArgs, deps: ExecuteMachineDeps): Promise<ToolCallResult>;
|
|
528
528
|
/** Every failure is a normal result with `isError: true` and a structured body (R25). */
|
|
529
|
-
declare function errorResult(error: StructuredError): CallToolResult;
|
|
529
|
+
export declare function errorResult(error: StructuredError): CallToolResult;
|
|
530
530
|
//#endregion
|
|
531
531
|
//#region src/catalog/call.d.ts
|
|
532
532
|
/**
|
|
@@ -572,9 +572,9 @@ type CallToolOutcome = {
|
|
|
572
572
|
reason: string;
|
|
573
573
|
};
|
|
574
574
|
/** The single inputRequest / pending key of a `call` blob (R36). */
|
|
575
|
-
declare const CALL_KEY = "call";
|
|
575
|
+
export declare const CALL_KEY = "call";
|
|
576
576
|
/** Run `call_tool` for one `tools/call`, first attempt or MRTR retry. */
|
|
577
|
-
declare function callTool(args: CallToolArgs, deps: CallToolDeps): Promise<ToolCallResult>;
|
|
577
|
+
export declare function callTool(args: CallToolArgs, deps: CallToolDeps): Promise<ToolCallResult>;
|
|
578
578
|
//#endregion
|
|
579
579
|
//#region src/catalog/canonical.d.ts
|
|
580
580
|
/**
|
|
@@ -598,9 +598,9 @@ declare function callTool(args: CallToolArgs, deps: CallToolDeps): Promise<ToolC
|
|
|
598
598
|
* by the blob's `pending` entry alone (R36, D9).
|
|
599
599
|
*/
|
|
600
600
|
/** Canonical JSON text of a plain JSON value. Throws `validate` on non-JSON. */
|
|
601
|
-
declare function canonicalJson(value: unknown): string;
|
|
601
|
+
export declare function canonicalJson(value: unknown): string;
|
|
602
602
|
/** The text a `call` blob is bound to (R36): `{ kind: "call", name, args }`. */
|
|
603
|
-
declare function canonicalRequest(name: string, args: Record<string, unknown>): string;
|
|
603
|
+
export declare function canonicalRequest(name: string, args: Record<string, unknown>): string;
|
|
604
604
|
//#endregion
|
|
605
605
|
//#region src/catalog/validate-args.d.ts
|
|
606
606
|
/**
|
|
@@ -618,14 +618,161 @@ declare function canonicalRequest(name: string, args: Record<string, unknown>):
|
|
|
618
618
|
* argument name is ordinary data (S5/S6).
|
|
619
619
|
*/
|
|
620
620
|
/** Throws a `validate`-phase {@link ProjectionError} naming the offending property. */
|
|
621
|
-
declare function validateArgsShape(toolName: string, args: Record<string, unknown>, schema: Record<string, unknown>): void;
|
|
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;
|
|
622
769
|
//#endregion
|
|
623
770
|
//#region src/typegen/generate.d.ts
|
|
624
771
|
/**
|
|
625
772
|
* Module specifier authored machines import the tools surface from (R4).
|
|
626
773
|
* The sandbox component mounts {@link GeneratedToolTypes.bridgeSource} here.
|
|
627
774
|
*/
|
|
628
|
-
declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
775
|
+
export declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
629
776
|
/**
|
|
630
777
|
* Name of the global the sandbox host MUST inject before authored code runs.
|
|
631
778
|
*
|
|
@@ -646,7 +793,7 @@ declare const TOOLS_MODULE_SPECIFIER = "@astral-mcp/tools";
|
|
|
646
793
|
* - If the hook is missing, every tool function throws, keeping the bridge
|
|
647
794
|
* inert outside a properly initialized sandbox (S1).
|
|
648
795
|
*/
|
|
649
|
-
declare const TOOL_CALL_HOST_GLOBAL = "__projection_toolcall";
|
|
796
|
+
export declare const TOOL_CALL_HOST_GLOBAL = "__projection_toolcall";
|
|
650
797
|
/** Output of {@link generateToolTypes}. */
|
|
651
798
|
interface GeneratedToolTypes {
|
|
652
799
|
/** `.d.ts` text for the `@astral-mcp/tools` surface (serve via discover_apis, R3). */
|
|
@@ -683,7 +830,11 @@ interface ToolTypeText {
|
|
|
683
830
|
* exactly one server in v1, per R30's single-instance instantiation) or a
|
|
684
831
|
* {@link ServerCatalog} directly.
|
|
685
832
|
*/
|
|
686
|
-
declare function generateToolTypes(catalog: ToolCatalog | ServerCatalog): GeneratedToolTypes;
|
|
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
|
+
}
|
|
687
838
|
//#endregion
|
|
688
839
|
//#region src/typegen/json-schema.d.ts
|
|
689
840
|
/**
|
|
@@ -693,59 +844,22 @@ declare function generateToolTypes(catalog: ToolCatalog | ServerCatalog): Genera
|
|
|
693
844
|
* @param indent - Indentation prefix of the line the type is emitted on;
|
|
694
845
|
* nested object literals indent relative to it.
|
|
695
846
|
*/
|
|
696
|
-
declare function schemaToTsType(schema: unknown, indent?: string): string;
|
|
847
|
+
export declare function schemaToTsType(schema: unknown, indent?: string): string;
|
|
697
848
|
/**
|
|
698
849
|
* True when the schema requires at least one argument property — used to
|
|
699
850
|
* decide whether the generated tool function's `args` parameter is optional.
|
|
700
851
|
*/
|
|
701
|
-
declare function schemaRequiresArgs(schema: unknown): boolean;
|
|
702
|
-
//#endregion
|
|
703
|
-
//#region src/catalog/search.d.ts
|
|
704
|
-
interface SearchToolsArgs {
|
|
705
|
-
/** Plain substring filter over name and description (case-insensitive). */
|
|
706
|
-
query?: string;
|
|
707
|
-
/** Opaque cursor from a previous page's `nextCursor`. */
|
|
708
|
-
cursor?: string;
|
|
709
|
-
}
|
|
710
|
-
interface SearchToolsOptions {
|
|
711
|
-
/** Per-tool policy overrides (R14); decides the rendered posture. */
|
|
712
|
-
policy?: PolicyOverrides;
|
|
713
|
-
/** Tools per page. Default {@link DEFAULT_SEARCH_PAGE_SIZE}, clamped to [1, 200]. */
|
|
714
|
-
pageSize?: number;
|
|
715
|
-
}
|
|
716
|
-
/** Page size — a transport bound, independent of the R37 inline threshold. */
|
|
717
|
-
declare const DEFAULT_SEARCH_PAGE_SIZE = 50;
|
|
718
|
-
/** `query` is capped (R33): it is matched as a plain substring, never a regex. */
|
|
719
|
-
declare const MAX_QUERY_CHARS = 200;
|
|
720
|
-
/** The three normative posture strings (R33) — models match on these. */
|
|
721
|
-
type ToolPosture = 'runs immediately' | 'asks for approval' | 'blocked by policy';
|
|
722
|
-
/** One entry of a `search_tools` page (R33). */
|
|
723
|
-
interface ToolSummary {
|
|
724
|
-
name: string;
|
|
725
|
-
purpose: string;
|
|
726
|
-
posture: ToolPosture;
|
|
727
|
-
destructive: boolean;
|
|
728
|
-
}
|
|
729
|
-
interface SearchToolsPage {
|
|
730
|
-
tools: ToolSummary[];
|
|
731
|
-
/** Matching tools across all pages. */
|
|
732
|
-
total: number;
|
|
733
|
-
nextCursor?: string;
|
|
734
|
-
}
|
|
735
|
-
/** Map a policy decision to its plain-words posture (R33). */
|
|
736
|
-
declare function postureOf(decision: PolicyDecision): ToolPosture;
|
|
737
|
-
/** Summarize one catalog entry (R33). */
|
|
738
|
-
declare function summarizeTool(entry: ToolCatalogEntry, policy?: PolicyOverrides): ToolSummary;
|
|
739
|
-
/**
|
|
740
|
-
* Run `search_tools`. Throws a `validate`-phase {@link ProjectionError} for a
|
|
741
|
-
* malformed cursor, one issued for a different query, or one pointing past
|
|
742
|
-
* the end of the results (R33).
|
|
743
|
-
*/
|
|
744
|
-
declare function searchTools(catalog: ServerCatalog, args: SearchToolsArgs, options?: SearchToolsOptions): CallToolResult;
|
|
852
|
+
export declare function schemaRequiresArgs(schema: unknown): boolean;
|
|
745
853
|
//#endregion
|
|
746
854
|
//#region src/catalog/describe.d.ts
|
|
747
855
|
interface DescribeToolArgs {
|
|
748
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;
|
|
749
863
|
}
|
|
750
864
|
interface DescribeToolOptions {
|
|
751
865
|
/** Per-tool policy overrides (R14); decides the rendered posture. */
|
|
@@ -773,7 +887,7 @@ interface ToolDescription {
|
|
|
773
887
|
* Run `describe_tool`. Throws a `validate`-phase {@link ProjectionError}
|
|
774
888
|
* when the wrapped server declares no such tool (R34).
|
|
775
889
|
*/
|
|
776
|
-
declare function describeTool(catalog: ServerCatalog, args: DescribeToolArgs, options?: DescribeToolOptions): CallToolResult;
|
|
890
|
+
export declare function describeTool(catalog: ServerCatalog, args: DescribeToolArgs, options?: DescribeToolOptions): CallToolResult;
|
|
777
891
|
//#endregion
|
|
778
892
|
//#region src/catalog/schema-safety.d.ts
|
|
779
893
|
/**
|
|
@@ -802,9 +916,9 @@ declare function describeTool(catalog: ServerCatalog, args: DescribeToolArgs, op
|
|
|
802
916
|
* Pure and total: never throws, never returns anything but plain JSON.
|
|
803
917
|
*/
|
|
804
918
|
/** Keywords that survive sanitization (R34). */
|
|
805
|
-
declare const SCHEMA_KEY_ALLOWLIST: ReadonlySet<string>;
|
|
919
|
+
export declare const SCHEMA_KEY_ALLOWLIST: ReadonlySet<string>;
|
|
806
920
|
/** Rendered-schema cap per tool, in characters of its JSON text (R34). */
|
|
807
|
-
declare const MAX_SCHEMA_CHARS: number;
|
|
921
|
+
export declare const MAX_SCHEMA_CHARS: number;
|
|
808
922
|
interface SanitizedSchema {
|
|
809
923
|
/** The sanitized schema, always a plain JSON object. */
|
|
810
924
|
schema: Record<string, unknown>;
|
|
@@ -817,31 +931,53 @@ interface SanitizedSchema {
|
|
|
817
931
|
* Non-object input (a server declaring `inputSchema: true`, or garbage)
|
|
818
932
|
* sanitizes to `{}`.
|
|
819
933
|
*/
|
|
820
|
-
declare function sanitizeSchema(schema: unknown, maxChars?: number): SanitizedSchema;
|
|
934
|
+
export declare function sanitizeSchema(schema: unknown, maxChars?: number): SanitizedSchema;
|
|
821
935
|
//#endregion
|
|
822
|
-
//#region src/
|
|
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;
|
|
823
971
|
/**
|
|
824
|
-
*
|
|
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).
|
|
825
975
|
*/
|
|
826
|
-
declare
|
|
827
|
-
readonly phase: ErrorPhase;
|
|
828
|
-
readonly diagnostics: Diagnostic[];
|
|
829
|
-
readonly hint: string;
|
|
830
|
-
logs: LogEntry[];
|
|
831
|
-
constructor(phase: ErrorPhase, message: string, options?: {
|
|
832
|
-
diagnostics?: Diagnostic[];
|
|
833
|
-
hint?: string;
|
|
834
|
-
logs?: LogEntry[];
|
|
835
|
-
cause?: unknown;
|
|
836
|
-
});
|
|
837
|
-
toStructured(): StructuredError;
|
|
838
|
-
}
|
|
839
|
-
/** Convert any thrown value into a StructuredError, defaulting to `runtime` phase. */
|
|
840
|
-
declare function toStructuredError(err: unknown, logs?: LogEntry[]): StructuredError;
|
|
976
|
+
export declare function searchTools(catalog: ServerCatalog, args: SearchToolsArgs, options?: SearchToolsOptions): CallToolResult;
|
|
841
977
|
//#endregion
|
|
842
978
|
//#region src/mrtr/discover.d.ts
|
|
843
979
|
/** Stable URIs the server serves via `resources/read` (R3). */
|
|
844
|
-
declare const RESOURCE_URIS: {
|
|
980
|
+
export declare const RESOURCE_URIS: {
|
|
845
981
|
readonly toolTypes: "projection://types/tools.d.ts";
|
|
846
982
|
readonly contract: "projection://docs/authoring-contract.md";
|
|
847
983
|
readonly happyPath: "projection://examples/happy-path.ts";
|
|
@@ -857,12 +993,12 @@ interface ProjectionResource {
|
|
|
857
993
|
/** Resource-level metadata (e.g. the MCP Apps `ui` object). */
|
|
858
994
|
_meta?: Record<string, unknown>;
|
|
859
995
|
}
|
|
860
|
-
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";
|
|
861
|
-
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";
|
|
862
998
|
/** Build the resources Projection serves for a wrapped server (R3). */
|
|
863
|
-
declare function buildResources(catalog: ServerCatalog, dts: string): ProjectionResource[];
|
|
999
|
+
export declare function buildResources(catalog: ServerCatalog, dts: string): ProjectionResource[];
|
|
864
1000
|
/** R37: above this many tools, `discover_apis` defers the per-tool list to the catalog tools. */
|
|
865
|
-
declare const DEFAULT_INLINE_TOOL_THRESHOLD = 40;
|
|
1001
|
+
export declare const DEFAULT_INLINE_TOOL_THRESHOLD = 40;
|
|
866
1002
|
interface DiscoverApisOptions {
|
|
867
1003
|
/** Whether the catalog projection (`search_tools` / `describe_tool`) is served (R37). */
|
|
868
1004
|
catalog?: boolean;
|
|
@@ -881,7 +1017,7 @@ interface DiscoverApisOptions {
|
|
|
881
1017
|
* per-tool overview is replaced by the tool count and a pointer to
|
|
882
1018
|
* `search_tools` / `describe_tool` — the `.d.ts` resource stays complete.
|
|
883
1019
|
*/
|
|
884
|
-
declare function discoverApis(catalog: ServerCatalog, overview: string, options?: DiscoverApisOptions): CallToolResult;
|
|
1020
|
+
export declare function discoverApis(catalog: ServerCatalog, overview: string, options?: DiscoverApisOptions): CallToolResult;
|
|
885
1021
|
/** Which projections a facade serves (R1, R32). */
|
|
886
1022
|
interface ProjectionSelection {
|
|
887
1023
|
codeMode: boolean;
|
|
@@ -892,15 +1028,15 @@ interface ProjectionSelection {
|
|
|
892
1028
|
* projections in service (R29). The preamble is library copy the
|
|
893
1029
|
* integrating developer can replace wholesale.
|
|
894
1030
|
*/
|
|
895
|
-
declare function buildInstructions(catalog: ServerCatalog, preamble?: string, projections?: ProjectionSelection): string;
|
|
1031
|
+
export declare function buildInstructions(catalog: ServerCatalog, preamble?: string, projections?: ProjectionSelection): string;
|
|
896
1032
|
/** Preamble when only code mode is on (R29). */
|
|
897
|
-
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.";
|
|
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.";
|
|
898
1034
|
/** Preamble when only the catalog projection is on (R29, R32). */
|
|
899
|
-
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.";
|
|
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.";
|
|
900
1036
|
/** Preamble when both projections are on: the routing rule (R29). */
|
|
901
|
-
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.";
|
|
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.";
|
|
902
1038
|
/** The R29 preamble variant for a projection selection. */
|
|
903
|
-
declare function defaultPreamble(projections: ProjectionSelection): string;
|
|
1039
|
+
export declare function defaultPreamble(projections: ProjectionSelection): string;
|
|
904
1040
|
//#endregion
|
|
905
1041
|
//#region src/wrap.d.ts
|
|
906
1042
|
interface WrapOptions {
|
|
@@ -908,7 +1044,10 @@ interface WrapOptions {
|
|
|
908
1044
|
blob: BlobSealerConfig;
|
|
909
1045
|
/** Resource cap overrides, clamped at the hard maxima (R12). */
|
|
910
1046
|
caps?: Partial<ResourceCaps>;
|
|
911
|
-
/**
|
|
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
|
+
*/
|
|
912
1051
|
policy?: PolicyOverrides;
|
|
913
1052
|
/** Masks sensitive argument fields before they reach an approval prompt (R16). */
|
|
914
1053
|
redact?: RedactionHook;
|
|
@@ -995,6 +1134,7 @@ interface ProjectionFacade {
|
|
|
995
1134
|
/** Run `describe_tool` (R34). Failures come back as R25 structured error results. */
|
|
996
1135
|
describeTool(args: {
|
|
997
1136
|
name: string;
|
|
1137
|
+
types?: boolean;
|
|
998
1138
|
}): CallToolResult;
|
|
999
1139
|
/**
|
|
1000
1140
|
* Run `call_tool` (R35) for one `tools/call`, first attempt or retry.
|
|
@@ -1014,7 +1154,7 @@ interface ProjectionFacade {
|
|
|
1014
1154
|
* Wrap an MCP server (an in-process instance or a connected client) into a
|
|
1015
1155
|
* Projection facade.
|
|
1016
1156
|
*/
|
|
1017
|
-
declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
1157
|
+
export declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
1018
1158
|
//#endregion
|
|
1019
1159
|
//#region src/apps/dashboard.d.ts
|
|
1020
1160
|
/**
|
|
@@ -1045,10 +1185,10 @@ declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions)
|
|
|
1045
1185
|
* `{ phase, message, hint, logs }`.
|
|
1046
1186
|
*/
|
|
1047
1187
|
/** URI the dashboard is served under. MCP Apps mandates the ui:// scheme. */
|
|
1048
|
-
declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
1188
|
+
export declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
1049
1189
|
/** MIME type the MCP Apps spec mandates for app HTML resources. */
|
|
1050
|
-
declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
1051
|
-
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";
|
|
1052
1192
|
//#endregion
|
|
1053
1193
|
//#region src/prompts/workflow-prompts.d.ts
|
|
1054
1194
|
interface WorkflowPromptDefinition {
|
|
@@ -1062,9 +1202,9 @@ interface WorkflowPromptDefinition {
|
|
|
1062
1202
|
}>;
|
|
1063
1203
|
build(args: Record<string, string | undefined>, catalog: ServerCatalog): string;
|
|
1064
1204
|
}
|
|
1065
|
-
declare const SAVE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1066
|
-
declare const VISUALIZE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1067
|
-
declare const WORKFLOW_PROMPTS: readonly WorkflowPromptDefinition[];
|
|
1205
|
+
export declare const SAVE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1206
|
+
export declare const VISUALIZE_WORKFLOW_PROMPT: WorkflowPromptDefinition;
|
|
1207
|
+
export declare const WORKFLOW_PROMPTS: readonly WorkflowPromptDefinition[];
|
|
1068
1208
|
//#endregion
|
|
1069
1209
|
//#region src/introspector/introspector.d.ts
|
|
1070
1210
|
/** A wrapped-server source: an in-process instance or a connected client. */
|
|
@@ -1080,7 +1220,7 @@ type IntrospectorSources = Record<ServerAlias, ServerSource>;
|
|
|
1080
1220
|
* {@link ToolCatalog}, and executes tool calls (implements
|
|
1081
1221
|
* {@link ToolExecutor}). Construct with {@link createIntrospector}.
|
|
1082
1222
|
*/
|
|
1083
|
-
declare class Introspector implements ToolExecutor {
|
|
1223
|
+
export declare class Introspector implements ToolExecutor {
|
|
1084
1224
|
#private;
|
|
1085
1225
|
private constructor();
|
|
1086
1226
|
static create(sources: IntrospectorSources): Promise<Introspector>;
|
|
@@ -1111,126 +1251,7 @@ declare class Introspector implements ToolExecutor {
|
|
|
1111
1251
|
*
|
|
1112
1252
|
* v1 usage: `createIntrospector({ [DEFAULT_SERVER_ALIAS]: serverOrClient })`.
|
|
1113
1253
|
*/
|
|
1114
|
-
declare function createIntrospector(sources: IntrospectorSources): Promise<Introspector>;
|
|
1115
|
-
//#endregion
|
|
1116
|
-
//#region src/text-safety.d.ts
|
|
1117
|
-
/**
|
|
1118
|
-
* Rendering untrusted strings inertly (S5, S6).
|
|
1119
|
-
*
|
|
1120
|
-
* Tool names, descriptions, the wrapped server's identity, and machine state
|
|
1121
|
-
* names all flow from a possibly third-party server or a model-authored
|
|
1122
|
-
* machine. Wherever they are rendered into human-facing prompt copy or into
|
|
1123
|
-
* generated source, they must not be able to forge structure with control
|
|
1124
|
-
* characters (newlines, ESC for ANSI sequences) or reorder text with Unicode
|
|
1125
|
-
* bidi overrides. Centralizing the character class here keeps every call site
|
|
1126
|
-
* on the same, complete definition — an earlier divergence let generated
|
|
1127
|
-
* `.d.ts`/bridge comments miss the directional-isolate range that the
|
|
1128
|
-
* elicitation copy already stripped.
|
|
1129
|
-
*/
|
|
1130
|
-
/**
|
|
1131
|
-
* Replace control and bidi characters with the replacement character.
|
|
1132
|
-
* `allowNewline` keeps `\n` (for multi-line blocks whose formatting newlines
|
|
1133
|
-
* are part of the rendering, e.g. a pretty-printed JSON block).
|
|
1134
|
-
*/
|
|
1135
|
-
declare function neutralizeControlChars(text: string, options?: {
|
|
1136
|
-
allowNewline?: boolean;
|
|
1137
|
-
}): string;
|
|
1138
|
-
/** Truncate to `maxChars`, appending an ellipsis when shortened. */
|
|
1139
|
-
declare function capLength(text: string, maxChars: number): string;
|
|
1140
|
-
//#endregion
|
|
1141
|
-
//#region src/policy/decision.d.ts
|
|
1142
|
-
/**
|
|
1143
|
-
* Decide the policy for a catalog tool (R14).
|
|
1144
|
-
*
|
|
1145
|
-
* - A developer override (`auto` | `ask` | `deny`) always wins.
|
|
1146
|
-
* - With no override, `annotations.readOnlyHint === true` yields `auto`;
|
|
1147
|
-
* an absent or `false` hint yields `ask` (S5: unannotated defaults to ask).
|
|
1148
|
-
* - An override entry with an unrecognized value (possible when the config
|
|
1149
|
-
* arrives untyped) fails safe to `ask` — it never grants `auto`.
|
|
1150
|
-
*
|
|
1151
|
-
* Only own properties of `overrides` are consulted, so tools named like
|
|
1152
|
-
* `Object.prototype` members (`toString`, `constructor`, ...) cannot pick up
|
|
1153
|
-
* inherited junk as a decision.
|
|
1154
|
-
*/
|
|
1155
|
-
declare function decidePolicy(entry: ToolCatalogEntry, overrides?: PolicyOverrides): PolicyDecision;
|
|
1156
|
-
/** Result of resolving a pending call against a server catalog. */
|
|
1157
|
-
type ResolvedCallPolicy = {
|
|
1158
|
-
ok: true;
|
|
1159
|
-
decision: PolicyDecision;
|
|
1160
|
-
entry: ToolCatalogEntry;
|
|
1161
|
-
} | {
|
|
1162
|
-
ok: false;
|
|
1163
|
-
error: ProjectionError;
|
|
1164
|
-
};
|
|
1165
|
-
/**
|
|
1166
|
-
* Resolve a machine-requested tool call against the server catalog and
|
|
1167
|
-
* decide its policy.
|
|
1168
|
-
*
|
|
1169
|
-
* Returns the decision together with the matching catalog entry (the entry
|
|
1170
|
-
* is what elicitation copy must be built from — S6), or a structured
|
|
1171
|
-
* `validate`-phase {@link ProjectionError} when the machine names a tool the
|
|
1172
|
-
* wrapped server does not declare.
|
|
1173
|
-
*/
|
|
1174
|
-
declare function resolveCallPolicy(call: PendingToolCall, catalog: ServerCatalog, overrides?: PolicyOverrides): ResolvedCallPolicy;
|
|
1175
|
-
/**
|
|
1176
|
-
* Canonical TOOL_DENIED reason for calls blocked by a `deny` policy
|
|
1177
|
-
* decision. A `deny` decision never produces an elicitation — the machine
|
|
1178
|
-
* host injects `TOOL_DENIED` with this reason instead.
|
|
1179
|
-
*/
|
|
1180
|
-
declare const POLICY_DENIED_REASON = "denied by server policy";
|
|
1181
|
-
/**
|
|
1182
|
-
* Build the TOOL_DENIED reason string for a policy-denied call. With a tool
|
|
1183
|
-
* name it names the denied tool so the machine (and audit trail) can tell
|
|
1184
|
-
* which call was blocked.
|
|
1185
|
-
*/
|
|
1186
|
-
declare function policyDeniedReason(toolName?: string): string;
|
|
1187
|
-
//#endregion
|
|
1188
|
-
//#region src/policy/elicitation.d.ts
|
|
1189
|
-
/** Structured approval copy for one gated call (input to the MRTR adapter). */
|
|
1190
|
-
interface ElicitationCopy {
|
|
1191
|
-
/** Short action title, e.g. `Approve: delete file`. */
|
|
1192
|
-
title: string;
|
|
1193
|
-
/** Full human-readable summary (plain text with an indented JSON block). */
|
|
1194
|
-
message: string;
|
|
1195
|
-
/** Tool name, taken from the catalog entry. */
|
|
1196
|
-
toolName: string;
|
|
1197
|
-
/** Machine state path that requested the call (raw; render with care). */
|
|
1198
|
-
stateName: string;
|
|
1199
|
-
/** The redacted arguments as rendered in `message` (JSON text, possibly truncated). */
|
|
1200
|
-
args: string;
|
|
1201
|
-
/** True when the catalog entry carries `destructiveHint: true`. */
|
|
1202
|
-
destructive: boolean;
|
|
1203
|
-
}
|
|
1204
|
-
interface ElicitationCopyOptions {
|
|
1205
|
-
/** Redaction hook applied to args before any rendering (R16). */
|
|
1206
|
-
redact?: RedactionHook;
|
|
1207
|
-
/**
|
|
1208
|
-
* Who asked: a machine state (default) or a direct `call_tool` request
|
|
1209
|
-
* (R35). Selects the footer; nothing else differs.
|
|
1210
|
-
*/
|
|
1211
|
-
origin?: 'machine' | 'direct';
|
|
1212
|
-
/**
|
|
1213
|
-
* Backstop cap on the whole rendered args JSON, in characters. Default
|
|
1214
|
-
* 4096. Each string leaf is independently capped at 512 characters first.
|
|
1215
|
-
*/
|
|
1216
|
-
maxArgsChars?: number;
|
|
1217
|
-
}
|
|
1218
|
-
/**
|
|
1219
|
-
* Build the approval summary for a gated call.
|
|
1220
|
-
*
|
|
1221
|
-
* `entry` MUST be the catalog entry the call was resolved against (use
|
|
1222
|
-
* `resolveCallPolicy`); the copy takes the tool name, title and description
|
|
1223
|
-
* from it, never from the pending call or its arguments.
|
|
1224
|
-
*/
|
|
1225
|
-
declare function buildElicitationCopy(call: PendingToolCall, entry: ToolCatalogEntry, options?: ElicitationCopyOptions): ElicitationCopy;
|
|
1226
|
-
/**
|
|
1227
|
-
* The one-line human purpose: the first sentence of the server's
|
|
1228
|
-
* description, neutralized and capped. Runs of replacement characters
|
|
1229
|
-
* (neutralized control bytes) are collapsed so a hostile or malformed
|
|
1230
|
-
* description does not render as a wall of `�`. Undefined when the server
|
|
1231
|
-
* gave no usable description.
|
|
1232
|
-
*/
|
|
1233
|
-
declare function purposeSentence(description: string | undefined): string | undefined;
|
|
1254
|
+
export declare function createIntrospector(sources: IntrospectorSources): Promise<Introspector>;
|
|
1234
1255
|
//#endregion
|
|
1235
1256
|
//#region src/sandbox/session.d.ts
|
|
1236
1257
|
/** A tool call surfaced from the `@astral-mcp/tools` bridge inside the VM. */
|
|
@@ -1293,7 +1314,7 @@ interface SandboxSession {
|
|
|
1293
1314
|
* bridge, evaluate the authored module, and return a handle for driving it.
|
|
1294
1315
|
* See ./index.ts for the full boundary contract.
|
|
1295
1316
|
*/
|
|
1296
|
-
declare function createSandboxSession(options: SandboxSessionOptions): Promise<SandboxSession>;
|
|
1317
|
+
export declare function createSandboxSession(options: SandboxSessionOptions): Promise<SandboxSession>;
|
|
1297
1318
|
//#endregion
|
|
1298
1319
|
//#region src/machine-host/host.d.ts
|
|
1299
1320
|
interface RunSegmentOptions {
|
|
@@ -1343,14 +1364,14 @@ interface RunSegmentOptions {
|
|
|
1343
1364
|
* check of its own — `executeMachine` enforces `maxInputBytes` before calling
|
|
1344
1365
|
* it. Callers invoking `runSegment` directly must bound `input` themselves.
|
|
1345
1366
|
*/
|
|
1346
|
-
declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>;
|
|
1367
|
+
export declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>;
|
|
1347
1368
|
//#endregion
|
|
1348
1369
|
//#region src/machine-host/contract.d.ts
|
|
1349
1370
|
/**
|
|
1350
1371
|
* Human-readable authoring contract. `discover_apis` publishes this inline
|
|
1351
1372
|
* (R3) so a model can author a valid machine without fetching resources.
|
|
1352
1373
|
*/
|
|
1353
|
-
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";
|
|
1354
1375
|
//#endregion
|
|
1355
|
-
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 };
|
|
1356
1377
|
//# sourceMappingURL=index.d.mts.map
|