Skip to main content
The <mcp-iframe> custom element wraps an iframe and automatically exposes its tools, resources, and prompts to the parent page’s navigator.modelContext.

Installation

npm install @mcp-b/mcp-iframe @modelcontextprotocol/sdk
Requires @mcp-b/global polyfill in both parent and child pages.

Quick Start

Parent page — import to auto-register the element:
<script type="module">
  import '@mcp-b/mcp-iframe';
</script>

<mcp-iframe src="./child-app.html" id="my-app"></mcp-iframe>

<script type="module">
  document.querySelector('mcp-iframe')
    .addEventListener('mcp-iframe-ready', (e) => {
      console.log('Tools:', e.detail.tools);
    });
</script>
Child page — register tools via @mcp-b/global:
import '@mcp-b/global';

navigator.modelContext.registerTool({
  name: 'calculate',
  description: 'Perform a calculation',
  inputSchema: { /* ... */ },
  execute: async (args) => ({ content: [{ type: 'text', text: 'Result' }] })
});

Item Prefixing

Items are exposed with the element’s id as prefix to prevent naming conflicts:
Child registersParent sees
calculatemy-app:calculate
config://settingsmy-app:config://settings

Attributes

Standard iframe attributes (src, width, height, sandbox, etc.) are mirrored to the internal iframe.

MCP-Specific Attributes

AttributeDefaultDescription
target-originAuto-detectedOrigin for postMessage security
channel'mcp-iframe'Channel identifier
call-timeout30000Tool call timeout (ms)
prefix-separator':'Separator between prefix and name

Events

EventDetailDescription
mcp-iframe-ready{ tools, resources, prompts }Connection established
mcp-iframe-error{ error }Connection failed
mcp-iframe-tools-changed{ tools, resources, prompts }Items refreshed
mcpIframe.addEventListener('mcp-iframe-ready', (e) => {
  console.log('Tools:', e.detail.tools);       // ['my-app:calculate', ...]
  console.log('Resources:', e.detail.resources);
  console.log('Prompts:', e.detail.prompts);
});

Properties & Methods

PropertyTypeDescription
readybooleanConnection status
iframeHTMLIFrameElementThe wrapped iframe
exposedToolsstring[]Prefixed tool names
exposedResourcesstring[]Prefixed resource URIs
exposedPromptsstring[]Prefixed prompt names
itemPrefixstringCurrent prefix (e.g., my-app:)
MethodDescription
refresh()Re-fetch items from iframe

Multiple Iframes

Each iframe uses its id as prefix:
<mcp-iframe src="./calc.html" id="calc"></mcp-iframe>
<mcp-iframe src="./todos.html" id="todos"></mcp-iframe>
Exposes: calc:add, calc:multiply, todos:create, todos:list, etc.

Cross-Origin

For cross-origin iframes, set target-origin explicitly:
<mcp-iframe
  src="https://other-domain.com/app.html"
  id="external"
  target-origin="https://other-domain.com"
></mcp-iframe>
The child must configure IframeChildTransport with allowed origins. See Security Guide for details.

Custom Registration

import { registerMCPIframeElement } from '@mcp-b/mcp-iframe';
registerMCPIframeElement('custom-mcp-frame');