Skip to main content
A Web Component that connects to an MCP server inside an iframe and republishes its tools on the parent page’s document.modelContext. With MCP-B extensions on the parent, it also republishes resources and prompts. Tool and prompt names include the element’s id; resource URIs use an mcp-iframe: wrapper URI.

Installation

Install mcp-iframe

Child server requirement

The iframe must run an MCP server connected to IframeChildTransport. Merely installing a document.modelContext implementation in the child does not expose an MCP endpoint to the parent element. @mcp-b/global supplies the server and selects IframeChildTransport automatically when it runs in an iframe. Configure the parent origins before importing it:
Child runtime configuration
IframeChildTransport requires a non-empty allowedOrigins list. The global runtime defaults it to ['*'] when omitted; use exact parent origins in production. A manually created MCP server can instead connect to IframeChildTransport directly.
Native cross-document WebMCP does not require this package. It uses iframe allow="tools" and parent-side getTools({fromOrigins}), both enforced by the browser and independent of the MCP transport’s target-origin and allowedOrigins.

Minimal example

Entry points


Attributes

Standard iframe attributes (sandbox, allow, width, height, loading, referrerpolicy, name, srcdoc, allowfullscreen, credentialless) are mirrored to the internal <iframe> element. For cross-origin children that use the native WebMCP API, set allow="tools" to delegate that browser feature. The attribute does not establish or authorize the MCP-B bridge. Sandboxed iframes without allow-same-origin, and sources whose URL origin is null, have opaque origins. Set target-origin="*" for those sources. Other sources use the explicit attribute or the origin inferred from src.

Scoping tools to the parent

A child narrows an individual tool to named embedder origins by passing exposedTo to registerTool:
Embedded anywhere else, that tool never reaches the parent’s exposedTools and cannot be called through the element. Tools registered without exposedTo stay visible to whichever parent the child transport already allows. Two limits apply:
  • exposedTo only narrows. The child transport’s allowedOrigins still decides who may connect at all, and no allowlist widens past it.
  • Enforcement is the child’s own JavaScript, not the browser. Native WebMCP has the user agent enforce exposedTo, so a compromised child cannot opt out. Treat the bridge’s version as scoping rather than a boundary against the child itself. See Security and human in the loop.

Events

The tools and prompts arrays contain parent-side names. The resources array contains parent-side wrapper URIs for static resources and resource templates.

Name prefixing

Tools and prompts from the iframe are registered on the parent as {id}{separator}{name}: The parent model context performs final tool-name validation. A rejected registration emits mcp-iframe-error and disconnects the element without leaving a partial registration set. Bridged tools retain their title and WebMCP readOnlyHint annotation.

Resource URI wrapping

Resource URIs use the mcp-iframe: scheme instead of name concatenation. A resource config://settings in an iframe with id="my-app" becomes mcp-iframe:?source=my-app_&uri=config%3A%2F%2Fsettings on the parent. Resource templates use the same wrapper. Template expressions remain expressions, so config://users/{userId} can be listed and resolved through the parent.

Properties


Methods

If fetching or parent registration fails, refresh() rejects after emitting mcp-iframe-error and disconnecting the element. It also rejects if the iframe connection changes before the refresh completes.

Programmatic registration

To register the custom element with a different tag name:
Register a custom element name
The /element entry point does not register <mcp-iframe>. The package root does.

Lifecycle

  1. On connectedCallback, the element creates an internal <iframe> and mirrors attributes.
  2. When the iframe fires its load event, the element creates an IframeParentTransport and an MCP Client, then connects.
  3. The element subscribes to each list_changed notification advertised by the child.
  4. Tools, resources, resource templates, and prompts are fetched without using cached list responses.
  5. Each item is registered on the parent’s document.modelContext. Tool and prompt names use the element prefix, while resources use wrapper URIs.
  6. The mcp-iframe-ready event fires. Later child list changes replace the parent registrations in order and fire mcp-iframe-items-changed.
  7. On disconnectedCallback, notification handlers and registrations are removed, and the client and transport are closed.
Changing src, srcdoc, target-origin, or channel while connected triggers a reconnection cycle.