feat(mcp): interactive recent-meetings UI widget (MCP Apps / SEP-1865)#1495
Merged
Conversation
Expose an interactive "recent meetings" widget from the Transcripted MCP server via the MCP Apps extension (io.modelcontextprotocol/ui, SEP-1865): a card list of the N most recent meetings, each with inline audio playback and a raw-transcript view, rendered inside a rendering-capable agent client. - show_recent_meetings tool returns a self-contained text/html;profile=mcp-app widget as an inline embedded resource + structuredContent + a text fallback, linked via _meta.ui.resourceUri and openai/outputTemplate. - ui://transcripted/recent-meetings.html registered as a readable resource. - Reuses the existing meeting/transcript/audio access; adds a UI layer, not new data plumbing. Audio is base64-inlined (size-capped) and plays from a data: URI under the MCP Apps default sandbox CSP. - Fully local: no network, no CDN. Local audio/transcripts travel with the widget over the local stdio transport; nothing leaves the Mac. - Theme-aware (light/dark). 11 new tests; full MCP suite green (170). Renders inline today in ChatGPT, VS Code, Cursor, and Goose. Claude Desktop/web is announced but unverified on some builds; the Claude Code CLI shows the text fallback (no iframe surface). See docs/mcp-ui-recent-meetings.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the first interactive UI surface to Transcripted's MCP server: a
show_recent_meetingstool that renders a card list of recent meetings insidea rendering-capable agent client — each card with a ▶ Play control for the
meeting audio and a View raw transcript toggle. Not a wall of text; real,
renderable UI in the chat client.
This is the minimal first slice of the just-merged
MCP Apps design (#1491), Interpretation 2.
It reuses the existing read-only data surface (
list_meetings/read_meeting/the
audio/<stem>_audio/bundles) and adds a UI layer on top — no new dataplumbing.
How it works (MCP Apps / SEP-1865)
Built against the official MCP Apps extension (
io.modelcontextprotocol/ui,spec
2026-01-26— the standardized successor tomcp-ui):ui://transcripted/recent-meetings.html(MIMEtext/html;profile=mcp-app),served via
resources/read.show_recent_meetingslinks to it via_meta.ui.resourceUriand_meta["openai/outputTemplate"](ChatGPT/Apps SDK alias).a text fallback, the data-baked widget HTML as an inline embedded
resource (mcp-ui
rawHtmlpattern), andstructuredContent(the meetingmodel) for hosts that push tool output into the rendered template.
Privacy: nothing leaves this Mac
The widget is fully self-contained — inline CSS/JS, no CDN, no network. Audio
and transcripts are read from the local capture library and travel with the
widget over the local stdio transport to the local client. No remote host is in
the loop. The sandbox runs under the MCP Apps default CSP
(
connect-src 'none'; media-src 'self' data:), so the widget cannot reach thenetwork; audio plays from a
data:audio/mp4;base64,…URI, which the defaultpolicy allows. This matches the app's "your content never leaves this Mac"
posture exactly.
Renders today in: … / needs client support for: … (honest)
MCP Apps shipped 2026-01-26 and host support is uneven. Grounded in the spec +
client docs:
_meta-stripping bug)So: renders inline today in ChatGPT, VS Code, Cursor, and Goose. Needs client
support in Claude Desktop/web. The Claude Code CLI shows the text list (by
design — no iframe surface).
Did I get it rendering in a real client?
No local desktop client reliably renders MCP Apps today (Claude Code is a
terminal; Claude Desktop's rendering is contested per #671), so I verified where
it counts:
rendering host uses. Cards render, ▶ Play injects a working
<audio>player (real duration), View raw transcript expands the real transcript,
light + dark both clean, zero console errors. Driven against 162 real
meetings (106 with audio).
initialize→resources/list→tools/list→tools/call show_recent_meetings→resources/read, assertingthe capabilities,
_meta, embedded resource, andstructuredContentshapes.docs/mcp-ui-recent-meetings.mddocuments the per-client matrix and the exactsteps to render it in a rendering-capable client.
Tests
RecentMeetingsWidgetTests): builder (transcript+audio embed,Mix-over-Mic preference, size-cap fallbacks, budget), HTML self-containment +
theme-awareness + script-breakout neutralization, and the tool/resource wire
shape.
repo-hygienechecks (duplicate-declaration, agent-preflight) pass locally.Known limitations (minimal slice)
recordings fall back to showing their local
audio/<stem>_audio/path. The nextstep is lazy fetch over the postMessage bridge (
get_meeting_audioon a playclick), which scales past the inline budget but needs a host that forwards
widget→server tool calls.
🤖 Generated with Claude Code