MCP Apps and canvas bridge
This page documents the UI-capability bridge added in the refreshed @github/copilot 1.0.54 package. It covers two related but distinct surfaces:
- Canvas renderer support lets SDK/server clients register renderable canvases, expose model tools for opening and acting on those canvases, and receive canvas lifecycle events.
- MCP Apps support lets MCP servers expose UI metadata/resources behind an opt-in
mcp-appssession capability, with app-originated MCP tool calls reported back through session events.
Read this with Embedded server, ACP, and JSON-RPC protocol for session create/resume APIs, MCP host, transports, and tools for MCP server lifecycle, and Copilot SDK extension bridge for SDK extension process boundaries.
Source anchors
app.js is bundled/minified, so semantic aliases below are explanatory. Approximate line numbers refer to the extracted 1.0.54 package.
| Area | Semantic alias | Minified anchor / string | Approx. line | What it proves |
|---|---|---|---|---|
| Feature gate | MCP Apps gate | MCP_APPS, COPILOT_MCP_APPS, bqe(...) | 240, 4593 | MCP Apps is experimental by default and can be enabled through the environment override. |
| Canvas model tools | Canvas tool provider | list_canvas_capabilities, open_canvas, invoke_canvas_action | 372 | The model-visible tool layer can inspect, open, and act on canvases. |
| Canvas system prompt | Canvas instructions | <canvases>, open_canvas, list_canvas_capabilities | 4260 | The prompt tells the model when and how to use canvases. |
| Canvas manager | Canvas registry/instances | A0t, registerProvider, openInstances, availability | 4821 | Providers register canvas declarations; open instances become ready/stale and emit events. |
| Canvas events | Session canvas events | session.canvas.opened, session.canvas.registry_changed | 4821 | Canvas lifecycle updates are ephemeral session events. |
| SDK/server capability ingress | Session capability options | requestCanvasRenderer, requestMcpApps, buildSdkSessionCapabilities | 6375 | SDK/server create/resume can opt sessions into canvas and MCP Apps capabilities. |
| SDK connection registration | Canvas provider registration | registerCanvasesForConnection(...) | 6375 | Connected SDK/server clients can register canvas providers by connection. |
| MCP Apps diagnostics | MCP Apps API surface | mcp.apps.diagnose, _meta.ui, McpAppsDiagnoseResult | 4856 | Runtime exposes a diagnostic API for capability and _meta.ui visibility. |
| MCP Apps tool calls | App-originated MCP call event | mcp_app.tool_call_complete, supportsMcpApps() | 4940 | App-originated MCP calls emit success/error/duration/result metadata. |
Capability model
Canvas and MCP Apps are both session capabilities, but they enter through different gates.
flowchart TD Client[SDK / server client] --> Create[session.create or session.resume] Create --> CanvasReq{requestCanvasRenderer?} Create --> McpAppsReq{requestMcpApps?}
CanvasReq -->|yes| CanvasCap[add canvas-renderer capability] McpAppsReq -->|yes| McpGate{MCP_APPS or COPILOT_MCP_APPS=true?} McpGate -->|yes| McpAppsCap[add mcp-apps capability] McpGate -->|no| Drop[warn and do not advertise mcpApps]
CanvasCap --> Caps[capabilities.changed / session capabilities] McpAppsCap --> CapsThe server returns UI capability flags such as ui.canvases and ui.mcpApps from session create/resume/get-foreground paths. Capability provider changes are also projected through capabilities.changed.
Canvas lifecycle
Canvas providers are registered by connected SDK/server clients rather than discovered from the filesystem. A provider contributes one or more canvas declarations with:
| Field | Role |
|---|---|
id | Provider-local canvas identifier. |
displayName | Human-readable name. |
description | Short description shown to the agent in canvas catalogs. |
inputSchema | Optional JSON schema for opening the canvas. |
actions | Optional action names, descriptions, and input schemas for open instances. |
The runtime validates declarations before accepting them:
- canvas IDs must be present and unique for a provider;
- action names cannot use the reserved
canvas.prefix; - open/action input schemas are compiled and invalid schemas reject registration;
- a provider cannot overwrite another live provider’s
extensionId/canvasIdpair.
When registration succeeds, the runtime emits session.canvas.registry_changed with the currently available canvases.
Opening and using a canvas
The model sees canvas-specific tools when the canvas renderer capability is present:
| Tool | Purpose |
|---|---|
list_canvas_capabilities | Inspect a specific canvas declaration and action schemas. |
open_canvas | Open or focus a canvas using a caller-chosen stable instanceId. |
invoke_canvas_action | Invoke a named action on an open canvas instance. |
open_canvas is idempotent for an existing instanceId; re-opening focuses or no-ops the existing surface. Open results are normalized, and URL results are limited to http: or https: schemes. When a canvas opens, focuses, is rehydrated, or changes availability, the runtime emits session.canvas.opened.
Provider disconnect and reconnect
Open canvas instances survive provider disconnects as stale records:
sequenceDiagram participant Client as SDK/server client participant Registry as Canvas registry participant Session as Session events participant Model as Model tools
Client->>Registry: registerProvider(canvases) Registry->>Session: session.canvas.registry_changed Model->>Registry: open_canvas(instanceId, canvasId) Registry->>Client: canvas.open request Registry->>Session: session.canvas.opened(ready) Client--xRegistry: disconnect / unregisterProvider Registry->>Session: session.canvas.opened(stale, reopen=true) Client->>Registry: registerProvider(canvases) Registry->>Session: session.canvas.opened(ready, reopen=true)If the model tries to act on a stale instance, routing fails with a provider-unavailable error and the model should re-issue open_canvas after a provider reconnects.
MCP Apps lifecycle
MCP Apps is separate from canvas providers. It starts from MCP server tool/resource metadata and is gated by MCP_APPS or COPILOT_MCP_APPS=true.
Runtime behavior visible in the bundle:
- Session create/resume requests
requestMcpApps. - The server only adds
mcp-appsif the feature gate or env override is enabled. - MCP clients advertise UI capability to capable servers.
- The MCP tool list path tolerates
_meta.uithrough a lenient schema path. - Runtime diagnostics can report whether the session has
mcp-apps, whether the gate is enabled, and how many tools expose_meta.ui. - App-originated MCP calls emit
mcp_app.tool_call_complete.
The mcp_app.tool_call_complete event includes:
| Field | Meaning |
|---|---|
serverName / toolName | MCP server and tool invoked by the app view. |
arguments | Optional arguments passed to the underlying tools/call. |
success | False if the call threw or returned an MCP isError result. |
durationMs | Wall-clock duration for the underlying call. |
result / error | Normal MCP result or thrown error message. |
toolMeta.ui | Relevant UI metadata copied from the MCP tool. |
MCP Apps does not bypass normal MCP setup. Servers still come from the MCP config merge, pass through policy filters, authenticate via the existing OAuth path when needed, and expose tools through the same host/client registry.
Relationship between canvas and MCP Apps
Canvas and MCP Apps both create richer UI paths, but they are not the same mechanism.
| Concern | Canvas renderer | MCP Apps |
|---|---|---|
| Primary provider | SDK/server client connection. | MCP server tool/resource metadata. |
| Capability flag | canvas-renderer, returned as ui.canvases. | mcp-apps, returned as ui.mcpApps. |
| Model tools | list_canvas_capabilities, open_canvas, invoke_canvas_action. | Normal MCP tools plus app-originated tool/resource operations. |
| Main events | session.canvas.registry_changed, session.canvas.opened. | mcp_app.tool_call_complete. |
| Gate | Session request/capability support. | Session request plus MCP_APPS or COPILOT_MCP_APPS=true. |
The shared operational point is that both surfaces make a connected host UI more capable while keeping the session event stream and MCP/SDK boundaries explicit.
Failure modes and caveats
| Case | Runtime behavior |
|---|---|
requestMcpApps without gate/env | Server logs a warning and does not advertise ui.mcpApps. |
| Canvas provider missing | open_canvas fails with a canvas-not-found error. |
| Canvas ID ambiguous across providers | Runtime asks the model/client to provide extensionId. |
| Canvas provider disconnects | Open instances become stale; re-open or provider reconnect is needed. |
| Canvas provider returns unsupported URL scheme | Runtime rejects the open result. |
App calls an MCP tool without mcp-apps capability | Session rejects the app-originated call/resource path. |
| MCP tool has no callable UI metadata | App-originated call path rejects it as not callable from MCP Apps. |
Documentation action from the 1.0.54 delta
This subsystem is the only new atlas delta from the 1.0.54 update that warranted a dedicated page. Other deltas were narrower and are covered in existing pages:
| Delta | Documentation action |
|---|---|
security-review built-in agent and /security-review | Covered in Built-in agents, Agent and task orchestration, and Prompt sources. |
deferred-tool-loading custom-agent frontmatter | Covered in Custom agents and skills packaging. |
preMcpToolCall hook | Covered in Hooks, events, and automation. |
New env/gate strings such as COPILOT_PLUGIN_DIR_ONLY, COPILOT_ENABLE_SECRET_FILTERING, and TARGETED_VALIDATION_PROMPT | Narrow knobs or gated support surfaces; keep with existing plugin/redaction/feature-gate docs unless a future question needs a deeper runtime pass. |
Related docs
Created and maintained by Yingting Huang.