MCP and federation
The Model Context Protocol shows up on the platform in two ways: your agents call out to MCP servers as tools, and authorized-application endpoints can carry the task identity to a partner server. That identity may be caller-attributed or federation-proven; the receiving server chooses which trust level it accepts.
Both directions here are outbound — your agent is the client. To let another system drive your agent, expose it through your own backend using the SDK and the identity model in Authentication.
Recipe MCP: agents calling out
Your agent or recipe can call external MCP servers as tools. You make a server available by configuring an mcp endpoint binding; the binding decides which server is reached and how the call is authenticated. The agent then calls the server’s tools the same way it calls any other tool.
Discovery happens once, when a task boots: the runtime reads each server’s tool catalog at that point and uses it for the task’s lifetime. Attaching or re-pointing an MCP endpoint takes effect on the next task, the same way recipe pins do.
A connector supplies an MCP server the same way, with one difference: the endpoint and its credential come from a customer’s authorized connection rather than from a binding you configure, and the credential is attached at egress instead of reaching the sandbox. Everything below — the three gates, the intersection, the two modes — applies to a connector-backed server unchanged.
Which tools an agent gets
Access to MCP tools is declared in the recipe, and the runtime enforces it. Three independent gates apply, and the effective tool set is their intersection:
-
The recipe package declares which servers the recipe may use, and which of their tools, in
package.jsonunderpi.mcp:{ "pi": { "mcp": { "manifests": ["mcp.json"], "servers": [ { "id": "contacts", "tools": { "include": ["*"], "exclude": ["delete_contact"] } } ] } } } -
Each agent selects the subset it needs in its agent YAML, in an
mcp:block that picks a mode and lists servers:tools: - bash mcp: mode: cli servers: contacts: include: ["*"] exclude: [delete_contact]mode: cligives the agent the session-localmcpcommand described below.mode: toolsregisters each authorized tool with Pi directly. -
The endpoint binding supplies the endpoint that makes an authorized server reachable, and the catalog it exposes at boot. A binding never expands authorization.
include names what the agent may reach: ["*"] means the server’s whole tool set (including tools the server adds later), and a list of exact names means just those. exclude subtracts exact names after inclusion and always wins. "*" is a whole-toolset sentinel, not a glob, so search_* is invalid. Every gate is fail-closed: a server with no include, a server left out of servers, and an omitted mcp: block all mean no access, so a recipe can never grant more than it wrote down.
An invalid MCP policy fails closed: the task won’t launch the agent with guessed access. Validate at author time with introspection check, which reports an agent naming a server the package never declared, an unknown mode, and a selector that is neither an exact tool name nor "*". Note what it does not flag, because these are policy rather than mistakes: a server with no include and a selection that resolves to no tools both validate, and both mean no access at run time.
The in-session mcp CLI
Inside the sandbox, an agent that selects mode: cli gets a session-local mcp command (materialized at .pi/bin/mcp and put on the session’s PATH), invoked through its command-execution tool (normally bash). The CLI is capability-scoped: it can only see the servers and tools the recipe and agent selected, it rejects ad-hoc servers, config overrides, and transport flags, and OAuth is always headless (cached credentials work; no browser flow can launch from a task).
It exposes exactly four commands:
| Command | What it does |
|---|---|
mcp search "<query>" [--limit N] [--regex] | Search the session’s available tools over names, descriptions, and argument docs. |
mcp list [server[.tool]] [--schema] | Inventory: servers with tool counts, one server’s compact tool signatures, or one tool’s input/output contract with --schema. |
mcp call server.tool key=value… | Invoke one tool. Named args are schema-coerced; pass nested payloads with --json '<json>' (or --json - from stdin) and file contents with key=@path. |
mcp run [--var KEY=value] [file] | Run a JavaScript workflow (from a file or stdin) that composes several tool calls. |
mcp run scripts call tools as tools["server"]["tool"]({ ...args }) and get decoded JSON back by default; --var KEY=value passes dynamic values in as vars.KEY so heredocs stay quoted. Workflows are resource-bounded (2-minute wall clock, 60s per call, 100 calls, bounded concurrency) and every call must be awaited. Search and list output is compact text designed for token efficiency; JSON is reserved for actual tool results.
Nothing is injected into the agent’s prompt automatically: the runtime adds no
implicit MCP instructions or capability notices. A recipe that wants its agent
to use MCP tools says so in its own SYSTEM.md or the agent’s
system_instructions; the CLI itself is discoverable via mcp --help.
Carrying the task identity
When an agent reaches a partner’s MCP server on behalf of a user, Introspection applies a short-lived, platform-signed identity JWT at the network boundary. The credential never enters the sandbox.
The JWT type preserves how the user was established:
| Type | User identity | When to accept it |
|---|---|---|
identity_assertion | Proven through the application’s configured identity provider | The server requires an independently verified partner user |
identity_attribution | Supplied by an authenticated API key or service account | The server trusts that application to choose the correct user |
The MCP server verifies the JWT signature against the application’s published assertion JWKS, then validates issuer, audience, expiry, subject, token type, and task ID. A valid signature alone does not make caller attribution equivalent to federation.
Giving the partner a verification anchor
Each application publishes its own keys, scoped by the application’s client id — not its UUID. Retrieve the client id from the application record, then give the receiving system:
issuer https://<control-plane-host>/v1/applications/<client-id>
JWKS https://<control-plane-host>/v1/applications/<client-id>/.well-known/jwks.jsonA partner that registers external issuers by discovery can be given the issuer alone: the same path also serves an OpenID discovery document at /.well-known/openid-configuration, carrying the issuer and jwks_uri. That is the shorter integration path where the receiving system supports it.
Rotating an application key publishes the new key under a new kid at the same JWKS URL, so a partner pinned to the URL picks it up without a configuration change. A partner that pinned an individual key instead must be updated before the old key is removed.
The assertion authenticates the subject; it does not authorize data in the receiving system. The MCP server still checks what that subject may read or change. Page context and prompt metadata are never authority.
Authentication modes for an MCP endpoint
An mcp endpoint can authenticate in one of three ways, independent of the protocol it speaks:
| Mode | What it does |
|---|---|
| Authorized application | A signed task identity is applied to the call. The endpoint decides whether it accepts federation-proven assertions, caller attribution, or both. |
| Bearer token | A shared token is applied to every call (for example, a bot token). No per-user identity. |
| Unauthenticated | No credential; allowlist-only egress. |
See Authentication & identity for the caller methods and trust levels that produce these assertion types.
Related
- Platform: the unified map for source control, tools, models, and protected execution.
- Bindings: where
mcpendpoints and their credentials live. - Connectors: MCP servers whose credential comes from a customer’s authorized provider account.
- Authentication & identity: API keys, service accounts, federation, and identity trust levels.
- SDK authentication: configure the corresponding token flows.
- API Reference: the REST surface behind these features.