MCP
Two gates decide what an agent can call, and one of two modes decides how.
An agent can call an MCP tool only when two separate declarations both allow it. The package says what the whole recipe may ever touch, and each agent says which part of that its own role needs.
| Declared in | Answers | Written by |
|---|---|---|
package.json | What may this recipe touch at all? | Whoever owns the package |
agents/*.yaml | What does this one role need? | Whoever writes the agent |
Both gates fail closed, so anything neither of them named is unavailable rather than merely unused. Widening an agent can only ever reach as far as the package already allows, which is what makes the package file the one place to review when you want to know a recipe's blast radius.
Declare the package boundary
Policy rules
- Prefer exact tool names.
"*"permits the package-visible set including tools the server adds later. - Patterns such as
search_*are invalid. It is exact names or"*". excluderemoves exact names after inclusion and always wins.- An agent can only narrow. It can never add capability the package did not declare.
- Omitting a server, or the whole agent
mcpblock, means no access to it. "required": truethat cannot be bound fails the session at launch rather than starting without the capability.manifestsis optional, and points at portable endpoint definitions the package ships with.
Narrow it per agent
MCP tools are selected here, never in the agent's ordinary tools list. A declared mcp block replaces the inherited one whole, so a derived agent must restate its mode and servers. That is deliberate: it makes a capability change visible in the diff of the agent that made it.
CLI mode
mode: cli gives the agent one mcp command containing only its authorized tools. A large server costs one tool definition instead of forty, and the agent discovers narrowly, reads one schema, then calls.
Sessions expose only search, list, call and run. Interactive authentication, administrative commands, URL selectors, ad-hoc transports, config overrides and persistence flags are all rejected, so a session cannot reach past its materialized surface. Delegating to another agent does not give the parent that child's capabilities.
Tools mode
mode: tools registers each authorized tool with Pi directly, which is what you want when the model should see real tool schemas. Every resolved agent owns its mode independently, so a root and its subagents may differ. With no mode anywhere in a chain, a resolved agent gets CLI.
Deferred tools
defer hides authorized tools at session start; eager subtracts exceptions and wins when a tool matches both. Neither can authorize a tool that include and exclude did not, and both are invalid in CLI mode. Omit defer to expose everything immediately.
Deferred tools stay authorized and discoverable. When any exist, Recipes registers mcp_search, which searches only the authorized deferred catalog and adds matches to the active set for the next request. It never grants access beyond servers.
This is Pi's own deferred tool loading, applied to MCP. A loader tool stays active, the searchable tools start inactive, and activation is additive. On models with native support the prompt prefix survives and the new definitions load at the tool-result position; elsewhere Pi falls back to sending the updated active list. You get the token saving without implementing any of it.
Endpoints and credentials
The package declares which servers a recipe may use. Where those servers live, and what authenticates to them, is supplied where the recipe runs. See Running locally for .pi/mcp.local.json and local OAuth, and Deploying for host bindings and terminating auth at the edge.