Repository navigation
Description
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:
- Setup Phase (
#setuphash): One-time server configuration and authentication - 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)
Handshake Security
Origin Validation Protocol:
- Inner Frame sends initial message with
targetOrigin: '*'(doesn't know parent origin) - Outer Frame replies using Inner Frame's known origin
- Inner Frame validates
event.originand pins it for all subsequent messages - All future communication uses pinned origins for security
Session Management:
- MCP Client generates unique
sessionIdfor each server connection - Server uses
sessionIdto scope persistent storage (API keys, preferences) - Same
sessionIdused 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
allowattributes 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 UIrequired: 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→TransportAcceptedMCPMessage(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
- Origin Isolation: Only explicitly allowed origins can establish connections
- Message Integrity: PostMessage provides tamper-proof message delivery
- Process Isolation: Browser contexts are isolated by default
- No Ambient Authority: Each connection requires explicit handshake
Security Considerations
- Iframe Sandboxing: Clients should apply appropriate sandbox attributes
- Content Security Policy: Both parties should implement restrictive CSP
- User Consent: Setup phase enables explicit permission flows
- 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
horner commentedon Jul 19, 2025
horner commentedon Jul 19, 2025
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:
In this setup:
tools/executerequests up to the parent viapostMessage.This model:
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 --> BInvert the roles:
This setup is ideal for:
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!
jmandel commentedon Jul 19, 2025
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...
jmandel commentedon Jul 20, 2025
@horner I gave this a shot -- working great, thank you for the suggestion.
MiguelsPizza commentedon Jul 20, 2025
@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
jmandel commentedon Jul 20, 2025
The transports are in https://github.com/jmandel/mcp-postmessage/tree/main/src/sdk/transport/postmessage and they can be used in either direction.
jmandel commentedon Jul 24, 2025
I moved the technical protocol write-up out of the issue description and into PR #1052.
dsp-ant commentedon Aug 1, 2025
In order to be a proper SEP, this would require a sponsor, and most importantly a working implementation
jmandel commentedon Aug 1, 2025
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.
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?)
evalstate commentedon Aug 1, 2025
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.
jmandel commentedon Aug 5, 2025
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.)
dsp-ant commentedon Nov 24, 2025
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.