MCP Apps
How permdock/mcp decides who may see an MCP Apps ui:// view and call the tools it drives.
Draft posture: build (pinned to MCP Apps 2026-01-26, specification/2026-01-26/apps.mdx at modelcontextprotocol/ext-apps v2.0.3, per watch list)
What it is
MCP Apps (SEP-1865, extension id io.modelcontextprotocol/ui) lets an MCP server ship an interactive HTML view for a tool. The host renders the view in a sandboxed iframe and talks to it over JSON-RPC on postMessage:
- A tool names its view in
_meta.ui.resourceUri, aui://resource whosemimeTypeistext/html;profile=mcp-app. The host fetches it withresources/read. _meta.ui.visibilitylists who may call the tool:"model"(the agent) and"app"(a view). The host hides a tool without"model"from the agent and rejects a view's call to a tool without"app".- A view calls tools and reads resources through the host, which forwards
tools/callandresources/readto the same server with the user's session. - The view declares the origins it fetches from in
_meta.ui.csp; the host builds the iframe's Content Security Policy from them.
Why it matters for PermDock
A view is a resource the server serves, and every tool it calls is a tool call. Both reach the server as ordinary MCP requests, so both need the same decision as the tool that opened the view. A view registered without a decision would show a user an interface for a tool they cannot call, and its HTML may embed data. An app-only tool is still a tool: the host hides it from the agent, but any client that holds the token can call it.
How PermDock uses it
guarded.registerTool(
"show_posts",
{
permission: permissions.post.list,
_meta: { ui: { resourceUri: "ui://posts/board" } },
},
listHandler,
);
guarded.registerResource(
"board",
"ui://posts/board",
{ mimeType: "text/html;profile=mcp-app" },
readBoard,
);- A
ui://view registered without apermissiontakes the permission of the tool whose_meta.ui.resourceUrinames it, forresources/listandresources/read(MCP Apps views). - A view no tool links is hidden and refused. Two tools that link one view under different permissions throw at registration.
- Every
tools/callis decided, whatever itsvisibility. - The deprecated flat
_meta["ui/resourceUri"]key is not read; a view linked only through it needs its ownpermission. - The sandbox, the CSP and the
postMessagebridge are the host's. PermDock does not render views.
Mapping table
| MCP Apps concept | PermDock concept |
|---|---|
ui:// resource | registerResource on the guarded server; permission optional |
_meta.ui.resourceUri on a tool | Links the view to the tool's permission |
resources/list and resources/read | Filtered and decided with the linking tool's permission |
_meta.ui.visibility: ["app"] | Host-side listing rule; tools/call is decided as for any tool |
A view's tools/call through the host | The same protectServer decision, with the user's token |
_meta.ui.csp, sandbox proxy | Host responsibility; out of PermDock's scope |
Graceful degradation (text content) | Unchanged: refusals are text plus structuredContent, readable without UI |
Sources
- MCP Apps specification 2026-01-26, sections Resource Discovery and Visibility.
- SEP-1865.
Last updated on
MCP authorization
How the Model Context Protocol 2026-07-28 authorization model (OAuth 2.1 resource servers, scope challenges, RFC 8707, MRTR, CIMD, RFC 9207, Enterprise-Managed Authorization) maps onto permdock/mcp.
OpenID AuthZEN
How PermDock speaks the OpenID AuthZEN Authorization API 1.0 as a policy decision point (permdock/authzen) and as a policy enforcement point (the pdp provider).