cookbook-mcp-postmessage
v0.1.3
Published
Browser-ready Model Context Protocol (MCP) SDK with PostMessage transport for client and server implementations
Maintainers
Readme
cookbook-mcp-postmessage
Browser-focused Model Context Protocol (MCP) helpers that wrap the official @modelcontextprotocol/sdk with postMessage transports. Use it to connect iframe-hosted MCP servers and the parent window (or any other browsing context) without setting up a network service.
Features
- ESM-only distribution (
package.jsondeclares"type": "module") - Re-exports the upstream MCP client/server classes so you stay aligned with the official SDK
- PostMessage transports (
IframeServerTransport,IframeClientTransport,ParentClientTransport) plus a genericPostMessageTransport - Zod re-export and MCP request/response schemas for building typed tools and resources
- Ships both modern ESM bundles (
*.esm.js) and IIFE builds for direct<script>usage
Installation
npm install cookbook-mcp-postmessageNote CommonJS
require()is not supported. Use native ESM or dynamicimport()from CJS.
Usage
Running an MCP server inside an iframe
This mirrors the implementation in examples/2-plots-mcp-postmessage/src/main.tsx.
import {
Server,
IframeServerTransport,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListToolsRequestSchema,
CallToolRequestSchema,
} from 'cookbook-mcp-postmessage/server';
const server = new Server(
{ name: 'plots-mcp-server', version: '1.0.0' },
{
capabilities: {
resources: {},
tools: {},
},
}
);
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: 'resource://plots/readme.md',
name: 'README.md',
description: 'Example static resource',
mimeType: 'text/markdown',
},
],
}));
server.setRequestHandler(ReadResourceRequestSchema, async (request) => ({
contents: [
{
uri: request.params.uri,
mimeType: 'text/markdown',
text: '# Hello from the iframe server!\n',
},
],
}));
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'hello',
description: 'Greets the supplied name',
inputSchema: {
type: 'object',
properties: { name: { type: 'string', description: 'Name to greet' } },
required: ['name'],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name !== 'hello') {
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [{ type: 'text', text: `Hello, ${args.name}! 👋` }],
};
});
const transport = new IframeServerTransport(window.parent, 'https://app.example');
await server.connect(transport);IframeServerTransport listens for JSON-RPC messages from the parent window, enforces the targetOrigin, and sends responses back through postMessage.
Connecting from the parent window
import { Client, ParentClientTransport } from 'cookbook-mcp-postmessage';
const client = new Client(
{ name: 'plots-web', version: '1.0.0' },
{
capabilities: {
resources: {},
tools: {},
},
}
);
const iframe = document.querySelector<HTMLIFrameElement>('#plots');
if (!iframe) throw new Error('plots iframe not found');
const transport = new ParentClientTransport(iframe, 'https://plots-mcp.example');
await client.connect(transport);
const { resources } = await client.listResources({});
console.log('Available resources:', resources);ParentClientTransport sends JSON-RPC requests to the iframe and only trusts responses from that specific iframe.contentWindow.
Using the universal PostMessage transport
If you need to connect arbitrary browsing contexts (for example, two peer tabs via window.open), construct PostMessageTransport directly:
import { PostMessageTransport, Client } from 'cookbook-mcp-postmessage';
const transport = new PostMessageTransport({
targetWindow: otherWindow,
targetOrigin: 'https://other.example',
sourceWindow: otherWindow,
});
const client = new Client({ name: 'peer', version: '0.1.0' });
await client.connect(transport);Browser bundles
When you cannot use a bundler, the package exposes prebuilt bundles on any CDN that mirrors npm:
<!-- Client (IIFE) -->
<script src="https://unpkg.com/[email protected]/dist/mcp-client-sdk.min.js"></script>
<!-- Server (IIFE) -->
<script src="https://unpkg.com/[email protected]/dist/mcp-server-sdk.min.js"></script>
<!-- Module builds (optional) -->
<script type="module">
import { Client } from 'https://unpkg.com/[email protected]/dist/mcp-client-sdk.esm.js';
// ...
</script>API overview
Main entry (import {...} from 'cookbook-mcp-postmessage') exports:
Client,Server, andMcpServerfrom the official MCP SDKPostMessageTransport,IframeClientTransport,IframeServerTransport,ParentClientTransport, plus helper factoriescreateIframeTransport/createParentTransport- Zod re-export as
z - MCP request/result schemas such as
ListToolsRequestSchema,CallToolRequestSchema,ListResourcesResult, etc.
Dedicated entry points (cookbook-mcp-postmessage/client and /server) mirror the same exports but let bundlers split the client/server bundles.
Browser compatibility
- Chrome / Edge 88+
- Firefox 89+
- Safari 14+
The SDK relies on postMessage, async/await, and ES2020 features. Older browsers need polyfills.
Examples
See examples/1-plots-mcp-sse and examples/2-plots-mcp-postmessage in this repository for end-to-end setups that load MCP servers inside iframes and talk to them from a parent window.
License
MIT
