@ggui-ai/mcp-server 0.6.2 → 0.7.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.
Files changed (36) hide show
  1. package/dist/api-renders-routes.d.ts.map +1 -1
  2. package/dist/api-renders-routes.js +9 -1
  3. package/dist/browser-cors.d.ts +29 -0
  4. package/dist/browser-cors.d.ts.map +1 -0
  5. package/dist/browser-cors.js +64 -0
  6. package/dist/build-mcp.d.ts.map +1 -1
  7. package/dist/build-mcp.js +5 -1
  8. package/dist/code-store-fs.d.ts +3 -0
  9. package/dist/code-store-fs.d.ts.map +1 -1
  10. package/dist/code-store-fs.js +27 -3
  11. package/dist/ggui-session-channel/outbound.d.ts.map +1 -1
  12. package/dist/ggui-session-channel/outbound.js +12 -0
  13. package/dist/ggui-session-channel/socket-router.d.ts +33 -0
  14. package/dist/ggui-session-channel/socket-router.d.ts.map +1 -1
  15. package/dist/ggui-session-channel/socket-router.js +155 -0
  16. package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
  17. package/dist/ggui-session-channel/subscribe.js +43 -2
  18. package/dist/ggui-session-channel.d.ts +114 -0
  19. package/dist/ggui-session-channel.d.ts.map +1 -1
  20. package/dist/ggui-session-channel.js +77 -2
  21. package/dist/health-routes.d.ts +3 -0
  22. package/dist/health-routes.d.ts.map +1 -1
  23. package/dist/health-routes.js +11 -1
  24. package/dist/mcp-apps-outbound.d.ts +191 -30
  25. package/dist/mcp-apps-outbound.d.ts.map +1 -1
  26. package/dist/mcp-apps-outbound.js +843 -223
  27. package/dist/origin-validation.d.ts +120 -0
  28. package/dist/origin-validation.d.ts.map +1 -0
  29. package/dist/origin-validation.js +199 -0
  30. package/dist/render-read-gate.d.ts +50 -0
  31. package/dist/render-read-gate.d.ts.map +1 -0
  32. package/dist/render-read-gate.js +36 -0
  33. package/dist/server.d.ts +164 -4
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +206 -20
  36. package/package.json +12 -12
@@ -60,6 +60,54 @@ import { type GguiSessionChannelBootstrap, type GguiSessionChannelCookieAuth } f
60
60
  import type { Logger } from "./logger.js";
61
61
  /** Default URL path for the channel endpoint. Operators can override. */
62
62
  export declare const DEFAULT_RENDER_CHANNEL_PATH = "/ws";
63
+ /**
64
+ * Coarse ws-level `maxPayload` memory backstop (1 MiB) applied to EVERY
65
+ * inbound frame on EVERY socket, INCLUDING already-subscribed ones —
66
+ * unlike the other three pre-subscribe caps in this file, this one is
67
+ * NOT subscriber-exempt. It bounds the absolute per-frame buffer a
68
+ * hostile peer can force before the frame is even assembled: a 100x
69
+ * reduction from the `ws` library's own ~100 MiB default, applied
70
+ * uniformly regardless of subscribe state.
71
+ *
72
+ * `ActionEnvelope` (the post-subscribe `action` payload) has no
73
+ * protocol-level max size, so this ceiling can NOT be sized to provably
74
+ * never clip a legitimate frame — it is a deliberately generous-but-
75
+ * finite backstop, not a guarantee. The closest documented protocol-
76
+ * level payload bound is `CONTEXT_SNAPSHOT_MAX_BYTES` (64 KiB, the
77
+ * `ggui_runtime_sync_context` MCP tool call — a related but distinct
78
+ * transport from this WS channel), which puts 1 MiB at roughly 16x
79
+ * headroom over the largest structured payload the protocol formally
80
+ * bounds. Operators whose legitimate `action` frames exceed 1 MiB
81
+ * (e.g. large form submissions) should raise {@link maxPayloadBytes},
82
+ * or set it to `0` to fall back to the `ws` library default. Distinct from
83
+ * the tight, pre-subscribe-only, subscriber-exempt
84
+ * {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}. Disable this one
85
+ * with `0`.
86
+ */
87
+ export declare const DEFAULT_WS_MAX_PAYLOAD_BYTES = 1048576;
88
+ /**
89
+ * Per-frame byte ceiling on PRE-SUBSCRIBE frames (64 KiB). Pre-subscribe
90
+ * traffic is tiny (a subscribe carrying a JWT is under 1 KiB), so this
91
+ * is ~70x headroom yet caps a pre-auth memory-abuse frame. Enforced
92
+ * per-frame, keyed on "not yet a subscriber", so post-subscribe frames
93
+ * are exempt. Disable with `0`.
94
+ */
95
+ export declare const DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES = 65536;
96
+ /**
97
+ * Grace window (30 s) an unauthenticated socket has to complete a valid
98
+ * subscribe before it is closed. Open→subscribe is normally sub-second;
99
+ * 30 s tolerates a slow bootstrap-token verify while bounding how long a
100
+ * credential-less socket holds a slot. Disable with `0`.
101
+ */
102
+ export declare const DEFAULT_PRE_SUBSCRIBE_IDLE_MS = 30000;
103
+ /**
104
+ * Concurrent PENDING (pre-subscribe) socket ceiling (1024). Honest
105
+ * clients leave the pending state in under a second, so 1024 in-flight
106
+ * handshakes is far beyond any real burst yet bounds a credential-less
107
+ * connection flood. Counts pending sockets only — never subscribers.
108
+ * Disable with `0`.
109
+ */
110
+ export declare const DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS = 1024;
63
111
  export type { GguiSessionChannelLocalToolsOptions } from "./ggui-session-channel/channel-subscriptions.js";
64
112
  export type { GguiSessionChannelBootstrap, GguiSessionChannelBootstrapRefreshResult, GguiSessionChannelBootstrapVerifyResult, GguiSessionChannelCookieAuth, } from "./ggui-session-channel/subscribe.js";
65
113
  export interface GguiSessionChannelOptions {
@@ -228,6 +276,58 @@ export interface GguiSessionChannelOptions {
228
276
  * identically in both modes.
229
277
  */
230
278
  readonly versionPolicy?: "advisory" | "reject";
279
+ /**
280
+ * Coarse ws-level `maxPayload` memory backstop (bytes) applied to
281
+ * EVERY inbound frame on EVERY socket, INCLUDING already-subscribed
282
+ * ones — the largest single frame the server will assemble before
283
+ * rejecting it (ws closes 1009). Distinct from
284
+ * {@link maxPreSubscribePayloadBytes}: that one is the tight,
285
+ * subscriber-exempt, credential-less bound; this one is a generous-
286
+ * but-finite global ceiling applied uniformly regardless of subscribe
287
+ * state.
288
+ *
289
+ * `ActionEnvelope` (the post-subscribe `action` payload) has no
290
+ * protocol-level max size, so this default can NOT be sized to
291
+ * provably never clip a legitimate frame — see
292
+ * {@link DEFAULT_WS_MAX_PAYLOAD_BYTES} for the sizing rationale.
293
+ * Operators expecting `action` frames larger than the default should
294
+ * raise this value.
295
+ *
296
+ * Defaults to {@link DEFAULT_WS_MAX_PAYLOAD_BYTES} (1 MiB). `0`
297
+ * disables the ws-level check (falls back to the ws library's own
298
+ * ~100 MiB default).
299
+ */
300
+ readonly maxPayloadBytes?: number;
301
+ /**
302
+ * Per-frame byte ceiling for PRE-SUBSCRIBE (not-yet-registered)
303
+ * sockets. A pre-subscribe frame larger than this closes the socket
304
+ * (1009) before it is parsed. Subscribed sockets are exempt — only
305
+ * the coarse {@link maxPayloadBytes} backstop applies to them.
306
+ *
307
+ * Defaults to {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}
308
+ * (64 KiB). `0` disables the pre-subscribe payload cap.
309
+ */
310
+ readonly maxPreSubscribePayloadBytes?: number;
311
+ /**
312
+ * Grace window (ms) a socket has to complete a valid subscribe before
313
+ * it is closed (1008). Armed on connection, cleared on successful
314
+ * subscribe — a registered subscriber is never reaped, so long-idle
315
+ * and reconnecting viewers keep the existing keepalive behavior.
316
+ *
317
+ * Defaults to {@link DEFAULT_PRE_SUBSCRIBE_IDLE_MS} (30 s). `0`
318
+ * disables the idle timeout.
319
+ */
320
+ readonly preSubscribeIdleMs?: number;
321
+ /**
322
+ * Concurrent PENDING (pre-subscribe) socket ceiling. A new upgrade
323
+ * that would exceed it is cleanly closed (1013). Counts only sockets
324
+ * that have not completed a valid subscribe — subscriber fan-out is
325
+ * never bounded here.
326
+ *
327
+ * Defaults to {@link DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS} (1024).
328
+ * `0` disables the ceiling.
329
+ */
330
+ readonly maxPreSubscribeConnections?: number;
231
331
  /**
232
332
  * Optional hook fired synchronously when the local subscriber count
233
333
  * for `sessionId` transitions 0 → 1 (the first subscriber for that
@@ -412,6 +512,20 @@ export interface GguiSessionChannelServer {
412
512
  readonly subscriberCount: number;
413
513
  /** Number of distinct renders with at least one subscriber. */
414
514
  readonly renderCount: number;
515
+ /**
516
+ * Monotonic counts of pre-subscribe cap-driven closures/refusals
517
+ * (ggui#444), surfaced on `/ggui/health` for operator diagnosis of a
518
+ * credential-less abuse burst. Each field only ever increases over
519
+ * the channel's lifetime:
520
+ * - `payload` — oversized pre-subscribe frames rejected (1009).
521
+ * - `idle` — sockets closed for never subscribing in time (1008).
522
+ * - `connection` — upgrades refused past the pending ceiling (1013).
523
+ */
524
+ readonly preSubscribeRejections: {
525
+ readonly payload: number;
526
+ readonly idle: number;
527
+ readonly connection: number;
528
+ };
415
529
  /**
416
530
  * Close every live subscriber + the underlying ws server. Idempotent.
417
531
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ggui-session-channel.d.ts","sourceRoot":"","sources":["../src/ggui-session-channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ggui-session-channel.d.ts","sourceRoot":"","sources":["../src/ggui-session-channel.ts"],"names":[],"mappings":"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"}
@@ -61,6 +61,54 @@ import { createSubscribeHandlers, } from "./ggui-session-channel/subscribe.js";
61
61
  import { createSubscriberLifecycle } from "./ggui-session-channel/subscriber-lifecycle.js";
62
62
  /** Default URL path for the channel endpoint. Operators can override. */
63
63
  export const DEFAULT_RENDER_CHANNEL_PATH = "/ws";
64
+ /**
65
+ * Coarse ws-level `maxPayload` memory backstop (1 MiB) applied to EVERY
66
+ * inbound frame on EVERY socket, INCLUDING already-subscribed ones —
67
+ * unlike the other three pre-subscribe caps in this file, this one is
68
+ * NOT subscriber-exempt. It bounds the absolute per-frame buffer a
69
+ * hostile peer can force before the frame is even assembled: a 100x
70
+ * reduction from the `ws` library's own ~100 MiB default, applied
71
+ * uniformly regardless of subscribe state.
72
+ *
73
+ * `ActionEnvelope` (the post-subscribe `action` payload) has no
74
+ * protocol-level max size, so this ceiling can NOT be sized to provably
75
+ * never clip a legitimate frame — it is a deliberately generous-but-
76
+ * finite backstop, not a guarantee. The closest documented protocol-
77
+ * level payload bound is `CONTEXT_SNAPSHOT_MAX_BYTES` (64 KiB, the
78
+ * `ggui_runtime_sync_context` MCP tool call — a related but distinct
79
+ * transport from this WS channel), which puts 1 MiB at roughly 16x
80
+ * headroom over the largest structured payload the protocol formally
81
+ * bounds. Operators whose legitimate `action` frames exceed 1 MiB
82
+ * (e.g. large form submissions) should raise {@link maxPayloadBytes},
83
+ * or set it to `0` to fall back to the `ws` library default. Distinct from
84
+ * the tight, pre-subscribe-only, subscriber-exempt
85
+ * {@link DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES}. Disable this one
86
+ * with `0`.
87
+ */
88
+ export const DEFAULT_WS_MAX_PAYLOAD_BYTES = 1_048_576;
89
+ /**
90
+ * Per-frame byte ceiling on PRE-SUBSCRIBE frames (64 KiB). Pre-subscribe
91
+ * traffic is tiny (a subscribe carrying a JWT is under 1 KiB), so this
92
+ * is ~70x headroom yet caps a pre-auth memory-abuse frame. Enforced
93
+ * per-frame, keyed on "not yet a subscriber", so post-subscribe frames
94
+ * are exempt. Disable with `0`.
95
+ */
96
+ export const DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES = 65_536;
97
+ /**
98
+ * Grace window (30 s) an unauthenticated socket has to complete a valid
99
+ * subscribe before it is closed. Open→subscribe is normally sub-second;
100
+ * 30 s tolerates a slow bootstrap-token verify while bounding how long a
101
+ * credential-less socket holds a slot. Disable with `0`.
102
+ */
103
+ export const DEFAULT_PRE_SUBSCRIBE_IDLE_MS = 30_000;
104
+ /**
105
+ * Concurrent PENDING (pre-subscribe) socket ceiling (1024). Honest
106
+ * clients leave the pending state in under a second, so 1024 in-flight
107
+ * handshakes is far beyond any real burst yet bounds a credential-less
108
+ * connection flood. Counts pending sockets only — never subscribers.
109
+ * Disable with `0`.
110
+ */
111
+ export const DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS = 1_024;
64
112
  /**
65
113
  * Build an OSS live-channel server. The returned object is designed to be
66
114
  * composed into `createGguiServer` — see `server.ts` for the wire-up.
@@ -73,9 +121,25 @@ export function createGguiSessionChannelServer(opts) {
73
121
  // Live-tail pub/sub. Default in-process; multi-process deployments
74
122
  // bind a pubsub-backed StreamFanout via `opts.streamFanout`.
75
123
  const streamFanout = opts.streamFanout ?? new InProcessStreamFanout();
124
+ // Pre-subscribe caps (ggui#444) — bound what a not-yet-subscribed
125
+ // (credential-less) socket can consume. Resolved once here; `0`
126
+ // disables a given cap. See the DEFAULT_* constants for rationale.
127
+ const wsMaxPayloadBytes = opts.maxPayloadBytes ?? DEFAULT_WS_MAX_PAYLOAD_BYTES;
128
+ const preSubscribeCaps = {
129
+ maxPayloadBytes: opts.maxPreSubscribePayloadBytes ?? DEFAULT_PRE_SUBSCRIBE_MAX_PAYLOAD_BYTES,
130
+ idleMs: opts.preSubscribeIdleMs ?? DEFAULT_PRE_SUBSCRIBE_IDLE_MS,
131
+ maxConnections: opts.maxPreSubscribeConnections ?? DEFAULT_MAX_PRE_SUBSCRIBE_CONNECTIONS,
132
+ };
133
+ // Live monotonic counters surfaced on `/ggui/health`. The router owns
134
+ // the increments; the health getter below reads a snapshot.
135
+ const preSubscribeRejections = { payload: 0, idle: 0, connection: 0 };
76
136
  // `noServer: true` means we own the upgrade wiring (see handleUpgrade);
77
- // ws won't try to bind its own port.
78
- const wss = new WebSocketServer({ noServer: true });
137
+ // ws won't try to bind its own port. `maxPayload` is the coarse global
138
+ // memory backstop; the tight pre-subscribe payload cap is enforced
139
+ // per-frame in the socket router. `0` → fall back to the ws default.
140
+ const wss = wsMaxPayloadBytes > 0
141
+ ? new WebSocketServer({ noServer: true, maxPayload: wsMaxPayloadBytes })
142
+ : new WebSocketServer({ noServer: true });
79
143
  /**
80
144
  * Flat set of all live WS subscribers. Replaces the per-render
81
145
  * `subscribersByRender` Map — routing is now StreamFanout's job;
@@ -162,6 +226,8 @@ export function createGguiSessionChannelServer(opts) {
162
226
  handleInboundAction,
163
227
  handleChannelSubscribe,
164
228
  handleChannelUnsubscribe,
229
+ preSubscribeCaps,
230
+ preSubscribeRejections,
165
231
  });
166
232
  return {
167
233
  path,
@@ -218,6 +284,15 @@ export function createGguiSessionChannelServer(opts) {
218
284
  renders.add(sub.sessionId);
219
285
  return renders.size;
220
286
  },
287
+ get preSubscribeRejections() {
288
+ // Snapshot so callers can't mutate the live counters through the
289
+ // getter's return value.
290
+ return {
291
+ payload: preSubscribeRejections.payload,
292
+ idle: preSubscribeRejections.idle,
293
+ connection: preSubscribeRejections.connection,
294
+ };
295
+ },
221
296
  async close() {
222
297
  // Close every open socket + drain its StreamFanout subscription.
223
298
  // `wss.close` terminates the server but not in-flight sockets,
@@ -66,6 +66,9 @@ interface MountOptions {
66
66
  readonly oauthIssuerUrl?: string;
67
67
  /** Structured logger for unexpected auth-check failures. */
68
68
  readonly logger: Logger;
69
+ /** Effective browser-origin allowlist, for operator diagnosis of CORS
70
+ * failures — which are otherwise invisible server-side. */
71
+ readonly corsOrigins?: ReadonlyArray<string>;
69
72
  }
70
73
  /**
71
74
  * Mount `/ggui/live` + `/ggui/health` + `/ggui/auth-check` onto the
@@ -1 +1 @@
1
- {"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;QACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAClD,CAAC,CAAC;IACH;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,wBAAwB,GAAG,IAAI,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,CAAA;KAAE,CAAC;IACrE,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAmH1D"}
1
+ {"version":3,"file":"health-routes.d.ts","sourceRoot":"","sources":["../src/health-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;QACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAClD,CAAC,CAAC;IACH;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,wBAAwB,GAAG,IAAI,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,GAAG,WAAW,CAAA;KAAE,CAAC;IACrE,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;gEAC4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAuI1D"}
@@ -40,7 +40,7 @@ const READINESS_CHECK_TIMEOUT_MS = 1_000;
40
40
  * express app. Returns nothing — the routes self-register.
41
41
  */
42
42
  export function mountHealthRoutes(opts) {
43
- const { app, info, toolCount, readinessChecks, getChannel, threads, auth, oauthEnabled, logger } = opts;
43
+ const { app, info, toolCount, readinessChecks, getChannel, threads, auth, oauthEnabled, logger, corsOrigins, } = opts;
44
44
  async function runReadinessChecks() {
45
45
  if (readinessChecks.length === 0) {
46
46
  return { allReady: true, results: {} };
@@ -86,8 +86,18 @@ export function mountHealthRoutes(opts) {
86
86
  path: channel.path,
87
87
  subscribers: channel.subscriberCount,
88
88
  renders: channel.renderCount,
89
+ // Pre-subscribe cap-hit counters (ggui#444) — operator
90
+ // signal for a credential-less abuse burst. Monotonic; all
91
+ // zero on a healthy server.
92
+ caps: {
93
+ preSubscribeRejections: channel.preSubscribeRejections,
94
+ },
89
95
  };
90
96
  }
97
+ body.cors = {
98
+ loopback: true,
99
+ origins: corsOrigins === undefined ? [] : [...corsOrigins],
100
+ };
91
101
  // Thread-transport presence + durability claim. When present,
92
102
  // `durability` is exactly what the caller declared — 'ephemeral'
93
103
  // by default so Portal does not silently hide its non-durable
@@ -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
@@ -281,20 +284,6 @@ export interface SelfContainedShellInputs {
281
284
  * @public
282
285
  */
283
286
  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
287
  /**
299
288
  * Options for {@link registerGguiRenderResourceTemplate}.
300
289
  *
@@ -310,10 +299,13 @@ export interface GguiRenderResourceTemplateOptions {
310
299
  * Content-addressable code-blob store. When wired alongside
311
300
  * {@link codeBaseUrl}, the resource template hashes the render's
312
301
  * componentCode, writes it to the store, and inlines the resulting
313
- * `codeUrl` into the shell bootstrap. Without these deps the
314
- * resource path emits the loading shell when the render is a
315
- * compiled component (the static-component channel cannot deliver
316
- * without a URL).
302
+ * `codeUrl` into the shell bootstrap.
303
+ *
304
+ * This is one of the two delivery channels; {@link mintWsToken} is
305
+ * the other, and a compiled component needs at least one of them. A
306
+ * read that resolves a render this server can deliver by neither
307
+ * fails with `NOT_MOUNTABLE` rather than returning a shell that would
308
+ * never paint.
317
309
  */
318
310
  readonly codeStore?: import("@ggui-ai/mcp-server-core").CodeStore;
319
311
  /**
@@ -339,6 +331,68 @@ export interface GguiRenderResourceTemplateOptions {
339
331
  * at hook-mount with a clear "not provided" message).
340
332
  */
341
333
  readonly appMetadataStore?: import("@ggui-ai/mcp-server-core").AppMetadataStore;
334
+ /**
335
+ * Durable per-session identity records. When wired alongside
336
+ * {@link durableBlueprints}, a read of a locator whose render row is
337
+ * GONE resolves the record instead of giving up: the render is
338
+ * re-created from it and mounts live, with the props it last
339
+ * carried.
340
+ *
341
+ * Absent ⇒ neither store is consulted, and `NOT_SUPPORTED` takes
342
+ * `NOT_FOUND`'s place wholesale — the honest answer for a server on
343
+ * which an evicted locator can never come back. Wholesale is the
344
+ * load-bearing word: it answers for a locator that never existed AND
345
+ * for one whose row exists but the caller may not read, so the choice
346
+ * of code says nothing about which locators exist. Reads that get far
347
+ * enough to fail `NOT_MOUNTABLE` still do — that verdict is about the
348
+ * caller's own render, not about this server's memory.
349
+ *
350
+ * Binding a store whose records do not outlive the render rows
351
+ * themselves buys nothing — the record is read precisely when the
352
+ * row is gone.
353
+ */
354
+ readonly renderIdentityStore?: import("@ggui-ai/mcp-server-core").RenderIdentityStore;
355
+ /**
356
+ * Durable blueprint pair — row metadata plus the compiled body
357
+ * behind its content hash. The re-mint path needs BOTH halves: the
358
+ * record names a blueprint, the blueprint names a body, and the body
359
+ * is what a re-created render mounts. A pair carrying only
360
+ * `blueprintStore` persists metadata for other consumers but cannot
361
+ * complete a re-mint, so the path skips as if unwired.
362
+ *
363
+ * Same shape the registration path writes through, so a deployment
364
+ * threads one pair to both ends.
365
+ */
366
+ readonly durableBlueprints?: BlueprintDurabilityDeps;
367
+ /**
368
+ * Render-row retention window in ms — the SAME operator knob
369
+ * `ggui_render` stamps new renders with. The read path spends it in
370
+ * two places, and both are lifecycle decisions about a row this
371
+ * handler is putting back into service:
372
+ *
373
+ * - a re-mint commits its reconstructed row with this lifetime;
374
+ * - a read of a row that is present but PAST its expiry gives the
375
+ * row this lifetime again, so the live-channel token minted in
376
+ * the same read cannot outlive the row it addresses.
377
+ *
378
+ * Absent ⇒ one hour, matching `ggui_render`'s own fallback. Setting
379
+ * it on a deployment whose renders live far longer than an hour is
380
+ * what stops a rehydrated render from being quietly demoted to a
381
+ * fraction of its neighbours' lifetime.
382
+ */
383
+ readonly renderTtlMs?: number;
384
+ /**
385
+ * #457 — total-lifetime bound on RESURRECTION: an expired row's read
386
+ * (and a re-mint's fresh commit) may never advance `expiresAt` past
387
+ * `createdAt + maxRenderLifetimeMs`. Unset = unbounded, today's
388
+ * behavior — the knob exists because operator-set short TTLs are
389
+ * exactly where uncapped in-grace self-extension keeps a PII row
390
+ * alive forever on one poll per (TTL + grace). Live-row heartbeats
391
+ * are deliberately NOT capped (active-use lease renewal is intended);
392
+ * rows whose `createdAt` projects the legacy 0 sentinel are exempt
393
+ * (a cap keyed on 0 would mass-kill pre-column rows).
394
+ */
395
+ readonly maxRenderLifetimeMs?: number;
342
396
  /**
343
397
  * Vector store backing the blueprint registry. When wired alongside
344
398
  * `defaultAppIdFallback`, the resource handler runs a registry-only
@@ -346,9 +400,26 @@ export interface GguiRenderResourceTemplateOptions {
346
400
  * (`ui://ggui/render/{sessionId}/{blueprintKey}`): if the render is
347
401
  * gone but the blueprint registry still holds the entry, return the
348
402
  * static initial render (default props + default context) instead of
349
- * the dead "Generating UI…" loading shell. Single-tenant OSS sees
350
- * meaningful improvement; multi-tenant deployments leave both options
351
- * undefined to keep the loading-shell behavior on render miss.
403
+ * failing the read.
404
+ *
405
+ * The lookup is keyed by the caller-supplied `blueprintKey` under
406
+ * `defaultAppIdFallback` alone — it never reads the render row — so
407
+ * it answers the same for a caller who may not read the row as for
408
+ * one probing a locator that never existed. That is what keeps it
409
+ * safe to run on a refused read, which it must, or refusal would
410
+ * become distinguishable from a miss.
411
+ *
412
+ * Leaving both options undefined does NOT return callers to a
413
+ * placeholder shell — there is no longer one to return. It removes
414
+ * the third resolution, so a read that neither the row nor a re-mint
415
+ * can serve fails typed: `NOT_FOUND`, or `NOT_SUPPORTED` on a
416
+ * deployment that also keeps no durable record, or `NOT_MOUNTABLE`
417
+ * where the row is the caller's own and simply has no component yet.
418
+ * Deployments serving
419
+ * more than one tenant from one registry scope are the reason the
420
+ * option exists at all: the fallback discloses whether a blueprint
421
+ * key exists under that scope, so leave it unset if that is not
422
+ * acceptable.
352
423
  */
353
424
  readonly vectorStore?: VectorStore;
354
425
  /**
@@ -363,10 +434,17 @@ export interface GguiRenderResourceTemplateOptions {
363
434
  /**
364
435
  * App-id used for blueprint-registry scoping when the render has
365
436
  * been evicted. The registry is per-`appId`, but a missing render
366
- * has no way to derive its tenant — multi-tenant deployments leave
367
- * this undefined to fail-safe back to the loading shell. Single-
368
- * tenant OSS sets `'builder'` (the universal-MCP default identity)
369
- * and rehydrate works across render expiry / process restart.
437
+ * has no way to derive whose it was, so the fallback needs one scope
438
+ * named up front. Set to `'builder'` (the universal-MCP default
439
+ * identity) and rehydrate works across render expiry / process
440
+ * restart.
441
+ *
442
+ * Leaving it undefined disables the fallback entirely — the reads it
443
+ * would have served fail typed instead (`NOT_FOUND`, or
444
+ * `NOT_SUPPORTED` where no durable record is kept). That is the
445
+ * setting for a deployment that cannot accept the fallback answering
446
+ * "a blueprint with this key exists under this scope" to whoever
447
+ * asks; it is not a way to get a gentler response.
370
448
  */
371
449
  readonly defaultAppIdFallback?: string;
372
450
  /**
@@ -403,6 +481,21 @@ export interface GguiRenderResourceTemplateOptions {
403
481
  readonly token: string;
404
482
  readonly expiresAt: string;
405
483
  };
484
+ /**
485
+ * Per-request handler-context accessor — the SAME AsyncLocalStorage
486
+ * read the tool path uses. The per-session resource handler gates
487
+ * reads on it (render-read-gate.ts). Absent ⇒ the handler fails
488
+ * closed for rows scoped to any app other than the single-tenant
489
+ * default (compose paths that cannot thread a context keep working
490
+ * for OSS single-tenant flows only).
491
+ */
492
+ readonly getContext?: () => HandlerContext | undefined;
493
+ /**
494
+ * Structured logger for warn-level denial audit lines
495
+ * (`render_resource_read_denied`). Absent ⇒ denials are silent
496
+ * server-side (still enforced — only the log line is skipped).
497
+ */
498
+ readonly logger?: Logger;
406
499
  }
407
500
  /**
408
501
  * Register a `ui://ggui/render/{sessionId}` resource template. Each
@@ -416,11 +509,79 @@ export interface GguiRenderResourceTemplateOptions {
416
509
  * legacy postMessage shell at the static URI, self-contained shell at
417
510
  * the templated URI.
418
511
  *
419
- * Failure modes:
420
- * - GguiSession not found → loading shell (host re-fetches; absent
421
- * render is a transient state immediately after `ggui_render`).
422
- * - GguiSession found, no componentCode yet → loading shell.
423
- * - GguiSession found, componentCode present → self-contained shell.
512
+ * # The obligation
513
+ *
514
+ * A read returns EITHER a shell carrying mount material — a static
515
+ * component URL, a live channel, or a system card — OR exactly one
516
+ * typed JSON-RPC error. There is no third outcome, and in particular no
517
+ * successful result wrapping a shell that can never paint anything. A
518
+ * host can check this without trusting the server: if it got
519
+ * `contents`, it got something mountable.
520
+ *
521
+ * The obligation covers outcomes this server can DECIDE. A malfunction
522
+ * still reaches the caller as an internal error (`-32603`) carrying
523
+ * none of the four codes: a template wired with an empty `runtimeUrl`,
524
+ * or a delivery channel that faults **and leaves the read with no other
525
+ * channel to mount through**. A fault the read survives — the usual
526
+ * case on a deployment wiring both channels — is not an outcome at all;
527
+ * the render mounts through whatever is left. That split is deliberate:
528
+ * `-32603` says "something is broken here", which the four codes must
529
+ * never be diluted into claiming, and equally must not be raised over a
530
+ * blip the server routed around.
531
+ *
532
+ * Three resolutions are tried, in this order, and any of them can
533
+ * produce the mount:
534
+ *
535
+ * 1. The render row itself.
536
+ * 2. A re-mint from the durable identity record, when the row is gone
537
+ * and this server keeps one ({@link GguiRenderResourceTemplateOptions.renderIdentityStore}
538
+ * + {@link GguiRenderResourceTemplateOptions.durableBlueprints}).
539
+ * 3. The blueprint registry, keyed by the locator's own `blueprintKey`
540
+ * — the original component with its authoring-time defaults rather
541
+ * than the state the render last held.
542
+ *
543
+ * # Failure modes
544
+ *
545
+ * Which code a given read produces is fully predictable from two facts:
546
+ * whether this server binds a durable substrate (both
547
+ * {@link GguiRenderResourceTemplateOptions.renderIdentityStore} and
548
+ * {@link GguiRenderResourceTemplateOptions.durableBlueprints} — either
549
+ * one alone is as good as neither), and how far the read got.
550
+ *
551
+ * - `NOT_FOUND` (`-32002`) — nothing resolved the locator, **and** the
552
+ * response for a caller who may not read a locator that DOES
553
+ * resolve. Those two are byte-identical by construction: both route
554
+ * through the protocol's projection, which substitutes a constant
555
+ * message and drops `detail`. A distinguishable refusal would turn
556
+ * this read into an oracle for the existence of other callers'
557
+ * renders, so the equality is a security property, not a courtesy.
558
+ * - `NOT_SUPPORTED` (`-32006`) — the same two cases, on a server with
559
+ * no durable substrate: an evicted locator can never be restored
560
+ * here, so saying "not found" would understate it. It takes
561
+ * `NOT_FOUND`'s place WHOLESALE on such a server rather than
562
+ * answering for some locators and not others — a server that said
563
+ * `NOT_FOUND` for a row it refused and `NOT_SUPPORTED` for one that
564
+ * never existed would have rebuilt the same oracle out of the two
565
+ * codes. Correspondingly, a server that DOES bind the substrate
566
+ * never emits it.
567
+ * - `BLUEPRINT_UNRESOLVABLE` (`-32006`) — a record named the render
568
+ * but its component is gone; `detail` names which link broke.
569
+ * Reachable only after the access check.
570
+ * - `NOT_MOUNTABLE` (`-32006`) — something resolved, but nothing
571
+ * mountable can be produced from it: no delivery channel is wired
572
+ * (neither {@link GguiRenderResourceTemplateOptions.codeStore} nor
573
+ * {@link GguiRenderResourceTemplateOptions.mintWsToken}), the row's
574
+ * generation has not committed a component yet, or a registry
575
+ * blueprint matched but cannot be delivered. Unlike the pair above,
576
+ * this one does NOT vary with the substrate: it is what the
577
+ * caller's OWN row gets on every server, because "this server
578
+ * cannot rehydrate" is not the useful truth for a row that is
579
+ * sitting right there. Reachable only after the access check, or —
580
+ * for the registry case — off the caller's own supplied key, so it
581
+ * discloses nothing either way.
582
+ *
583
+ * A URI matching neither template never reaches any of this: the
584
+ * transport rejects it as invalid params, outside these four codes.
424
585
  *
425
586
  * Returns nothing; mutates the server in place.
426
587
  *
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-apps-outbound.d.ts","sourceRoot":"","sources":["../src/mcp-apps-outbound.ts"],"names":[],"mappings":"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"}