# How to Configure MCP Apps with Inline iframe Rendering in Agent-Native

> Learn how to configure MCP Apps with inline iframe rendering in agent-native. Mount the MCP server plugin, expose iframeTitle, and detect the embed surface on the client.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-27

---

**To configure MCP Apps with inline iframe rendering in Agent-Native, mount the MCP server plugin with `mountMCP`, expose an `iframeTitle` property in each action definition, and detect the embed surface on the client side using the `?embedded` query flag to handle sandbox restrictions.**

Agent-Native ships with a built-in MCP (Multi-Chat-Partner) runtime that allows template apps to load as embedded widgets inside external hosts like ChatGPT or Claude. This guide explains the three-step configuration process required to enable inline iframe rendering, referencing the official implementation in the BuilderIO/agent-native repository.

## Mount the MCP Server Plugin

The first step to enable inline rendering is registering your app as an MCP provider. In the server initialization code, import `mountMCP` from `@agent-native/core/mcp` and invoke it with your app metadata and action definitions.

In [`templates/plan/server/plugins/00-mcp.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/plan/server/plugins/00-mcp.ts), the Plan template registers itself as follows:

```typescript
import { mountMCP } from "@agent-native/core/mcp";
import { loadActionsFromStaticRegistry } from "@agent-native/core/server";
import actionsRegistry from "../../.generated/actions-registry.js";

export default function planMcpPlugin(nitroApp: any) {
  const actions = {
    ...loadActionsFromStaticRegistry(actionsRegistry),
    // optional automation tool entries
  };

  mountMCP(nitroApp, {
    name: "Plan",
    title: "Agent-Native Plan",
    appId: "plan",
    description:
      "Create, review, update, publish, and export Agent-Native visual plans.",
    websiteUrl: "https://plan.agent-native.com",
    actions,
    productionActions: actions,
    connectorCatalog: PLAN_CONNECTOR_CATALOG,
  });
}

```

The `mountMCP` function tells the Nitro server that this template is an MCP-enabled app. The `actions` object defines the public surface that the host may invoke, while the `title` property provides the default app-level title.

## Expose iframeTitle Metadata for Inline Actions

For an action to render inside an inline iframe, it must export an `iframeTitle` property. This metadata tells the MCP host how to label the sandboxed container when displaying your UI widget.

In [`templates/plan/actions/get-visual-plan.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/plan/actions/get-visual-plan.ts), the action definition includes the required field:

```typescript
export const getVisualPlan = defineAction({
  // tool definition and parameters
  iframeTitle: "Agent-Native Plan",
  // optional: iframeWidth and iframeHeight for size hints
  run: async (args) => {
    // Generate HTML or MDX content
    return {
      html: `<div>Plan content here</div>`
    };
  },
});

```

The `iframeTitle` string is not the URL or HTML body—it serves as the accessible title for the iframe element. The host automatically creates a sandboxed `<iframe title="Agent-Native Plan">` with appropriate security attributes when this action is invoked.

Other actions follow the same pattern, including [`create-visual-plan.ts`](https://github.com/BuilderIO/agent-native/blob/main/create-visual-plan.ts), [`list-visual-plans.ts`](https://github.com/BuilderIO/agent-native/blob/main/list-visual-plans.ts), and templates like [`design/actions/show-design-questions.ts`](https://github.com/BuilderIO/agent-native/blob/main/design/actions/show-design-questions.ts).

## Detect the Embed Surface on the Client

When an MCP host loads your app inline, it appends `?embedded=1` or `?embedded=true` to the URL. Your client-side code must detect this flag to handle asset restrictions imposed by the host's `COEP` and `CORP` policies.

The Calendar template provides a helper function in [`templates/calendar/app/lib/mcp-embed.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/calendar/app/lib/mcp-embed.ts):

```typescript
export function isMcpEmbedSurface(): boolean {
  if (typeof window === "undefined") return false;
  const value = new URLSearchParams(window.location.search).get("embedded");
  return value === "1" || value === "true";
}

```

Use this helper to switch between external and same-origin assets:

```tsx
import { isMcpEmbedSurface } from "@/app/lib/mcp-embed";

export default function Page() {
  const avatarUrl = isMcpEmbedSurface()
    ? "/assets/placeholder-avatar.png"
    : user.avatarUrl;

  return <img src={avatarUrl} alt="avatar" />;
}

```

Equivalent helpers exist in the Mail, Design, and Slides templates under `templates/*/app/lib/mcp-embed.ts`.

## Complete Minimal Example

Here is a complete configuration that combines server registration, action definition, and client-side adaptation:

```typescript
// server/plugins/mcp.ts
import { mountMCP } from "@agent-native/core/mcp";
import { loadActionsFromStaticRegistry } from "@agent-native/core/server";
import actionsRegistry from "../../.generated/actions-registry.js";

export default function myAppPlugin(app: any) {
  const actions = loadActionsFromStaticRegistry(actionsRegistry);
  
  mountMCP(app, {
    name: "MyApp",
    title: "My Inline MCP",
    appId: "myapp",
    description: "Demo MCP app with inline iframe support.",
    websiteUrl: "https://myapp.example.com",
    actions,
    productionActions: actions,
    connectorCatalog: [],
  });
}

```

```typescript
// actions/show-widget.ts
export const showWidget = defineAction({
  iframeTitle: "My Inline Widget",
  iframeWidth: "400",
  iframeHeight: "300",
  run: async () => {
    return {
      html: `<div>Hello from inline iframe</div>`
    };
  },
});

```

```typescript
// client.tsx
import { isMcpEmbedSurface } from "@/app/lib/mcp-embed";

const imageSrc = isMcpEmbedSurface() 
  ? "/assets/placeholder.png" 
  : "https://external.com/image.png";

```

When the MCP host invokes the `show-widget` tool, it receives the `iframeTitle` and renders the app inside a sandboxed iframe directly within the conversation UI.

## Summary

- **Register the MCP app** using `mountMCP` in a server plugin like [`templates/plan/server/plugins/00-mcp.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/plan/server/plugins/00-mcp.ts) to expose actions to external hosts.
- **Add `iframeTitle`** to every action definition that should support inline rendering; this property identifies the iframe for the host UI.
- **Detect the embed surface** using `isMcpEmbedSurface()` to handle strict sandbox policies and serve same-origin assets when `?embedded=1` is present.
- **Reference templates** in the BuilderIO/agent-native repository (Calendar, Mail, Design, Slides) for production examples of MCP embed detection.

## Frequently Asked Questions

### What is the MCP runtime in Agent-Native?

The MCP runtime is a built-in server-side system in Agent-Native that implements the Multi-Chat-Partner protocol, enabling template apps to register tools and render UI widgets inside external AI hosts like ChatGPT or Claude as sandboxed iframes.

### Why is the `iframeTitle` property required for inline rendering?

The `iframeTitle` property provides the accessible title attribute for the sandboxed iframe element that the host creates. Without this metadata, the host cannot properly label the embedded surface for accessibility or distinguish it from other potential inline applications.

### How do I handle COEP and CORP policy restrictions in an embedded iframe?

MCP hosts enforce strict Cross-Origin Embedder Policies that block external images and assets. Use the `isMcpEmbedSurface()` helper to detect the `?embedded` query flag and switch to same-origin placeholder assets that comply with the host's sandbox requirements.

### Can I customize the iframe dimensions for my MCP app?

Yes, in addition to `iframeTitle`, you can export optional `iframeWidth` and `iframeHeight` properties in your action definition. These values suggest the initial dimensions to the MCP host, though the host may apply its own constraints based on available UI space.