MCP API¶
Model Context Protocol (MCP) client support. Build MCP server toolsets and attach
them to an agent via the mcp_servers parameter of
create_deep_agent. See
MCP servers for the conceptual overview.
build_mcp_server¶
pydantic_deep.mcp.build_mcp_server(config, resolver=None, *, oauth_token_storage=None)
¶
Build a connected pydantic-ai MCP toolset from a config.
Resolves the auth secret (if any) and injects it as an HTTP header (for
bearer/header auth) or a subprocess env var (for env auth).
Wraps the toolset in a PrefixedToolset when tool_prefix is set.
When config.init_timeout is set it is forwarded to the MCPToolset,
raising the connect/initialize deadline above pydantic-ai's 5s default
for servers that are slow to become ready.
Only the server's tools are built here. To also expose its resources or
skill:// skills to the model, set include_resources / include_skills
on the config and build via :meth:MCPRegistry.build_active.
For stdio servers, the subprocess receives config.env (plus any
env-kind auth var) layered on top of the MCP SDK's safe default
environment (PATH, HOME, …) — the parent process's full environment
is intentionally not inherited, so secrets like API keys are never
leaked to a third-party server. Add anything else a server needs (proxies,
NODE_EXTRA_CA_CERTS, …) explicitly via config.env.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
oauth_token_storage
|
Any | None
|
A persistent |
None
|
Raises:
| Type | Description |
|---|---|
MCPNotInstalledError
|
if the |
probe_mcp_server¶
pydantic_deep.mcp.probe_mcp_server(server, timeout=10.0)
async
¶
Connect to a built MCP server and list its tools, with a timeout.
Returns a :class:MCPProbeResult capturing success + tool names, or the
error string on failure. Never raises.
create_mcp_resources_toolset¶
Most MCP servers are used for their tools, but a server can also publish
resources — docs, templates, or FastMCP skill://.../SKILL.md skills. pydantic-ai
surfaces only the tools to the model, so set include_resources=True (or
include_skills=True for skills specifically) on an
MCPServerConfig and build with
MCPRegistry.build_active to attach a second
toolset that lets the model discover and read them:
from pydantic_deep.mcp import MCPRegistry, MCPServerConfig
registry = MCPRegistry([
MCPServerConfig(
name="service",
transport="http",
url="https://example.com/mcp/",
include_skills=True, # exposes list_mcp_skills / load_mcp_skill
),
])
mcp_servers = registry.build_active() # tools toolset + resources toolset
The resources toolset adds list_mcp_resources / read_mcp_resource, plus
list_mcp_skills / load_mcp_skill when include_skills is set. It binds to the
same underlying MCPToolset, so tools and resources share one connection.
Every server's tools carry a prefix, so the example above registers
service_list_mcp_skills, service_load_mcp_skill and so on. The prefix is the
server's tool_prefix when set, otherwise its name — without it, two servers
exposing their resources would register identical tool names and pydantic-ai
would reject the collision and fail the run.
With include_skills the toolset also lists the server's skills in the system
prompt, so the model knows the guidance exists before it reaches for the server's
operational tools rather than having to go looking for it.
A server that is unreachable degrades the same way its tools do: these tools
return the error as text instead of raising out of agent.run().
Use create_mcp_resources_toolset directly to wrap a server you built yourself —
pass tool_prefix if more than one server will expose its resources.
pydantic_deep.mcp.create_mcp_resources_toolset(provider, *, server_name, id=None, include_skills=True, tool_prefix=None)
¶
Build a toolset that exposes an MCP server's resources to the model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
MCPResourceProvider
|
The connected MCP server (anything with |
required |
server_name
|
str
|
Server identifier, used in the toolset id, the tool descriptions and the skill error text. |
required |
id
|
str | None
|
Explicit toolset id (defaults to |
None
|
include_skills
|
bool
|
Also register |
True
|
tool_prefix
|
str | None
|
Prepended to every tool name as |
None
|
Returns:
| Type | Description |
|---|---|
FunctionToolset[Any]
|
A |
FunctionToolset[Any]
|
(when |
builtin_mcp_servers¶
pydantic_deep.mcp.builtin_mcp_servers()
¶
Return fresh :class:MCPServerConfig instances for the built-in servers.
All are disabled by default — the user opts in via /mcp.
auth_satisfied¶
pydantic_deep.mcp.auth_satisfied(config, resolver=None)
¶
True when the server needs no pre-stored secret, or its secret resolves.
oauth servers are always considered satisfied here — they authorize
interactively at connect time, with no token to enter up front.
parse_mcp_servers¶
pydantic_deep.mcp.parse_mcp_servers(servers, *, enabled=True)
¶
Convert a mcpServers mapping to :class:MCPServerConfig list.
Recognises stdio (command), HTTP (type: http/streamable-http or a
bare url) and SSE (type: sse). WebSocket (type: ws) and malformed
entries are skipped. ${VAR} references in command/args/env/url/headers are
expanded. Tokens already present in env/headers are carried over.
MCPServerConfig¶
pydantic_deep.mcp.MCPServerConfig
dataclass
¶
Connection + auth description for a single MCP server.
A stdio server requires command; http/sse servers require url.
init_timeout = None
class-attribute
instance-attribute
¶
Seconds to wait for the initial connection + initialize handshake.
None uses pydantic-ai's default (5s). Raise it for servers that are slow
to become ready (e.g. one that opens a database connection on startup),
which would otherwise fail with "Failed to initialize server session".
include_resources = False
class-attribute
instance-attribute
¶
Expose the server's MCP resources to the model via list_mcp_resources /
read_mcp_resource. Off by default — most servers are used for tools only.
include_skills = False
class-attribute
instance-attribute
¶
Expose the server's skill://.../SKILL.md resources via list_mcp_skills
/ load_mcp_skill (and enables resource reading). See issue #178.
requires_auth
property
¶
True when a pre-stored secret must be provided before use.
oauth returns False: there's no token to enter up front — the client
runs the OAuth flow interactively at connect time.
MCPAuth¶
pydantic_deep.mcp.MCPAuth
dataclass
¶
Describes how to authenticate to an MCP server using a stored secret.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
secret_key
|
str
|
Name under which the token is stored (keystore / env var),
e.g. |
''
|
kind
|
MCPAuthKind
|
How auth is performed (see :data: |
'bearer'
|
header
|
str
|
Header name for |
'Authorization'
|
env_var
|
str | None
|
Environment variable name for |
None
|
value_template
|
str
|
Template formatted with |
'Bearer {token}'
|
instructions
|
str
|
Human-readable hint on how to obtain the token, shown in the CLI login flow. |
''
|
client_name
|
str | None
|
OAuth client name advertised during dynamic client
registration ( |
None
|
render_value(token)
¶
Format value_template with the resolved token.
MCPRegistry¶
pydantic_deep.mcp.MCPRegistry
¶
A mutable collection of MCP server configs with secret-aware building.
build_active(on_degraded=None)
¶
Build toolsets for every server that is enabled and authenticated.
Each is wrapped via :func:make_resilient so that a configured server
which turns out to be unreachable at runtime contributes no tools rather
than failing the entire agent run. on_degraded(name, reason) is
forwarded to each wrapper.
A server with include_resources / include_skills set contributes a
second toolset exposing its MCP resources (and skill:// skills) to the
model. It binds to the same underlying MCPToolset so tools and
resources share one connection, and its tools are prefixed per server so
several such servers can be active at once.
MCPProbeResult¶
pydantic_deep.mcp.MCPProbeResult
dataclass
¶
Outcome of a connection probe against an MCP server.
MCPNotInstalledError¶
pydantic_deep.mcp.MCPNotInstalledError
¶
Bases: ImportError
Raised when building an MCP server but the optional dependency is absent.