@ggui-ai/mcp-server 0.7.0 → 0.9.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 +32 -23
- package/dist/api-renders-stream-route.d.ts +80 -0
- package/dist/api-renders-stream-route.d.ts.map +1 -0
- package/dist/api-renders-stream-route.js +311 -0
- package/dist/build-mcp.d.ts +10 -0
- package/dist/build-mcp.d.ts.map +1 -1
- package/dist/build-mcp.js +64 -4
- 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 +21 -5
- package/dist/ggui-session-channel/action-ingress.d.ts +2 -2
- package/dist/ggui-session-channel/action-ingress.d.ts.map +1 -1
- package/dist/ggui-session-channel/channel-subscriptions.d.ts +4 -4
- package/dist/ggui-session-channel/channel-subscriptions.d.ts.map +1 -1
- package/dist/ggui-session-channel/internal-types.d.ts +63 -9
- package/dist/ggui-session-channel/internal-types.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.d.ts +15 -5
- package/dist/ggui-session-channel/outbound.d.ts.map +1 -1
- package/dist/ggui-session-channel/outbound.js +64 -24
- package/dist/ggui-session-channel/socket-router.d.ts +8 -3
- package/dist/ggui-session-channel/socket-router.d.ts.map +1 -1
- package/dist/ggui-session-channel/socket-router.js +6 -1
- package/dist/ggui-session-channel/subscribe.d.ts +48 -3
- package/dist/ggui-session-channel/subscribe.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscribe.js +97 -36
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts +23 -13
- package/dist/ggui-session-channel/subscriber-lifecycle.d.ts.map +1 -1
- package/dist/ggui-session-channel/subscriber-lifecycle.js +24 -11
- package/dist/ggui-session-channel.d.ts +58 -11
- package/dist/ggui-session-channel.d.ts.map +1 -1
- package/dist/ggui-session-channel.js +55 -19
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/instructions-presets.js +10 -10
- package/dist/mcp-apps-outbound.d.ts +93 -4
- package/dist/mcp-apps-outbound.d.ts.map +1 -1
- package/dist/mcp-apps-outbound.js +460 -105
- package/dist/mcp-endpoint-routes.d.ts +17 -5
- package/dist/mcp-endpoint-routes.d.ts.map +1 -1
- package/dist/mcp-endpoint-routes.js +2 -0
- package/dist/oauth-as-routes.d.ts.map +1 -1
- package/dist/oauth-as-routes.js +36 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +8 -1
- package/dist/runtime-bundle-hash.d.ts +43 -0
- package/dist/runtime-bundle-hash.d.ts.map +1 -0
- package/dist/runtime-bundle-hash.js +66 -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 +21 -5
- package/dist/server.d.ts +83 -14
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +167 -15
- package/package.json +12 -12
package/dist/server.js
CHANGED
|
@@ -44,7 +44,7 @@ import { createInMemoryBlueprintSearch, createInMemoryGeneratorRegistry, FixedWi
|
|
|
44
44
|
import { createGguiListGadgetsHandler, createGguiListThemesHandler, } from "@ggui-ai/mcp-server-handlers/app-discovery";
|
|
45
45
|
import { createDescribeBlueprintFormatHandler, createDescribeDataContractFormatHandler, createGetBlueprintBoilerplateHandler, createGetExampleBlueprintsHandler, createListAvailablePrimitivesHandler, createListFeaturedBlueprintsHandler, createRenderBlueprintHandler, createSearchBlueprintsHandler, createValidateBlueprintHandler, } from "@ggui-ai/mcp-server-handlers/blueprints";
|
|
46
46
|
import { createGguiOpsDeleteBlueprintHandler, createGguiOpsGenerateBlueprintHandler, createGguiOpsListBlueprintsHandler, createGguiOpsRegisterBlueprintHandler, createGguiOpsUpdateBlueprintHandler, } from "@ggui-ai/mcp-server-handlers/ops-blueprint";
|
|
47
|
-
import { setCacheTraceSink, setPayloadTraceSink } from "@ggui-ai/mcp-server-handlers/renders";
|
|
47
|
+
import { setCacheTraceSink, setPayloadTraceSink, wsOriginToHttpOrigin, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
48
48
|
import { loadTheme } from "@ggui-ai/project-config/node";
|
|
49
49
|
import { LIFECYCLE_CHANNEL } from "@ggui-ai/protocol";
|
|
50
50
|
import { setLlmTraceSink } from "@ggui-ai/ui-gen/harness/llm-trace-sink";
|
|
@@ -52,6 +52,7 @@ import { setValidatorTraceSink } from "@ggui-ai/ui-gen/harness/validator-trace-s
|
|
|
52
52
|
import express from "express";
|
|
53
53
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
54
54
|
import { randomBytes } from "node:crypto";
|
|
55
|
+
import fs from "node:fs";
|
|
55
56
|
import path from "node:path";
|
|
56
57
|
import { BoundedCacheTraceSink, mountConsoleCacheRoutes } from "./console-cache.js";
|
|
57
58
|
import { applyDevtoolSecurityHeaders } from "./console-headers.js";
|
|
@@ -59,6 +60,7 @@ import { BoundedLlmTraceSink, mountConsoleLlmTraceRoutes } from "./console-llm-t
|
|
|
59
60
|
import { BoundedPayloadTraceSink, mountConsolePayloadsRoutes } from "./console-payloads.js";
|
|
60
61
|
import { mountDevtoolThemeRoutes, } from "./console-theme-routes.js";
|
|
61
62
|
import { mountConsoleTimelineRoutes } from "./console-timeline.js";
|
|
63
|
+
import { buildInlineRenderShellHtml } from "./mcp-apps-outbound.js";
|
|
62
64
|
import { BoundedValidatorTraceSink, mountConsoleValidatorRoutes } from "./console-validator.js";
|
|
63
65
|
// Operator-class MCP handlers — twelve `ggui_ops_*` handlers across
|
|
64
66
|
// four domains (apps / orgs / connector-keys / coupon). Every factory
|
|
@@ -69,12 +71,13 @@ import { createCreateAppHandler, createDeleteAppHandler, createListAppsHandler,
|
|
|
69
71
|
import { createIssueConnectorKeyHandler, createListConnectorKeysHandler, createRevokeConnectorKeyHandler, } from "@ggui-ai/mcp-server-handlers/ops-connector-keys";
|
|
70
72
|
import { createRedeemCouponHandler, } from "@ggui-ai/mcp-server-handlers/ops-coupon";
|
|
71
73
|
import { createCreateOrgHandler, createGetOrgBalanceHandler, createInviteToOrgHandler, createListOrgsHandler, createRemoveOrgMemberHandler, createRenameOrgHandler, createRevokeInviteHandler, } from "@ggui-ai/mcp-server-handlers/ops-orgs";
|
|
72
|
-
import { createGguiConsumeHandler, createGguiDeclareToolCatalogHandler, createGguiEmitHandler, createGguiGetSessionHandler, createGguiHandshakeHandler, createGguiListSessionsHandler, createGguiRefreshWsTokenHandler, createGguiRenderHandler, createGguiSubmitActionHandler, createGguiSyncContextHandler, createGguiUpdateHandler, InMemoryToolIdentityCatalogStore, createInMemoryProvisionalPreviewRegistry, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
74
|
+
import { createGguiConsumeHandler, createGguiDeclareToolCatalogHandler, createGguiEmitHandler, createGguiGetSessionHandler, createGguiHandshakeHandler, createGguiListSessionsHandler, createGguiRefreshWsTokenHandler, createGguiRenderHandler, createGguiRuntimePullHandler, createGguiRuntimeTelemetryHandler, createGguiSubmitActionHandler, createGguiSyncContextHandler, createGguiUpdateHandler, createGguiAmendHandler, InMemoryToolIdentityCatalogStore, createInMemoryProvisionalPreviewRegistry, } from "@ggui-ai/mcp-server-handlers/renders";
|
|
73
75
|
import { DEFAULT_ADMIN_BLUEPRINTS_PATH, mountAdminBlueprintsTransport, } from "./admin-blueprints-transport.js";
|
|
74
76
|
import { mountAdminOAuthProvidersTransport } from "./admin-oauth-providers-transport.js";
|
|
75
77
|
import { DEFAULT_BUILDER_APP_ID, defaultAppIdFromIdentity } from "./auth.js";
|
|
76
78
|
import { mountMcpEndpoints } from "./mcp-endpoint-routes.js";
|
|
77
79
|
import { mountApiRendersRoutes } from "./api-renders-routes.js";
|
|
80
|
+
import { mountApiRendersStreamRoute } from "./api-renders-stream-route.js";
|
|
78
81
|
import { mountConsoleBlueprintRoutes } from "./console-blueprint-routes.js";
|
|
79
82
|
import { mountConsoleChatRoutes } from "./console-chat-routes.js";
|
|
80
83
|
import { mountConsoleConfigRoutes } from "./console-config-routes.js";
|
|
@@ -91,6 +94,7 @@ import { mountHealthRoutes } from "./health-routes.js";
|
|
|
91
94
|
import { mountOAuthAuthorizationServerRoutes } from "./oauth-as-routes.js";
|
|
92
95
|
import { mountOAuthClientsRoutes } from "./oauth-clients-routes.js";
|
|
93
96
|
import { mountRuntimeBundleRoute } from "./runtime-bundle-route.js";
|
|
97
|
+
import { computeRuntimeBundleHash, insertRuntimeBundleHash, } from "./runtime-bundle-hash.js";
|
|
94
98
|
import { createCsrfMiddleware, mountCsrfTokenRoute } from "./csrf-middleware.js";
|
|
95
99
|
import { mountEmailLoginRoutes } from "./email-login.js";
|
|
96
100
|
import { resolveMcpInstructions } from "./instructions-presets.js";
|
|
@@ -108,7 +112,7 @@ import { InMemoryOAuthStorage } from "./oauth.js";
|
|
|
108
112
|
import { DEFAULT_PAIRING_ADMIN_INIT_PATH, DEFAULT_PAIRING_PATH, mountPairingTransport, } from "./pairing-transport.js";
|
|
109
113
|
import { createPairLoginRateLimitMiddleware } from "./rate-limit-middleware.js";
|
|
110
114
|
import { createGguiSessionChannelServer, } from "./ggui-session-channel.js";
|
|
111
|
-
import { buildRequestContextMiddleware, resolveRuntimeUrl } from "./request-context.js";
|
|
115
|
+
import { buildRequestContextMiddleware, resolvePublicBaseUrl, resolveRuntimeUrl, } from "./request-context.js";
|
|
112
116
|
import { composePreviewReservedValidator, mergeReservedValidators } from "./reserved-validators.js";
|
|
113
117
|
import { checkRenderSchemaCompat, DEFAULT_SCHEMA_COMPAT_MODE, } from "./schema-compat.js";
|
|
114
118
|
import { createSecurityHeadersMiddleware } from "./security-headers-middleware.js";
|
|
@@ -204,6 +208,7 @@ export function defaultHandlers(deps) {
|
|
|
204
208
|
embedding: deps.embedding,
|
|
205
209
|
vectors: deps.vectors,
|
|
206
210
|
...(deps.blueprints ? { blueprints: deps.blueprints } : {}),
|
|
211
|
+
...(deps.registrySearch ? { registry: deps.registrySearch } : {}),
|
|
207
212
|
}),
|
|
208
213
|
createListFeaturedBlueprintsHandler(deps.blueprints ? { blueprints: deps.blueprints } : {}),
|
|
209
214
|
// Spec / discovery handlers — zero-deps. These may be tagged
|
|
@@ -281,6 +286,30 @@ export function defaultHandlers(deps) {
|
|
|
281
286
|
? { renderIdentityStore: deps.render.renderIdentityStore }
|
|
282
287
|
: {}),
|
|
283
288
|
}));
|
|
289
|
+
// `ggui_runtime_pull` — terminal bridge-pull rung of the live-channel
|
|
290
|
+
// failover ladder (WS → SSE → HTTP polling → bridge-pull). A
|
|
291
|
+
// CSP-jailed MCP Apps iframe pulls the GguiSessionEvent ledger over
|
|
292
|
+
// the host's tools/call postMessage relay — same
|
|
293
|
+
// `_meta.ui.visibility: ['app']` channel as ggui_runtime_submit_action,
|
|
294
|
+
// same ledger + horizon semantics as `GET /api/sessions/:id/events`
|
|
295
|
+
// (both read `renderStore.listEventsSince`). Wired only when a
|
|
296
|
+
// renderStore is bound (render is on) — without render there is no
|
|
297
|
+
// ledger to serve.
|
|
298
|
+
handlers.push(createGguiRuntimePullHandler({
|
|
299
|
+
renderStore: deps.render.renderStore,
|
|
300
|
+
}));
|
|
301
|
+
// `ggui_runtime_telemetry` — the iframe runtime's transport
|
|
302
|
+
// self-report (visibility ['app'], same view-callable channel as
|
|
303
|
+
// submit_action/pull). Sandboxed hosts (claude.ai's
|
|
304
|
+
// claudemcpcontent frames) expose no readable console and no
|
|
305
|
+
// network, so the delivery ladder's behavior there is invisible
|
|
306
|
+
// WITHOUT this channel: the view batches its rung transitions +
|
|
307
|
+
// doorbell events and this handler logs them for operators.
|
|
308
|
+
// Fire-and-forget, store-less — gated on deps.render only because
|
|
309
|
+
// the ladder it reports on exists only when renders do.
|
|
310
|
+
handlers.push(createGguiRuntimeTelemetryHandler({
|
|
311
|
+
...(deps.logger ? { logger: deps.logger } : {}),
|
|
312
|
+
}));
|
|
284
313
|
// `ggui_runtime_refresh_ws_token` — G14 (2026-05-23) signed-
|
|
285
314
|
// envelope refresh tool. Registered only when a refresh seam is
|
|
286
315
|
// wired (typically `channelBootstrap.refresh` from the
|
|
@@ -364,12 +393,29 @@ export function defaultHandlers(deps) {
|
|
|
364
393
|
// re-apply patched props on the live mount without a WS round-trip.
|
|
365
394
|
...(deps.update.mintBootstrap ? { mintWsToken: deps.update.mintBootstrap } : {}),
|
|
366
395
|
...(deps.update.runtimeUrl !== undefined ? { runtimeUrl: deps.update.runtimeUrl } : {}),
|
|
396
|
+
...(deps.update.sessionApiBaseUrl !== undefined
|
|
397
|
+
? { sessionApiBaseUrl: deps.update.sessionApiBaseUrl }
|
|
398
|
+
: {}),
|
|
367
399
|
...(deps.update.themeId !== undefined ? { themeId: deps.update.themeId } : {}),
|
|
368
400
|
...(deps.update.themeMode !== undefined ? { themeMode: deps.update.themeMode } : {}),
|
|
369
401
|
...(deps.update.themeProvider !== undefined
|
|
370
402
|
? { themeProvider: deps.update.themeProvider }
|
|
371
403
|
: {}),
|
|
372
404
|
}));
|
|
405
|
+
// ggui_amend rides the SAME deps slot (#483 tool split): one
|
|
406
|
+
// mutation core, one wiring. It reads only the mutation-flow deps
|
|
407
|
+
// (renderStore / identity / notifier) — the bootstrap-emission
|
|
408
|
+
// options above are meaningless to a tool that emits no result
|
|
409
|
+
// meta by design.
|
|
410
|
+
handlers.push(createGguiAmendHandler({
|
|
411
|
+
renderStore: deps.update.renderStore,
|
|
412
|
+
...(deps.update.renderIdentityStore
|
|
413
|
+
? { renderIdentityStore: deps.update.renderIdentityStore }
|
|
414
|
+
: {}),
|
|
415
|
+
...(deps.update.propsUpdateNotifier
|
|
416
|
+
? { propsUpdateNotifier: deps.update.propsUpdateNotifier }
|
|
417
|
+
: {}),
|
|
418
|
+
}));
|
|
373
419
|
}
|
|
374
420
|
// ggui_consume registers whenever render is bound (it shares the
|
|
375
421
|
// GguiSessionStore for sessionId resolution + tenancy checks).
|
|
@@ -512,6 +558,9 @@ export function defaultHandlers(deps) {
|
|
|
512
558
|
: {}),
|
|
513
559
|
...(deps.render.mintBootstrap ? { mintWsToken: deps.render.mintBootstrap } : {}),
|
|
514
560
|
...(deps.render.runtimeUrl !== undefined ? { runtimeUrl: deps.render.runtimeUrl } : {}),
|
|
561
|
+
...(deps.render.sessionApiBaseUrl !== undefined
|
|
562
|
+
? { sessionApiBaseUrl: deps.render.sessionApiBaseUrl }
|
|
563
|
+
: {}),
|
|
515
564
|
...(deps.render.themeId !== undefined ? { themeId: deps.render.themeId } : {}),
|
|
516
565
|
...(deps.render.themeMode !== undefined ? { themeMode: deps.render.themeMode } : {}),
|
|
517
566
|
...(deps.render.themeProvider !== undefined
|
|
@@ -541,10 +590,11 @@ export function defaultHandlers(deps) {
|
|
|
541
590
|
? { checkRenderContracts: deps.render.checkRenderContracts }
|
|
542
591
|
: {}),
|
|
543
592
|
// Content-addressable code store. Both fields are forwarded
|
|
544
|
-
// together; the render handler
|
|
545
|
-
//
|
|
546
|
-
//
|
|
547
|
-
//
|
|
593
|
+
// together; the render handler requires both to emit
|
|
594
|
+
// `codeUrl`. Absent or partial = no cache-addressable static
|
|
595
|
+
// channel; the bootstrap still carries the inline `codeB64`
|
|
596
|
+
// twin for under-cap renders and mounts through the live trio
|
|
597
|
+
// where minted (see render.ts handler body).
|
|
548
598
|
...(deps.render.codeStore && deps.render.codeBaseUrl
|
|
549
599
|
? {
|
|
550
600
|
codeStore: deps.render.codeStore,
|
|
@@ -770,7 +820,38 @@ export function createGguiServer(opts = {}) {
|
|
|
770
820
|
const runtimeBundleFile = runtimeConfig.distDir !== undefined
|
|
771
821
|
? path.join(runtimeConfig.distDir, "iframe-runtime.js")
|
|
772
822
|
: RUNTIME_BUNDLE_FILE;
|
|
773
|
-
|
|
823
|
+
// Bundle bytes, captured ONCE at composition. Feed three consumers:
|
|
824
|
+
// the content hash below, the immutable hashed route (which must
|
|
825
|
+
// serve exactly the bytes its name hashes — see runtime-bundle-
|
|
826
|
+
// route.ts), and the opt-in inline-runtime shell. Unreadable file ⇒
|
|
827
|
+
// undefined ⇒ every consumer falls back to its pre-#472 behavior.
|
|
828
|
+
let runtimeBundleBytes;
|
|
829
|
+
if (runtimeEnabled) {
|
|
830
|
+
try {
|
|
831
|
+
runtimeBundleBytes = fs.readFileSync(runtimeBundleFile);
|
|
832
|
+
}
|
|
833
|
+
catch {
|
|
834
|
+
// The plain route's own existsSync handles the missing-bundle
|
|
835
|
+
// warning; nothing extra to say here.
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
// Content-hashed runtime URL (#472). The stamped `runtimeUrl` (and
|
|
839
|
+
// the hashed route it points at) embeds sha256[0..12) of the bytes:
|
|
840
|
+
// clients cache one download per content version with zero
|
|
841
|
+
// revalidations, and a deploy rolls over by changing the URL. The
|
|
842
|
+
// rewrite applies to a configured absolute `runtime.url` ONLY when
|
|
843
|
+
// its filename matches the served bundle's route (a CDN fronting
|
|
844
|
+
// THIS server still resolves the hashed name at its origin); a URL
|
|
845
|
+
// pointing at a foreign copy is left untouched, and
|
|
846
|
+
// `runtime.hashedUrl: false` opts out entirely.
|
|
847
|
+
const runtimeBundleHash = runtimeBundleBytes !== undefined && runtimeConfig.hashedUrl !== false
|
|
848
|
+
? computeRuntimeBundleHash(runtimeBundleBytes)
|
|
849
|
+
: undefined;
|
|
850
|
+
const insertHash = (urlOrPath) => runtimeBundleHash === undefined
|
|
851
|
+
? urlOrPath
|
|
852
|
+
: insertRuntimeBundleHash(urlOrPath, runtimeBundleHash, runtimePath.slice(runtimePath.lastIndexOf("/") + 1));
|
|
853
|
+
const hashedRuntimePath = runtimeBundleHash !== undefined ? insertHash(runtimePath) : undefined;
|
|
854
|
+
const runtimeBootstrapUrl = insertHash(runtimeConfig.url ?? runtimePath);
|
|
774
855
|
// Lazy resolver: each render/update handler invocation looks up the
|
|
775
856
|
// request-context-derived absolute base inside the request scope
|
|
776
857
|
// (via AsyncLocalStorage). Static `publicBaseUrl` wins when set;
|
|
@@ -1185,6 +1266,7 @@ export function createGguiServer(opts = {}) {
|
|
|
1185
1266
|
// Registers `ggui_runtime_declare_tool_catalog`.
|
|
1186
1267
|
toolIdentityCatalogStore,
|
|
1187
1268
|
...(opts.blueprintProvider ? { blueprints: opts.blueprintProvider } : {}),
|
|
1269
|
+
...(opts.registrySearch ? { registrySearch: opts.registrySearch } : {}),
|
|
1188
1270
|
// UI registry for `ggui_render_blueprint`. Absent = render tool
|
|
1189
1271
|
// is NOT registered on this server (defaultHandlers' own opt-in
|
|
1190
1272
|
// rule). OSS CLI wires a `LocalUiRegistry` here so manifest
|
|
@@ -1270,6 +1352,14 @@ export function createGguiServer(opts = {}) {
|
|
|
1270
1352
|
// an absolute URL instead of the relative default that
|
|
1271
1353
|
// breaks under srcdoc iframes (claude.ai).
|
|
1272
1354
|
runtimeUrl: resolveRuntimeUrlForResultMeta,
|
|
1355
|
+
// Session-API base for `pollingUrl` + `sseUrl` stamping.
|
|
1356
|
+
// Same lazy request-scope resolution as runtimeUrl:
|
|
1357
|
+
// static publicBaseUrl wins, X-Forwarded-Host honored
|
|
1358
|
+
// for loopback peers, `undefined` outside any request —
|
|
1359
|
+
// the handler then falls back to the minted trio's
|
|
1360
|
+
// wsUrl origin flip (OSS dev: `ws://localhost/ws` →
|
|
1361
|
+
// `http://localhost`).
|
|
1362
|
+
sessionApiBaseUrl: () => resolvePublicBaseUrl(opts.publicBaseUrl),
|
|
1273
1363
|
// Forward operator-picked theme onto every
|
|
1274
1364
|
// `ai.ggui/render.themeId` slice field so MCP Apps hosts
|
|
1275
1365
|
// (claude.ai, Claude Desktop) that mount via the
|
|
@@ -1458,10 +1548,10 @@ export function createGguiServer(opts = {}) {
|
|
|
1458
1548
|
? { renderIdentityStore: opts.renderIdentityStore }
|
|
1459
1549
|
: {}),
|
|
1460
1550
|
propsUpdateNotifier: {
|
|
1461
|
-
sendPropsUpdate: async (sessionId, props) => {
|
|
1551
|
+
sendPropsUpdate: async (sessionId, props, epoch) => {
|
|
1462
1552
|
if (!channelForHealth)
|
|
1463
1553
|
return;
|
|
1464
|
-
await channelForHealth.sendPropsUpdate(sessionId, props);
|
|
1554
|
+
await channelForHealth.sendPropsUpdate(sessionId, props, epoch);
|
|
1465
1555
|
},
|
|
1466
1556
|
},
|
|
1467
1557
|
// Bootstrap-emission deps. Mirror render so MCP Apps hosts
|
|
@@ -1475,6 +1565,9 @@ export function createGguiServer(opts = {}) {
|
|
|
1475
1565
|
// same absolute URL when the server sits behind a tunnel
|
|
1476
1566
|
// / reverse proxy.
|
|
1477
1567
|
runtimeUrl: resolveRuntimeUrlForResultMeta,
|
|
1568
|
+
// Session-API base — matches render so both tools stamp
|
|
1569
|
+
// identical `pollingUrl` + `sseUrl` values.
|
|
1570
|
+
sessionApiBaseUrl: () => resolvePublicBaseUrl(opts.publicBaseUrl),
|
|
1478
1571
|
...(opts.theme !== undefined && opts.theme.source === "preset"
|
|
1479
1572
|
? { themeId: opts.theme.preset }
|
|
1480
1573
|
: {}),
|
|
@@ -1782,15 +1875,40 @@ export function createGguiServer(opts = {}) {
|
|
|
1782
1875
|
logger,
|
|
1783
1876
|
corsOrigins: originHostPolicy.allowedOrigins,
|
|
1784
1877
|
});
|
|
1878
|
+
// Inline-runtime shell (opt-in): embed the runtime bundle's source
|
|
1879
|
+
// into the static-resource shell so fetch-blocked hosts (iframe CSP
|
|
1880
|
+
// without external script-src) can still boot. Resolved ONCE at
|
|
1881
|
+
// composition time from the same bundle file the runtime mount
|
|
1882
|
+
// serves. An explicit `shellHtml` wins; a read failure warns and
|
|
1883
|
+
// falls back to the thin shell (the server still works everywhere
|
|
1884
|
+
// the thin shell worked).
|
|
1885
|
+
let inlineShellHtml;
|
|
1886
|
+
if (mcpAppsEnabled && mcpAppsConfig.inlineRuntimeShell === true) {
|
|
1887
|
+
if (runtimeBundleBytes !== undefined) {
|
|
1888
|
+
inlineShellHtml = buildInlineRenderShellHtml(runtimeBundleBytes.toString("utf8"));
|
|
1889
|
+
}
|
|
1890
|
+
else {
|
|
1891
|
+
// inlineRuntimeShell is on but the runtime bundle could not be
|
|
1892
|
+
// read at composition — serve the thin postMessage shell instead.
|
|
1893
|
+
logger.warn("mcp_apps_inline_shell_bundle_unreadable", {
|
|
1894
|
+
runtimeBundleFile,
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1785
1898
|
// Per-boot `buildMcpServer` options — every input below is fixed at
|
|
1786
1899
|
// composition time, so the bundle is assembled once and the MCP
|
|
1787
1900
|
// endpoint family spreads a fresh copy per request.
|
|
1788
1901
|
const buildMcpOptions = {
|
|
1789
1902
|
mcpAppsOutbound: mcpAppsEnabled,
|
|
1790
|
-
// Caller-provided `shellHtml` overrides the default
|
|
1791
|
-
// `installMcpAppsOutbound` falls back to
|
|
1792
|
-
// `GGUI_RENDER_SHELL_HTML` constant when
|
|
1793
|
-
|
|
1903
|
+
// Caller-provided `shellHtml` overrides the default (and the
|
|
1904
|
+
// inline-runtime shell); `installMcpAppsOutbound` falls back to
|
|
1905
|
+
// its baked `GGUI_RENDER_SHELL_HTML` constant when both are
|
|
1906
|
+
// absent.
|
|
1907
|
+
...(mcpAppsConfig.shellHtml !== undefined
|
|
1908
|
+
? { shellHtml: mcpAppsConfig.shellHtml }
|
|
1909
|
+
: inlineShellHtml !== undefined
|
|
1910
|
+
? { shellHtml: inlineShellHtml }
|
|
1911
|
+
: {}),
|
|
1794
1912
|
// Forward the operator-supplied public origin so the static
|
|
1795
1913
|
// `ui://ggui/render` resource declares `_meta.ui.csp` for
|
|
1796
1914
|
// spec-compliant hosts (Claude Desktop / claude.ai Connector /
|
|
@@ -1798,6 +1916,18 @@ export function createGguiServer(opts = {}) {
|
|
|
1798
1916
|
// (`connect-src 'none'`) blocks the iframe from fetching the
|
|
1799
1917
|
// runtime bundle and opening the WebSocket.
|
|
1800
1918
|
...(opts.publicBaseUrl !== undefined ? { publicBaseUrl: opts.publicBaseUrl } : {}),
|
|
1919
|
+
// Live-channel origins for the static shell's CSP declaration:
|
|
1920
|
+
// the WS endpoint + its http-origin flip (the session-API base the
|
|
1921
|
+
// sseUrl/pollingUrl stamps derive from when `publicBaseUrl` is
|
|
1922
|
+
// unset — the cloud pod's posture, see compose.ts's Origin/Host
|
|
1923
|
+
// ruling). Cross-origin hosts (claude.ai) build the frame CSP from
|
|
1924
|
+
// the STATIC shell resource they mount; per-render declarations
|
|
1925
|
+
// never reach it, so without these entries every network rung of
|
|
1926
|
+
// the failover ladder (WS, SSE, HTTP polling) is `connect-src`-
|
|
1927
|
+
// blocked in the frame — observed live in #471 round 11.
|
|
1928
|
+
...(mcpAppsEnabled
|
|
1929
|
+
? { extraConnectUrls: [wsUrl, wsOriginToHttpOrigin(wsUrl)] }
|
|
1930
|
+
: {}),
|
|
1801
1931
|
// Per-render self-contained shell registration. Only wired
|
|
1802
1932
|
// when MCP Apps is on AND the render store is resolved —
|
|
1803
1933
|
// both preconditions for `ggui_render.resultMeta` stamping a
|
|
@@ -1964,7 +2094,15 @@ export function createGguiServer(opts = {}) {
|
|
|
1964
2094
|
// `runtime.url`. The bootstrap still carries a `runtimeUrl` so
|
|
1965
2095
|
// the shell knows where to look — just not our HTTP listener.
|
|
1966
2096
|
if (runtimeEnabled) {
|
|
1967
|
-
mountRuntimeBundleRoute({
|
|
2097
|
+
mountRuntimeBundleRoute({
|
|
2098
|
+
app,
|
|
2099
|
+
runtimePath,
|
|
2100
|
+
runtimeBundleFile,
|
|
2101
|
+
logger,
|
|
2102
|
+
...(hashedRuntimePath !== undefined && runtimeBundleBytes !== undefined
|
|
2103
|
+
? { hashed: { path: hashedRuntimePath, source: runtimeBundleBytes } }
|
|
2104
|
+
: {}),
|
|
2105
|
+
});
|
|
1968
2106
|
}
|
|
1969
2107
|
// R6 /state snapshot + R7 /events cursor-replay reads — see
|
|
1970
2108
|
// `./api-renders-routes.ts` for the wsToken auth posture, tenancy
|
|
@@ -1989,6 +2127,20 @@ export function createGguiServer(opts = {}) {
|
|
|
1989
2127
|
resolveRuntimeUrl: resolveRuntimeUrlForResultMeta,
|
|
1990
2128
|
logger,
|
|
1991
2129
|
});
|
|
2130
|
+
// SSE live stream (the ladder's middle rung) — same wsToken auth
|
|
2131
|
+
// posture as /state and /events; see `./api-renders-stream-route.ts`
|
|
2132
|
+
// for the framing contract. The channel is late-bound via the same
|
|
2133
|
+
// `() => channelForHealth` pattern as `stream.channelProvider`:
|
|
2134
|
+
// route mounting runs before `createGguiSessionChannelServer`, and
|
|
2135
|
+
// the mcpApps ⇒ renderChannel throw above guarantees a channel
|
|
2136
|
+
// exists by listen time.
|
|
2137
|
+
mountApiRendersStreamRoute({
|
|
2138
|
+
app,
|
|
2139
|
+
renderStore,
|
|
2140
|
+
secret: sharedTokenSecret,
|
|
2141
|
+
channelProvider: () => channelForHealth,
|
|
2142
|
+
logger,
|
|
2143
|
+
});
|
|
1992
2144
|
}
|
|
1993
2145
|
// Content-addressable code + contract-validator delivery — see
|
|
1994
2146
|
// `./code-routes.ts` for the route contract (cache posture, CORS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ggui-ai/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Self-hosted MCP server for the ggui protocol. An HTTP/MCP binding layer over @ggui-ai/mcp-server-handlers and the reference adapters from @ggui-ai/mcp-server-core — run it via `ggui serve`.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ggui",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"resend": "^6.12.2",
|
|
33
33
|
"ws": "^8.20.1",
|
|
34
34
|
"zod": "^4.3.6",
|
|
35
|
-
"@ggui-ai/
|
|
36
|
-
"@ggui-ai/
|
|
37
|
-
"@ggui-ai/mcp-server-handlers": "0.
|
|
38
|
-
"@ggui-ai/negotiator": "0.
|
|
39
|
-
"@ggui-ai/mcp-server-core": "0.
|
|
40
|
-
"@ggui-ai/preview-a2ui": "0.
|
|
41
|
-
"@ggui-ai/project-config": "0.
|
|
42
|
-
"@ggui-ai/
|
|
43
|
-
"@ggui-ai/ui-
|
|
44
|
-
"@ggui-ai/
|
|
35
|
+
"@ggui-ai/iframe-runtime": "0.9.0",
|
|
36
|
+
"@ggui-ai/console": "0.9.0",
|
|
37
|
+
"@ggui-ai/mcp-server-handlers": "0.9.0",
|
|
38
|
+
"@ggui-ai/negotiator": "0.9.0",
|
|
39
|
+
"@ggui-ai/mcp-server-core": "0.9.0",
|
|
40
|
+
"@ggui-ai/preview-a2ui": "0.9.0",
|
|
41
|
+
"@ggui-ai/project-config": "0.9.0",
|
|
42
|
+
"@ggui-ai/ui-gen": "0.9.0",
|
|
43
|
+
"@ggui-ai/ui-registry": "0.9.0",
|
|
44
|
+
"@ggui-ai/protocol": "0.9.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/express": "^5.0.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@types/ws": "^8.5.10",
|
|
51
51
|
"typescript": "^5.0.0",
|
|
52
52
|
"vitest": "^3.2.6",
|
|
53
|
-
"@ggui-ai/protocol-conformance": "0.
|
|
53
|
+
"@ggui-ai/protocol-conformance": "0.9.0"
|
|
54
54
|
},
|
|
55
55
|
"repository": {
|
|
56
56
|
"type": "git",
|