Skip to content

feat: add MCP Apps (SEP-1865) support#1335

Merged
SteveSandersonMS merged 40 commits into
mainfrom
feat/mcp-apps-support
May 28, 2026
Merged

feat: add MCP Apps (SEP-1865) support#1335
SteveSandersonMS merged 40 commits into
mainfrom
feat/mcp-apps-support

Conversation

@mattdholloway
Copy link
Copy Markdown
Contributor

@mattdholloway mattdholloway commented May 19, 2026

Adds opt-in MCP Apps (SEP-1865) support across all SDKs: a new enableMcpApps session flag and regenerated RPC/session-event types.

Changes

  • enableMcpApps opt-in (SessionConfig + ResumeSessionConfig in all SDKs) — plumbed to wire field requestMcpApps. Defaults to false; hosts without an iframe renderer are unaffected.
  • Capability detection — consumers inspect capabilities.ui.mcpApps on the create/resume response to detect whether the runtime honored the opt-in

@mattdholloway
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Adds opt-in 'enableMcpApps' session capability that advertises the
'extensions.io.modelcontextprotocol/ui' extension to MCP servers and
exposes 'session.rpc.mcp.apps.*' JSON-RPC methods.

Node SDK gains two pure helpers for hosts rendering 'ui://' MCP App
bundles in iframes:

- buildMcpAppsCspHeader — constructs the Content-Security-Policy header
  per SEP-1865 §UI Resource Format + §Security Implications, including
  the restrictive default ('connect-src none') when '_meta.ui.csp' is
  absent and constructed defaults ('connect-src self', etc.) when it is
  declared.
- buildMcpAppsAllowAttribute — maps '_meta.ui.permissions' to the iframe
  'allow' attribute (Permission Policy).

Co-authored-by: Copilot <[email protected]>
@mattdholloway mattdholloway force-pushed the feat/mcp-apps-support branch from 5f12d41 to 0827b5a Compare May 19, 2026 16:51
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by SDK Consistency Review Agent for issue #1335 · ● 793.2K

Comment thread nodejs/src/types.ts
mattdholloway and others added 3 commits May 20, 2026 11:05
Mirror nodejs enableMcpApps across the other four SDKs so hosts using
them can opt into MCP Apps (SEP-1865) UI passthrough by sending
requestMcpApps on session.create / session.resume.

- python: enable_mcp_apps kwarg on create_session / resume_session
- go: EnableMcpApps field on SessionConfig / ResumeSessionConfig
- dotnet: EnableMcpApps property on SessionConfig / ResumeSessionConfig
- rust: request_mcp_apps field + with_request_mcp_apps builder

Co-authored-by: Copilot <[email protected]>
@github-actions

This comment has been minimized.

mattdholloway and others added 3 commits May 20, 2026 14:55
Port the CSP directive injection defense from copilot-agent-runtime PR
#7605 into the SDK. Without sanitization, an MCP server returning
`frameDomains: ['evil.com; form-action *']` could break out of one CSP
directive and inject sibling directives (CSP first-occurrence rule then
lets an earlier injected `script-src *` win).

Each server-supplied entry is now:
- rejected if it contains CSP metacharacters ([;,\\s'"\\\\])
- accepted verbatim for the bare-scheme allowlist (data:, blob:,
  mediastream:, filesystem:)
- otherwise parsed via URL and canonicalized to its origin; opaque
  origins (where `URL.origin` is the literal string 'null') are dropped

Adds 10 sanitization tests mirroring runtime PR coverage.

Co-authored-by: Copilot <[email protected]>
Reflect the runtime-side gate added in copilot-agent-runtime PR #7605:
requestMcpApps is now honored server-side only when the MCP_APPS feature
flag or COPILOT_MCP_APPS=true env override is set; otherwise the opt-in
is silently dropped (the runtime logs a warning, but the SDK consumer
sees nothing). Update the JSDoc / docstrings on Node, Go, .NET, and Rust
to document this and to point at capabilities.ui.mcpApps on the
create/resume response as the way to detect the silent drop. Also adds
the diagnose method to the enumerated mcp.apps.* RPCs.

Co-authored-by: Copilot <[email protected]>
@github-actions

This comment has been minimized.

mattdholloway and others added 2 commits May 20, 2026 16:31
Expose the runtime's response capability so consumers can detect when
their enableMcpApps opt-in was silently dropped by the runtime gate
(MCP_APPS feature flag / COPILOT_MCP_APPS env override unset).

For each SDK:
- Add mcpApps?: bool to the SessionUiCapabilities type
- After session.create / session.resume, if the consumer requested the
  opt-in but capabilities.ui.mcpApps is not true on the response, log
  a warning (console.warn / logger.warning / slog / tracing::warn /
  fmt.Fprintf(os.Stderr, ...)) so the silent drop is discoverable.

Co-authored-by: Copilot <[email protected]>
Comment thread nodejs/src/client.ts Fixed
@github-actions

This comment has been minimized.

- python: ruff format reflowed the new _warn_if_mcp_apps_dropped helper
- rust: tests/e2e/elicitation.rs constructs UiCapabilities as a struct
  literal; the new mcp_apps field made it non-exhaustive

Co-authored-by: Copilot <[email protected]>
@github-actions

This comment has been minimized.

…t-logging

CodeQL flags any value flowing from process.env as sensitive via taint
analysis (joinSession() reads process.env.SESSION_ID which propagates to
resumeSession's sessionId argument). The session ID is a UUID and not
actually sensitive, but the alert noise is not worth it -- the warning
is per-call so the consumer already knows which session triggered it.

Co-authored-by: Copilot <[email protected]>
@mattdholloway
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@mattdholloway
Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Copy link
Copy Markdown
Contributor

Copilot AI commented May 28, 2026

@copilot resolve the merge conflicts in this pull request

Merged main and resolved conflicts in dotnet/src/Client.cs, go/types.go, java/src/main/java/com/github/copilot/CopilotClient.java, nodejs/src/client.ts, and rust/src/session.rs — kept main's restructured RPC/EMPTY-mode flow and rebound the existing warnIfMcpAppsDropped calls onto the response/post-create session id. Go build, .NET net8.0 build, Node build, Rust cargo check --lib (with COPILOT_SKIP_CLI_DOWNLOAD=1 for the sandboxed TLS), and Java mvn compile + spotless:apply all pass.

@github-actions

This comment has been minimized.

Comment thread nodejs/src/mcpAppsSandbox.ts Outdated
Comment thread dotnet/src/Client.cs Outdated
@IrynaKulakova IrynaKulakova requested a review from jmoseley May 28, 2026 12:52
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

SteveSandersonMS and others added 3 commits May 28, 2026 18:08
- Fix broken @link in Java SessionConfig (com.github.copilot.sdk.CopilotSession -> com.github.copilot.CopilotSession)

- Revert stray mode change on .githooks/pre-commit (100755 -> 100644)

- Rust: make enable_mcp_apps Option<bool> for consistency with sibling opt-ins (e.g. enable_config_discovery)

- Python: remove stray blank line after logger init in client.py

- Drop incorrect 'the SDK also logs a warning' wording from Python docstrings (the SDK no longer emits a warning; only the runtime does)

Co-authored-by: Copilot <[email protected]>
Mark the new SEP-1865 MCP Apps public APIs as experimental across .NET, Node, Python, Go and Rust SDKs, following each SDK's existing convention (e.g. canvas surface):

- .NET: [Experimental(Diagnostics.Experimental)] on SessionConfigBase.EnableMcpApps and SessionUiCapabilities.McpApps. No #pragma needed at internal call sites because GHCP001 is in the project's NoWarn.

- Node: @experimental JSDoc tag on SessionConfigBase.enableMcpApps and SessionCapabilities.ui.mcpApps.

- Python: **Experimental.** lead-in on enable_mcp_apps parameter docstrings (create_session, resume_session) and SessionUiCapabilities.mcpApps.

- Go: // Experimental: ... doc lines on SessionConfig.EnableMcpApps, ResumeSessionConfig.EnableMcpApps and UICapabilities.McpApps.

- Rust: **Experimental.** first paragraph on SessionConfig.enable_mcp_apps, ResumeSessionConfig.enable_mcp_apps, with_enable_mcp_apps (x2) and UiCapabilities.mcp_apps.

Java is intentionally skipped — the repo has no precedent for marking Java APIs as experimental, so introducing a convention here is out of scope for this commit.

Co-authored-by: Copilot <[email protected]>
…ield

Match the surrounding request_* bool fields (request_user_input, request_permission, request_exit_plan_mode, request_auto_mode_switch, request_elicitation, hooks) which all serialize unconditionally. Snapshots don't capture these fields so there is no compatibility cost.

Co-authored-by: Copilot <[email protected]>
Copy link
Copy Markdown
Contributor

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mattdholloway! Will merge when checks pass.

@github-actions
Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review ✅

This PR implements enableMcpApps consistently across all six SDK implementations. Here's a summary:

SDK Config field Capabilities field Experimental marker
Node.js enableMcpApps?: boolean capabilities.ui.mcpApps?: boolean @experimental JSDoc
Python enable_mcp_apps: bool = False param ui.mcp_apps **Experimental.** in docstring
Go EnableMcpApps bool UiCapabilities.McpApps bool // Experimental: comment
.NET [Experimental] bool EnableMcpApps [Experimental] bool? McpApps [Experimental] attribute
Java isEnableMcpApps() / setEnableMcpApps() SessionUiCapabilities.McpApps Javadoc @apiNote
Rust enable_mcp_apps: Option<bool> + builder UiCapabilities.mcp_apps: Option<bool> /// **Experimental.**

API naming follows language conventions — camelCase (Node/Java), snake_case (Python/Rust), PascalCase (Go/.NET).

Wire protocol is consistent — all SDKs send requestMcpApps: true only when opted in. Rust serializes it as false when unset (matching its established pattern for all boolean wire flags like requestElicitation, requestHooks, etc.), which is wire-compatible since the server treats absent and false equivalently.

No cross-SDK consistency issues found.

Generated by SDK Consistency Review Agent for issue #1335 · ● 6.7M ·

@SteveSandersonMS SteveSandersonMS added this pull request to the merge queue May 28, 2026
Merged via the queue into main with commit 4e3b8e2 May 28, 2026
43 checks passed
@SteveSandersonMS SteveSandersonMS deleted the feat/mcp-apps-support branch May 28, 2026 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants