Skip to content

SEP: postMessage Transport for MCP #1005

Closed

Description

@jmandel

SEP: postMessage Transport

Preamble

Title: postMessage Transport
Author: Josh Mandel (@jmandel)
Status: Proposal
Type: Standards Track
Created: 2025-07-19
Full Spec Proposal: Draft
Reference Implementation: Demo | Source

Abstract

This SEP proposes a postMessage transport for the Model Context Protocol (MCP) that enables secure communication between clients and servers running in different browser contexts (iframes or popup windows). The transport leverages the browser's window.postMessage API to provide zero-installation MCP connections with support for a two-phase connection model: a one-time setup phase for configuration and authentication, and a transport phase for ongoing MCP communication. This approach enables new use cases including direct access to browser-sandboxed APIs, edge computing for privacy-sensitive applications, and rich user interfaces for MCP tools.

Motivation

Current MCP transports require either local installation or remote server processing, creating fundamental barriers to adoption and new capabilities:

Installation Barriers: STDIO servers require software installation, creating security risks from running untrusted code with system access and limiting reach to users who are willing to ignore these risks or have the technical expertise to mitigate them.

Privacy Trade-offs: Streamable HTTP servers require all relevant data to be present on or copied to a remove machine, which is undesirable in privacy-sensitive contexts.

Limited UX: MCP interactions are confined to text-based exchanges, preventing rich interactive experiences and progressive enhancement of client interfaces through embedded server UX.

Design Principles

This transport enables four transformative capabilities:

Zero Installation: Servers distributed as URLs eliminate installation friction and security risks, enabling instant access to MCP capabilities in browser-sandboxed environments.

Privacy-First Processing: Browser-local execution ensures sensitive data can stay on the user's device, enabling new classes of privacy-preserving AI tools.

Progressive UX Enhancement: Servers can embed rich interactive interfaces directly in client applications, transforming MCP from text-based to visually enhanced experiences.

Edge Computing: Computation occurs in the user's browser context, reducing latency and server costs while improving data locality.

Core Concepts

The postMessage transport is designed around two key sets of roles: the Window Hierarchy and the MCP Protocol Roles. Understanding their separation is crucial.

Window Hierarchy Roles (Physical Layer)

This describes the browser window relationship, which is what the transport components are built on.

  • Outer Frame: The main, controlling window. It embeds and manages the other window.
  • Inner Frame: The subordinate, controlled window, typically an <iframe> or a popup.

MCP Protocol Roles (Logical Layer)

This describes the roles defined by the Model Context Protocol itself.

  • MCP Client: The entity that initiates actions by calling tools.
  • MCP Server: The entity that provides tools and responds to tools/list.

Supported Architectures

By separating the window hierarchy from MCP roles, the transport supports two powerful patterns:

Standard Architecture (Client-in-Control)

  • Outer Frame: MCP Client
  • Inner Frame: MCP Server
  • Use Case: A primary application (like a chat client) embeds and consumes tools from third-party services.

Inverted Architecture (Server-in-Control)

  • Outer Frame: MCP Server
  • Inner Frame: MCP Client
  • Use Case: A primary application (like a user dashboard) provides contextual data as tools to an embedded, sandboxed AI copilot.
Transport Feature Standard Architecture Inverted Architecture
Outer Frame Role MCP Client MCP Server
Inner Frame Role MCP Server MCP Client
Who provides tools? Inner Frame Outer Frame
Who calls tools? Outer Frame Inner Frame

Protocol Overview

Two-Phase Connection Model

The transport uses distinct phases to handle server lifecycle:

  1. Setup Phase (#setup hash): One-time server configuration and authentication
  2. Transport Phase (no hash): Ongoing MCP communication with configured servers

Message Flow Diagram

sequenceDiagram
    participant OuterFrame
    participant SetupFrame as InnerFrame (Setup)
    participant TransportFrame as InnerFrame (Transport)

    Note over OuterFrame,SetupFrame: Setup Phase - Server Configuration
    OuterFrame->>OuterFrame: Start listening for messages
    OuterFrame->>SetupFrame: Create iframe, load server URL with #setup hash
    SetupFrame->>OuterFrame: SetupHandshake (targetOrigin: '*')
    OuterFrame->>SetupFrame: SetupHandshakeReply (sessionId, protocolVersion)
    Note over SetupFrame: Pin origin from event.origin<br/>Optional: Show setup UI
    SetupFrame->>OuterFrame: SetupComplete (displayName, transportVisibility)
    Note over OuterFrame: Persist server configuration<br/>Destroy setup iframe

    Note over OuterFrame,TransportFrame: Transport Phase - Active MCP Session (Later)
    OuterFrame->>OuterFrame: Start listening for messages
    OuterFrame->>TransportFrame: Create NEW iframe, load server URL (no hash)
    TransportFrame->>OuterFrame: TransportHandshake (targetOrigin: '*')
    OuterFrame->>TransportFrame: TransportHandshakeReply (same sessionId)
    Note over TransportFrame: Pin origin from event.origin
    TransportFrame->>OuterFrame: TransportAccepted

    Note over OuterFrame,TransportFrame: MCP Protocol Communication
    OuterFrame->>TransportFrame: MCPMessage (initialize)
    TransportFrame->>OuterFrame: MCPMessage (initialized)
    OuterFrame->>TransportFrame: MCPMessage (tools/list)
    TransportFrame->>OuterFrame: MCPMessage (tool definitions)
    OuterFrame->>TransportFrame: MCPMessage (tools/call)
    TransportFrame->>OuterFrame: MCPMessage (tool result)
Loading

Handshake Security

Origin Validation Protocol:

  1. Inner Frame sends initial message with targetOrigin: '*' (doesn't know parent origin)
  2. Outer Frame replies using Inner Frame's known origin
  3. Inner Frame validates event.origin and pins it for all subsequent messages
  4. All future communication uses pinned origins for security

Session Management:

  • MCP Client generates unique sessionId for each server connection
  • Server uses sessionId to scope persistent storage (API keys, preferences)
  • Same sessionId used across setup and transport phases for data continuity

Permission Declaration System

Servers can declare browser permissions needed upfront:

requestedPermissions: [{
  name: "geolocation",
  phase: ["transport"],
  required: true,
  purpose: "To provide local weather forecasts and alerts"
}]

Benefits:

  • Transparent Consent: Users see all permissions before embedding server
  • Proactive Sandboxing: Clients configure iframe allow attributes automatically
  • Security: Prevents hidden capability escalation during runtime

Version Negotiation

Setup handshake includes semantic version negotiation:

  • Server declares supported version range (minProtocolVersion, maxProtocolVersion)
  • Client selects highest compatible version within range
  • Prevents compatibility issues between transport implementations

Transport Visibility Control

Servers specify their UI visibility needs during transport phase:

  • hidden: Server runs invisibly (most common)
  • optional: User can choose to show/hide server UI
  • required: Server must remain visible (e.g., live visualizations)

Message Types

The protocol defines 8 message types with MCP_ prefix:

Setup Phase (3 messages):

  • SetupHandshake → SetupHandshakeReply → SetupComplete

Transport Phase (5 messages):

  • TransportHandshake → TransportHandshakeReply → TransportAccepted
  • MCPMessage (bidirectional MCP protocol wrapper)
  • SetupRequired (optional, triggers re-authentication)

Design Rationale

Key Design Decisions

This section explains the major design choices made in the postMessage transport and their rationale.

Two-Phase Protocol Design

Decision: Separate setup and transport phases with distinct handshake protocols.

Rationale:

  • Invisible Server Configuration: Servers that run hidden during transport can still surface user-visible setup UI when first added, ensuring proper authentication and configuration even for background services
  • Standard UX Pattern: Follows the familiar pattern where servers are configured once, then can be connected/disconnected repeatedly without reconfiguration - matching user expectations from other systems
  • Persistent vs Ephemeral State: Setup handles persistent configuration (API keys, preferences) while transport handles ephemeral connection state, preventing configuration loss during reconnections
  • Separation of Concerns: Configuration complexity is isolated from runtime performance, allowing transport phase to be lightweight and fast

Window Hierarchy vs MCP Role Separation

Decision: Distinguish "physical" browser window relationships from "logical" MCP client/server roles.

Rationale:

  • Architectural Flexibility: Enables both standard (client-in-control) and inverted (server-in-control) patterns
  • Composability: Applications can embed AI assistants or be embedded by them without protocol changes
  • Clarity: Prevents confusion between browser containment and MCP responsibilities
  • Innovation: Unlocks new patterns like dashboards providing contextual tools to embedded AI copilots

Origin-Based Security Model

Decision: Rely exclusively on browser's event.origin validation with explicit allowlists.

Rationale:

  • Browser Native: Leverages the browser's tamper-proof origin enforcement
  • No Custom Auth: Avoids complex authentication schemes that increase attack surface
  • Simplified Implementation: Single validation point reduces security bugs
  • Zero Trust: Every message is validated regardless of session state

Session ID Orchestration by Client

Decision: MCP Client generates and provides sessionId to MCP Server.

Rationale:

  • Data Isolation: Servers can safely scope storage without collision risk
  • Session Continuity: Clients can reuse sessions across page reloads
  • Stateless Servers: Servers don't need to track active sessions globally
  • Multi-Client Support: Same server can handle multiple client sessions independently

Permission Declaration System

Decision: Servers declare needed permissions upfront rather than requesting on-demand.

Rationale:

  • Transparent Consent: Users see all permissions before embedding
  • Sandbox Configuration: Clients can set restrictive iframe attributes proactively
  • Security Principle: Explicit permission requests prevent hidden capability escalation
  • User Control: Clients can reject servers with excessive permission requirements

Hash-Based Phase Detection

Decision: Use URL hash parameters (#setup vs no hash) to indicate protocol phase.

Rationale:

  • Stateless Detection: Servers can determine phase without external state
  • URL Simplicity: Same base URL serves both phases
  • Browser Compatibility: Hash parameters work universally across browsers
  • Developer Clarity: Visible indication of which phase is active

Alternative Approaches Considered

Single-Phase Protocol

Alternative: Combine setup and transport into single handshake.
Rejected Because: Would force all servers to show setup UI even when none needed, breaking "servers as URLs" goal.

Token-Based Authentication

Alternative: Use JWT or similar tokens for auth instead of origins.
Rejected Because: Increases complexity, requires key management, and adds attack vectors beyond browser's built-in security.

Server-Orchestrated Sessions

Alternative: Let servers generate their own session IDs.
Rejected Because: Creates collision risks, prevents client-controlled session continuity, and complicates multi-client scenarios.

Dynamic Permission Requests

Alternative: Allow runtime permission requests like mobile apps.
Rejected Because: Would surprise users with unexpected permission prompts and complicate client sandbox configuration.

Use Cases

Local File Access

Web-based servers can provide file access using the File System Access API:

  • AI assistants work with local files without uploads
  • Data never leaves the user's device
  • Full read/write capabilities with user permission

Privacy-Preserving Edge Computing

Healthcare and financial applications process sensitive data locally:

  • Patient records analyzed entirely in-browser
  • Complex computations using WebAssembly
  • No data transmission to external servers

Interactive Visualization Tools

Servers provide rich UI tools:

  • Diagram editors (like mermaid.live)
  • Data visualization dashboards
  • Interactive form builders
  • Real-time collaboration interfaces

Backwards Compatibility

As a new transport mechanism, the postMessage transport introduces no backwards compatibility issues. Existing MCP implementations using stdio or HTTP SSE transports continue to function unchanged. Clients and servers must explicitly opt into using the postMessage transport.

Reference Implementation

A complete reference implementation demonstrating all protocol features is available at https://github.com/jmandel/mcp-postmessage. A hosted demo of the implementation can be accessed at https://jmandel.github.io/mcp-postmessage.

Client Architecture

The demo client provides a full-featured MCP client interface that:

  • Server Management: Add, configure, and connect to multiple PostMessage servers
  • Setup Phase Handling: Manages both visible and hidden server setup workflows
  • Tool Discovery: Automatically discovers and displays available MCP tools from connected servers
  • Dynamic UI Generation: Creates forms for tool parameters based on MCP schema definitions
  • Real-time Communication: Handles bidirectional MCP message exchange during active sessions

Example Servers

Transport Features by Example

Transport Feature Pi Calculator JSON Analyzer Mermaid Editor Camera Tester
User-facing setup phase ❌ ✅ ❌ ✅
UI visibility at runtime 🔄 Optional 🚫 Hidden 👁️ Visible 🔄 Optional
Partitioned storage by sessionId ❌ ✅ ❌ ✅
Dynamic permissions ❌ ❌ ❌ ✅

The implementation includes four sample servers that demonstrate different protocol features:

Pi Calculator Server

  • Demonstrates: No user-facing setup phase, optionally visible UI at runtime (hide/show buttons)
  • Use Case: Mathematical computation with optional interactive visualization

JSON Analyzer Server

  • Demonstrates: User-facing setup phase, hidden UI at runtime, partitioned storage by sessionId
  • Use Case: Data processing and analysis with persistent configuration

Mermaid Editor Server

  • Demonstrates: No user-facing setup phase, visible UI at runtime (always shown)
  • Use Case: Interactive diagram editing requiring constant user visibility

Camera Tester Server

  • Demonstrates: User-facing setup phase, optionally visible UI at runtime, partitioned storage by sessionId, dynamic permissions (camera access)
  • Use Case: Privacy-preserving emotion analysis with on-demand camera access and AI integration

Each server demonstrates the complete protocol flow from setup through active MCP communication, providing practical patterns for implementers.

Security Implications

Validated Security Properties

  1. Origin Isolation: Only explicitly allowed origins can establish connections
  2. Message Integrity: PostMessage provides tamper-proof message delivery
  3. Process Isolation: Browser contexts are isolated by default
  4. No Ambient Authority: Each connection requires explicit handshake

Security Considerations

  1. Iframe Sandboxing: Clients should apply appropriate sandbox attributes
  2. Content Security Policy: Both parties should implement restrictive CSP
  3. User Consent: Setup phase enables explicit permission flows
  4. Data Validation: All message contents must be validated

Open Security Questions

The protocol addresses permission declaration and version negotiation. Additional areas for future consideration include standardized security profiles and cross-origin policy coordination.

Activity

  1. horner commented on Jul 19, 2025

    @horner
  2. horner commented on Jul 19, 2025

    @horner

    This is a fantastic proposal—thanks for laying out the postMessage transport in a clean, extensible way.

    One use case I’d love to see explicitly supported (or clarified) is the inverted architecture, where:

    • The LLM host/client (e.g. chat UI or orchestration logic) runs inside an iframe.
    • The MCP server (tools) is implemented by the parent page embedding the iframe.

    In this setup:

    • The iframe streams completions from the LLM and detects tool calls.
    • Instead of invoking tools locally (as in the standard iframe server setup), it forwards tools/execute requests up to the parent via postMessage.
    • The parent (which already has the user session, app context, and secure access to private APIs) handles the tool execution and sends results back down to the iframe.

    This model:

    • ✅ Keeps sensitive data and API access in the trusted parent domain
    • ✅ Eliminates the need for separate OAuth or cross-context credential sharing
    • ✅ Enables pluggable, embeddable assistants where each host site supplies its own toolset

    From what I can tell, this inversion is fully compatible with the current transport spec—but it might be helpful to explicitly call it out in the proposal as a supported pattern. A diagram or section clarifying both "LLM-in-parent" and "LLM-in-iframe" architectures could help implementers understand how flexible the postMessage transport is.

    Here’s a diagram of the inverted architecture:

    flowchart TD
      subgraph Parent_Page
        A[MCP Server Tools]
      end
      subgraph Iframe
        B[LLM Host and Client Chat UI]
      end
      B -- tools/execute via postMessage --> A
      A -- result via postMessage --> B
    
    Loading

    Invert the roles:

    • ✅ LLM chat UI + client lives inside an iframe (e.g., an embeddable assistant).
    • ✅ Tooling (MCP server) lives in the parent application (e.g., the app that owns the user’s data, session, permissions).

    This setup is ideal for:

    • SaaS providers embedding AI copilots (via iframe) into customer dashboards.
    • Platforms where tools are deeply tied to app state or session, and you want to avoid auth duplication.
    • Scenarios where LLM UX is shared, but tool access must be tightly scoped to the embedding application.

    Would love to hear thoughts from others on formalizing this variant or whether you’d be open to a PR that expands on it in the spec!

  3. jmandel commented on Jul 19, 2025

    @jmandel
    Author

    Cool idea @horner!

    One slight trick is timing/order of the handshakes -- in the protocol above, the server initiates the handshake (which works because the client as the server as the framed inner.entity, otherwise). The handshake language would have to change from "server/client" to "inner/outer party" perhaps.

    There may be other lurking issues I haven't thought of...

  4. jmandel commented on Jul 20, 2025

    @jmandel
    Author

    @horner I gave this a shot -- working great, thank you for the suggestion.

  5. MiguelsPizza commented on Jul 20, 2025

    @MiguelsPizza

    @jmandel Amazing work! Do you have the code for the inverted transports? I am going to see if they are compatible with MCP-B / WebMCP

    @horner What you are describing is the idea behind WebMCP but using an injected content script from a web-extension to allow the extension client to call tools declared in a webpage MCP server. It along side @jmandel 's current proposal solve many of the issues with remote MCP servers IMO

  6. jmandel commented on Jul 20, 2025

    @jmandel
    Author

    @jmandel Amazing work! Do you have the code for the inverted transports? I am going to see if they are compatible with MCP-B / WebMCP

    The transports are in https://github.com/jmandel/mcp-postmessage/tree/main/src/sdk/transport/postmessage and they can be used in either direction.

    • For the "Traditional Architecture", outer frame is an MCP client that uses the outer-frame-transport and loads an MCP server frame that uses inner-frame-transport (example src, demo)
    • For the "Inverted Architecture", outer frame is an MCP sever that uses the outer-frame-transport and loads an MCP client frame that uses inner-frame-transport (example src, demo)
  7. jmandel commented on Jul 24, 2025

    @jmandel
    Author

    I moved the technical protocol write-up out of the issue description and into PR #1052.

  8. dsp-ant commented on Aug 1, 2025

    @dsp-ant
    Member

    In order to be a proper SEP, this would require a sponsor, and most importantly a working implementation

  9. jmandel commented on Aug 1, 2025

    @jmandel
    Author

    Thanks @dsp-ant!

    Re: working implementation: I have linked to a working implementation under "Reference Implementation" at the top of the proposal, with more details about the components in the "Reference Implementation" section.

    Reference Implementation: Demo | Source

    Re: sponsor, is there a list of eligible sponsors? Perhaps a set of people we could @-mention here to gauge interest, or another established process? I appreciate your help navigating this process. (I have some experience in the HL7 world of healthcare standards, where there are regular workgroup calls in which project ideas can be introduced and sponsored. Is there something like this here?)

  10. evalstate commented on Aug 1, 2025

    @evalstate
    Member

    Hi @jmandel -- any of the current maintainers can be a sponsor - https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/MAINTAINERS.md

    We've recently published some new guides you might find helpful:
    https://modelcontextprotocol.io/community/communication
    https://modelcontextprotocol.io/community/sep-guidelines

    I would recommend, if you can, joining the Community Discord where it might be easier to discuss directly. There is currently a transport-wg (which I am participating in), so this might be a good fit for consideration there.

  11. jmandel commented on Aug 5, 2025

    @jmandel
    Author

    I wonder if any of @000-000-000-000-000, @pcarleton, or @localden might be willing to sponsor, or point me in the right direction (or tell if this is too far out of scope for SEP).

    (@evalstate I may be missing it but https://modelcontextprotocol.io/community/communication#discord doesn't seem to link to the community discord. I found https://discord.com/channels/1312302100125843476/1312302100125843479 through a web search but it doesn't seem to have the channels mentioned in the communication page of the spec, so I fear I'm in the wrong place.)

  12. dsp-ant commented on Nov 24, 2025

    @dsp-ant
    Member

    This SEP has not found a sponsor from the maintainer or core maintainer group and will be marked dormant. Please feel free to revive this if you find a sponsor.

    A few notes on this one. I can totally see the usecase here (and maybe is related to WebMCP, and appreciate your time and effort put into this.

    My principle for transports in MCP is that I want to keep the amount of transports small and for a very general usecase (local vs remote). I see the specification as the "minimal" amount an MCP client should implement. Adding more transports adds a proliferation for very specific use-cases but not for the general MCP ecosystem. As such I think this should either live as a separate, externally maintained extension to MCP or as community project with appropriate SDKs. I can see a world where experimental transports like this are an externally maintained extension and if they get traction, can move eventually into the spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions