@ggui-ai/mcp-server 0.6.3 → 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/dist/api-renders-routes.d.ts.map +1 -1
- package/dist/api-renders-routes.js +9 -1
- package/dist/browser-cors.d.ts +29 -0
- package/dist/browser-cors.d.ts.map +1 -0
- package/dist/browser-cors.js +64 -0
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +5 -1
- package/dist/code-store-fs.d.ts +3 -0
- package/dist/code-store-fs.d.ts.map +1 -1
- package/dist/code-store-fs.js +27 -3
- package/dist/console-session-routes.d.ts +10 -5
- package/dist/console-session-routes.d.ts.map +1 -1
- package/dist/console-session-routes.js +10 -5
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.js +12 -0
- package/dist/ggui-session-channel/socket-router.d.ts +33 -0
- package/dist/ggui-session-channel/socket-router.d.ts.map +1 -1
- package/dist/ggui-session-channel/socket-router.js +155 -0
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscribe.js +43 -2
- package/dist/ggui-session-channel.d.ts +114 -0
- package/dist/ggui-session-channel.d.ts.map +1 -1
- package/dist/ggui-session-channel.js +77 -2
- package/dist/health-routes.d.ts +3 -0
- package/dist/health-routes.d.ts.map +1 -1
- package/dist/health-routes.js +11 -1
- package/dist/mcp-apps-outbound.d.ts +236 -31
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +940 -261
- package/dist/origin-validation.d.ts +120 -0
- package/dist/origin-validation.d.ts.map +1 -0
- package/dist/origin-validation.js +199 -0
- package/dist/render-read-gate.d.ts +50 -0
- package/dist/render-read-gate.d.ts.map +1 -0
- package/dist/render-read-gate.js +36 -0
- package/dist/runtime-bundle-route.d.ts +15 -0
- package/dist/runtime-bundle-route.d.ts.map +1 -1
- package/dist/runtime-bundle-route.js +20 -4
- package/dist/server.d.ts +227 -9
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +292 -28
- package/package.json +12 -12
|
@@ -32,8 +32,11 @@
|
|
|
32
32
|
* same `@ggui-ai/mcp-server` instance that mints the bootstrap.
|
|
33
33
|
*/
|
|
34
34
|
import type { BlueprintIndex, GguiSessionStore, VectorStore } from "@ggui-ai/mcp-server-core";
|
|
35
|
+
import { type BlueprintDurabilityDeps } from "@ggui-ai/mcp-server-handlers/renders";
|
|
35
36
|
import { type McpAppAiGguiRenderMeta } from "@ggui-ai/protocol/integrations/mcp-apps";
|
|
36
37
|
import { type McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
38
|
+
import type { HandlerContext } from "@ggui-ai/mcp-server-handlers";
|
|
39
|
+
import type { Logger } from "./logger.js";
|
|
37
40
|
export declare const GGUI_RENDER_SHELL_HTML = "<!doctype html>\n<html lang=\"en\" style=\"height:100%;background-color:var(--ggui-color-surface, #1e293b)\"><head><meta charset=\"utf-8\"><title>ggui render</title></head>\n<body style=\"margin:0;height:100%;min-height:480px;background-color:var(--ggui-color-surface, #1e293b)\"><div id=\"ggui-root\" data-ggui-shell=\"thin\" style=\"height:100%;min-height:480px\"></div>\n<script>\n(function(){'use strict';\n// MCP Apps shell. Speaks the canonical postMessage protocol from\n// @modelcontextprotocol/ext-apps:\n// 1. iframe -> host: ui/initialize\n// 2. iframe -> host: ui/notifications/initialized\n// 3. host -> iframe: ui/notifications/tool-result (per CallToolResult)\n// On tool-result, read the slice envelope from _meta (spec-canonical\n// CallToolResult _meta at the top level), set window.__GGUI_META__ to\n// the envelope, fetch runtime as blob, inject as script.\n// Runtime auto-mounts inline. No nested iframe (claudemcpcontent.com\n// CSP frame-src forbids cross-origin frames). State machine matches\n// buildSelfContainedShell so the same runtime mounts both paths.\n//\n// R5 (2026-05-26): the historic /r/<shortCode> HTTP fallback was\n// removed along with the bearer-by-obscurity model -- hosts that strip\n// _meta no longer have a recovery path here. Spec-canonical hosts\n// deliver _meta inline and are unaffected.\n//\n// Phase B (2026-05-27): the historic two-slice envelope\n// (`ai.ggui/session` + `ai.ggui/stack-item`) collapsed to ONE flat\n// `ai.ggui/render` slice. runtimeUrl now lives directly on the\n// render slice; sessionId is the canonical identity.\nvar rpcId=1,pending={};\nvar rootEl=document.getElementById('ggui-root');\nrootEl.style.cssText='display:flex;flex-direction:column;height:100%;min-height:300px;margin:0';\nvar mounted=false;\nfunction setOverlay(text){\n if(mounted)return;\n rootEl.innerHTML='<div style=\"font:14px system-ui,sans-serif;padding:24px;color:#666\">'+text+'</div>';\n}\nfunction postNotification(method,params){\n try{window.parent.postMessage({jsonrpc:'2.0',method:method,params:params||{}},'*');}catch(e){}\n}\nfunction postRpc(method,params){\n return new Promise(function(res,rej){\n var id=rpcId++;pending[id]={res:res,rej:rej};\n try{window.parent.postMessage({jsonrpc:'2.0',id:id,method:method,params:params||{}},'*');}\n catch(e){delete pending[id];rej(e);}\n });\n}\nfunction postBootstrapFailed(reason,message){\n // Surface every shell-layer bootstrap-failure path as a typed\n // RendererBootFailedMessage envelope so hosts pinning the C9\n // error pane (McpAppIframe onError, IframeErrorPane) see the\n // failure instead of staring at the inert overlay until the test\n // times out. Reason codes match BootstrapFailureReason.\n try{window.parent.postMessage({type:'ggui:bootstrap-failed',reason:reason,message:message},'*');}catch(e){}\n}\nasync function mountFromMeta(envelope){\n if(mounted)return;\n // Slice envelope shape (Phase B): { \"ai.ggui/render\": { sessionId,\n // appId, runtimeUrl, ... } }. runtimeUrl on the render slice is\n // the only load-bearing field at the shell layer \u2014 it tells us\n // which iframe-runtime bundle to fetch. Everything else is\n // optional; the runtime decides at boot time based on the meta\n // it reads from window.__GGUI_META__.\n var renderSlice=envelope&&envelope['ai.ggui/render'];\n var runtimeUrl=renderSlice&&renderSlice.runtimeUrl;\n if(!envelope||typeof runtimeUrl!=='string'){\n setOverlay('Bootstrap payload malformed.');\n postBootstrapFailed('MALFORMED_BOOTSTRAP','Bootstrap payload malformed.');\n return;\n }\n setOverlay('Loading UI\u2026');\n window.__GGUI_META__=envelope;\n // Load the runtime bundle via a direct cross-origin script tag\n // (governed by CSP script-src) instead of fetch + Blob (governed by\n // CSP connect-src). claude.ai's claudemcpcontent.com iframe CSP\n // forbids cross-origin connect-src so fetch throws TypeError\n // 'Failed to fetch', but allows cross-origin script-src when the\n // bundle responds with the right CORS headers (the iframe-runtime\n // mount sets them). The self-contained shell already uses this\n // pattern; legacy postMessage shell now matches it.\n try{\n var s=document.createElement('script');\n s.type='module';\n // crossorigin=anonymous opts into CORS-mode error reporting.\n // Without it, cross-origin script tags get a sanitized\n // \"script error\" with no details, masking the real cause\n // (CSP block, CORS reject, module-evaluation throw). With it,\n // the error event surfaces the actual message in the iframe\n // console -- the bundle ships ACAO=* so credentialed mode is\n // unnecessary.\n s.crossOrigin='anonymous';\n s.src=runtimeUrl;\n s.onload=function(){mounted=true;};\n s.onerror=function(e){\n var msg='Runtime bundle failed to load: '+(e&&e.message||'script error');\n setOverlay(msg);\n postBootstrapFailed('BUNDLE_FETCH_FAILED',msg);\n };\n rootEl.innerHTML='';\n document.body.appendChild(s);\n }catch(e){\n var msg='Runtime bundle failed to load: '+(e&&e.message||e);\n setOverlay(msg);\n postBootstrapFailed('BUNDLE_FETCH_FAILED',msg);\n }\n}\nfunction readMetaFromCallToolResult(params){\n // MCP Apps spec (specification/2026-01-26/apps.mdx:1145-1155):\n // ui/notifications/tool-result\n // params: CallToolResult // Standard MCP type\n // So params IS the CallToolResult and _meta lives at the top\n // level. Spec-compliant hosts (Claude Desktop, claude.ai\n // Connector, Claude Code) deliver slice-envelope material here.\n // Single slice-envelope key (Phase B: ai.ggui/render). Only the\n // render slice's runtimeUrl is load-bearing at the shell layer;\n // the runtime reads everything else off window.__GGUI_META__\n // after we set it.\n if(!params||typeof params!=='object')return null;\n var meta=params._meta;\n if(!meta||typeof meta!=='object')return null;\n var renderSlice=meta['ai.ggui/render'];\n if(!renderSlice||typeof renderSlice!=='object')return null;\n if(typeof renderSlice.runtimeUrl!=='string')return null;\n return meta;\n}\nwindow.addEventListener('message',function(ev){\n var m=ev&&ev.data;\n if(!m||m.jsonrpc!=='2.0')return;\n if(m.id!=null&&pending[m.id]){\n var p=pending[m.id];delete pending[m.id];\n if(m.error)p.rej(m.error);else p.res(m.result);\n return;\n }\n if(m.method==='ui/notifications/tool-result'){\n // Spec-compliant hosts: m.params IS the CallToolResult; _meta is\n // at the top level.\n var specMeta=readMetaFromCallToolResult(m.params);\n if(specMeta){mountFromMeta(specMeta);return;}\n // R5 (2026-05-26) -- the /r/<shortCode> HTTP fallback was removed\n // along with the bearer-by-obscurity model. Hosts that strip\n // _meta on the tool-result wire have no fallback path here;\n // spec-canonical hosts deliver meta inline and land in the branch\n // above.\n }\n});\nsetOverlay('Initializing\u2026');\nvar initTimer=setTimeout(function(){\n setOverlay('Host did not respond to ui/initialize within 3s.');\n},3000);\npostRpc('ui/initialize',{\n appCapabilities:{},\n appInfo:{name:'ggui-render',version:'1.0.0'},\n protocolVersion:'2026-01-26'\n}).then(function(){\n clearTimeout(initTimer);\n postNotification('ui/notifications/initialized',{});\n // Wait for the host to send ui/notifications/tool-result carrying\n // the slice envelope in _meta \u2014 the spec-canonical delivery channel.\n // The ui/initialize result itself carries no slice meta (the\n // McpUiInitializeResult schema defines no such field).\n setOverlay('Waiting for tool result\u2026');\n}).catch(function(e){\n clearTimeout(initTimer);\n setOverlay('ui/initialize failed: '+(e&&e.message||JSON.stringify(e)));\n});\n})();\n</script></body></html>";
|
|
38
41
|
/**
|
|
39
42
|
* CSP `script-src` source expression that authorises the inline
|
|
@@ -75,7 +78,41 @@ export declare const GGUI_RENDER_SHELL_HTML = "<!doctype html>\n<html lang=\"en\
|
|
|
75
78
|
* the CSP it inherits.
|
|
76
79
|
*/
|
|
77
80
|
export declare const GGUI_RENDER_SHELL_SCRIPT_HASH: string;
|
|
78
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Build the INLINE-RUNTIME static shell: a standalone document carrying
|
|
83
|
+
* the iframe-runtime bundle in its own bytes instead of an external
|
|
84
|
+
* `<script src>` tag. For MCP Apps hosts whose iframe CSP forbids
|
|
85
|
+
* external `script-src` while permitting inline scripts — the thin
|
|
86
|
+
* postMessage shell can never load its runtime there, so the shell IS
|
|
87
|
+
* the runtime.
|
|
88
|
+
*
|
|
89
|
+
* Per-render state does NOT live here (same posture as the thin
|
|
90
|
+
* shell): the host delivers it via `ui/notifications/tool-result`,
|
|
91
|
+
* caught either by the buffer script (pre-parse arrivals) or by the
|
|
92
|
+
* runtime's own autostart listener. Live-channel / codeUrl fetches are
|
|
93
|
+
* unavailable under the CSP this shell targets; delivered meta is
|
|
94
|
+
* expected to carry the fetch-free channels (inline `codeB64`, inline
|
|
95
|
+
* `propsJson`).
|
|
96
|
+
*
|
|
97
|
+
* Served per-mount via `installMcpAppsOutbound({ shellHtml })` — the
|
|
98
|
+
* module-level thin-shell constants (and their pinned CSP hash) are
|
|
99
|
+
* deliberately untouched.
|
|
100
|
+
*/
|
|
101
|
+
export declare function buildInlineRenderShellHtml(runtimeSource: string): string;
|
|
102
|
+
export declare function registerGguiRenderResource(server: McpServer, shellHtml?: string, publicBaseUrl?: string,
|
|
103
|
+
/**
|
|
104
|
+
* Absolute runtime-bundle URL used as the CSP-declaration fallback
|
|
105
|
+
* when `publicBaseUrl` is absent — same posture as the per-render
|
|
106
|
+
* template registration ({@link buildCspMeta}'s second parameter).
|
|
107
|
+
* Deployments that publish an absolute `runtime.url` but
|
|
108
|
+
* deliberately do NOT set `publicBaseUrl` (it also feeds
|
|
109
|
+
* Origin/Host enforcement and OAuth) still get
|
|
110
|
+
* `_meta.ui.csp.{connectDomains,resourceDomains}` on the static
|
|
111
|
+
* resource read; before this fallback those reads carried no
|
|
112
|
+
* declaration at all and spec-compliant hosts applied the
|
|
113
|
+
* restrictive default (`connect-src 'none'`).
|
|
114
|
+
*/
|
|
115
|
+
runtimeUrl?: string): void;
|
|
79
116
|
/**
|
|
80
117
|
* Advertise the `io.modelcontextprotocol/ui` extension capability on
|
|
81
118
|
* an `McpServer`'s underlying `Server`. Idempotent - calling twice on
|
|
@@ -113,6 +150,16 @@ export interface SelfContainedShellInputs {
|
|
|
113
150
|
* renders without re-parsing.
|
|
114
151
|
*/
|
|
115
152
|
readonly codeHash?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Base64-encoded compiled component source inlined on the bootstrap
|
|
155
|
+
* — the fetch-free twin of {@link codeUrl}, decoded by the
|
|
156
|
+
* iframe-runtime instead of fetched. May coexist with codeUrl
|
|
157
|
+
* (consumers prefer the inline bytes); mutually exclusive with
|
|
158
|
+
* {@link systemKind}. For hosts whose iframe CSP blocks the codeUrl
|
|
159
|
+
* fetch, and for deployments whose code store is unwired or down —
|
|
160
|
+
* the inline bytes make the shell mountable independently of both.
|
|
161
|
+
*/
|
|
162
|
+
readonly codeB64?: string;
|
|
116
163
|
/**
|
|
117
164
|
* System-card kind identifier, mapped at runtime against the
|
|
118
165
|
* built-in `SYSTEM_CARD_REGISTRY`. Mutually exclusive with
|
|
@@ -281,20 +328,6 @@ export interface SelfContainedShellInputs {
|
|
|
281
328
|
* @public
|
|
282
329
|
*/
|
|
283
330
|
export declare function buildSelfContainedShell(opts: SelfContainedShellInputs): string;
|
|
284
|
-
/**
|
|
285
|
-
* Minimal "loading" HTML served when a per-render resource is fetched
|
|
286
|
-
* for a render whose visible-bits surface has no componentCode yet
|
|
287
|
-
* (placeholder, generation in flight). Renders a tiny status surface
|
|
288
|
-
* so hosts that pin lifecycle selectors don't see a blank document.
|
|
289
|
-
*
|
|
290
|
-
* Hosts SHOULD re-fetch when they observe additional `ggui_render`
|
|
291
|
-
* results on the same render — the per-call `_meta.ui.resourceUri`
|
|
292
|
-
* value stays stable across commits for a render, so re-fetching the
|
|
293
|
-
* same URI returns fresher HTML on the second try.
|
|
294
|
-
*
|
|
295
|
-
* @public
|
|
296
|
-
*/
|
|
297
|
-
export declare function buildSelfContainedLoadingShell(sessionId: string): string;
|
|
298
331
|
/**
|
|
299
332
|
* Options for {@link registerGguiRenderResourceTemplate}.
|
|
300
333
|
*
|
|
@@ -310,10 +343,13 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
310
343
|
* Content-addressable code-blob store. When wired alongside
|
|
311
344
|
* {@link codeBaseUrl}, the resource template hashes the render's
|
|
312
345
|
* componentCode, writes it to the store, and inlines the resulting
|
|
313
|
-
* `codeUrl` into the shell bootstrap.
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
346
|
+
* `codeUrl` into the shell bootstrap.
|
|
347
|
+
*
|
|
348
|
+
* This is one of the two delivery channels; {@link mintWsToken} is
|
|
349
|
+
* the other, and a compiled component needs at least one of them. A
|
|
350
|
+
* read that resolves a render this server can deliver by neither
|
|
351
|
+
* fails with `NOT_MOUNTABLE` rather than returning a shell that would
|
|
352
|
+
* never paint.
|
|
317
353
|
*/
|
|
318
354
|
readonly codeStore?: import("@ggui-ai/mcp-server-core").CodeStore;
|
|
319
355
|
/**
|
|
@@ -339,6 +375,68 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
339
375
|
* at hook-mount with a clear "not provided" message).
|
|
340
376
|
*/
|
|
341
377
|
readonly appMetadataStore?: import("@ggui-ai/mcp-server-core").AppMetadataStore;
|
|
378
|
+
/**
|
|
379
|
+
* Durable per-session identity records. When wired alongside
|
|
380
|
+
* {@link durableBlueprints}, a read of a locator whose render row is
|
|
381
|
+
* GONE resolves the record instead of giving up: the render is
|
|
382
|
+
* re-created from it and mounts live, with the props it last
|
|
383
|
+
* carried.
|
|
384
|
+
*
|
|
385
|
+
* Absent ⇒ neither store is consulted, and `NOT_SUPPORTED` takes
|
|
386
|
+
* `NOT_FOUND`'s place wholesale — the honest answer for a server on
|
|
387
|
+
* which an evicted locator can never come back. Wholesale is the
|
|
388
|
+
* load-bearing word: it answers for a locator that never existed AND
|
|
389
|
+
* for one whose row exists but the caller may not read, so the choice
|
|
390
|
+
* of code says nothing about which locators exist. Reads that get far
|
|
391
|
+
* enough to fail `NOT_MOUNTABLE` still do — that verdict is about the
|
|
392
|
+
* caller's own render, not about this server's memory.
|
|
393
|
+
*
|
|
394
|
+
* Binding a store whose records do not outlive the render rows
|
|
395
|
+
* themselves buys nothing — the record is read precisely when the
|
|
396
|
+
* row is gone.
|
|
397
|
+
*/
|
|
398
|
+
readonly renderIdentityStore?: import("@ggui-ai/mcp-server-core").RenderIdentityStore;
|
|
399
|
+
/**
|
|
400
|
+
* Durable blueprint pair — row metadata plus the compiled body
|
|
401
|
+
* behind its content hash. The re-mint path needs BOTH halves: the
|
|
402
|
+
* record names a blueprint, the blueprint names a body, and the body
|
|
403
|
+
* is what a re-created render mounts. A pair carrying only
|
|
404
|
+
* `blueprintStore` persists metadata for other consumers but cannot
|
|
405
|
+
* complete a re-mint, so the path skips as if unwired.
|
|
406
|
+
*
|
|
407
|
+
* Same shape the registration path writes through, so a deployment
|
|
408
|
+
* threads one pair to both ends.
|
|
409
|
+
*/
|
|
410
|
+
readonly durableBlueprints?: BlueprintDurabilityDeps;
|
|
411
|
+
/**
|
|
412
|
+
* Render-row retention window in ms — the SAME operator knob
|
|
413
|
+
* `ggui_render` stamps new renders with. The read path spends it in
|
|
414
|
+
* two places, and both are lifecycle decisions about a row this
|
|
415
|
+
* handler is putting back into service:
|
|
416
|
+
*
|
|
417
|
+
* - a re-mint commits its reconstructed row with this lifetime;
|
|
418
|
+
* - a read of a row that is present but PAST its expiry gives the
|
|
419
|
+
* row this lifetime again, so the live-channel token minted in
|
|
420
|
+
* the same read cannot outlive the row it addresses.
|
|
421
|
+
*
|
|
422
|
+
* Absent ⇒ one hour, matching `ggui_render`'s own fallback. Setting
|
|
423
|
+
* it on a deployment whose renders live far longer than an hour is
|
|
424
|
+
* what stops a rehydrated render from being quietly demoted to a
|
|
425
|
+
* fraction of its neighbours' lifetime.
|
|
426
|
+
*/
|
|
427
|
+
readonly renderTtlMs?: number;
|
|
428
|
+
/**
|
|
429
|
+
* #457 — total-lifetime bound on RESURRECTION: an expired row's read
|
|
430
|
+
* (and a re-mint's fresh commit) may never advance `expiresAt` past
|
|
431
|
+
* `createdAt + maxRenderLifetimeMs`. Unset = unbounded, today's
|
|
432
|
+
* behavior — the knob exists because operator-set short TTLs are
|
|
433
|
+
* exactly where uncapped in-grace self-extension keeps a PII row
|
|
434
|
+
* alive forever on one poll per (TTL + grace). Live-row heartbeats
|
|
435
|
+
* are deliberately NOT capped (active-use lease renewal is intended);
|
|
436
|
+
* rows whose `createdAt` projects the legacy 0 sentinel are exempt
|
|
437
|
+
* (a cap keyed on 0 would mass-kill pre-column rows).
|
|
438
|
+
*/
|
|
439
|
+
readonly maxRenderLifetimeMs?: number;
|
|
342
440
|
/**
|
|
343
441
|
* Vector store backing the blueprint registry. When wired alongside
|
|
344
442
|
* `defaultAppIdFallback`, the resource handler runs a registry-only
|
|
@@ -346,9 +444,26 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
346
444
|
* (`ui://ggui/render/{sessionId}/{blueprintKey}`): if the render is
|
|
347
445
|
* gone but the blueprint registry still holds the entry, return the
|
|
348
446
|
* static initial render (default props + default context) instead of
|
|
349
|
-
* the
|
|
350
|
-
*
|
|
351
|
-
*
|
|
447
|
+
* failing the read.
|
|
448
|
+
*
|
|
449
|
+
* The lookup is keyed by the caller-supplied `blueprintKey` under
|
|
450
|
+
* `defaultAppIdFallback` alone — it never reads the render row — so
|
|
451
|
+
* it answers the same for a caller who may not read the row as for
|
|
452
|
+
* one probing a locator that never existed. That is what keeps it
|
|
453
|
+
* safe to run on a refused read, which it must, or refusal would
|
|
454
|
+
* become distinguishable from a miss.
|
|
455
|
+
*
|
|
456
|
+
* Leaving both options undefined does NOT return callers to a
|
|
457
|
+
* placeholder shell — there is no longer one to return. It removes
|
|
458
|
+
* the third resolution, so a read that neither the row nor a re-mint
|
|
459
|
+
* can serve fails typed: `NOT_FOUND`, or `NOT_SUPPORTED` on a
|
|
460
|
+
* deployment that also keeps no durable record, or `NOT_MOUNTABLE`
|
|
461
|
+
* where the row is the caller's own and simply has no component yet.
|
|
462
|
+
* Deployments serving
|
|
463
|
+
* more than one tenant from one registry scope are the reason the
|
|
464
|
+
* option exists at all: the fallback discloses whether a blueprint
|
|
465
|
+
* key exists under that scope, so leave it unset if that is not
|
|
466
|
+
* acceptable.
|
|
352
467
|
*/
|
|
353
468
|
readonly vectorStore?: VectorStore;
|
|
354
469
|
/**
|
|
@@ -363,10 +478,17 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
363
478
|
/**
|
|
364
479
|
* App-id used for blueprint-registry scoping when the render has
|
|
365
480
|
* been evicted. The registry is per-`appId`, but a missing render
|
|
366
|
-
* has no way to derive
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
481
|
+
* has no way to derive whose it was, so the fallback needs one scope
|
|
482
|
+
* named up front. Set to `'builder'` (the universal-MCP default
|
|
483
|
+
* identity) and rehydrate works across render expiry / process
|
|
484
|
+
* restart.
|
|
485
|
+
*
|
|
486
|
+
* Leaving it undefined disables the fallback entirely — the reads it
|
|
487
|
+
* would have served fail typed instead (`NOT_FOUND`, or
|
|
488
|
+
* `NOT_SUPPORTED` where no durable record is kept). That is the
|
|
489
|
+
* setting for a deployment that cannot accept the fallback answering
|
|
490
|
+
* "a blueprint with this key exists under this scope" to whoever
|
|
491
|
+
* asks; it is not a way to get a gentler response.
|
|
370
492
|
*/
|
|
371
493
|
readonly defaultAppIdFallback?: string;
|
|
372
494
|
/**
|
|
@@ -403,6 +525,21 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
403
525
|
readonly token: string;
|
|
404
526
|
readonly expiresAt: string;
|
|
405
527
|
};
|
|
528
|
+
/**
|
|
529
|
+
* Per-request handler-context accessor — the SAME AsyncLocalStorage
|
|
530
|
+
* read the tool path uses. The per-session resource handler gates
|
|
531
|
+
* reads on it (render-read-gate.ts). Absent ⇒ the handler fails
|
|
532
|
+
* closed for rows scoped to any app other than the single-tenant
|
|
533
|
+
* default (compose paths that cannot thread a context keep working
|
|
534
|
+
* for OSS single-tenant flows only).
|
|
535
|
+
*/
|
|
536
|
+
readonly getContext?: () => HandlerContext | undefined;
|
|
537
|
+
/**
|
|
538
|
+
* Structured logger for warn-level denial audit lines
|
|
539
|
+
* (`render_resource_read_denied`). Absent ⇒ denials are silent
|
|
540
|
+
* server-side (still enforced — only the log line is skipped).
|
|
541
|
+
*/
|
|
542
|
+
readonly logger?: Logger;
|
|
406
543
|
}
|
|
407
544
|
/**
|
|
408
545
|
* Register a `ui://ggui/render/{sessionId}` resource template. Each
|
|
@@ -416,11 +553,79 @@ export interface GguiRenderResourceTemplateOptions {
|
|
|
416
553
|
* legacy postMessage shell at the static URI, self-contained shell at
|
|
417
554
|
* the templated URI.
|
|
418
555
|
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
556
|
+
* # The obligation
|
|
557
|
+
*
|
|
558
|
+
* A read returns EITHER a shell carrying mount material — a static
|
|
559
|
+
* component URL, a live channel, or a system card — OR exactly one
|
|
560
|
+
* typed JSON-RPC error. There is no third outcome, and in particular no
|
|
561
|
+
* successful result wrapping a shell that can never paint anything. A
|
|
562
|
+
* host can check this without trusting the server: if it got
|
|
563
|
+
* `contents`, it got something mountable.
|
|
564
|
+
*
|
|
565
|
+
* The obligation covers outcomes this server can DECIDE. A malfunction
|
|
566
|
+
* still reaches the caller as an internal error (`-32603`) carrying
|
|
567
|
+
* none of the four codes: a template wired with an empty `runtimeUrl`,
|
|
568
|
+
* or a delivery channel that faults **and leaves the read with no other
|
|
569
|
+
* channel to mount through**. A fault the read survives — the usual
|
|
570
|
+
* case on a deployment wiring both channels — is not an outcome at all;
|
|
571
|
+
* the render mounts through whatever is left. That split is deliberate:
|
|
572
|
+
* `-32603` says "something is broken here", which the four codes must
|
|
573
|
+
* never be diluted into claiming, and equally must not be raised over a
|
|
574
|
+
* blip the server routed around.
|
|
575
|
+
*
|
|
576
|
+
* Three resolutions are tried, in this order, and any of them can
|
|
577
|
+
* produce the mount:
|
|
578
|
+
*
|
|
579
|
+
* 1. The render row itself.
|
|
580
|
+
* 2. A re-mint from the durable identity record, when the row is gone
|
|
581
|
+
* and this server keeps one ({@link GguiRenderResourceTemplateOptions.renderIdentityStore}
|
|
582
|
+
* + {@link GguiRenderResourceTemplateOptions.durableBlueprints}).
|
|
583
|
+
* 3. The blueprint registry, keyed by the locator's own `blueprintKey`
|
|
584
|
+
* — the original component with its authoring-time defaults rather
|
|
585
|
+
* than the state the render last held.
|
|
586
|
+
*
|
|
587
|
+
* # Failure modes
|
|
588
|
+
*
|
|
589
|
+
* Which code a given read produces is fully predictable from two facts:
|
|
590
|
+
* whether this server binds a durable substrate (both
|
|
591
|
+
* {@link GguiRenderResourceTemplateOptions.renderIdentityStore} and
|
|
592
|
+
* {@link GguiRenderResourceTemplateOptions.durableBlueprints} — either
|
|
593
|
+
* one alone is as good as neither), and how far the read got.
|
|
594
|
+
*
|
|
595
|
+
* - `NOT_FOUND` (`-32002`) — nothing resolved the locator, **and** the
|
|
596
|
+
* response for a caller who may not read a locator that DOES
|
|
597
|
+
* resolve. Those two are byte-identical by construction: both route
|
|
598
|
+
* through the protocol's projection, which substitutes a constant
|
|
599
|
+
* message and drops `detail`. A distinguishable refusal would turn
|
|
600
|
+
* this read into an oracle for the existence of other callers'
|
|
601
|
+
* renders, so the equality is a security property, not a courtesy.
|
|
602
|
+
* - `NOT_SUPPORTED` (`-32006`) — the same two cases, on a server with
|
|
603
|
+
* no durable substrate: an evicted locator can never be restored
|
|
604
|
+
* here, so saying "not found" would understate it. It takes
|
|
605
|
+
* `NOT_FOUND`'s place WHOLESALE on such a server rather than
|
|
606
|
+
* answering for some locators and not others — a server that said
|
|
607
|
+
* `NOT_FOUND` for a row it refused and `NOT_SUPPORTED` for one that
|
|
608
|
+
* never existed would have rebuilt the same oracle out of the two
|
|
609
|
+
* codes. Correspondingly, a server that DOES bind the substrate
|
|
610
|
+
* never emits it.
|
|
611
|
+
* - `BLUEPRINT_UNRESOLVABLE` (`-32006`) — a record named the render
|
|
612
|
+
* but its component is gone; `detail` names which link broke.
|
|
613
|
+
* Reachable only after the access check.
|
|
614
|
+
* - `NOT_MOUNTABLE` (`-32006`) — something resolved, but nothing
|
|
615
|
+
* mountable can be produced from it: no delivery channel is wired
|
|
616
|
+
* (neither {@link GguiRenderResourceTemplateOptions.codeStore} nor
|
|
617
|
+
* {@link GguiRenderResourceTemplateOptions.mintWsToken}), the row's
|
|
618
|
+
* generation has not committed a component yet, or a registry
|
|
619
|
+
* blueprint matched but cannot be delivered. Unlike the pair above,
|
|
620
|
+
* this one does NOT vary with the substrate: it is what the
|
|
621
|
+
* caller's OWN row gets on every server, because "this server
|
|
622
|
+
* cannot rehydrate" is not the useful truth for a row that is
|
|
623
|
+
* sitting right there. Reachable only after the access check, or —
|
|
624
|
+
* for the registry case — off the caller's own supplied key, so it
|
|
625
|
+
* discloses nothing either way.
|
|
626
|
+
*
|
|
627
|
+
* A URI matching neither template never reaches any of this: the
|
|
628
|
+
* transport rejects it as invalid params, outside these four codes.
|
|
424
629
|
*
|
|
425
630
|
* Returns nothing; mutates the server in place.
|
|
426
631
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,
|
|
1
|
+
{"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"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"}
|