effect/ai: support the MCP Apps extension (`io.modelcontextprotocol/ui`)
Maintainer thường phản hồi trong vòng 1 ngày
@effect-bot đang làm issue này rồi.
Từ ngày 5/11/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Need
MCP Apps is the
stable MCP extension that lets a server give the human a visual for a tool call. A tool links to a ui:// HTML
resource. The host renders it in a sandboxed iframe, and the page (the spec calls it the View) talks to the host over
JSON-RPC on postMessage. A tool result serves two readers: structuredContent holds the data for the page and the
agent, and content holds the text for the model and for hosts without Apps. Claude (web and desktop), VS Code,
ChatGPT, Goose and others render MCP Apps.
An Effect MCP server can link a tool to a UI today only by hand: an untyped Tool.Meta record, a hand-written
extensions key, and a content effect that returns a raw ReadResourceResult. The page itself has no Effect
support. Concretely:
- No typed extension announcement,
ui://resource, resource_meta.ui(CSP, permissions, domain, border) or tool
_meta.ui(resourceUri,visibility).registerResourcehas no_metaoption. - No way to check whether the host supports Apps, other than reading
clientCapabilities.extensionsby hand. contentis always the JSON ofstructuredContent.McpServerignores a tool'stoModelOutput, so a tool
can't give the model a text summary while the page gets the data.- A handler can't see the JSON-RPC id of its own
tools/call.hostContext.toolInfo.idis the only standard key
a page has for the call that created it while that call is still running, so a server can't tie a page's polling
calls to the run they belong to. Handlers also can't seeMcp-Session-Id, the scope in which that id is unique
over sessionful HTTP.clientIdis assigned per HTTP POST, so it can't serve as that scope. McpClient.toolkitbinds tools markedvisibility: ["app"]for the model, though the spec says hosts MUST NOT
give them to the agent.McpClientcan't declare the extension.- Nothing for the page: the handshake, tool input and result, host context, calling server tools, display modes,
sizing and teardown.
The motivating consumer is the effect/test MCP server. Its tool results stay Schema'd data the agent acts on, and the
human gets a live view of a run, run reports and snapshot diffs in the host.
Prior art
- #6353 asks for first-class MCP Apps support: a
ui://resource kind and typedTool.Metakeys. This issue covers
that request. - Effect-TS/effect-smol#1440 added the
_metaandextensionspassthrough on MCP schemas, and
Effect-TS/effect-smol#1653 exposed the client capabilities to handlers. Both are what makes MCP Apps possible today. - @lloydrichards's examples (edu_mcp-apps,
interactivethings-data-viz-mcp-lab, and
the helpers posted on #6353) build MCP Apps on the currentMcpServer.makeUiResource,makeUiRenderTooland
makeUiAppToolare the shape the server half below makes first-class. The polling dashboard there is the pattern
the effect/test live view follows. - #8631 (Tasks) and the Skills extension set the pattern for extensions: a public module per extension, a server that
declares the extension once it is in use, andMcpClientoptions grouped underextensions. This proposal follows
it.
Alternatives considered
- Keep hand-writing
_metaand HTML resources. This works for the linkage, but nothing is typed or validated,
the model gets JSON where the spec suggests a summary, and the page side gets no help. - Use
@modelcontextprotocol/ext-appson the page. It is Promise- and zod-based, built on the TypeScript MCP
SDK, and useson*setters that must be registered beforeconnect(). It can't reuse the server'sTool
definitions to type calls and results. - Extend
McpClientto be the page's bridge.McpClientis request/response. The bridge is bidirectional: the
host sends notifications and theui/resource-teardownrequest. It also has its own handshake (ui/initialize). - Vary a tool's
_metaby host. In 2026-07-28,tools/listmust not vary per connection, and a
cacheScope: "public"list may be served to any client. Hosts without Apps already treat a linked tool as a plain
tool, andEnabledWhencovers text-only variants. - Correlate a page with its call through a server-minted handle in the result. The handle arrives only when the
call completes, which is too late for a long-running call. The request id is available from the start.
Solution
Two PRs, opened after #8631 merges because it changes the same files. The server and host parts come first, then the
page module. Both cover the stable 2026-01-26 spec plus the draft's ui/download-file and
ui/notifications/request-teardown. Names below are provisional.
1. Server and host
A new module, effect/ai/McpApps, for the extension itself:
- Schemas and constants:
ResourceMeta(with its CSP and permissions parts),ToolMeta,ClientCapabilities,
EXTENSION_IDandMIME_TYPE. McpApps.registerResourceandMcpApps.resource. The URI must beui://…, or registration fails with
IllegalArgumentError. The MIME typetext/html;profile=mcp-appgoes on the listing and on every content item,
and the resource metadata goes as_meta.uion both.- Registering an app resource declares the extension (
{}) on every protocol revision. An explicitextensions
record still merges in. - A tool annotation that
registerToolkitmerges into the tool's_meta.ui. Registration dies ifTool.Metaalso
setsui, or ifresourceUri(optional, as app-only tools have none) isn'tui://. Only the nested form is
written, not the deprecated_meta["ui/resourceUri"]. McpApps.isSupported(capabilities), usable inEnabledWhenand in handlers.
General fixes, in the existing modules:
- A
_metaoption forMcpServer.registerResourceandMcpServer.resource(the listing entry). toModelOutputbecomes the MCPcontent(text, image, audio, resource link or embedded resource), and
structuredContentstays the encoded success. Tools withouttoModelOutputare unchanged.McpRequestContextgainsrequestId, the JSON-RPC id as received, andsessionId. The docs say where the id is
unique on each transport: within the process on stdio, within the session over sessionful HTTP, and on 2026-07-28
only among the sender's requests still in flight. Fix theclientIddocs.McpClient.make({ extensions: { ui: true } })declares{ mimeTypes: ["text/html;profile=mcp-app"] }.
McpClient.toolkitskips tools whose visibility lacks"model".
Out of scope: result _meta, ui:// templates, and the host-side bridge (rendering, CSP, proxying).
2. The page
effect/ai/McpAppView, platform-agnostic:
- A
McpAppViewservice and layer over anypostMessage-capable target. It performs theui/initialize
handshake and buffers host messages from the moment it connects. - Host data as Effect types:
toolInput(anEffect)toolInputPartial(aStream)toolResult(anEffectthat fails withToolCancelled)hostContext(aSubscribablethat merges partial updates)hostInfoandhostCapabilities
toolCall(tool)decodes the input and the result with the tool's schemas.callTool(tool, params)calls a
server tool through the host, typed from the sameTooldefinitions. A failure is aToolErrorthat keeps the
result, as inMcpClient.callTool.readResource,openLink,sendMessage,updateModelContext,requestDisplayMode,sendSizeChanged,log,
downloadFileandrequestTeardown. They fail fast when the host lacks a capability the stable spec defines.run(program): onui/resource-teardown, the program and every fiber the bridge owns are interrupted, their
finalizers run, and only then does the host get its answer. Any other host request the page doesn't implement gets
JSON-RPC-32601(method not found).- It must work in opaque-origin documents, which is how hosts load pages (cf. #9196).
- A public in-memory test host for pages, in the style of
McpTest.
@effect/platform-browser adds only what needs the DOM: ResizeObserver auto-resize (on by default) and opt-in
helpers for the host's theme, CSS variables and fonts. Is that the right home, or should these stay in the core
module's docs as examples?
Out of scope: app-provided tools and WebMCP (see modelcontextprotocol/ext-apps#797; not planned), sampling from the
page, framework bindings, and HTML bundling.
Development uses MCPJam Inspector to render and check pages against
emulated hosts. The repo's tests use the in-memory test host.
- Ngôn ngữ chính
- TypeScript
- Star
- 16.7k
- Fork
- 808
- Merge trung bình
- 12 giờ 17 phút
- Pull request đã merge (30 ngày)
- 805
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Effect-TS/effect
-
McpServer.layerHttp: optional legacy GET SSE for idle list-change notificationsCó thể đã có người làm @effect-bot đã nhận 1 ngày trước. Đang mở
Effect-TS/effect#10436 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
SqlClient: a fiber forked inside a transaction keeps using its connection after the transaction endsCó thể đã có người làm @effect-bot đã nhận 1 ngày trước. Đang mởbug
Effect-TS/effect#10431 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
CLI completions stop offering repeatable flags after their first useCó thể đã có người làm @effect-bot đã nhận 1 ngày trước. Đang mở
Effect-TS/effect#10427 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
sql-pg: pgvector columns fail with "Invalid UTF-8 in text value"Có thể đã có người làm @effect-bot đã nhận 2 ngày trước. Đang mởbug
Effect-TS/effect#10420 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
cli: completions break for subcommand names with `:`Có thể đã có người làm @effect-bot đã nhận 2 ngày trước. Đang mở
Effect-TS/effect#10416 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của Effect-TS/effect
Issue tương tự
-
Add: Shop On TV SDĐang mởcheck:passed streams:add
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug implicit-state
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
-
book-layout.spec fails when the similar-books rail holds other projects' booksCó thể đã có người làm @praetorianer777 đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
praetorianer777/GoTome#373 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Tencent/tdesign-react#4465 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:cards enhancement ready-for-agent
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
fil-donadoni/tolaria#8883 ·
Maintainer thường phản hồi trong vòng 1 ngày