@astral-mcp/projection 0.2.0 → 0.4.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/dist/index.d.mts +62 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +240 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -326,7 +326,7 @@ declare function openBlob(blob: string, options: OpenBlobOptions): BlobPayload;
|
|
|
326
326
|
* CI instead of silently minting blobs with a stale version stamp.
|
|
327
327
|
*/
|
|
328
328
|
/** `@astral-mcp/projection` package version (must match packages/projection/package.json). */
|
|
329
|
-
declare const LIB_VERSION = "0.
|
|
329
|
+
declare const LIB_VERSION = "0.4.0";
|
|
330
330
|
/** Pinned XState version (must match the exact pin in package.json — D2). */
|
|
331
331
|
declare const XSTATE_VERSION = "5.32.5";
|
|
332
332
|
//#endregion
|
|
@@ -410,6 +410,19 @@ interface ExecuteMachineDeps {
|
|
|
410
410
|
* `McpRequestContext.era`; `undefined` is treated as legacy.
|
|
411
411
|
*/
|
|
412
412
|
protocolEra?: ProtocolEra;
|
|
413
|
+
/**
|
|
414
|
+
* Opt-in legacy-client compatibility (R28 amendment): when true, a
|
|
415
|
+
* suspension on a pre-2026-07-28 connection is returned as a normal
|
|
416
|
+
* `input_required` result and the SDK's serving layer fulfils it through
|
|
417
|
+
* old-style server→client `elicitation/create` requests, re-invoking this
|
|
418
|
+
* adapter with a byte-exact `requestState` echo and the collected
|
|
419
|
+
* `inputResponses` — the same retry envelope as a real MRTR retry, so
|
|
420
|
+
* every sealing/verification invariant runs unchanged. Cost: the
|
|
421
|
+
* `tools/call` stays open on this instance while the human answers, so
|
|
422
|
+
* statelessness (R27) is suspended for that call (free over stdio; needs
|
|
423
|
+
* session affinity over legacy HTTP). Default false: fail fast per R28.
|
|
424
|
+
*/
|
|
425
|
+
legacyElicitation?: boolean;
|
|
413
426
|
}
|
|
414
427
|
/**
|
|
415
428
|
* Run `execute_machine` for one `tools/call`, whether it is a first attempt
|
|
@@ -435,6 +448,8 @@ interface ProjectionResource {
|
|
|
435
448
|
description: string;
|
|
436
449
|
mimeType: string;
|
|
437
450
|
text: string;
|
|
451
|
+
/** Resource-level metadata (e.g. the MCP Apps `ui` object). */
|
|
452
|
+
_meta?: Record<string, unknown>;
|
|
438
453
|
}
|
|
439
454
|
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
455
|
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";
|
|
@@ -464,6 +479,17 @@ interface WrapOptions {
|
|
|
464
479
|
redact?: RedactionHook;
|
|
465
480
|
/** Replaces the library's code-mode preamble (R29). */
|
|
466
481
|
codeModePreamble?: string;
|
|
482
|
+
/** Compatibility switches for pre-2026-07-28 clients. */
|
|
483
|
+
compat?: {
|
|
484
|
+
/**
|
|
485
|
+
* Serve approval suspensions to legacy clients through the SDK's
|
|
486
|
+
* server→client `elicitation/create` shim instead of failing fast
|
|
487
|
+
* (R28 amendment; DECISIONS D6). The client must declare the
|
|
488
|
+
* `elicitation` capability. Statelessness is suspended for the open
|
|
489
|
+
* call — free over stdio, needs session affinity over legacy HTTP.
|
|
490
|
+
*/
|
|
491
|
+
legacyElicitation?: boolean;
|
|
492
|
+
};
|
|
467
493
|
/** Identity the servers built by `createServer` advertise. */
|
|
468
494
|
serverInfo?: Implementation;
|
|
469
495
|
}
|
|
@@ -508,6 +534,40 @@ interface ProjectionFacade {
|
|
|
508
534
|
*/
|
|
509
535
|
declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
510
536
|
//#endregion
|
|
537
|
+
//#region src/apps/dashboard.d.ts
|
|
538
|
+
/**
|
|
539
|
+
* MCP Apps workflow dashboard (PRD §12.1, second fenced use case).
|
|
540
|
+
*
|
|
541
|
+
* A static, library-authored HTML app that renders an `execute_machine`
|
|
542
|
+
* result — output, approval audit trail, console logs, or the structured
|
|
543
|
+
* error — inside the host's sandboxed iframe, per the MCP Apps extension
|
|
544
|
+
* (SEP-1865, spec 2026-01-26).
|
|
545
|
+
*
|
|
546
|
+
* Security posture (the §12.1 design constraint, satisfied by construction):
|
|
547
|
+
* - The HTML is a compile-time constant. No model-authored code, no
|
|
548
|
+
* template interpolation, no VM: UI rendering can never reach the tools
|
|
549
|
+
* bridge because nothing dynamic executes server-side at all.
|
|
550
|
+
* - Model-controlled data (outputs, audit args, log lines, error text)
|
|
551
|
+
* enters the DOM exclusively through `textContent` — the app never uses
|
|
552
|
+
* innerHTML — so hostile strings render inert (S6 extended to the app).
|
|
553
|
+
* - The app requests no host capabilities: `appCapabilities: {}`. It cannot
|
|
554
|
+
* call tools, open links, or write context; it only listens.
|
|
555
|
+
*
|
|
556
|
+
* Wire contract implemented (app side):
|
|
557
|
+
* - `ui/initialize` request → await result → `ui/notifications/initialized`.
|
|
558
|
+
* - Listens for `ui/notifications/tool-input`, `ui/notifications/tool-result`
|
|
559
|
+
* and `ui/notifications/tool-cancelled`; ignores everything else.
|
|
560
|
+
* - The result payload is the standard `CallToolResult` from
|
|
561
|
+
* `execute_machine`: `structuredContent` is either
|
|
562
|
+
* `{ output, approvals, logs }` or (with `isError`) the structured error
|
|
563
|
+
* `{ phase, message, hint, logs }`.
|
|
564
|
+
*/
|
|
565
|
+
/** URI the dashboard is served under. MCP Apps mandates the ui:// scheme. */
|
|
566
|
+
declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
567
|
+
/** MIME type the MCP Apps spec mandates for app HTML resources. */
|
|
568
|
+
declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
569
|
+
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";
|
|
570
|
+
//#endregion
|
|
511
571
|
//#region src/errors.d.ts
|
|
512
572
|
/**
|
|
513
573
|
* Error carrying the structured `isError` body every failure returns (R25).
|
|
@@ -858,5 +918,5 @@ declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>
|
|
|
858
918
|
*/
|
|
859
919
|
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
920
|
//#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 };
|
|
921
|
+
export { APPROVAL_SCHEMA, AUTHORING_CONTRACT, ApprovalVerdict, AuditEntry, BLOB_SCHEMA_VERSION, BlobPayload, BlobSealerConfig, type CallToolResult, type ContentBlock, DASHBOARD_HTML, DASHBOARD_RESOURCE_URI, 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, MCP_APP_MIME_TYPE, 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
922
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/blob/sealer.ts","../src/blob/versions.ts","../src/mrtr/protocol.ts","../src/mrtr/adapter.ts","../src/mrtr/discover.ts","../src/wrap.ts","../src/errors.ts","../src/introspector/introspector.ts","../src/typegen/generate.ts","../src/typegen/json-schema.ts","../src/text-safety.ts","../src/policy/decision.ts","../src/policy/elicitation.ts","../src/sandbox/session.ts","../src/machine-host/host.ts","../src/machine-host/contract.ts"],"mappings":";;;;;;;;;;;;;KAcY;cAEC,sBAAsB;;UAGlB;EACf;EACA;EACA;EACA;;UAGe;;EAEf;EACA;;EAEA,aAAa;;EAEb,eAAe;EACf,cAAc;;UAGC;;EAEf,SAAS,IAAI,aAAa;;UAGX;EACf,OAAO;;EAEP;;EAEA;EACA,OAAO;;;;;;;;;;iBAmBO,SAAS,SAAS,eAAe,eAAe;;iBAahD,SAAS,iBAAiB,SAAS;;UAKlC;EACf,SACE,OAAO,aACP,cACA,MAAM,0BACL,QAAQ;;KAGD;EACR;EAAU;;EAAsB;EAAW;IAAS;IAAiB;;;KAM7D;UAEK;;GAEd,mBAAmB;;;UAQL;;EAEf;EACA;EACA,MAAM;;EAEN;;;KAIU;EACN;EAAqB;EAAgB;;EACrC;EAAoB;EAAgB;IAAS;IAAiB;;;EAC9D;EAAqB;EAAgB;;KAM/B;UASK;EACf;;EAEA;EACA;;UAGe;EACf,OAAO;EACP;EACA,aAAa;;EAEb;EACA,MAAM;;KAGI;UAEK;EACf,OAAO;EACP;;EAEA;;EAEA;;UAOe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;cAGW,cAAc;cAad,UAAU;;iBAmCP,UAAU,WAAW,QAAQ,gBAAgB;cAehD;UAEI;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA,SAAS,eAAe;;;;;;;;EAQxB,OAAO;;EAEP;;EAEA;;EAEA;;EAEA;;UAGe;;EAEf,KAAK;;EAEL,eAAe;;EAEf;;EAEA;;;KAQU;EAAoB;;EAAuB;EAAkB;;;KAG7D;EAEN;;EAEA;;EAEA,OAAO;EACP,MAAM;;EAGN;;EAEA,SAAS,eAAe;;EAExB;EACA;EACA,OAAO;EACP,MAAM;;EAGN;EACA,OAAO;;UAGI;EACf;EACA;EACA,MAAM;EACN;EACA;;UAOe;;;;;GAKd,kBAAkB,MAAM,0BAA0B;;UAGpC;;EAEf,OAAO,QAAQ;;EAEf,SAAS;;EAET,MAAM;;EAEN,SAAS;;EAET;;;;;cCtSW;;cAGA;;cAGA;;iBA8MG,SAAS;UAIR;;EAEf;;EAEA;;EAEA;;EAEA,SAAS,eAAe;;EAExB,QAAQ;;EAER;;EAEA;;EAEA;;;;;;iBAOc,iBAAiB,OAAO,wBAAwB;;;;;;;;;iBA2BhD,SAAS,SAAS,aAAa,QAAQ;UA2BtC;;EAEf;;EAEA;EACA,QAAQ;;EAER;;;;;;;;;;;;;;;;;iBAkBc,SAAS,cAAc,SAAS,kBAAkB;;;;;;;;;;;;;;;cCxXrD;;cAGA;;;;;;;;KC0BD,iBAAiB;;;;;;;;;;;;;UAcZ;;EAEf;;EAEA,iBAAiB,mBAAiB;;;;;;;;;;;cAgBvB,iBAAiB;;;;;;;;;;;cAqBjB;;;;;;;;;;;iBAYG,aAAa,KAAK;;;UCpEjB,2BAA2B;;EAE1C;EACA;;EAEA;;UAGe;EACf,SAAS;EACT;EACA,UAAU;EACV,MAAM;EACN,OAAO,QAAQ;EACf,SAAS;EACT,SAAS;;;;;;EAMT,cAAc;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/blob/sealer.ts","../src/blob/versions.ts","../src/mrtr/protocol.ts","../src/mrtr/adapter.ts","../src/mrtr/discover.ts","../src/wrap.ts","../src/apps/dashboard.ts","../src/errors.ts","../src/introspector/introspector.ts","../src/typegen/generate.ts","../src/typegen/json-schema.ts","../src/text-safety.ts","../src/policy/decision.ts","../src/policy/elicitation.ts","../src/sandbox/session.ts","../src/machine-host/host.ts","../src/machine-host/contract.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,223 @@ import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
|
7
7
|
import { getModuleLoader, getTypescriptSupport, loadQuickJs } from "@sebastianwessel/quickjs";
|
|
8
8
|
import { readFileSync, readdirSync } from "node:fs";
|
|
9
9
|
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
//#region src/apps/dashboard.ts
|
|
11
|
+
/**
|
|
12
|
+
* MCP Apps workflow dashboard (PRD §12.1, second fenced use case).
|
|
13
|
+
*
|
|
14
|
+
* A static, library-authored HTML app that renders an `execute_machine`
|
|
15
|
+
* result — output, approval audit trail, console logs, or the structured
|
|
16
|
+
* error — inside the host's sandboxed iframe, per the MCP Apps extension
|
|
17
|
+
* (SEP-1865, spec 2026-01-26).
|
|
18
|
+
*
|
|
19
|
+
* Security posture (the §12.1 design constraint, satisfied by construction):
|
|
20
|
+
* - The HTML is a compile-time constant. No model-authored code, no
|
|
21
|
+
* template interpolation, no VM: UI rendering can never reach the tools
|
|
22
|
+
* bridge because nothing dynamic executes server-side at all.
|
|
23
|
+
* - Model-controlled data (outputs, audit args, log lines, error text)
|
|
24
|
+
* enters the DOM exclusively through `textContent` — the app never uses
|
|
25
|
+
* innerHTML — so hostile strings render inert (S6 extended to the app).
|
|
26
|
+
* - The app requests no host capabilities: `appCapabilities: {}`. It cannot
|
|
27
|
+
* call tools, open links, or write context; it only listens.
|
|
28
|
+
*
|
|
29
|
+
* Wire contract implemented (app side):
|
|
30
|
+
* - `ui/initialize` request → await result → `ui/notifications/initialized`.
|
|
31
|
+
* - Listens for `ui/notifications/tool-input`, `ui/notifications/tool-result`
|
|
32
|
+
* and `ui/notifications/tool-cancelled`; ignores everything else.
|
|
33
|
+
* - The result payload is the standard `CallToolResult` from
|
|
34
|
+
* `execute_machine`: `structuredContent` is either
|
|
35
|
+
* `{ output, approvals, logs }` or (with `isError`) the structured error
|
|
36
|
+
* `{ phase, message, hint, logs }`.
|
|
37
|
+
*/
|
|
38
|
+
/** URI the dashboard is served under. MCP Apps mandates the ui:// scheme. */
|
|
39
|
+
const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
40
|
+
/** MIME type the MCP Apps spec mandates for app HTML resources. */
|
|
41
|
+
const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
42
|
+
const DASHBOARD_HTML = `<!doctype html>
|
|
43
|
+
<html lang="en">
|
|
44
|
+
<head>
|
|
45
|
+
<meta charset="utf-8" />
|
|
46
|
+
<title>Projection workflow dashboard</title>
|
|
47
|
+
<style>
|
|
48
|
+
:root {
|
|
49
|
+
color-scheme: light dark;
|
|
50
|
+
--bg: #ffffff; --fg: #1a1a2e; --muted: #6b7280; --line: #e5e7eb;
|
|
51
|
+
--ok: #047857; --ok-bg: #ecfdf5; --err: #b91c1c; --err-bg: #fef2f2;
|
|
52
|
+
--chip: #eef2ff; --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
53
|
+
}
|
|
54
|
+
@media (prefers-color-scheme: dark) {
|
|
55
|
+
:root {
|
|
56
|
+
--bg: #111318; --fg: #e5e7eb; --muted: #9ca3af; --line: #2a2f3a;
|
|
57
|
+
--ok: #34d399; --ok-bg: #06281f; --err: #f87171; --err-bg: #2d1215;
|
|
58
|
+
--chip: #1e2433;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg);
|
|
62
|
+
font: 14px/1.5 system-ui, sans-serif; }
|
|
63
|
+
main { padding: 16px; max-width: 720px; }
|
|
64
|
+
h1 { font-size: 15px; margin: 0 0 12px; display: flex; gap: 8px; align-items: center; }
|
|
65
|
+
.chip { font-size: 12px; padding: 2px 10px; border-radius: 999px; background: var(--chip); }
|
|
66
|
+
.chip.ok { color: var(--ok); background: var(--ok-bg); }
|
|
67
|
+
.chip.err { color: var(--err); background: var(--err-bg); }
|
|
68
|
+
section { margin: 14px 0; }
|
|
69
|
+
section > h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
|
|
70
|
+
color: var(--muted); margin: 0 0 6px; }
|
|
71
|
+
pre { margin: 0; padding: 10px; background: var(--chip); border-radius: 8px;
|
|
72
|
+
font-family: var(--mono); font-size: 12px; overflow-x: auto; white-space: pre-wrap; }
|
|
73
|
+
table { border-collapse: collapse; width: 100%; font-size: 13px; }
|
|
74
|
+
th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line);
|
|
75
|
+
vertical-align: top; }
|
|
76
|
+
th { color: var(--muted); font-weight: 500; }
|
|
77
|
+
td.args { font-family: var(--mono); font-size: 12px; }
|
|
78
|
+
.log { font-family: var(--mono); font-size: 12px; padding: 2px 0; }
|
|
79
|
+
.log .level { color: var(--muted); margin-right: 6px; }
|
|
80
|
+
.hint { color: var(--muted); font-size: 13px; margin-top: 6px; }
|
|
81
|
+
.hidden { display: none; }
|
|
82
|
+
#waiting { color: var(--muted); }
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body>
|
|
86
|
+
<main>
|
|
87
|
+
<h1>Projection workflow <span id="status" class="chip">waiting…</span></h1>
|
|
88
|
+
<p id="waiting">Waiting for the workflow result from the host…</p>
|
|
89
|
+
<section id="output-section" class="hidden"><h2>Output</h2><pre id="output"></pre></section>
|
|
90
|
+
<section id="error-section" class="hidden"><h2>Error</h2>
|
|
91
|
+
<pre id="error"></pre><p id="error-hint" class="hint"></p></section>
|
|
92
|
+
<section id="approvals-section" class="hidden"><h2>Approval audit trail</h2>
|
|
93
|
+
<table><thead><tr><th>Tool</th><th>Decision</th><th>Arguments</th></tr></thead>
|
|
94
|
+
<tbody id="approvals"></tbody></table></section>
|
|
95
|
+
<section id="logs-section" class="hidden"><h2>Console</h2><div id="logs"></div></section>
|
|
96
|
+
</main>
|
|
97
|
+
<script>
|
|
98
|
+
'use strict';
|
|
99
|
+
(function () {
|
|
100
|
+
var nextId = 1;
|
|
101
|
+
var pending = new Map();
|
|
102
|
+
|
|
103
|
+
function post(message) { window.parent.postMessage(message, '*'); }
|
|
104
|
+
function request(method, params) {
|
|
105
|
+
return new Promise(function (resolve, reject) {
|
|
106
|
+
var id = nextId++;
|
|
107
|
+
pending.set(id, { resolve: resolve, reject: reject });
|
|
108
|
+
post({ jsonrpc: '2.0', id: id, method: method, params: params });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function notify(method, params) {
|
|
112
|
+
var message = { jsonrpc: '2.0', method: method };
|
|
113
|
+
if (params !== undefined) message.params = params;
|
|
114
|
+
post(message);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function byId(id) { return document.getElementById(id); }
|
|
118
|
+
function show(id) { byId(id).classList.remove('hidden'); }
|
|
119
|
+
function setStatus(text, cls) {
|
|
120
|
+
var chip = byId('status');
|
|
121
|
+
chip.textContent = text;
|
|
122
|
+
chip.className = 'chip' + (cls ? ' ' + cls : '');
|
|
123
|
+
byId('waiting').classList.add('hidden');
|
|
124
|
+
}
|
|
125
|
+
function pretty(value) {
|
|
126
|
+
try { return JSON.stringify(value, null, 2); } catch (e) { return String(value); }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// All model-controlled data enters the DOM via textContent only.
|
|
130
|
+
function renderResult(result) {
|
|
131
|
+
var structured = (result && result.structuredContent) || {};
|
|
132
|
+
if (result && result.isError) {
|
|
133
|
+
setStatus('failed: ' + String(structured.phase || 'error'), 'err');
|
|
134
|
+
byId('error').textContent =
|
|
135
|
+
String(structured.message || 'unknown error');
|
|
136
|
+
byId('error-hint').textContent = String(structured.hint || '');
|
|
137
|
+
show('error-section');
|
|
138
|
+
} else {
|
|
139
|
+
setStatus('completed', 'ok');
|
|
140
|
+
byId('output').textContent = pretty(
|
|
141
|
+
structured.output === undefined ? null : structured.output,
|
|
142
|
+
);
|
|
143
|
+
show('output-section');
|
|
144
|
+
}
|
|
145
|
+
var approvals = Array.isArray(structured.approvals) ? structured.approvals : [];
|
|
146
|
+
if (approvals.length > 0) {
|
|
147
|
+
var tbody = byId('approvals');
|
|
148
|
+
approvals.forEach(function (entry) {
|
|
149
|
+
var row = document.createElement('tr');
|
|
150
|
+
var tool = document.createElement('td');
|
|
151
|
+
tool.textContent = String(entry.tool || '');
|
|
152
|
+
var decision = document.createElement('td');
|
|
153
|
+
decision.textContent = String(entry.decision || '');
|
|
154
|
+
var args = document.createElement('td');
|
|
155
|
+
args.className = 'args';
|
|
156
|
+
args.textContent = pretty(entry.args || {});
|
|
157
|
+
row.appendChild(tool); row.appendChild(decision); row.appendChild(args);
|
|
158
|
+
tbody.appendChild(row);
|
|
159
|
+
});
|
|
160
|
+
show('approvals-section');
|
|
161
|
+
}
|
|
162
|
+
var logs = Array.isArray(structured.logs) ? structured.logs : [];
|
|
163
|
+
if (logs.length > 0) {
|
|
164
|
+
var list = byId('logs');
|
|
165
|
+
logs.forEach(function (entry) {
|
|
166
|
+
var line = document.createElement('div');
|
|
167
|
+
line.className = 'log';
|
|
168
|
+
var level = document.createElement('span');
|
|
169
|
+
level.className = 'level';
|
|
170
|
+
level.textContent = '[' + String(entry.level || 'log') + ']';
|
|
171
|
+
line.appendChild(level);
|
|
172
|
+
line.appendChild(document.createTextNode(String(entry.message || '')));
|
|
173
|
+
list.appendChild(line);
|
|
174
|
+
});
|
|
175
|
+
show('logs-section');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
window.addEventListener('message', function (event) {
|
|
180
|
+
// Only the embedding host may speak: forged tool-results from a hostile
|
|
181
|
+
// embedder could otherwise spoof the displayed audit trail.
|
|
182
|
+
if (event.source !== window.parent) return;
|
|
183
|
+
var message = event.data;
|
|
184
|
+
if (!message || message.jsonrpc !== '2.0') return;
|
|
185
|
+
if (message.id !== undefined && message.method === undefined) {
|
|
186
|
+
var waiter = pending.get(message.id);
|
|
187
|
+
if (waiter) {
|
|
188
|
+
pending.delete(message.id);
|
|
189
|
+
if (message.error) waiter.reject(message.error);
|
|
190
|
+
else waiter.resolve(message.result);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (message.method === 'ui/notifications/tool-input') {
|
|
195
|
+
setStatus('running…');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (message.method === 'ui/notifications/tool-result') {
|
|
199
|
+
renderResult(message.params);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (message.method === 'ui/notifications/tool-cancelled') {
|
|
203
|
+
var reason = message.params && message.params.reason;
|
|
204
|
+
setStatus('cancelled', 'err');
|
|
205
|
+
byId('error').textContent = String(reason || 'cancelled by the host');
|
|
206
|
+
show('error-section');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Host -> app REQUESTS (id + method) get an empty result: answers ping
|
|
210
|
+
// and ui/resource-teardown so hosts don't stall on their SHOULD-wait.
|
|
211
|
+
if (message.id !== undefined && message.method !== undefined) {
|
|
212
|
+
post({ jsonrpc: '2.0', id: message.id, result: {} });
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Handshake: initialize, then signal readiness. The host MUST NOT push
|
|
217
|
+
// tool data before ui/notifications/initialized.
|
|
218
|
+
request('ui/initialize', { appCapabilities: {} }).then(function () {
|
|
219
|
+
notify('ui/notifications/initialized');
|
|
220
|
+
});
|
|
221
|
+
})();
|
|
222
|
+
<\/script>
|
|
223
|
+
</body>
|
|
224
|
+
</html>
|
|
225
|
+
`;
|
|
226
|
+
//#endregion
|
|
10
227
|
//#region src/errors.ts
|
|
11
228
|
/**
|
|
12
229
|
* Error carrying the structured `isError` body every failure returns (R25).
|
|
@@ -378,7 +595,7 @@ const BLOB_SCHEMA_VERSION = 1;
|
|
|
378
595
|
* CI instead of silently minting blobs with a stale version stamp.
|
|
379
596
|
*/
|
|
380
597
|
/** `@astral-mcp/projection` package version (must match packages/projection/package.json). */
|
|
381
|
-
const LIB_VERSION = "0.
|
|
598
|
+
const LIB_VERSION = "0.4.0";
|
|
382
599
|
/** Pinned XState version (must match the exact pin in package.json — D2). */
|
|
383
600
|
const XSTATE_VERSION = "5.32.5";
|
|
384
601
|
//#endregion
|
|
@@ -604,7 +821,7 @@ function openBlob(blob, options) {
|
|
|
604
821
|
}
|
|
605
822
|
if (!isRecord(payload)) throw verificationError("blob payload malformed: not a JSON object", HINT_CORRUPT);
|
|
606
823
|
if (payload["v"] !== 1) throw verificationError(`unknown blob schema version ${JSON.stringify(payload["v"])} (this library expects 1)`, HINT_VERSION);
|
|
607
|
-
if (payload["libv"] !== "0.
|
|
824
|
+
if (payload["libv"] !== "0.4.0") throw verificationError(`library version mismatch: blob was sealed by @astral-mcp/projection ${JSON.stringify(payload["libv"])}, this instance runs ${LIB_VERSION}`, HINT_VERSION);
|
|
608
825
|
if (payload["xstatev"] !== "5.32.5") throw verificationError(`xstate version mismatch: blob snapshot was produced under xstate ${JSON.stringify(payload["xstatev"])}, this instance runs ${XSTATE_VERSION}`, HINT_VERSION);
|
|
609
826
|
assertPayloadShape(payload);
|
|
610
827
|
const verified = payload;
|
|
@@ -2170,7 +2387,7 @@ function suspendResult(outcome, args, deps, caps) {
|
|
|
2170
2387
|
hint,
|
|
2171
2388
|
logs: outcome.logs
|
|
2172
2389
|
});
|
|
2173
|
-
if (!supportsMrtr(deps.protocolEra)) return fail("protocol", `this machine needs approval for a non-read-only tool call, which requires MCP protocol revision ${MRTR_PROTOCOL_REVISION} or later (this request is being served on the ${deps.protocolEra ?? "legacy"} protocol era)`, "Author a machine that only calls read-only tools, or connect with a client that negotiates the 2026-07-28 revision (SDK v2: `versionNegotiation: { mode: \"auto\" }`).");
|
|
2390
|
+
if (!supportsMrtr(deps.protocolEra) && deps.legacyElicitation !== true) return fail("protocol", `this machine needs approval for a non-read-only tool call, which requires MCP protocol revision ${MRTR_PROTOCOL_REVISION} or later (this request is being served on the ${deps.protocolEra ?? "legacy"} protocol era)`, "Author a machine that only calls read-only tools, or connect with a client that negotiates the 2026-07-28 revision (SDK v2: `versionNegotiation: { mode: \"auto\" }`).");
|
|
2174
2391
|
if (outcome.trip > caps.maxRoundTrips) return fail("terminal", `this workflow reached the limit of ${caps.maxRoundTrips} approval round trips`, `Restructure the machine to need at most ${caps.maxRoundTrips} approval round trips.`);
|
|
2175
2392
|
const inputRequests = {};
|
|
2176
2393
|
for (const [key, call] of Object.entries(outcome.pending)) {
|
|
@@ -2368,6 +2585,14 @@ function buildResources(catalog, dts) {
|
|
|
2368
2585
|
description: "Example machine: continues gracefully when approval is declined.",
|
|
2369
2586
|
mimeType: "text/plain",
|
|
2370
2587
|
text: EXAMPLE_DENIAL_FALLBACK
|
|
2588
|
+
},
|
|
2589
|
+
{
|
|
2590
|
+
uri: DASHBOARD_RESOURCE_URI,
|
|
2591
|
+
name: "dashboard.html",
|
|
2592
|
+
description: "Workflow result dashboard rendered by MCP Apps hosts.",
|
|
2593
|
+
mimeType: MCP_APP_MIME_TYPE,
|
|
2594
|
+
text: DASHBOARD_HTML,
|
|
2595
|
+
_meta: { ui: { prefersBorder: true } }
|
|
2371
2596
|
}
|
|
2372
2597
|
];
|
|
2373
2598
|
}
|
|
@@ -2385,7 +2610,7 @@ function discoverApis(catalog, overview) {
|
|
|
2385
2610
|
"",
|
|
2386
2611
|
AUTHORING_CONTRACT
|
|
2387
2612
|
].join("\n");
|
|
2388
|
-
const links = buildResources(catalog, "").map((resource) => ({
|
|
2613
|
+
const links = buildResources(catalog, "").filter((resource) => !resource.uri.startsWith("ui://")).map((resource) => ({
|
|
2389
2614
|
type: "resource_link",
|
|
2390
2615
|
uri: resource.uri,
|
|
2391
2616
|
name: resource.name,
|
|
@@ -2850,7 +3075,8 @@ var Facade = class {
|
|
|
2850
3075
|
...options.caps !== void 0 ? { caps: options.caps } : {},
|
|
2851
3076
|
...options.policy !== void 0 ? { policy: options.policy } : {},
|
|
2852
3077
|
...options.redact !== void 0 ? { redact: options.redact } : {},
|
|
2853
|
-
...era !== void 0 ? { protocolEra: era } : {}
|
|
3078
|
+
...era !== void 0 ? { protocolEra: era } : {},
|
|
3079
|
+
...options.compat?.legacyElicitation === true ? { legacyElicitation: true } : {}
|
|
2854
3080
|
});
|
|
2855
3081
|
}
|
|
2856
3082
|
discoverApis() {
|
|
@@ -2866,7 +3092,10 @@ var Facade = class {
|
|
|
2866
3092
|
const server = new McpServer(this.deps.options.serverInfo ?? {
|
|
2867
3093
|
name: `projection-${this.deps.catalog.alias}`,
|
|
2868
3094
|
version: "0.1.0"
|
|
2869
|
-
}, {
|
|
3095
|
+
}, {
|
|
3096
|
+
instructions: this.instructions,
|
|
3097
|
+
inputRequired: { maxRounds: clampCaps(this.deps.options.caps ?? {}).maxRoundTrips }
|
|
3098
|
+
});
|
|
2870
3099
|
this.registerOn(server, ctx);
|
|
2871
3100
|
return server;
|
|
2872
3101
|
}
|
|
@@ -2875,7 +3104,8 @@ var Facade = class {
|
|
|
2875
3104
|
server.registerTool("execute_machine", {
|
|
2876
3105
|
title: "Execute a state machine",
|
|
2877
3106
|
description: EXECUTE_MACHINE_DESCRIPTION,
|
|
2878
|
-
inputSchema: EXECUTE_MACHINE_INPUT_SCHEMA
|
|
3107
|
+
inputSchema: EXECUTE_MACHINE_INPUT_SCHEMA,
|
|
3108
|
+
_meta: { ui: { resourceUri: DASHBOARD_RESOURCE_URI } }
|
|
2879
3109
|
}, async (args, ctx) => await this.executeMachine({
|
|
2880
3110
|
code: args.code,
|
|
2881
3111
|
...args.lang !== void 0 ? { lang: args.lang } : {},
|
|
@@ -2890,7 +3120,8 @@ var Facade = class {
|
|
|
2890
3120
|
}, () => this.discoverApis());
|
|
2891
3121
|
for (const resource of this.resources) server.registerResource(resource.name, resource.uri, {
|
|
2892
3122
|
description: resource.description,
|
|
2893
|
-
mimeType: resource.mimeType
|
|
3123
|
+
mimeType: resource.mimeType,
|
|
3124
|
+
...resource._meta !== void 0 ? { _meta: resource._meta } : {}
|
|
2894
3125
|
}, () => ({ contents: [{
|
|
2895
3126
|
uri: resource.uri,
|
|
2896
3127
|
mimeType: resource.mimeType,
|
|
@@ -2924,6 +3155,6 @@ const EXECUTE_MACHINE_INPUT_SCHEMA = z.object({
|
|
|
2924
3155
|
input: z.unknown().optional().describe("Passed to the machine as its `input`.")
|
|
2925
3156
|
});
|
|
2926
3157
|
//#endregion
|
|
2927
|
-
export { APPROVAL_SCHEMA, AUTHORING_CONTRACT, BLOB_SCHEMA_VERSION, DEFAULT_CAPS, DEFAULT_CODE_MODE_PREAMBLE, DEFAULT_MAX_BLOB_BYTES, DEFAULT_SERVER_ALIAS, DEFAULT_TTL_MS, ENVELOPE_PREFIX, EXAMPLE_DENIAL_FALLBACK, EXAMPLE_HAPPY_PATH, Introspector, LIB_VERSION, MAX_CAPS, MRTR_PROTOCOL_REVISION, POLICY_DENIED_REASON, ProjectionError, RESOURCE_URIS, TOOLS_MODULE_SPECIFIER, TOOL_CALL_HOST_GLOBAL, 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 };
|
|
3158
|
+
export { APPROVAL_SCHEMA, AUTHORING_CONTRACT, BLOB_SCHEMA_VERSION, DASHBOARD_HTML, DASHBOARD_RESOURCE_URI, DEFAULT_CAPS, DEFAULT_CODE_MODE_PREAMBLE, DEFAULT_MAX_BLOB_BYTES, DEFAULT_SERVER_ALIAS, DEFAULT_TTL_MS, ENVELOPE_PREFIX, EXAMPLE_DENIAL_FALLBACK, EXAMPLE_HAPPY_PATH, Introspector, LIB_VERSION, MAX_CAPS, MCP_APP_MIME_TYPE, MRTR_PROTOCOL_REVISION, POLICY_DENIED_REASON, ProjectionError, RESOURCE_URIS, TOOLS_MODULE_SPECIFIER, TOOL_CALL_HOST_GLOBAL, 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 };
|
|
2928
3159
|
|
|
2929
3160
|
//# sourceMappingURL=index.mjs.map
|