From fe8ef4c62106f87b11ca3bf4d2686b5b8882110e Mon Sep 17 00:00:00 2001 From: Andrew Harvard Date: Fri, 16 Jan 2026 14:07:55 -0500 Subject: [PATCH 1/3] fix(mcp-apps): update ui/message to use ContentBlock[] for content The MCP Apps draft spec (SEP-1865) has been in flux regarding the ui/message params.content type. After discussion with the spec authors, the agreed format is ContentBlock[] (array of content blocks) rather than a single ContentBlock object. This change: - Updates McpMethodParams['ui/message'] to expect content as ContentBlock[] - Adds ContentBlock type supporting text, image, and resource blocks - Updates the handler to extract text from the first text block in the array - Returns empty object {} on success per the spec Related spec discussions: - https://github.com/modelcontextprotocol/ext-apps/issues/48 - https://github.com/modelcontextprotocol/ext-apps/pull/119 - https://github.com/MCP-UI-Org/mcp-ui/pull/166 --- .../src/components/McpApps/McpAppRenderer.tsx | 20 ++++++++++++++----- ui/desktop/src/components/McpApps/types.ts | 12 +++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx index e3df201c114d..f99304af0855 100644 --- a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx +++ b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx @@ -128,12 +128,22 @@ export default function McpAppRenderer({ if (!append) { throw new Error('Message handler not available in this context'); } - append(content.text); + + if (!Array.isArray(content)) { + throw new Error('Invalid message format: content must be an array of ContentBlock'); + } + + // Extract first text from content blocks, ignoring other text blocks + const textContent = content.find((block) => block.type === 'text'); + if (!textContent || textContent.type !== 'text') { + throw new Error('Invalid message format: content must contain a text block'); + } + + // MCP Apps can send other content block types, but we only append text blocks for now + + append(textContent.text); window.dispatchEvent(new CustomEvent('scroll-chat-to-bottom')); - return { - status: 'success', - message: 'Message appended successfully', - } satisfies McpMethodResponse['ui/message']; + return {} satisfies McpMethodResponse['ui/message']; } case 'tools/call': { diff --git a/ui/desktop/src/components/McpApps/types.ts b/ui/desktop/src/components/McpApps/types.ts index 43ce6ecade11..c24c7ae80f85 100644 --- a/ui/desktop/src/components/McpApps/types.ts +++ b/ui/desktop/src/components/McpApps/types.ts @@ -1,8 +1,16 @@ export type { CspMetadata, CallToolResponse as ToolResult } from '../../api/types.gen'; +export type ContentBlock = + | { type: 'text'; text: string } + | { type: 'image'; data: string; mimeType: string } + | { + type: 'resource'; + resource: { uri: string; mimeType?: string; text?: string; blob?: string }; + }; + export type McpMethodParams = { 'ui/open-link': { url: string }; - 'ui/message': { content: { type: string; text: string } }; + 'ui/message': { role: 'user'; content: ContentBlock[] }; 'tools/call': { name: string; arguments?: Record }; 'resources/read': { uri: string }; 'notifications/message': { level?: string; logger?: string; data: unknown }; @@ -11,7 +19,7 @@ export type McpMethodParams = { export type McpMethodResponse = { 'ui/open-link': { status: string; message: string }; - 'ui/message': { status: string; message: string }; + 'ui/message': Record; 'tools/call': { content: unknown[]; isError: boolean; From defbe2fd50673d871181c628d9c0ec0ce391ad89 Mon Sep 17 00:00:00 2001 From: Andrew Harvard Date: Fri, 16 Jan 2026 14:16:21 -0500 Subject: [PATCH 2/3] Update ui/desktop/src/components/McpApps/McpAppRenderer.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ui/desktop/src/components/McpApps/McpAppRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx index f99304af0855..78b0b3773390 100644 --- a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx +++ b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx @@ -133,7 +133,7 @@ export default function McpAppRenderer({ throw new Error('Invalid message format: content must be an array of ContentBlock'); } - // Extract first text from content blocks, ignoring other text blocks + // Extract first text block from content, ignoring other block types const textContent = content.find((block) => block.type === 'text'); if (!textContent || textContent.type !== 'text') { throw new Error('Invalid message format: content must contain a text block'); From 4d547358b3c5c8ff96ad3553f2553231e1069c42 Mon Sep 17 00:00:00 2001 From: Andrew Harvard Date: Fri, 16 Jan 2026 14:16:35 -0500 Subject: [PATCH 3/3] Update ui/desktop/src/components/McpApps/McpAppRenderer.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ui/desktop/src/components/McpApps/McpAppRenderer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx index 78b0b3773390..c78e2b94a95b 100644 --- a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx +++ b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx @@ -135,7 +135,7 @@ export default function McpAppRenderer({ // Extract first text block from content, ignoring other block types const textContent = content.find((block) => block.type === 'text'); - if (!textContent || textContent.type !== 'text') { + if (!textContent) { throw new Error('Invalid message format: content must contain a text block'); }