Skip to content

feat(desktop): host MCP Apps as channel tabs - #3275

Draft
tmarman wants to merge 1 commit into
block:mainfrom
tmarman:feat/mcp-app-channel-tabs
Draft

feat(desktop): host MCP Apps as channel tabs#3275
tmarman wants to merge 1 commit into
block:mainfrom
tmarman:feat/mcp-app-channel-tabs

Conversation

@tmarman

@tmarman tmarman commented Jul 28, 2026

Copy link
Copy Markdown

Why

Channel conversation is the primary collaboration surface in Buzz, but some work benefits from a structured interface. MCP Apps provides an existing packaging and host protocol for sandboxed interactive HTML backed by MCP tools.

This draft lets a channel member connect a reviewed Streamable HTTP MCP server, install one of its advertised Apps, and use it as a tab beside Chat without giving the embedded App Buzz credentials or a general-purpose Tauri API.

I am opening this as a draft to validate the host security boundary and product fit before asking maintainers to accept the full implementation.

What

  • Negotiate capabilities.extensions["io.modelcontextprotocol/ui"].
  • Discover App resources through _meta.ui.resourceUri, with the deprecated flat form accepted for compatibility.
  • Validate text/html;profile=mcp-app resources.
  • Install and remove channel-scoped Apps and render them as tabs beside Chat.
  • Use the official @modelcontextprotocol/ext-apps AppBridge package.
  • Deliver initial tool input/results and allow App-visible MCP tool calls through the reviewed server connection.
  • Supply theme, locale, time zone, display mode, and container size as host context.
  • Require native user approval before an App can publish a bounded message to the channel.
  • Revalidate saved Apps when they reconnect.

Security boundary

  • Non-loopback MCP endpoints require HTTPS. Explicit loopback HTTP remains available for local development.
  • DNS results are validated and pinned. Private, reserved, mixed, and IPv4-in-IPv6 transitional addresses are rejected for public hosts.
  • Redirects are disabled. MCP responses and App HTML are capped at 4 MiB.
  • A Tauri-owned outer proxy hosts an inner srcdoc frame with sandbox="allow-scripts". The App receives an opaque origin and cannot share the proxy's storage principal.
  • Transport messages validate the exact source window and origin in both directions.
  • The server cannot replace Buzz's hard-coded sandbox flags.
  • The server-provided CSP is parsed as requested capability metadata. Invalid sources are dropped, omitted directives use closed defaults, and advertised external domains are shown before installation.
  • App tool calls are restricted to tools advertised with App visibility.
  • Buzz does not advertise open-link or model-context capabilities in this channel integration.

Risk assessment

High. This renders untrusted server-authored HTML inside the desktop client and lets that App call reviewed MCP tools. The opaque inner origin, closed browser permissions, exact transport validation, bounded content, and explicit channel-post approval are the primary controls.

This PR is independent from Remote Agency discovery and A2A invocation. It implements the authored UI host boundary only.

Deliberate limitations

  • Only Streamable HTTP MCP servers are supported. Stdio setup is not included.
  • Server authorization and OAuth are not implemented.
  • App installations are local to the current Buzz identity and device. They are not synchronized through Nostr.
  • Camera, microphone, location, and clipboard permissions are reported but not granted.
  • App-visible tool calls do not yet have per-call approval UI. Tool visibility is enforced, but destructive-tool policy must be resolved before this leaves draft.
  • The channel and thread are not automatically injected into tool arguments.
  • Inline and fullscreen display modes are supported. pip is not implemented.
  • App-originated posts require review, are length-bounded, and are rate-limited, but do not yet carry a standardized machine-readable Nostr provenance tag.

Tests

Validated on the reviewed source tree before the clean current-main contribution commit:

  • pnpm test from desktop/: 3,731 passed
  • pnpm typecheck, pnpm lint, and pnpm check from desktop/
  • cargo test mcp_apps from desktop/src-tauri/: 9 passed
  • cargo test from desktop/src-tauri/: 1,819 passed, 14 ignored; 3 diagnostics passed
  • cargo clippy --all-targets -- -D warnings from desktop/src-tauri/
  • cargo fmt --all -- --check

The personal-fork CI passed Rust lint, Desktop Core, all desktop smoke and integration shards, Windows Rust, web, and relay e2e. Fork Docker jobs compile and then fail when they try to write cache layers to ghcr.io/block/.... The fork macOS packaging job fails in the existing cold-cache mesh-llm checkout lookup.

Review focus

  1. Does the opaque inner origin plus exact outer transport validation establish the correct MCP Apps host boundary?
  2. Should App-visible tools require approval for every call, or use tool annotations and a risk policy?
  3. Should App installations remain local, or become community metadata after the host boundary is accepted?
  4. Which authentication flow should Buzz support first for remote MCP servers?
  5. Which existing Nostr convention, if any, should carry App-action provenance?

Add a reviewed Streamable HTTP MCP Apps connection flow, channel-scoped app tabs, an opaque-origin sandbox, and explicit approval before an app can publish to a Buzz channel. Buzz owns the MCP transport, capability policy, and host boundary.

Signed-off-by: Tim Marman <[email protected]>
@jmreijnen-parkbee

Copy link
Copy Markdown

Nice, this is exactly the kind of surface a channel-feature registry would give a first-class home. I just opened #3280 (RFC: a desktop ChannelFeaturePlugin registry) proposing that channel tabs/settings/sidebar entries be registered rather than hand-wired into the shared *ChannelContent shells and the ChannelScreen dispatch. MCP-App tabs would slot in as a plugin's tabs entry (with your security-boundary host as the tab body), alongside Sequence/board/docs, with no edits to the central shells. Happy to align on how App-tabs would register if the maintainers are warm to the registry direction.

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.

2 participants