From 5b264d7024628e06a507ad8d56999bac709b15b4 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Wed, 8 Jul 2026 02:11:07 +0300 Subject: [PATCH 1/4] feat(types): add Dynamic View Content types and schemas - McpUiResourceMeta.contentMimeTypes: renderer declaration for typed dynamic content payloads - McpUiContentBlockMeta: the _meta.ui.content marker for embedded resource blocks in tool results - McpUiClientCapabilities.contentMimeTypes: capability negotiation setting (supports ["*"] opaque forwarding) - Regenerated Zod schemas and re-exports Co-Authored-By: Claude Fable 5 --- src/generated/schema.json | 23 ++++++++++++++++ src/generated/schema.test.ts | 10 +++++++ src/generated/schema.ts | 52 ++++++++++++++++++++++++++++++++++++ src/spec.types.ts | 47 ++++++++++++++++++++++++++++++++ src/types.ts | 2 ++ 5 files changed, 134 insertions(+) diff --git a/src/generated/schema.json b/src/generated/schema.json index 80b4ac60d..6e4e71681 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -59,6 +59,23 @@ "items": { "type": "string" } + }, + "contentMimeTypes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "McpUiContentBlockMeta": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "rendererUri": { + "description": "URI of the `ui://` renderer resource this payload targets.\n\nIf omitted, the payload targets the calling tool's `_meta.ui.resourceUri`.\nExplicit targeting supports future multi-view tool results.", + "type": "string" } }, "additionalProperties": false @@ -4235,6 +4252,12 @@ "prefersBorder": { "description": "Visual boundary preference - true if view prefers a visible border.\n\nBoolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary.\n\n- `true`: request visible border + background\n- `false`: request no visible border + background\n- omitted: host decides border", "type": "boolean" + }, + "contentMimeTypes": { + "type": "array", + "items": { + "type": "string" + } } }, "additionalProperties": false diff --git a/src/generated/schema.test.ts b/src/generated/schema.test.ts index 57d989fd0..0dcc3f035 100644 --- a/src/generated/schema.test.ts +++ b/src/generated/schema.test.ts @@ -127,6 +127,10 @@ export type McpUiToolMetaSchemaInferredType = z.infer< typeof generated.McpUiToolMetaSchema >; +export type McpUiContentBlockMetaSchemaInferredType = z.infer< + typeof generated.McpUiContentBlockMetaSchema +>; + export type McpUiClientCapabilitiesSchemaInferredType = z.infer< typeof generated.McpUiClientCapabilitiesSchema >; @@ -305,6 +309,12 @@ expectType( ); expectType({} as McpUiToolMetaSchemaInferredType); expectType({} as spec.McpUiToolMeta); +expectType( + {} as McpUiContentBlockMetaSchemaInferredType, +); +expectType( + {} as spec.McpUiContentBlockMeta, +); expectType( {} as McpUiClientCapabilitiesSchemaInferredType, ); diff --git a/src/generated/schema.ts b/src/generated/schema.ts index 43687374e..71a9b877a 100644 --- a/src/generated/schema.ts +++ b/src/generated/schema.ts @@ -669,6 +669,21 @@ export const McpUiResourceMetaSchema = z.object({ .describe( "Visual boundary preference - true if view prefers a visible border.\n\nBoolean requesting whether a visible border and background is provided by the host. Specifying an explicit value for this is recommended because hosts' defaults may vary.\n\n- `true`: request visible border + background\n- `false`: request no visible border + background\n- omitted: host decides border", ), + /** + * @description MIME types of dynamic content payloads this view renders. + * + * When present, the view acts as a renderer for typed payloads returned by + * its associated tools as embedded resources marked with `_meta.ui.content` + * (see {@link McpUiContentBlockMeta `McpUiContentBlockMeta`}). Does not + * affect the resource's own `mimeType`, which remains + * `"text/html;profile=mcp-app"`. + * + * @example + * ```ts + * ["application/a2ui+json"] + * ``` + */ + contentMimeTypes: z.array(z.string()).optional(), }); /** @@ -742,6 +757,32 @@ export const McpUiToolMetaSchema = z.object({ permissions: z.never().optional(), }); +/** + * @description Metadata marking an embedded resource content block in a tool + * result as a dynamic view content payload. + * + * Placed at `_meta.ui.content` on `type: "resource"` content blocks within + * `CallToolResult.content`. Marked payloads are presentation data for the + * tool's view: hosts forward them unmodified to the view (via + * `ui/notifications/tool-result` and proxied `tools/call` responses) and + * exclude them from model context. The payload's `mimeType` must be declared + * in the target view's {@link McpUiResourceMeta.contentMimeTypes `contentMimeTypes`}. + */ +export const McpUiContentBlockMetaSchema = z.object({ + /** + * @description URI of the `ui://` renderer resource this payload targets. + * + * If omitted, the payload targets the calling tool's `_meta.ui.resourceUri`. + * Explicit targeting supports future multi-view tool results. + */ + rendererUri: z + .string() + .optional() + .describe( + "URI of the `ui://` renderer resource this payload targets.\n\nIf omitted, the payload targets the calling tool's `_meta.ui.resourceUri`.\nExplicit targeting supports future multi-view tool results.", + ), +}); + /** * @description MCP Apps capability settings advertised by clients to servers. * @@ -760,6 +801,17 @@ export const McpUiClientCapabilitiesSchema = z.object({ .describe( 'Array of supported MIME types for UI resources.\nMust include `"text/html;profile=mcp-app"` for MCP Apps support.', ), + /** + * @description Dynamic content payload MIME types the host will forward to + * views (see {@link McpUiContentBlockMeta `McpUiContentBlockMeta`}). + * + * Hosts may advertise `["*"]` to indicate they forward any payload type + * declared by a view's `contentMimeTypes` — hosts never need to interpret + * payloads, only route them into the sandboxed view. Servers should check + * this setting before registering renderer-pattern tools and degrade to + * text-only or `structuredContent`-driven variants when absent. + */ + contentMimeTypes: z.array(z.string()).optional(), }); /** diff --git a/src/spec.types.ts b/src/spec.types.ts index 7a8b33761..8f5980b8c 100644 --- a/src/spec.types.ts +++ b/src/spec.types.ts @@ -728,6 +728,21 @@ export interface McpUiResourceMeta { * - omitted: host decides border */ prefersBorder?: boolean; + /** + * @description MIME types of dynamic content payloads this view renders. + * + * When present, the view acts as a renderer for typed payloads returned by + * its associated tools as embedded resources marked with `_meta.ui.content` + * (see {@link McpUiContentBlockMeta `McpUiContentBlockMeta`}). Does not + * affect the resource's own `mimeType`, which remains + * `"text/html;profile=mcp-app"`. + * + * @example + * ```ts + * ["application/a2ui+json"] + * ``` + */ + contentMimeTypes?: string[]; } /** @@ -795,6 +810,27 @@ export interface McpUiToolMeta { permissions?: never; } +/** + * @description Metadata marking an embedded resource content block in a tool + * result as a dynamic view content payload. + * + * Placed at `_meta.ui.content` on `type: "resource"` content blocks within + * `CallToolResult.content`. Marked payloads are presentation data for the + * tool's view: hosts forward them unmodified to the view (via + * `ui/notifications/tool-result` and proxied `tools/call` responses) and + * exclude them from model context. The payload's `mimeType` must be declared + * in the target view's {@link McpUiResourceMeta.contentMimeTypes `contentMimeTypes`}. + */ +export interface McpUiContentBlockMeta { + /** + * @description URI of the `ui://` renderer resource this payload targets. + * + * If omitted, the payload targets the calling tool's `_meta.ui.resourceUri`. + * Explicit targeting supports future multi-view tool results. + */ + rendererUri?: string; +} + /** * Method string constants for MCP Apps protocol messages. * @@ -855,4 +891,15 @@ export interface McpUiClientCapabilities { * Must include `"text/html;profile=mcp-app"` for MCP Apps support. */ mimeTypes?: string[]; + /** + * @description Dynamic content payload MIME types the host will forward to + * views (see {@link McpUiContentBlockMeta `McpUiContentBlockMeta`}). + * + * Hosts may advertise `["*"]` to indicate they forward any payload type + * declared by a view's `contentMimeTypes` — hosts never need to interpret + * payloads, only route them into the sandboxed view. Servers should check + * this setting before registering renderer-pattern tools and degrade to + * text-only or `structuredContent`-driven variants when absent. + */ + contentMimeTypes?: string[]; } diff --git a/src/types.ts b/src/types.ts index 7fc6b7188..22c6efb2d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -66,6 +66,7 @@ export { type McpUiRequestDisplayModeResult, type McpUiToolVisibility, type McpUiToolMeta, + type McpUiContentBlockMeta, type McpUiClientCapabilities, } from "./spec.types.js"; @@ -134,6 +135,7 @@ export { McpUiRequestDisplayModeResultSchema, McpUiToolVisibilitySchema, McpUiToolMetaSchema, + McpUiContentBlockMetaSchema, } from "./generated/schema.js"; // Re-export SDK types used in protocol type unions From 4821123332209f3d6ce6965cf873daf35c6e7ae0 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Wed, 8 Jul 2026 02:17:50 +0300 Subject: [PATCH 2/4] feat: add Dynamic View Content helpers New src/ui-content.ts module, re-exported from the app, app-bridge, and server entry points: - createViewContentBlock(): server-side helper producing an embedded resource block marked with _meta.ui.content (validates text/blob exclusivity and rejects ui:// payload URIs) - getViewContentBlocks() / isViewContentBlock(): view-side extraction of marked payloads from tool results, with mimeType/rendererUri filters - supportsContentMimeType(): capability check honoring the ["*"] wildcard, for servers gating renderer-pattern tools and hosts type-filtering payloads Includes type-checked JSDoc examples (ui-content.examples.ts) and unit tests. Co-Authored-By: Claude Fable 5 --- src/app-bridge.ts | 1 + src/app.ts | 1 + src/server/index.ts | 1 + src/ui-content.examples.ts | 78 ++++++++++++++ src/ui-content.test.ts | 179 ++++++++++++++++++++++++++++++ src/ui-content.ts | 216 +++++++++++++++++++++++++++++++++++++ 6 files changed, 476 insertions(+) create mode 100644 src/ui-content.examples.ts create mode 100644 src/ui-content.test.ts create mode 100644 src/ui-content.ts diff --git a/src/app-bridge.ts b/src/app-bridge.ts index 23383c40f..cef4f4d26 100644 --- a/src/app-bridge.ts +++ b/src/app-bridge.ts @@ -94,6 +94,7 @@ import { McpUiToolMeta, } from "./types"; export * from "./types"; +export * from "./ui-content"; export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE } from "./app"; import { RESOURCE_URI_META_KEY } from "./app"; export { PostMessageTransport } from "./message-transport"; diff --git a/src/app.ts b/src/app.ts index adfad5c77..a3e9466db 100644 --- a/src/app.ts +++ b/src/app.ts @@ -83,6 +83,7 @@ export type { export { PostMessageTransport } from "./message-transport"; export * from "./types"; +export * from "./ui-content"; export { applyHostStyleVariables, applyHostFonts, diff --git a/src/server/index.ts b/src/server/index.ts index c90514acd..7d307f7dc 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -62,6 +62,7 @@ import type { // Re-exports for convenience export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE }; export type { ResourceMetadata, ToolCallback }; +export * from "../ui-content.js"; /** * Base tool configuration matching the standard MCP server tool options. diff --git a/src/ui-content.examples.ts b/src/ui-content.examples.ts new file mode 100644 index 000000000..6911da016 --- /dev/null +++ b/src/ui-content.examples.ts @@ -0,0 +1,78 @@ +/** + * Type-checked examples for {@link ui-content!} helpers. + * + * These examples are included in the API documentation via code fences with + * `source` attributes. Each function's region markers define the code snippet + * that appears in the docs. + * + * @module + */ + +import type { App } from "./app"; +import { + createViewContentBlock, + getViewContentBlocks, + supportsContentMimeType, +} from "./ui-content"; +import type { McpUiClientCapabilities } from "./spec.types"; + +declare const app: App; +declare const uiCap: McpUiClientCapabilities | undefined; +declare function searchFlights(route: string): Promise<{ summary: string }>; +declare function buildA2uiSurface(route: string): string; +declare function renderA2ui(payloads: string[]): void; + +const A2UI_MIME_TYPE = "application/a2ui+json"; + +async function createViewContentBlockExamples(route: string) { + //#region createViewContentBlock_toolResult + // Server: return a typed payload alongside the text fallback + const flights = await searchFlights(route); + return { + content: [ + { type: "text" as const, text: flights.summary }, + createViewContentBlock({ + uri: `a2ui://flight-server/surfaces/${encodeURIComponent(route)}`, + mimeType: A2UI_MIME_TYPE, + text: buildA2uiSurface(route), + }), + ], + }; + //#endregion createViewContentBlock_toolResult +} + +function getViewContentBlocksExamples() { + //#region getViewContentBlocks_ontoolresult + // View: extract payloads from delivered tool results + app.ontoolresult = (result) => { + const payloads = getViewContentBlocks(result, { + mimeType: A2UI_MIME_TYPE, + }); + renderA2ui( + payloads.map((block) => + "text" in block.resource + ? block.resource.text + : atob(block.resource.blob), + ), + ); + }; + //#endregion getViewContentBlocks_ontoolresult +} + +function supportsContentMimeTypeExamples() { + //#region supportsContentMimeType_checkSupport + // Server: register the renderer-pattern tool only when the host + // forwards this payload type (handles the ["*"] wildcard) + if (supportsContentMimeType(uiCap?.contentMimeTypes, A2UI_MIME_TYPE)) { + // register tool returning marked A2UI payloads + } else { + // register text-only or structuredContent-driven variant + } + //#endregion supportsContentMimeType_checkSupport +} + +export { + createViewContentBlockExamples, + getViewContentBlocksExamples, + supportsContentMimeTypeExamples, +}; diff --git a/src/ui-content.test.ts b/src/ui-content.test.ts new file mode 100644 index 000000000..d8e667353 --- /dev/null +++ b/src/ui-content.test.ts @@ -0,0 +1,179 @@ +import { describe, it, expect } from "bun:test"; +import { + createViewContentBlock, + getViewContentBlocks, + isViewContentBlock, + supportsContentMimeType, +} from "./ui-content"; +import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; + +const A2UI_MIME_TYPE = "application/a2ui+json"; + +describe("createViewContentBlock", () => { + it("should create a marked embedded resource block from text", () => { + const block = createViewContentBlock({ + uri: "a2ui://server/surfaces/1", + mimeType: A2UI_MIME_TYPE, + text: '{"beginRendering":{}}', + }); + expect(block).toEqual({ + type: "resource", + resource: { + uri: "a2ui://server/surfaces/1", + mimeType: A2UI_MIME_TYPE, + text: '{"beginRendering":{}}', + }, + _meta: { ui: { content: {} } }, + }); + }); + + it("should create a block from blob", () => { + const block = createViewContentBlock({ + uri: "data://server/1", + mimeType: "application/octet-stream", + blob: "AAAA", + }); + expect(block.resource).toEqual({ + uri: "data://server/1", + mimeType: "application/octet-stream", + blob: "AAAA", + }); + }); + + it("should include rendererUri in the marker when provided", () => { + const block = createViewContentBlock({ + uri: "a2ui://server/surfaces/1", + mimeType: A2UI_MIME_TYPE, + text: "{}", + rendererUri: "ui://server/renderer", + }); + expect(block._meta.ui.content).toEqual({ + rendererUri: "ui://server/renderer", + }); + }); + + it("should reject providing neither or both of text and blob", () => { + expect(() => + createViewContentBlock({ uri: "a2ui://x", mimeType: A2UI_MIME_TYPE }), + ).toThrow("exactly one of `text` or `blob`"); + expect(() => + createViewContentBlock({ + uri: "a2ui://x", + mimeType: A2UI_MIME_TYPE, + text: "{}", + blob: "AAAA", + }), + ).toThrow("exactly one of `text` or `blob`"); + }); + + it("should reject ui:// payload URIs", () => { + expect(() => + createViewContentBlock({ + uri: "ui://server/renderer", + mimeType: A2UI_MIME_TYPE, + text: "{}", + }), + ).toThrow("ui://"); + }); +}); + +describe("isViewContentBlock", () => { + it("should accept marked embedded resources", () => { + const block = createViewContentBlock({ + uri: "a2ui://x", + mimeType: A2UI_MIME_TYPE, + text: "{}", + }); + expect(isViewContentBlock(block)).toBe(true); + }); + + it("should reject unmarked and non-resource blocks", () => { + expect(isViewContentBlock({ type: "text", text: "hi" })).toBe(false); + expect( + isViewContentBlock({ + type: "resource", + resource: { uri: "file://x", mimeType: "text/plain", text: "hi" }, + }), + ).toBe(false); + expect( + isViewContentBlock({ + type: "resource", + resource: { uri: "file://x", mimeType: "text/plain", text: "hi" }, + _meta: { ui: {} }, + }), + ).toBe(false); + }); +}); + +describe("getViewContentBlocks", () => { + const result: Pick = { + content: [ + { type: "text", text: "Found 3 flights" }, + createViewContentBlock({ + uri: "a2ui://server/surfaces/1", + mimeType: A2UI_MIME_TYPE, + text: "{}", + }), + { + type: "resource", + resource: { uri: "file://report", mimeType: "text/csv", text: "a,b" }, + }, + createViewContentBlock({ + uri: "custom://server/2", + mimeType: "application/vnd.custom+json", + text: "{}", + rendererUri: "ui://server/other-renderer", + }), + ], + }; + + it("should return only marked blocks, in order", () => { + const blocks = getViewContentBlocks(result); + expect(blocks.map((b) => b.resource.uri)).toEqual([ + "a2ui://server/surfaces/1", + "custom://server/2", + ]); + }); + + it("should filter by mimeType", () => { + const blocks = getViewContentBlocks(result, { mimeType: A2UI_MIME_TYPE }); + expect(blocks.map((b) => b.resource.uri)).toEqual([ + "a2ui://server/surfaces/1", + ]); + }); + + it("should filter by rendererUri, including untargeted blocks", () => { + expect( + getViewContentBlocks(result, { + rendererUri: "ui://server/other-renderer", + }).map((b) => b.resource.uri), + ).toEqual(["a2ui://server/surfaces/1", "custom://server/2"]); + expect( + getViewContentBlocks(result, { + rendererUri: "ui://server/renderer", + }).map((b) => b.resource.uri), + ).toEqual(["a2ui://server/surfaces/1"]); + }); + + it("should handle results with no content", () => { + expect(getViewContentBlocks({ content: [] })).toEqual([]); + }); +}); + +describe("supportsContentMimeType", () => { + it("should match declared MIME types", () => { + expect(supportsContentMimeType([A2UI_MIME_TYPE], A2UI_MIME_TYPE)).toBe( + true, + ); + expect(supportsContentMimeType(["text/plain"], A2UI_MIME_TYPE)).toBe(false); + }); + + it("should honor the wildcard", () => { + expect(supportsContentMimeType(["*"], A2UI_MIME_TYPE)).toBe(true); + }); + + it("should return false when unset", () => { + expect(supportsContentMimeType(undefined, A2UI_MIME_TYPE)).toBe(false); + expect(supportsContentMimeType([], A2UI_MIME_TYPE)).toBe(false); + }); +}); diff --git a/src/ui-content.ts b/src/ui-content.ts new file mode 100644 index 000000000..6c9674629 --- /dev/null +++ b/src/ui-content.ts @@ -0,0 +1,216 @@ +/** + * Helpers for **Dynamic View Content**: typed presentation payloads carried in + * tool results as embedded resource content blocks marked with + * `_meta.ui.content`. + * + * A view declares the payload MIME types it renders via + * {@link types!McpUiResourceMeta.contentMimeTypes `contentMimeTypes`} on its UI + * resource. Tools associated with that view return payloads as marked embedded + * resources ({@link createViewContentBlock `createViewContentBlock`}), hosts + * forward them unmodified, and the view extracts them from tool results + * ({@link getViewContentBlocks `getViewContentBlocks`}). + * + * @module + */ +import type { + CallToolResult, + ContentBlock, + EmbeddedResource, +} from "@modelcontextprotocol/sdk/types.js"; +import type { McpUiContentBlockMeta } from "./spec.types"; + +/** + * An embedded resource content block marked as a dynamic view content payload. + * + * @see {@link isViewContentBlock `isViewContentBlock`} to narrow a content block to this type + */ +export type ViewContentBlock = EmbeddedResource & { + _meta: { + ui: { + content: McpUiContentBlockMeta; + }; + }; +}; + +/** + * Options for creating a dynamic view content block. + * + * @see {@link createViewContentBlock `createViewContentBlock`} + */ +export type CreateViewContentBlockOptions = { + /** + * Ephemeral payload identifier (any scheme except `ui://`, which is + * reserved for renderable UI resources). + */ + uri: string; + /** + * Payload MIME type. Must be declared in the target view's + * `contentMimeTypes`. + */ + mimeType: string; + /** Payload as a string. Exactly one of `text` or `blob` must be provided. */ + text?: string; + /** Base64-encoded payload. Exactly one of `text` or `blob` must be provided. */ + blob?: string; + /** + * URI of the `ui://` renderer resource this payload targets. If omitted, + * the payload targets the calling tool's `_meta.ui.resourceUri`. + */ + rendererUri?: string; +}; + +/** + * Create an embedded resource content block marked as dynamic view content. + * + * Servers include the returned block in `CallToolResult.content`. Hosts that + * negotiated dynamic content support forward it unmodified to the tool's view + * (and exclude it from model context). + * + * @example + * ```ts source="./ui-content.examples.ts#createViewContentBlock_toolResult" + * // Server: return a typed payload alongside the text fallback + * const flights = await searchFlights(route); + * return { + * content: [ + * { type: "text" as const, text: flights.summary }, + * createViewContentBlock({ + * uri: `a2ui://flight-server/surfaces/${encodeURIComponent(route)}`, + * mimeType: A2UI_MIME_TYPE, + * text: buildA2uiSurface(route), + * }), + * ], + * }; + * ``` + * + * @see {@link getViewContentBlocks `getViewContentBlocks`} for the view-side extraction helper + */ +export function createViewContentBlock( + options: CreateViewContentBlockOptions, +): ViewContentBlock { + const { uri, mimeType, text, blob, rendererUri } = options; + if ((text === undefined) === (blob === undefined)) { + throw new Error( + "createViewContentBlock: exactly one of `text` or `blob` must be provided", + ); + } + if (uri.startsWith("ui://")) { + throw new Error( + "createViewContentBlock: payload URIs must not use the ui:// scheme (reserved for renderable UI resources)", + ); + } + return { + type: "resource", + resource: + text !== undefined + ? { uri, mimeType, text } + : { uri, mimeType, blob: blob! }, + _meta: { + ui: { + content: rendererUri !== undefined ? { rendererUri } : {}, + }, + }, + }; +} + +/** + * Check whether a content block is a dynamic view content payload (an + * embedded resource marked with `_meta.ui.content`). + */ +export function isViewContentBlock( + block: ContentBlock, +): block is ViewContentBlock { + if (block.type !== "resource") { + return false; + } + const ui = block._meta?.["ui"]; + if (typeof ui !== "object" || ui === null) { + return false; + } + const content = (ui as Record)["content"]; + return typeof content === "object" && content !== null; +} + +/** + * Options for extracting dynamic view content payloads from a tool result. + * + * @see {@link getViewContentBlocks `getViewContentBlocks`} + */ +export type GetViewContentBlocksOptions = { + /** Only return payloads with this MIME type. */ + mimeType?: string; + /** + * Only return payloads targeting this renderer: blocks whose + * `_meta.ui.content.rendererUri` equals this URI, plus blocks with no + * explicit `rendererUri` (which target the calling tool's default view). + */ + rendererUri?: string; +}; + +/** + * Extract dynamic view content payloads from a tool result, in array order. + * + * Views use this on results delivered via `ui/notifications/tool-result` + * (the {@link app!App.ontoolresult `ontoolresult`} handler) and on results + * returned from {@link app!App.callServerTool `callServerTool`}. + * + * @example + * ```ts source="./ui-content.examples.ts#getViewContentBlocks_ontoolresult" + * // View: extract payloads from delivered tool results + * app.ontoolresult = (result) => { + * const payloads = getViewContentBlocks(result, { + * mimeType: A2UI_MIME_TYPE, + * }); + * renderA2ui( + * payloads.map((block) => + * "text" in block.resource ? block.resource.text : atob(block.resource.blob), + * ), + * ); + * }; + * ``` + */ +export function getViewContentBlocks( + result: Pick, + options: GetViewContentBlocksOptions = {}, +): ViewContentBlock[] { + const { mimeType, rendererUri } = options; + return (result.content ?? []).filter(isViewContentBlock).filter((block) => { + if (mimeType !== undefined && block.resource.mimeType !== mimeType) { + return false; + } + if (rendererUri !== undefined) { + const target = block._meta.ui.content.rendererUri; + return target === undefined || target === rendererUri; + } + return true; + }); +} + +/** + * Check whether a payload MIME type is included in a set of supported + * dynamic content MIME types, honoring the `["*"]` wildcard. + * + * Servers use this against the host's negotiated + * {@link types!McpUiClientCapabilities.contentMimeTypes `contentMimeTypes`} + * extension setting before registering renderer-pattern tools; hosts can use + * it against a view's declared `contentMimeTypes` to type-filter payloads. + * + * @example + * ```ts source="./ui-content.examples.ts#supportsContentMimeType_checkSupport" + * // Server: register the renderer-pattern tool only when the host + * // forwards this payload type (handles the ["*"] wildcard) + * if (supportsContentMimeType(uiCap?.contentMimeTypes, A2UI_MIME_TYPE)) { + * // register tool returning marked A2UI payloads + * } else { + * // register text-only or structuredContent-driven variant + * } + * ``` + */ +export function supportsContentMimeType( + contentMimeTypes: string[] | undefined, + mimeType: string, +): boolean { + if (!contentMimeTypes) { + return false; + } + return contentMimeTypes.includes("*") || contentMimeTypes.includes(mimeType); +} From dc2e3098390c5aa40cff8c6e5b5b86365b2c1016 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Wed, 8 Jul 2026 02:42:07 +0300 Subject: [PATCH 3/4] feat(examples): add dynamic-content-server example A full worked example of Dynamic View Content: - Generic renderer view (no domain-specific presentation logic) that declares contentMimeTypes, extracts marked payloads from tool results with getViewContentBlocks(), and renders them via createElement/ textContent only (payloads are untrusted input) - search-flights tool returning a text fallback plus a declarative UI payload built with createViewContentBlock() - select-flight app-visibility tool driven by the renderer's event bridge, whose responses carry new payloads (the interactive loop) - E2E coverage with a golden screenshot generated in the CI-identical Playwright container Also fixes basic-host sandbox.html serving under dot-directory checkouts (e.g. git worktrees in .claude/worktrees): res.sendFile with an absolute path applies the dotfiles=ignore rule to every path segment and 404s; pass the file relative to a root instead. package-lock.json: new workspace entry, plus npm dedup of nested @types/node/undici-types entries. Co-Authored-By: Claude Fable 5 --- examples/basic-host/serve.ts | 5 +- examples/dynamic-content-server/.gitignore | 2 + examples/dynamic-content-server/README.md | 66 +++ examples/dynamic-content-server/dynamic-ui.ts | 47 ++ examples/dynamic-content-server/main.ts | 93 ++++ examples/dynamic-content-server/mcp-app.html | 17 + examples/dynamic-content-server/package.json | 53 +++ examples/dynamic-content-server/server.ts | 268 +++++++++++ .../dynamic-content-server/src/global.css | 92 ++++ .../dynamic-content-server/src/mcp-app.css | 81 ++++ .../dynamic-content-server/src/mcp-app.ts | 162 +++++++ examples/dynamic-content-server/tsconfig.json | 19 + .../tsconfig.server.json | 17 + .../dynamic-content-server/vite.config.ts | 24 + package-lock.json | 439 +++--------------- src/ui-content.ts | 4 +- tests/e2e/servers.spec.ts | 5 + .../dynamic-content.png | Bin 0 -> 70266 bytes 18 files changed, 1006 insertions(+), 388 deletions(-) create mode 100644 examples/dynamic-content-server/.gitignore create mode 100644 examples/dynamic-content-server/README.md create mode 100644 examples/dynamic-content-server/dynamic-ui.ts create mode 100644 examples/dynamic-content-server/main.ts create mode 100644 examples/dynamic-content-server/mcp-app.html create mode 100644 examples/dynamic-content-server/package.json create mode 100644 examples/dynamic-content-server/server.ts create mode 100644 examples/dynamic-content-server/src/global.css create mode 100644 examples/dynamic-content-server/src/mcp-app.css create mode 100644 examples/dynamic-content-server/src/mcp-app.ts create mode 100644 examples/dynamic-content-server/tsconfig.json create mode 100644 examples/dynamic-content-server/tsconfig.server.json create mode 100644 examples/dynamic-content-server/vite.config.ts create mode 100644 tests/e2e/servers.spec.ts-snapshots/dynamic-content.png diff --git a/examples/basic-host/serve.ts b/examples/basic-host/serve.ts index bc3fbff14..2ab7c2bf0 100644 --- a/examples/basic-host/serve.ts +++ b/examples/basic-host/serve.ts @@ -124,7 +124,10 @@ sandboxApp.get(["/", "/sandbox.html"], (req, res) => { res.setHeader("Pragma", "no-cache"); res.setHeader("Expires", "0"); - res.sendFile(join(DIRECTORY, "sandbox.html")); + // Pass the file relative to `root` — with an absolute path, express applies + // its dotfiles="ignore" rule to every segment and 404s when the repo checkout + // lives under a dot-directory (e.g. git worktrees in .claude/worktrees). + res.sendFile("sandbox.html", { root: DIRECTORY }); }); sandboxApp.use((_req, res) => { diff --git a/examples/dynamic-content-server/.gitignore b/examples/dynamic-content-server/.gitignore new file mode 100644 index 000000000..b94707787 --- /dev/null +++ b/examples/dynamic-content-server/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ diff --git a/examples/dynamic-content-server/README.md b/examples/dynamic-content-server/README.md new file mode 100644 index 000000000..95d2fd3a7 --- /dev/null +++ b/examples/dynamic-content-server/README.md @@ -0,0 +1,66 @@ +# Example: Dynamic View Content + +An MCP App example demonstrating **Dynamic View Content**: a generic, predeclared renderer view driven by typed payloads that tools return as embedded resources marked with `_meta.ui.content`. + +Instead of baking presentation into the template and passing data via `structuredContent`, the server generates a declarative UI document at tool-call time. The host forwards the payload (unmodified, and excluded from model context) to the renderer view, which interprets it. Button clicks in the rendered surface are bridged back into `tools/call` requests to an app-visibility tool, whose responses carry new payloads — closing the interactive loop. + +This is the pattern used by generative UI formats such as [A2UI](https://a2ui.org) (`application/a2ui+json`). This example uses a deliberately tiny stand-in format (`application/vnd.example.dynamic-ui+json`, defined in [`dynamic-ui.ts`](dynamic-ui.ts)) so the plumbing stays easy to follow. + +## MCP Client Configuration + +Add to your MCP client configuration (stdio transport): + +```json +{ + "mcpServers": { + "dynamic-content": { + "command": "npx", + "args": [ + "-y", + "--silent", + "--registry=https://registry.npmjs.org/", + "@modelcontextprotocol/server-dynamic-content", + "--stdio" + ] + } + } +} +``` + +### Local Development + +To test local modifications, use this configuration (replace `~/code/ext-apps` with your clone path): + +```json +{ + "mcpServers": { + "dynamic-content": { + "command": "bash", + "args": [ + "-c", + "cd ~/code/ext-apps/examples/dynamic-content-server && npm run build >&2 && node dist/index.js --stdio" + ] + } + } +} +``` + +## Overview + +- A renderer resource declaring the payload types it renders via `contentMimeTypes` in its `_meta.ui` +- A model-visible tool (`search-flights`) returning a text fallback for model context plus a marked payload created with [`createViewContentBlock`](https://apps.extensions.modelcontextprotocol.io/api/functions/app.createViewContentBlock.html) +- An app-visibility tool (`select-flight`, hidden from the model) that the renderer's event bridge calls; its response carries the next payload +- A generic renderer extracting payloads with [`getViewContentBlocks`](https://apps.extensions.modelcontextprotocol.io/api/functions/app.getViewContentBlocks.html) and building DOM with `createElement`/`textContent` only — payloads are untrusted input + +## Key Files + +- [`dynamic-ui.ts`](dynamic-ui.ts) - The example payload format (MIME type + component types) +- [`server.ts`](server.ts) - Renderer resource + tools returning marked payloads +- [`mcp-app.html`](mcp-app.html) / [`src/mcp-app.ts`](src/mcp-app.ts) - The generic renderer view and its event bridge + +## Getting Started + +```bash +npm install +npm run dev +``` diff --git a/examples/dynamic-content-server/dynamic-ui.ts b/examples/dynamic-content-server/dynamic-ui.ts new file mode 100644 index 000000000..194405b90 --- /dev/null +++ b/examples/dynamic-content-server/dynamic-ui.ts @@ -0,0 +1,47 @@ +/** + * @file Shared definition of this example's dynamic content payload format. + * + * This is a deliberately tiny declarative UI language, standing in for real + * generative UI formats such as A2UI (`application/a2ui+json`). The server + * produces documents in this format at tool-call time; the generic renderer + * view interprets them. The MCP Apps plumbing is identical for any format: + * the payload rides in tool results as an embedded resource marked with + * `_meta.ui.content`, typed by its MIME type. + */ + +/** MIME type of this example's dynamic content payloads. */ +export const DYNAMIC_UI_MIME_TYPE = "application/vnd.example.dynamic-ui+json"; + +/** A node in the declarative component tree. */ +export type UiComponent = + | { + kind: "text"; + text: string; + variant?: "title" | "body" | "note"; + } + | { + kind: "row" | "column"; + children: UiComponent[]; + } + | { + kind: "card"; + children: UiComponent[]; + } + | { + kind: "button"; + label: string; + /** + * The event bridge: the renderer translates a click into a `tools/call` + * request for this (typically app-visibility) tool. The response carries + * new marked payloads, which the renderer applies. + */ + action: { + tool: string; + arguments: Record; + }; + }; + +/** A dynamic content payload document: a surface to render. */ +export type UiSurface = { + surface: UiComponent[]; +}; diff --git a/examples/dynamic-content-server/main.ts b/examples/dynamic-content-server/main.ts new file mode 100644 index 000000000..e7c040bdb --- /dev/null +++ b/examples/dynamic-content-server/main.ts @@ -0,0 +1,93 @@ +/** + * Entry point for running the MCP server. + * Run with: npx mcp-server-dynamic-content + * Or: node dist/index.js [--stdio] + */ + +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; +import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; +import cors from "cors"; +import type { Request, Response } from "express"; +import { createServer } from "./server.js"; + +/** + * Starts an MCP server with Streamable HTTP transport in stateless mode. + * + * @param createServer - Factory function that creates a new McpServer instance per request. + */ +export async function startStreamableHTTPServer( + createServer: () => McpServer, +): Promise { + const port = parseInt(process.env.PORT ?? "3001", 10); + + const app = createMcpExpressApp({ host: "0.0.0.0" }); + app.use(cors()); + + app.all("/mcp", async (req: Request, res: Response) => { + const server = createServer(); + const transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: undefined, + }); + + res.on("close", () => { + transport.close().catch(() => {}); + server.close().catch(() => {}); + }); + + try { + await server.connect(transport); + await transport.handleRequest(req, res, req.body); + } catch (error) { + console.error("MCP error:", error); + if (!res.headersSent) { + res.status(500).json({ + jsonrpc: "2.0", + error: { code: -32603, message: "Internal server error" }, + id: null, + }); + } + } + }); + + const httpServer = app.listen(port, (err) => { + if (err) { + console.error("Failed to start server:", err); + process.exit(1); + } + console.log(`MCP server listening on http://localhost:${port}/mcp`); + }); + + const shutdown = () => { + console.log("\nShutting down..."); + httpServer.close(() => process.exit(0)); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); +} + +/** + * Starts an MCP server with stdio transport. + * + * @param createServer - Factory function that creates a new McpServer instance. + */ +export async function startStdioServer( + createServer: () => McpServer, +): Promise { + await createServer().connect(new StdioServerTransport()); +} + +async function main() { + if (process.argv.includes("--stdio")) { + await startStdioServer(createServer); + } else { + await startStreamableHTTPServer(createServer); + } +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/examples/dynamic-content-server/mcp-app.html b/examples/dynamic-content-server/mcp-app.html new file mode 100644 index 000000000..7c446a407 --- /dev/null +++ b/examples/dynamic-content-server/mcp-app.html @@ -0,0 +1,17 @@ + + + + + + + Dynamic Content Renderer + + +
+
+

Waiting for content…

+
+
+ + + diff --git a/examples/dynamic-content-server/package.json b/examples/dynamic-content-server/package.json new file mode 100644 index 000000000..c96ac23b9 --- /dev/null +++ b/examples/dynamic-content-server/package.json @@ -0,0 +1,53 @@ +{ + "name": "@modelcontextprotocol/server-dynamic-content", + "version": "1.7.4", + "type": "module", + "description": "MCP App Server example demonstrating Dynamic View Content: a generic renderer view driven by typed payloads returned from tool calls as marked embedded resources", + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/ext-apps", + "directory": "examples/dynamic-content-server" + }, + "license": "MIT", + "main": "dist/server.js", + "files": [ + "dist" + ], + "scripts": { + "build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"", + "watch": "cross-env INPUT=mcp-app.html vite build --watch", + "serve": "bun --watch main.ts", + "serve:stdio": "bun main.ts --stdio", + "start": "cross-env NODE_ENV=development npm run build && npm run serve", + "start:stdio": "cross-env NODE_ENV=development npm run build 1>&2 && npm run serve:stdio", + "dev": "cross-env NODE_ENV=development concurrently \"npm run watch\" \"npm run serve\"", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "@modelcontextprotocol/ext-apps": "^1.7.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "cors": "^2.8.5", + "express": "^5.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.0", + "@types/node": "22.10.0", + "concurrently": "^9.2.1", + "cross-env": "^10.1.0", + "typescript": "^5.9.3", + "vite": "^6.0.0", + "vite-plugin-singlefile": "^2.3.0" + }, + "types": "dist/server.d.ts", + "exports": { + ".": { + "types": "./dist/server.d.ts", + "default": "./dist/server.js" + } + }, + "bin": { + "mcp-server-dynamic-content": "dist/index.js" + } +} diff --git a/examples/dynamic-content-server/server.ts b/examples/dynamic-content-server/server.ts new file mode 100644 index 000000000..e76141c5c --- /dev/null +++ b/examples/dynamic-content-server/server.ts @@ -0,0 +1,268 @@ +/** + * @file MCP server demonstrating Dynamic View Content. + * + * The predeclared `ui://` resource is a generic renderer: it declares (via + * `contentMimeTypes`) that it renders `application/vnd.example.dynamic-ui+json` + * payloads. Tools don't bake data into the template — they return declarative + * UI documents as embedded resources marked with `_meta.ui.content`, which the + * host forwards to the view. Button clicks in the view come back as + * `tools/call` requests to an app-visibility tool, whose response carries new + * payloads — closing the interactive loop. + */ +import { + createViewContentBlock, + registerAppResource, + registerAppTool, + RESOURCE_MIME_TYPE, +} from "@modelcontextprotocol/ext-apps/server"; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import type { + CallToolResult, + ReadResourceResult, +} from "@modelcontextprotocol/sdk/types.js"; +import fs from "node:fs/promises"; +import path from "node:path"; +import { z } from "zod"; +import { DYNAMIC_UI_MIME_TYPE, type UiSurface } from "./dynamic-ui.js"; + +// Works both from source (server.ts) and compiled (dist/server.js) +const DIST_DIR = import.meta.filename.endsWith(".ts") + ? path.join(import.meta.dirname, "dist") + : import.meta.dirname; + +const RESOURCE_URI = "ui://dynamic-content-server/renderer.html"; + +type Flight = { + id: string; + airline: string; + departure: string; + arrival: string; + price: number; +}; + +const FLIGHTS: Flight[] = [ + { + id: "UA954", + airline: "United", + departure: "08:10", + arrival: "12:35", + price: 1240, + }, + { + id: "LY007", + airline: "El Al", + departure: "10:45", + arrival: "15:20", + price: 1180, + }, + { + id: "DL221", + airline: "Delta", + departure: "16:30", + arrival: "21:05", + price: 990, + }, +]; + +/** Build the flight results surface — the server generates UI at call time. */ +function flightResultsSurface(destination: string): UiSurface { + return { + surface: [ + { kind: "text", variant: "title", text: `Flights to ${destination}` }, + { + kind: "column", + children: FLIGHTS.map((flight) => ({ + kind: "card" as const, + children: [ + { + kind: "row" as const, + children: [ + { + kind: "text" as const, + text: `${flight.airline} ${flight.id}`, + }, + { + kind: "text" as const, + variant: "note" as const, + text: `${flight.departure} → ${flight.arrival}`, + }, + { kind: "text" as const, text: `$${flight.price}` }, + { + kind: "button" as const, + label: "Select", + // The renderer's event bridge turns this into a tools/call + action: { + tool: "select-flight", + arguments: { flightId: flight.id }, + }, + }, + ], + }, + ], + })), + }, + { kind: "text", variant: "note", text: "Prices include taxes and fees." }, + ], + }; +} + +/** Build the confirmation surface returned by the app-visibility tool. */ +function confirmationSurface(flight: Flight): UiSurface { + return { + surface: [ + { kind: "text", variant: "title", text: "Flight selected" }, + { + kind: "card", + children: [ + { + kind: "text", + text: `${flight.airline} ${flight.id}, departs ${flight.departure}`, + }, + { kind: "text", text: `Total: $${flight.price}` }, + { + kind: "text", + variant: "note", + text: "This is a demo — nothing was booked.", + }, + ], + }, + { + kind: "button", + label: "Back to results", + action: { + tool: "search-flights", + arguments: { destination: "San Francisco" }, + }, + }, + ], + }; +} + +/** + * Creates a new MCP server instance with tools and resources registered. + */ +export function createServer(): McpServer { + const server = new McpServer({ + name: "Dynamic View Content Example Server", + version: "1.0.0", + }); + + // Model-visible tool: returns a text fallback for model context plus a + // marked dynamic content payload for the renderer view. + // + // Production servers should gate this registration on the host's negotiated + // `contentMimeTypes` extension setting — see `getUiCapability` and + // `supportsContentMimeType` — and degrade to a text-only variant otherwise. + registerAppTool( + server, + "search-flights", + { + title: "Search Flights", + description: + "Search for flights to a destination and present the options.", + inputSchema: { + destination: z + .string() + .describe("Destination city") + .default("San Francisco"), + }, + _meta: { ui: { resourceUri: RESOURCE_URI } }, + }, + async ({ destination }): Promise => { + const cheapest = FLIGHTS.reduce((a, b) => (a.price <= b.price ? a : b)); + return { + content: [ + // Text fallback: model context and text-only hosts + { + type: "text", + text: `Found ${FLIGHTS.length} flights to ${destination}. Cheapest: ${cheapest.airline} ${cheapest.id} at $${cheapest.price}.`, + }, + // Dynamic content payload: forwarded to the renderer view, + // excluded from model context + createViewContentBlock({ + uri: `dynamic-ui://dynamic-content-server/surfaces/${encodeURIComponent(destination)}`, + mimeType: DYNAMIC_UI_MIME_TYPE, + text: JSON.stringify(flightResultsSurface(destination)), + }), + ], + }; + }, + ); + + // App-visibility tool: hidden from the model, called by the renderer's + // event bridge. Its response carries the next payload in the loop. + registerAppTool( + server, + "select-flight", + { + title: "Select Flight", + description: "Select a flight from previously presented options.", + inputSchema: { + flightId: z.string().describe("Flight id from the presented options"), + }, + _meta: { ui: { resourceUri: RESOURCE_URI, visibility: ["app"] } }, + }, + async ({ flightId }): Promise => { + const flight = FLIGHTS.find((f) => f.id === flightId); + if (!flight) { + return { + content: [{ type: "text", text: `Unknown flight: ${flightId}` }], + isError: true, + }; + } + return { + content: [ + { + type: "text", + text: `Selected ${flight.airline} ${flight.id} ($${flight.price}).`, + }, + createViewContentBlock({ + uri: `dynamic-ui://dynamic-content-server/surfaces/confirmation-${flight.id}`, + mimeType: DYNAMIC_UI_MIME_TYPE, + text: JSON.stringify(confirmationSurface(flight)), + }), + ], + }; + }, + ); + + // The renderer resource: predeclared, prefetchable, reviewable. It declares + // the payload MIME types it renders via `contentMimeTypes`. + registerAppResource( + server, + RESOURCE_URI, + RESOURCE_URI, + { + mimeType: RESOURCE_MIME_TYPE, + _meta: { + ui: { + contentMimeTypes: [DYNAMIC_UI_MIME_TYPE], + prefersBorder: true, + }, + }, + }, + async (): Promise => { + const html = await fs.readFile( + path.join(DIST_DIR, "mcp-app.html"), + "utf-8", + ); + return { + contents: [ + { + uri: RESOURCE_URI, + mimeType: RESOURCE_MIME_TYPE, + text: html, + _meta: { + ui: { + contentMimeTypes: [DYNAMIC_UI_MIME_TYPE], + prefersBorder: true, + }, + }, + }, + ], + }; + }, + ); + + return server; +} diff --git a/examples/dynamic-content-server/src/global.css b/examples/dynamic-content-server/src/global.css new file mode 100644 index 000000000..801291f46 --- /dev/null +++ b/examples/dynamic-content-server/src/global.css @@ -0,0 +1,92 @@ +:root { + color-scheme: light dark; + + /* + * Fallbacks for host style variables used by this app. + * The host may provide these (and many more) via the host context. + */ + --color-text-primary: light-dark(#1f2937, #f3f4f6); + --color-text-inverse: light-dark(#f3f4f6, #1f2937); + --color-text-info: light-dark(#1d4ed8, #60a5fa); + --color-background-primary: light-dark(#ffffff, #1a1a1a); + --color-background-inverse: light-dark(#1a1a1a, #ffffff); + --color-background-info: light-dark(#eff6ff, #1e3a5f); + --color-ring-primary: light-dark(#3b82f6, #60a5fa); + --border-radius-md: 6px; + --border-width-regular: 1px; + --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + --font-weight-normal: 400; + --font-weight-bold: 700; + --font-text-md-size: 1rem; + --font-text-md-line-height: 1.5; + --font-heading-3xl-size: 2.25rem; + --font-heading-3xl-line-height: 1.1; + --font-heading-2xl-size: 1.875rem; + --font-heading-2xl-line-height: 1.2; + --font-heading-xl-size: 1.5rem; + --font-heading-xl-line-height: 1.25; + --font-heading-lg-size: 1.25rem; + --font-heading-lg-line-height: 1.3; + --font-heading-md-size: 1rem; + --font-heading-md-line-height: 1.4; + --font-heading-sm-size: 0.875rem; + --font-heading-sm-line-height: 1.4; + + /* Spacing derived from host typography */ + --spacing-unit: var(--font-text-md-size); + --spacing-xs: calc(var(--spacing-unit) * 0.25); + --spacing-sm: calc(var(--spacing-unit) * 0.5); + --spacing-md: var(--spacing-unit); + --spacing-lg: calc(var(--spacing-unit) * 1.5); + + /* App accent color (customize for your brand) */ + --color-accent: #2563eb; + --color-text-on-accent: #ffffff; +} + +* { + box-sizing: border-box; +} + +html, body { + font-family: var(--font-sans); + font-size: var(--font-text-md-size); + font-weight: var(--font-weight-normal); + line-height: var(--font-text-md-line-height); + color: var(--color-text-primary); +} + +h1 { + font-size: var(--font-heading-3xl-size); + line-height: var(--font-heading-3xl-line-height); +} +h2 { + font-size: var(--font-heading-2xl-size); + line-height: var(--font-heading-2xl-line-height); +} +h3 { + font-size: var(--font-heading-xl-size); + line-height: var(--font-heading-xl-line-height); +} +h4 { + font-size: var(--font-heading-lg-size); + line-height: var(--font-heading-lg-line-height); +} +h5 { + font-size: var(--font-heading-md-size); + line-height: var(--font-heading-md-line-height); +} +h6 { + font-size: var(--font-heading-sm-size); + line-height: var(--font-heading-sm-line-height); +} + +code, pre, kbd { + font-family: var(--font-mono); + font-size: 1em; +} + +b, strong { + font-weight: var(--font-weight-bold); +} diff --git a/examples/dynamic-content-server/src/mcp-app.css b/examples/dynamic-content-server/src/mcp-app.css new file mode 100644 index 000000000..80453f190 --- /dev/null +++ b/examples/dynamic-content-server/src/mcp-app.css @@ -0,0 +1,81 @@ +body { + margin: 0; + background: var(--color-background-primary); +} + +.main { + padding: var(--spacing-md); +} + +.surface { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.surface.busy { + opacity: 0.6; + pointer-events: none; +} + +.status { + color: var(--color-text-info); + margin: 0; +} + +.text { + margin: 0; +} + +.text-title { + margin: 0 0 var(--spacing-xs); +} + +.text-note { + font-size: 0.875em; + opacity: 0.7; +} + +.row { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--spacing-sm); + flex-wrap: wrap; +} + +.row > .text { + flex: 1 1 auto; +} + +.column { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.card { + border: var(--border-width-regular) solid + color-mix(in srgb, var(--color-text-primary) 15%, transparent); + border-radius: var(--border-radius-md); + padding: var(--spacing-sm) var(--spacing-md); +} + +button { + font: inherit; + padding: var(--spacing-xs) var(--spacing-md); + border: none; + border-radius: var(--border-radius-md); + background: var(--color-accent); + color: var(--color-text-on-accent); + cursor: pointer; +} + +button:hover { + filter: brightness(1.1); +} + +button:focus-visible { + outline: 2px solid var(--color-ring-primary); + outline-offset: 1px; +} diff --git a/examples/dynamic-content-server/src/mcp-app.ts b/examples/dynamic-content-server/src/mcp-app.ts new file mode 100644 index 000000000..e1e40b898 --- /dev/null +++ b/examples/dynamic-content-server/src/mcp-app.ts @@ -0,0 +1,162 @@ +/** + * @file A generic dynamic content renderer. + * + * This view contains no flight-specific presentation logic. It interprets + * declarative payload documents (see ../dynamic-ui.ts) extracted from tool + * results with `getViewContentBlocks`, and bridges payload-level button + * actions back into `tools/call` requests. The same pattern applies to real + * generative UI formats such as A2UI. + * + * Security note: payloads are untrusted input. The renderer builds DOM with + * `createElement`/`textContent` only — never `innerHTML` of payload-derived + * strings. + */ +import { + App, + applyDocumentTheme, + applyHostFonts, + applyHostStyleVariables, + getViewContentBlocks, + type McpUiHostContext, +} from "@modelcontextprotocol/ext-apps"; +import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { + DYNAMIC_UI_MIME_TYPE, + type UiComponent, + type UiSurface, +} from "../dynamic-ui"; +import "./global.css"; +import "./mcp-app.css"; + +const mainEl = document.querySelector(".main") as HTMLElement; +const surfaceEl = document.getElementById("surface")!; + +function handleHostContextChanged(ctx: McpUiHostContext) { + if (ctx.theme) { + applyDocumentTheme(ctx.theme); + } + if (ctx.styles?.variables) { + applyHostStyleVariables(ctx.styles.variables); + } + if (ctx.styles?.css?.fonts) { + applyHostFonts(ctx.styles.css.fonts); + } + if (ctx.safeAreaInsets) { + mainEl.style.paddingTop = `${ctx.safeAreaInsets.top}px`; + mainEl.style.paddingRight = `${ctx.safeAreaInsets.right}px`; + mainEl.style.paddingBottom = `${ctx.safeAreaInsets.bottom}px`; + mainEl.style.paddingLeft = `${ctx.safeAreaInsets.left}px`; + } +} + +const app = new App({ name: "Dynamic Content Renderer", version: "1.0.0" }); + +function setStatus(text: string) { + surfaceEl.replaceChildren(); + const status = document.createElement("p"); + status.className = "status"; + status.textContent = text; + surfaceEl.append(status); +} + +/** The event bridge: payload-level actions become MCP tool calls. */ +async function invokeAction(action: { + tool: string; + arguments: Record; +}) { + surfaceEl.classList.add("busy"); + try { + const result = await app.callServerTool({ + name: action.tool, + arguments: action.arguments, + }); + applyToolResult(result); + } catch (e) { + console.error("Action failed:", e); + setStatus("Something went wrong — check the console."); + } finally { + surfaceEl.classList.remove("busy"); + } +} + +function renderComponent(component: UiComponent): HTMLElement { + switch (component.kind) { + case "text": { + const variant = component.variant ?? "body"; + const el = document.createElement(variant === "title" ? "h3" : "p"); + el.className = `text text-${variant}`; + el.textContent = component.text; + return el; + } + case "row": + case "column": + case "card": { + const el = document.createElement("div"); + el.className = component.kind; + el.append(...component.children.map(renderComponent)); + return el; + } + case "button": { + const el = document.createElement("button"); + el.textContent = component.label; + el.addEventListener("click", () => invokeAction(component.action)); + return el; + } + default: { + // Unknown component kinds are skipped, not errors: payload formats + // evolve independently of the renderer. + const el = document.createElement("span"); + el.hidden = true; + return el; + } + } +} + +function renderSurface(document_: UiSurface) { + surfaceEl.replaceChildren(...document_.surface.map(renderComponent)); +} + +/** Extract marked payloads from any tool result and render them in order. */ +function applyToolResult(result: CallToolResult) { + const payloads = getViewContentBlocks(result, { + mimeType: DYNAMIC_UI_MIME_TYPE, + }); + if (payloads.length === 0) { + console.info("Tool result carried no dynamic content payloads:", result); + return; + } + for (const block of payloads) { + if ("text" in block.resource) { + try { + renderSurface(JSON.parse(block.resource.text) as UiSurface); + } catch (e) { + console.error("Invalid payload from", block.resource.uri, e); + } + } + } +} + +app.ontoolinput = (params) => { + console.info("Received tool call input:", params); + setStatus("Searching…"); +}; + +app.ontoolresult = (result) => { + console.info("Received tool call result:", result); + applyToolResult(result); +}; + +app.ontoolcancelled = (params) => { + console.info("Tool call cancelled:", params.reason); + setStatus("Cancelled."); +}; + +app.onerror = console.error; +app.onhostcontextchanged = handleHostContextChanged; + +app.connect().then(() => { + const ctx = app.getHostContext(); + if (ctx) { + handleHostContextChanged(ctx); + } +}); diff --git a/examples/dynamic-content-server/tsconfig.json b/examples/dynamic-content-server/tsconfig.json new file mode 100644 index 000000000..685c9a73f --- /dev/null +++ b/examples/dynamic-content-server/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "server.ts", "dynamic-ui.ts"] +} diff --git a/examples/dynamic-content-server/tsconfig.server.json b/examples/dynamic-content-server/tsconfig.server.json new file mode 100644 index 000000000..6201840fb --- /dev/null +++ b/examples/dynamic-content-server/tsconfig.server.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "./dist", + "rootDir": ".", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true + }, + "include": ["server.ts", "dynamic-ui.ts"] +} diff --git a/examples/dynamic-content-server/vite.config.ts b/examples/dynamic-content-server/vite.config.ts new file mode 100644 index 000000000..6ff6d9979 --- /dev/null +++ b/examples/dynamic-content-server/vite.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from "vite"; +import { viteSingleFile } from "vite-plugin-singlefile"; + +const INPUT = process.env.INPUT; +if (!INPUT) { + throw new Error("INPUT environment variable is not set"); +} + +const isDevelopment = process.env.NODE_ENV === "development"; + +export default defineConfig({ + plugins: [viteSingleFile()], + build: { + sourcemap: isDevelopment ? "inline" : undefined, + cssMinify: !isDevelopment, + minify: !isDevelopment, + + rollupOptions: { + input: INPUT, + }, + outDir: "dist", + emptyOutDir: false, + }, +}); diff --git a/package-lock.json b/package-lock.json index 29e905875..2111c8446 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,23 +89,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-host/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-host/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-preact": { "name": "@modelcontextprotocol/server-basic-preact", "version": "1.7.4", @@ -133,23 +116,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-server-preact/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-preact/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-react": { "name": "@modelcontextprotocol/server-basic-react", "version": "1.7.4", @@ -180,23 +146,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-server-react/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-react/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-solid": { "name": "@modelcontextprotocol/server-basic-solid", "version": "1.7.4", @@ -224,23 +173,6 @@ "vite-plugin-solid": "^2.11.12" } }, - "examples/basic-server-solid/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-solid/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-svelte": { "name": "@modelcontextprotocol/server-basic-svelte", "version": "1.7.4", @@ -268,23 +200,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-server-svelte/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-svelte/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-vanillajs": { "name": "@modelcontextprotocol/server-basic-vanillajs", "version": "1.7.4", @@ -310,23 +225,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-server-vanillajs/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-vanillajs/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/basic-server-vue": { "name": "@modelcontextprotocol/server-basic-vue", "version": "1.7.4", @@ -354,23 +252,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/basic-server-vue/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/basic-server-vue/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/budget-allocator-server": { "name": "@modelcontextprotocol/server-budget-allocator", "version": "1.7.4", @@ -397,23 +278,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/budget-allocator-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/budget-allocator-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/cohort-heatmap-server": { "name": "@modelcontextprotocol/server-cohort-heatmap", "version": "1.7.4", @@ -444,23 +308,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/cohort-heatmap-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/cohort-heatmap-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/customer-segmentation-server": { "name": "@modelcontextprotocol/server-customer-segmentation", "version": "1.7.4", @@ -487,23 +334,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/customer-segmentation-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/customer-segmentation-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/debug-server": { "name": "@modelcontextprotocol/server-debug", "version": "1.7.4", @@ -529,7 +359,32 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/debug-server/node_modules/@types/node": { + "examples/dynamic-content-server": { + "name": "@modelcontextprotocol/server-dynamic-content", + "version": "1.7.4", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/ext-apps": "^1.7.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "cors": "^2.8.5", + "express": "^5.1.0", + "zod": "^4.1.13" + }, + "bin": { + "mcp-server-dynamic-content": "dist/index.js" + }, + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.0", + "@types/node": "22.10.0", + "concurrently": "^9.2.1", + "cross-env": "^10.1.0", + "typescript": "^5.9.3", + "vite": "^6.0.0", + "vite-plugin-singlefile": "^2.3.0" + } + }, + "examples/dynamic-content-server/node_modules/@types/node": { "version": "22.10.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", @@ -539,7 +394,7 @@ "undici-types": "~6.20.0" } }, - "examples/debug-server/node_modules/undici-types": { + "examples/dynamic-content-server/node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", @@ -573,23 +428,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/integration-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/integration-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/lazy-auth-server": { "name": "@modelcontextprotocol/server-lazy-auth", "version": "1.7.4", @@ -615,23 +453,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/lazy-auth-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/lazy-auth-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/map-server": { "name": "@modelcontextprotocol/server-map", "version": "1.7.4", @@ -657,23 +478,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/map-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/map-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/pdf-server": { "name": "@modelcontextprotocol/server-pdf", "version": "1.7.4", @@ -701,23 +505,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/pdf-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/pdf-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/qr-server": { "name": "@modelcontextprotocol/server-qr", "version": "1.7.4", @@ -748,16 +535,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/quickstart/node_modules/@types/node": { - "version": "22.19.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.5.tgz", - "integrity": "sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, "examples/say-server": { "name": "@modelcontextprotocol/server-say", "version": "1.7.4", @@ -798,23 +575,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/scenario-modeler-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/scenario-modeler-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/shadertoy-server": { "name": "@modelcontextprotocol/server-shadertoy", "version": "1.7.4", @@ -840,23 +600,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/shadertoy-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/shadertoy-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/sheet-music-server": { "name": "@modelcontextprotocol/server-sheet-music", "version": "1.7.4", @@ -883,23 +626,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/sheet-music-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/sheet-music-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/system-monitor-server": { "name": "@modelcontextprotocol/server-system-monitor", "version": "1.7.4", @@ -927,23 +653,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/system-monitor-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/system-monitor-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/threejs-server": { "name": "@modelcontextprotocol/server-threejs", "version": "1.7.4", @@ -976,23 +685,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/threejs-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/threejs-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/transcript-server": { "name": "@modelcontextprotocol/server-transcript", "version": "1.7.4", @@ -1019,23 +711,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/transcript-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/transcript-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/video-resource-server": { "name": "@modelcontextprotocol/server-video-resource", "version": "1.7.4", @@ -1061,23 +736,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/video-resource-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/video-resource-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "examples/wiki-explorer-server": { "name": "@modelcontextprotocol/server-wiki-explorer", "version": "1.7.4", @@ -1105,23 +763,6 @@ "vite-plugin-singlefile": "^2.3.0" } }, - "examples/wiki-explorer-server/node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "examples/wiki-explorer-server/node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/code-frame": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", @@ -1153,6 +794,7 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -2618,6 +2260,7 @@ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "license": "MIT", + "peer": true, "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", @@ -2693,6 +2336,10 @@ "resolved": "examples/debug-server", "link": true }, + "node_modules/@modelcontextprotocol/server-dynamic-content": { + "resolved": "examples/dynamic-content-server", + "link": true + }, "node_modules/@modelcontextprotocol/server-lazy-auth": { "resolved": "examples/lazy-auth-server", "link": true @@ -3757,6 +3404,7 @@ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -3969,6 +3617,7 @@ "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -4252,6 +3901,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4583,6 +4233,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5319,6 +4970,7 @@ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -5772,6 +5424,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -6175,6 +5828,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -7328,6 +6982,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -7537,6 +7192,7 @@ "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -7658,6 +7314,7 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.1.tgz", "integrity": "sha512-9GOc+8T6LN4aByLN75uRvMbrwY5RDBW6lSlknsY4LEa9ZmWcxKcRe1G/Q3HZXjltxMHTrStnvrwAICxZrhldtg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -7950,6 +7607,7 @@ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -8094,6 +7752,7 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.1.tgz", "integrity": "sha512-eArsJmvl3xZVuTYD852PzIEdg2wgDdIZ1NEsIPbzAukHwi284B18No4nK2rCO9AwsWUDza4Cjvmoa4HaojTl5g==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -8408,6 +8067,7 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9076,6 +8736,7 @@ "integrity": "sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@gerrit0/mini-shiki": "^3.17.0", "lunr": "^2.3.9", @@ -9139,6 +8800,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9232,6 +8894,7 @@ "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -9385,6 +9048,7 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9417,6 +9081,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.27", "@vue/compiler-sfc": "3.5.27", @@ -9560,6 +9225,7 @@ "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -9610,6 +9276,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/ui-content.ts b/src/ui-content.ts index 6c9674629..f6e961efc 100644 --- a/src/ui-content.ts +++ b/src/ui-content.ts @@ -162,7 +162,9 @@ export type GetViewContentBlocksOptions = { * }); * renderA2ui( * payloads.map((block) => - * "text" in block.resource ? block.resource.text : atob(block.resource.blob), + * "text" in block.resource + * ? block.resource.text + * : atob(block.resource.blob), * ), * ); * }; diff --git a/tests/e2e/servers.spec.ts b/tests/e2e/servers.spec.ts index a3c30d8a8..d96f86f2e 100644 --- a/tests/e2e/servers.spec.ts +++ b/tests/e2e/servers.spec.ts @@ -117,6 +117,11 @@ const ALL_SERVERS = [ dir: "customer-segmentation-server", }, { key: "debug-server", name: "Debug MCP App Server", dir: "debug-server" }, + { + key: "dynamic-content", + name: "Dynamic View Content Example Server", + dir: "dynamic-content-server", + }, { key: "map-server", name: "CesiumJS Map Server", dir: "map-server" }, { key: "pdf-server", name: "PDF Server", dir: "pdf-server" }, { key: "qr-server", name: "QR Code Server", dir: "qr-server" }, diff --git a/tests/e2e/servers.spec.ts-snapshots/dynamic-content.png b/tests/e2e/servers.spec.ts-snapshots/dynamic-content.png new file mode 100644 index 0000000000000000000000000000000000000000..3f387fc688c762320a91fadc164d6c08dd54d586 GIT binary patch literal 70266 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 literal 0 HcmV?d00001 From 2cdc509ce6f2d1cbe6570cb60694fc1e31f44d4e Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Wed, 8 Jul 2026 03:59:25 +0300 Subject: [PATCH 4/4] fix: regenerate package-lock.json with npm 10 for npm ci compatibility The previous lockfile update was generated with a newer npm that deduped the nested examples/*/node_modules/@types/node and undici-types entries, which npm 10 (Node 22, used in CI) still resolves as required - so npm ci failed with 'lock file out of sync'. Regenerated from main's lockfile via npm install --package-lock-only in a linux/amd64 node:22 container; the diff vs main is now purely additive (the dynamic-content-server workspace entries only). Co-Authored-By: Claude Fable 5 --- package-lock.json | 423 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 401 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2111c8446..1a20022cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,6 +89,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-host/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-host/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-preact": { "name": "@modelcontextprotocol/server-basic-preact", "version": "1.7.4", @@ -116,6 +133,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-server-preact/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-preact/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-react": { "name": "@modelcontextprotocol/server-basic-react", "version": "1.7.4", @@ -146,6 +180,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-server-react/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-react/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-solid": { "name": "@modelcontextprotocol/server-basic-solid", "version": "1.7.4", @@ -173,6 +224,23 @@ "vite-plugin-solid": "^2.11.12" } }, + "examples/basic-server-solid/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-solid/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-svelte": { "name": "@modelcontextprotocol/server-basic-svelte", "version": "1.7.4", @@ -200,6 +268,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-server-svelte/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-svelte/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-vanillajs": { "name": "@modelcontextprotocol/server-basic-vanillajs", "version": "1.7.4", @@ -225,6 +310,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-server-vanillajs/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-vanillajs/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/basic-server-vue": { "name": "@modelcontextprotocol/server-basic-vue", "version": "1.7.4", @@ -252,6 +354,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/basic-server-vue/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/basic-server-vue/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/budget-allocator-server": { "name": "@modelcontextprotocol/server-budget-allocator", "version": "1.7.4", @@ -278,6 +397,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/budget-allocator-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/budget-allocator-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/cohort-heatmap-server": { "name": "@modelcontextprotocol/server-cohort-heatmap", "version": "1.7.4", @@ -308,6 +444,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/cohort-heatmap-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/cohort-heatmap-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/customer-segmentation-server": { "name": "@modelcontextprotocol/server-customer-segmentation", "version": "1.7.4", @@ -334,6 +487,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/customer-segmentation-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/customer-segmentation-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/debug-server": { "name": "@modelcontextprotocol/server-debug", "version": "1.7.4", @@ -359,6 +529,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/debug-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/debug-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/dynamic-content-server": { "name": "@modelcontextprotocol/server-dynamic-content", "version": "1.7.4", @@ -428,6 +615,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/integration-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/integration-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/lazy-auth-server": { "name": "@modelcontextprotocol/server-lazy-auth", "version": "1.7.4", @@ -453,6 +657,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/lazy-auth-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/lazy-auth-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/map-server": { "name": "@modelcontextprotocol/server-map", "version": "1.7.4", @@ -478,6 +699,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/map-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/map-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/pdf-server": { "name": "@modelcontextprotocol/server-pdf", "version": "1.7.4", @@ -505,6 +743,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/pdf-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/pdf-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/qr-server": { "name": "@modelcontextprotocol/server-qr", "version": "1.7.4", @@ -535,6 +790,16 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/quickstart/node_modules/@types/node": { + "version": "22.19.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.5.tgz", + "integrity": "sha512-HfF8+mYcHPcPypui3w3mvzuIErlNOh2OAG+BCeBZCEwyiD5ls2SiCwEyT47OELtf7M3nHxBdu0FsmzdKxkN52Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, "examples/say-server": { "name": "@modelcontextprotocol/server-say", "version": "1.7.4", @@ -575,6 +840,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/scenario-modeler-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/scenario-modeler-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/shadertoy-server": { "name": "@modelcontextprotocol/server-shadertoy", "version": "1.7.4", @@ -600,6 +882,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/shadertoy-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/shadertoy-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/sheet-music-server": { "name": "@modelcontextprotocol/server-sheet-music", "version": "1.7.4", @@ -626,6 +925,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/sheet-music-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/sheet-music-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/system-monitor-server": { "name": "@modelcontextprotocol/server-system-monitor", "version": "1.7.4", @@ -653,6 +969,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/system-monitor-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/system-monitor-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/threejs-server": { "name": "@modelcontextprotocol/server-threejs", "version": "1.7.4", @@ -685,6 +1018,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/threejs-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/threejs-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/transcript-server": { "name": "@modelcontextprotocol/server-transcript", "version": "1.7.4", @@ -711,6 +1061,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/transcript-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/transcript-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/video-resource-server": { "name": "@modelcontextprotocol/server-video-resource", "version": "1.7.4", @@ -736,6 +1103,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/video-resource-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/video-resource-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "examples/wiki-explorer-server": { "name": "@modelcontextprotocol/server-wiki-explorer", "version": "1.7.4", @@ -763,6 +1147,23 @@ "vite-plugin-singlefile": "^2.3.0" } }, + "examples/wiki-explorer-server/node_modules/@types/node": { + "version": "22.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", + "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "examples/wiki-explorer-server/node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", @@ -794,7 +1195,6 @@ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -2260,7 +2660,6 @@ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "license": "MIT", - "peer": true, "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", @@ -3404,7 +3803,6 @@ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", @@ -3617,7 +4015,6 @@ "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3901,7 +4298,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4233,7 +4629,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4970,7 +5365,6 @@ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -5424,7 +5818,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -5828,7 +6221,6 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -6982,7 +7374,6 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -7192,7 +7583,6 @@ "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -7314,7 +7704,6 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.1.tgz", "integrity": "sha512-9GOc+8T6LN4aByLN75uRvMbrwY5RDBW6lSlknsY4LEa9ZmWcxKcRe1G/Q3HZXjltxMHTrStnvrwAICxZrhldtg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -7607,7 +7996,6 @@ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -7752,7 +8140,6 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.1.tgz", "integrity": "sha512-eArsJmvl3xZVuTYD852PzIEdg2wgDdIZ1NEsIPbzAukHwi284B18No4nK2rCO9AwsWUDza4Cjvmoa4HaojTl5g==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -8067,7 +8454,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8736,7 +9122,6 @@ "integrity": "sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@gerrit0/mini-shiki": "^3.17.0", "lunr": "^2.3.9", @@ -8800,7 +9185,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8894,7 +9278,6 @@ "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -9048,7 +9431,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -9081,7 +9463,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.27", "@vue/compiler-sfc": "3.5.27", @@ -9225,7 +9606,6 @@ "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -9276,7 +9656,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }