Skip to main content
Version: 1.9.0

Govern MCP Apps (interactive tool UIs)

With MCP Apps, a tool can show an interactive page: a chart, a form, a dashboard. The client draws the page in a sandboxed frame next to the chat, and the page can call the server's tools. That is useful, and it is also a new way in for hidden instructions and a new way out for data. The page is HTML and script written by the server, and it can ask the client to let it reach other websites.

DVARA, the AI governance platform, governs these pages. The DVARA MCP Gateway carries MCP Apps between your clients and your MCP servers only where a workspace allows it. It serves only the page an operator approved, it limits the websites and browser permissions a page may ask for, it scans the page for personal data and prompt injection, and it records each page it serves in the tamper-evident audit trail.

Enterprise only

Not included in DVARA Open Source.

What are MCP Apps?​

MCP Apps is an MCP extension, named io.modelcontextprotocol/ui. Like every MCP extension, it is off until both sides ask for it.

  • A server offers a page as a resource with a ui:// address and the type text/html;profile=mcp-app.
  • A tool points to its page in _meta.ui.resourceUri. Its _meta.ui.visibility says who may call it: the model, the page (app), or both.
  • The page's own _meta.ui.csp lists the websites it needs (for data, scripts, images, frames), and _meta.ui.permissions the browser features it wants (camera, microphone, location, clipboard).
  • The client draws the page and builds its content security policy from that list. The Gateway does not draw anything. It decides what reaches the client.

When does the Gateway relay MCP Apps?​

All of these must be true:

  1. The client is on MCP 2026-07-28 and declares the extension on the request.
  2. The workspace allows the extension (see Control which MCP extensions a client may use). A workspace policy can still deny it.
  3. The MCP server declares the extension, on 2026-07-28.

Otherwise the client sees ordinary tools with no page. MCP Apps is off by default. To allow it for one workspace, add io.modelcontextprotocol/ui on Agents → MCP Extensions in Flightdeck. To allow it everywhere:

DVARA_MCP_GATEWAY_EXTENSIONS_ALLOWED=io.modelcontextprotocol/ui

Approve a page once, serve only that page​

When a workspace allows MCP Apps, a tool sync reads each tool's page and pins its fingerprint with the tool's definition. Later:

  • The Gateway serves a page only while it matches the approved fingerprint.
  • If the server changes a page, the next sync holds the change for approval, the same way it holds a changed tool description. The server is quarantined until someone approves it, and the approved page stays in use until then.
  • A tool whose page could not be read is not shown with a page until a sync reads it.
note

Turning MCP Apps on for a workspace whose tools were already approved asks for approval once for each tool that has a page: its definition gained a part.

Limit what a page may reach​

A page can only ask the client to allow the websites and browser permissions on the workspace's lists. Both lists are empty by default, so a page that loads nothing from outside and asks for no permission is served, and any other is refused until you allow what it needs.

WhatWorkspace settingFleet default
Websites a page may namemcp.apps.allowed-domainsDVARA_MCP_GATEWAY_APPS_ALLOWED_DOMAINS
Browser permissions a page may ask formcp.apps.allowed-permissionsDVARA_MCP_GATEWAY_APPS_ALLOWED_PERMISSIONS
Largest pagenoneDVARA_MCP_GATEWAY_APPS_MAX_RESOURCE_BYTES (1 MiB)

A website is written as an origin, such as https://api.example.com, or with a wildcard for its subdomains, such as https://*.example.com. The permissions are camera, microphone, geolocation and clipboardWrite, the four that MCP Apps defines.

Set the workspace's lists in one of these places:

WhereWho
Agents → MCP Extensions in Flightdeck, the MCP Apps cardWorkspace admin
The workspace form's MCP extensions → MCP Apps section in FlightdeckPlatform owner
The workspace's metadata, in a GitOps importWhoever runs the import

Leave a list blank to use the fleet default, or enter none to allow nothing. All three places check what you enter and save nothing if one entry is wrong: a website that is not an origin, a path after the host, a wildcard over a whole top-level domain such as https://*.com, or a permission that is not one of the four (clipboard-write is refused; the name is clipboardWrite). A change in Flightdeck is recorded in the audit trail.

workspaces:
- name: analytics
metadata:
mcp.extensions.allowed: io.modelcontextprotocol/ui
mcp.apps.allowed-domains: https://api.weather.example, https://*.jsdelivr.net

Turn MCP Apps off for one server or one tool​

Allowing MCP Apps is a workspace decision. Rules can then turn it off for one server or one tool, without touching the rest. Write one rule per line:

RuleMeans
deny githubNo App for any tool of the server github
deny github/delete_repoNo App for that one tool
allow github/create_chartAn App for that tool, even if its server is denied
deny *No App on any server, unless a narrower rule allows one

The most specific rule decides: a rule for the tool, then a rule for its server, then *. So a tool's deny beats its server's allow, and

deny *
allow github/create_chart

keeps MCP Apps for one tool only. A rule never turns MCP Apps on where the workspace does not allow it.

A tool whose App is turned off still works as a plain tool: the client gets no page link for it, a tool meant only for the page is not listed, and a read of its page is refused with MCP_APP_REFUSED and the reason policy_denied. Set the rules in the same places as the lists; in GitOps the key is mcp.apps.rules.

See each page on the server's page​

From 1.9.0 an MCP server's page in Flightdeck has an App pages card. Platform roles see it, and so do a workspace's admin and developers. For each tool with a page it shows:

  • the page address and who may see the tool (model, app);
  • the approved version the tool is pinned to, or not pinned when the last sync could not read the page;
  • the websites and permissions the page declares, with any that the workspace's lists do not allow marked;
  • the rule that decides: one for the tool, one for the server, one for every server, or none, so the workspace decides;
  • whether the Gateway serves the page, and why not when it does not.

The card shows only what DVARA records about a page, never the page itself. When the workspace sets no list of its own, the card says the Gateway's default decides, because those defaults are set on the Gateway, not in Flightdeck. A server whose tools have no page says so.

What else the Gateway checks​

  • Personal data and prompt injection. The page's HTML and scripts go through the workspace's PII and injection scans, as any tool result does. A page sent as base64 is decoded first, so it cannot hide from them.
  • App-only tools. A tool meant only for the page (visibility app) is left out of the tool list for a client without MCP Apps, so it never reaches a model, and a call to it from such a client is refused.
  • Calls the page makes. A page calls tools through the client, so each call is an ordinary tool call through the Gateway: policy, budgets, approvals, scans and audit all apply.

What is recorded​

EventWhen
MCP_APP_REFUSEDA page or an app-only tool call is refused. The reason says why: not_negotiated, not_pinned, changed, domain_not_allowed, permission_not_allowed, too_large, wrong_mime_type, malformed, app_only_tool, policy_denied (a rule turned the App off) or policy_error (the rules could not be read).
MCP_APP_RESOURCE_SERVEDA page was served: its approved fingerprint, the fingerprint of what was sent, whether a scan changed it, its websites and permissions, and the tools that point to it.
MCP_APP_TEMPLATES_SYNCEDA tool sync read the pages, with each one's fingerprint, size, websites and permissions, for review.

Limits​

  • MCP Apps works with clients and servers on MCP 2026-07-28. Through an older server it is not relayed.
  • A server that builds a new page for each request cannot be served: its fingerprint never matches.

Where to go next​