---
title: "MCP Protocol"
description: "Expose your agent-native app as a remote MCP server so Claude, ChatGPT, Claude Code, Cursor, and other AI tools can call your app's actions directly."
---

# MCP Protocol

Every agent-native app automatically exposes a remote MCP (Model Context Protocol) server. This lets external AI tools like Claude, ChatGPT custom MCP apps, Claude Code, Cursor, Codex, VS Code GitHub Copilot, and Windsurf discover and call your app's actions directly — no extra code needed.

**Which page do I need?**

| Goal                                                        | Page                                     |
| ----------------------------------------------------------- | ---------------------------------------- |
| Connect Claude / ChatGPT / Codex / Cursor to a hosted app   | [External Agents](/docs/external-agents) |
| Make your app callable over MCP (server setup, auth, tools) | This page                                |
| Give your app's agent more tools from external MCP servers  | [MCP Clients](/docs/mcp-clients)         |
| App-to-app delegation via JSON-RPC                          | [A2A Protocol](/docs/a2a-protocol)       |
| Build or embed interactive MCP App UIs                      | [MCP Apps](/docs/mcp-apps)               |

If your goal is to connect Claude, ChatGPT, Claude Code, Codex, Cursor, or Claude Cowork to hosted agent-native apps, start with [External Agents](/docs/external-agents). It documents the recommended single Dispatch connector at `https://dispatch.agent-native.com/_agent-native/mcp`, direct per-app URLs for isolated app access, standard remote MCP OAuth, fallback config for older clients, MCP Apps inline UIs, and deep links back into the UI. This page is the lower-level MCP server reference.

## Overview {#overview}

MCP is the standard protocol for connecting AI tools to external capabilities. When you deploy an agent-native app, it auto-mounts an MCP endpoint alongside the existing A2A endpoint. Any MCP-compatible client can connect and use your app's tools.

Key concepts:

- **Auto-mounted** — every app gets `/_agent-native/mcp` for free, no setup required
- **Streamable HTTP** — uses the modern MCP transport over standard HTTP (POST + SSE)
- **Same actions** — the exact same action registry that powers agent chat and A2A
- **`ask-agent` tool** — a meta-tool that delegates to the full agent loop for complex tasks
- **MCP Apps** — actions can advertise inline HTML UIs through the official `io.modelcontextprotocol/ui` extension
- **Standard remote MCP OAuth** — OAuth 2.1 discovery, dynamic client registration, authorization-code + PKCE, refresh-token rotation
- **Bearer auth fallback** — uses `ACCESS_TOKEN`, `ACCESS_TOKENS`, or connect-minted JWTs for clients that cannot run OAuth

## MCP vs A2A {#mcp-vs-a2a}

Both protocols are auto-mounted. Use whichever fits your use case:

|                    | MCP                                                                      | A2A                                          |
| ------------------ | ------------------------------------------------------------------------ | -------------------------------------------- |
| **Best for**       | External tools calling your app                                          | Agent-to-agent communication                 |
| **Protocol**       | MCP Streamable HTTP                                                      | JSON-RPC 2.0                                 |
| **Tool discovery** | `tools/list`                                                             | Agent card at `/.well-known/agent-card.json` |
| **Endpoint**       | `/_agent-native/mcp`                                                     | `/_agent-native/a2a`                         |
| **Supported by**   | Claude, ChatGPT, Claude Code, Cursor, Codex, Cowork, and other MCP hosts | Other agent-native apps                      |
| **Execution**      | Direct tool calls (no extra LLM)                                         | Full agent loop (LLM reasoning)              |

You can also use the `ask-agent` MCP tool to get the best of both worlds — call it from Claude Code and let your app's agent reason through complex tasks.

## Manual MCP client config {#manual-config}

For the recommended one-command setup, use [External Agents](/docs/external-agents). If you are hand-writing MCP config for an OAuth-capable client, add your app as a remote MCP server with no static headers:

```bash
claude mcp add --transport http mail https://mail.example.com/_agent-native/mcp
```

Or write the entry by hand in `.mcp.json` (project scope) or `~/.claude.json` (user scope):

```jsonc
// .mcp.json
{
  "mcpServers": {
    "mail": {
      "type": "http",
      "url": "https://mail.example.com/_agent-native/mcp",
    },
  },
}
```

Then run `/mcp` in Claude Code and choose **Authenticate**. For clients that cannot perform remote MCP OAuth, use the Connect page or a static bearer-token entry with `headers.Authorization`. Once authenticated, you can use your app's tools naturally:

```
> draft an email to John about the Q3 report

Claude Code calls: draft-email(to: "john@example.com", subject: "Q3 Report", body: "...")
```

## Connecting from other MCP clients {#other-clients}

Any MCP client that supports Streamable HTTP transport can connect. The endpoint is:

```
POST https://your-app.example.com/_agent-native/mcp
```

The server supports the standard MCP handshake: `initialize` → `initialized` → `tools/list` → `tools/call`.

If an action declares `mcpApp`, the server also advertises the official MCP Apps extension (`io.modelcontextprotocol/ui`) and supports `resources/list`, `resources/templates/list`, and `resources/read` for the app resource. Hosts that render MCP Apps can show the UI inline; hosts that do not can still call the tool and use the deep-link fallback. Product UIs should use `embedApp()` so the inline surface is the real React app route, or a focused route that renders a shared React component such as an Analytics chart, not a separate plain HTML implementation. The server emits both standard MCP Apps metadata and ChatGPT Apps SDK compatibility metadata so app-capable hosts can find the same `ui://` resource. The current official extension matrix includes Claude, Claude Desktop, VS Code GitHub Copilot, Goose, Postman, MCPJam, ChatGPT, and Cursor; host support varies by version and plan, so use the [External Agents MCP Apps notes](/docs/external-agents#mcp-apps-compatibility) for the user-facing guidance.

### MCP App embed bridge {#mcp-app-embed-bridge}

`embedApp()` is the low-level URL-first MCP App helper: it launches a signed app
route inline through transplant (Claude), controlled-frame (ChatGPT), or direct
navigation, mediates host actions over the `ui/*` JSON-RPC bridge (and the
`agentNative.mcpHost.*` postMessage relay for the controlled-frame path), and
clamps the resource shell height so a full-app route does not render as an
oversized chat artifact.

See [MCP Apps](/docs/mcp-apps#mcp-app-bridge) for the full embed bridge details — transplant vs controlled-frame, the `ui/*` and postMessage tables, `create_embed_session` / `embedStartUrl`, CSP and domain rules, extension `srcDoc` embedding, height clamping, and the host bridge client API.

## Tools {#tools}

Stdio/code developer clients can see all connected app actions as MCP tools
when they explicitly request the full catalog. Chat-style app hosts, including
OAuth callers that request `mcp:apps` and generic authenticated remote
HTTP/static-token callers, get a compact app-host catalog by default:
app-facing builtins (`list_apps`, `open_app`, `ask_app`, and app-only
`create_embed_session`) plus rare actions marked `mcpApp.compactCatalog: true`.
Their `resources/list` is compact too, normally advertising only the generic
`open_app` embed resource. `publicAgent.expose` remains the opt-in for safe
read/ingest tools outside that compact app catalog. This keeps ChatGPT/Claude
app-host discovery small while preserving the full developer surface for local
agents.

The mapping is direct:

| Action property    | MCP tool property |
| ------------------ | ----------------- |
| `tool.description` | `description`     |
| `tool.parameters`  | `inputSchema`     |
| Action name        | Tool name         |

When `mcpApp` is present, the tool entry also includes `_meta.ui.resourceUri`, `_meta["ui/resourceUri"]`, and `_meta["openai/outputTemplate"]`, and the corresponding `ui://` resource is returned as `text/html;profile=mcp-app`.

### The `ask-agent` tool {#ask-agent}

In addition to individual action tools, every MCP server includes an `ask-agent` meta-tool. This sends a natural-language message to the app's AI agent and returns the response.

Use `ask-agent` for complex tasks that benefit from the agent's reasoning and context:

```json
{
  "name": "ask-agent",
  "arguments": {
    "message": "Draft a follow-up email to the Q3 planning thread with John, summarizing the action items we discussed"
  }
}
```

The agent runs the same loop as the interactive chat — it can call multiple tools, reason about context, and produce a thoughtful response.

## Authentication {#authentication}

The MCP endpoint supports standard remote MCP OAuth plus the existing bearer-token fallback:

| Mode                        | How it works                                                                                                          |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Standard MCP OAuth          | Client discovers auth from `WWW-Authenticate`, registers, runs PKCE, and sends `Authorization: Bearer <access-token>` |
| Connect-minted JWT          | `npx @agent-native/core@latest connect` / the Connect page mints a per-user, revocable JWT                            |
| `ACCESS_TOKEN`              | Static bearer token — client sends `Authorization: Bearer <token>`                                                    |
| `ACCESS_TOKENS`             | Comma-separated list of valid static bearer tokens                                                                    |
| `A2A_SECRET`                | JWT-based auth — tokens are verified cryptographically                                                                |
| _(none set, loopback only)_ | No auth required for local dev probes                                                                                 |

For OAuth-capable MCP hosts, configure the remote server URL with no static headers:

```bash
claude mcp add --transport http agent-native https://dispatch.agent-native.com/_agent-native/mcp
```

The first unauthenticated MCP request receives:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://dispatch.agent-native.com/.well-known/oauth-protected-resource", scope="mcp:read mcp:write mcp:apps"
```

Discovery endpoints:

| Endpoint                                  | Purpose                                     |
| ----------------------------------------- | ------------------------------------------- |
| `/.well-known/oauth-protected-resource`   | RFC 9728 protected-resource metadata        |
| `/.well-known/oauth-authorization-server` | OAuth authorization server metadata         |
| `/_agent-native/mcp/oauth/register`       | Dynamic public-client registration          |
| `/_agent-native/mcp/oauth/authorize`      | Browser authorization + consent             |
| `/_agent-native/mcp/oauth/token`          | Authorization-code and refresh-token grants |

Access tokens are signed JWTs whose audience is the exact MCP resource URL. The server accepts only tokens issued for itself and applies scopes before listing/calling tools:

| Scope       | Allows                                      |
| ----------- | ------------------------------------------- |
| `mcp:read`  | read-only actions                           |
| `mcp:write` | mutating actions and `ask-agent`            |
| `mcp:apps`  | MCP Apps resources (`ui://` HTML resources) |

Refresh tokens are stored only as hashes and are rotated on every refresh. `npx @agent-native/core@latest connect` writes this URL-only OAuth entry for Claude Code clients by default; keep the Connect page, `npx @agent-native/core@latest connect --token <token>`, and static bearer config for local stdio proxying, older clients, and emergency/debug flows.

## Custom MCP setup {#custom-setup}

The MCP server is auto-mounted by the agent-chat plugin. For most apps, no configuration is needed. If you need custom behavior, you can mount it manually in a server plugin:

```ts
// server/plugins/mcp.ts
import { mountMCP } from "@agent-native/core/mcp";
import { autoDiscoverActions } from "@agent-native/core/server";

export default defineNitroPlugin(async (nitro) => {
  const actions = await autoDiscoverActions(import.meta.url);

  mountMCP(nitro, {
    name: "My App",
    description: "Custom MCP server",
    actions,
    // Optional: provide ask-agent handler
    askAgent: async (message) => {
      // Your custom agent logic
      return "Response";
    },
    // Optional: override the route prefix (default "/_agent-native")
    // routePrefix: "/_agent-native",
  });
});
```

## Example: analytics from Claude Code {#example}

You have a deployed analytics app at `analytics.example.com`. From Claude Code:

```bash
claude mcp add --transport http analytics https://analytics.example.com/_agent-native/mcp
```

Or add it by hand in `.mcp.json`:

```jsonc
// .mcp.json
{
  "mcpServers": {
    "analytics": {
      "type": "http",
      "url": "https://analytics.example.com/_agent-native/mcp",
    },
  },
}
```

Now in Claude Code:

```
> How many signups did we get last week?

Claude Code calls: run-query(sql: "SELECT count(*) FROM signups WHERE created_at > now() - interval '7 days'")
→ "1,247 signups last week"
```

For more complex analysis:

```
> Ask the analytics agent to prepare a full breakdown of Q3 signups by source, with trends

Claude Code calls: ask-agent(message: "Prepare a full breakdown of Q3 signups by source, with trends")
→ The analytics agent runs multiple queries, reasons about the data, and returns a formatted report
```
