@astral-mcp/projection 0.2.0 → 0.3.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 +38 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +233 -6
- 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.3.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
|
|
@@ -435,6 +435,8 @@ interface ProjectionResource {
|
|
|
435
435
|
description: string;
|
|
436
436
|
mimeType: string;
|
|
437
437
|
text: string;
|
|
438
|
+
/** Resource-level metadata (e.g. the MCP Apps `ui` object). */
|
|
439
|
+
_meta?: Record<string, unknown>;
|
|
438
440
|
}
|
|
439
441
|
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
442
|
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";
|
|
@@ -508,6 +510,40 @@ interface ProjectionFacade {
|
|
|
508
510
|
*/
|
|
509
511
|
declare function wrapMcpServer(source: McpServer | Client, options: WrapOptions): Promise<ProjectionFacade>;
|
|
510
512
|
//#endregion
|
|
513
|
+
//#region src/apps/dashboard.d.ts
|
|
514
|
+
/**
|
|
515
|
+
* MCP Apps workflow dashboard (PRD §12.1, second fenced use case).
|
|
516
|
+
*
|
|
517
|
+
* A static, library-authored HTML app that renders an `execute_machine`
|
|
518
|
+
* result — output, approval audit trail, console logs, or the structured
|
|
519
|
+
* error — inside the host's sandboxed iframe, per the MCP Apps extension
|
|
520
|
+
* (SEP-1865, spec 2026-01-26).
|
|
521
|
+
*
|
|
522
|
+
* Security posture (the §12.1 design constraint, satisfied by construction):
|
|
523
|
+
* - The HTML is a compile-time constant. No model-authored code, no
|
|
524
|
+
* template interpolation, no VM: UI rendering can never reach the tools
|
|
525
|
+
* bridge because nothing dynamic executes server-side at all.
|
|
526
|
+
* - Model-controlled data (outputs, audit args, log lines, error text)
|
|
527
|
+
* enters the DOM exclusively through `textContent` — the app never uses
|
|
528
|
+
* innerHTML — so hostile strings render inert (S6 extended to the app).
|
|
529
|
+
* - The app requests no host capabilities: `appCapabilities: {}`. It cannot
|
|
530
|
+
* call tools, open links, or write context; it only listens.
|
|
531
|
+
*
|
|
532
|
+
* Wire contract implemented (app side):
|
|
533
|
+
* - `ui/initialize` request → await result → `ui/notifications/initialized`.
|
|
534
|
+
* - Listens for `ui/notifications/tool-input`, `ui/notifications/tool-result`
|
|
535
|
+
* and `ui/notifications/tool-cancelled`; ignores everything else.
|
|
536
|
+
* - The result payload is the standard `CallToolResult` from
|
|
537
|
+
* `execute_machine`: `structuredContent` is either
|
|
538
|
+
* `{ output, approvals, logs }` or (with `isError`) the structured error
|
|
539
|
+
* `{ phase, message, hint, logs }`.
|
|
540
|
+
*/
|
|
541
|
+
/** URI the dashboard is served under. MCP Apps mandates the ui:// scheme. */
|
|
542
|
+
declare const DASHBOARD_RESOURCE_URI = "ui://projection/dashboard.html";
|
|
543
|
+
/** MIME type the MCP Apps spec mandates for app HTML resources. */
|
|
544
|
+
declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
545
|
+
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";
|
|
546
|
+
//#endregion
|
|
511
547
|
//#region src/errors.d.ts
|
|
512
548
|
/**
|
|
513
549
|
* Error carrying the structured `isError` body every failure returns (R25).
|
|
@@ -858,5 +894,5 @@ declare function runSegment(options: RunSegmentOptions): Promise<SegmentOutcome>
|
|
|
858
894
|
*/
|
|
859
895
|
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
896
|
//#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 };
|
|
897
|
+
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
898
|
//# 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;;;;;;;;;iBAUM,eACpB,MAAM,oBACN,MAAM,qBACL,QAAQ;;;;
|
|
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.3.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.3.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;
|
|
@@ -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,
|
|
@@ -2875,7 +3100,8 @@ var Facade = class {
|
|
|
2875
3100
|
server.registerTool("execute_machine", {
|
|
2876
3101
|
title: "Execute a state machine",
|
|
2877
3102
|
description: EXECUTE_MACHINE_DESCRIPTION,
|
|
2878
|
-
inputSchema: EXECUTE_MACHINE_INPUT_SCHEMA
|
|
3103
|
+
inputSchema: EXECUTE_MACHINE_INPUT_SCHEMA,
|
|
3104
|
+
_meta: { ui: { resourceUri: DASHBOARD_RESOURCE_URI } }
|
|
2879
3105
|
}, async (args, ctx) => await this.executeMachine({
|
|
2880
3106
|
code: args.code,
|
|
2881
3107
|
...args.lang !== void 0 ? { lang: args.lang } : {},
|
|
@@ -2890,7 +3116,8 @@ var Facade = class {
|
|
|
2890
3116
|
}, () => this.discoverApis());
|
|
2891
3117
|
for (const resource of this.resources) server.registerResource(resource.name, resource.uri, {
|
|
2892
3118
|
description: resource.description,
|
|
2893
|
-
mimeType: resource.mimeType
|
|
3119
|
+
mimeType: resource.mimeType,
|
|
3120
|
+
...resource._meta !== void 0 ? { _meta: resource._meta } : {}
|
|
2894
3121
|
}, () => ({ contents: [{
|
|
2895
3122
|
uri: resource.uri,
|
|
2896
3123
|
mimeType: resource.mimeType,
|
|
@@ -2924,6 +3151,6 @@ const EXECUTE_MACHINE_INPUT_SCHEMA = z.object({
|
|
|
2924
3151
|
input: z.unknown().optional().describe("Passed to the machine as its `input`.")
|
|
2925
3152
|
});
|
|
2926
3153
|
//#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 };
|
|
3154
|
+
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
3155
|
|
|
2929
3156
|
//# sourceMappingURL=index.mjs.map
|