How to Use MCPServerTool in Pydantic AI

Learn how to use Pydantic AI's provider-side MCPServerTool with OpenAI Responses, Anthropic, and xAI. Configure auth, allowed tools, connectors, and know when to choose it over MCPServer or FastMCPToolset.

If MCPServer is the control path and FastMCPToolset is the convenience path, MCPServerTool is the offload path.

That one distinction clears up most of the confusion.

People see the name and assume MCPServerTool is just one more way for their app to speak MCP. It is not. When you use it, your app is no longer the MCP client. The model provider is. That changes almost everything: where the server must live, which API you need, how auth is passed, what features you give up, and why performance can improve.

As of April 1, 2026, the official Pydantic AI docs still describe MCPServerTool as the built-in tool for remote MCP servers, with communication handled by the provider. The same docs also warn that this path does not support many of the more advanced agent-side MCP features, but can give you better context use, caching, and lower overhead because the request does not bounce back through your app.

That is a very specific tradeoff. Sometimes it is exactly what you want. Sometimes it is the wrong tool entirely.

This guide focuses on the practical side:

  • using builtin_tools=[MCPServerTool(...)]
  • choosing a supported provider and model path
  • configuring auth, allowed tools, and headers
  • using OpenAI connector URLs
  • knowing when to stop and use MCPServer instead

If you want the big-picture comparison first, read our guide to MCPServer, FastMCPToolset, and MCPServerTool. If you want the richer agent-side client path, the companion guide on connecting Pydantic AI to MCP servers with MCPServer covers that route.

What you’ll learn:

  • what MCPServerTool actually does inside Pydantic AI
  • which providers support it and which do not
  • how to wire a remote MCP server with OpenAI Responses or Anthropic
  • how to scope access with allowed_tools, auth tokens, and headers
  • when provider-side MCP is cleaner than agent-side MCP

Time required: 20-30 minutes
Difficulty level: Intermediate

Step 1: Understand What MCPServerTool Really Is

MCPServerTool is a built-in tool, not a toolset.

That means you register it like this:

from pydantic_ai import Agent, MCPServerTool

agent = Agent(
    "openai-responses:gpt-5.2",
    builtin_tools=[
        MCPServerTool(
            id="deepwiki",
            url="https://mcp.deepwiki.com/mcp",
        )
    ],
)

Not like this:

agent = Agent(
    "...",
    toolsets=[...],  # wrong path for MCPServerTool
)

That detail matters because built-in tools run on the provider side. The Pydantic AI docs phrase it pretty plainly: MCPServerTool is for remote MCP servers with communication handled by the model provider.

So the mental model is:

  • your app sends a model request
  • the provider decides to use the built-in MCP tool
  • the provider reaches the remote MCP server directly
  • the MCP exchange happens there, not inside your Python process

Once you see it that way, a lot of downstream rules stop feeling arbitrary.

One side note from the same docs: if you want a more model-agnostic route with automatic local fallback, they point you to the higher-level MCP capability instead of MCPServerTool directly.

Step 2: Start with the Two Hard Constraints

Before you write a line of code, check these two things.

Constraint 1: The MCP server must be reachable by the provider

If your MCP server only lives on localhost, inside a private Docker network, or behind infrastructure the provider cannot see, MCPServerTool is not the right choice.

The docs explicitly say this path requires the MCP server to live at a public URL the provider can reach.

So this is a bad fit:

  • local stdio servers
  • http://localhost:3001/mcp
  • internal-only VPN endpoints
  • private staging URLs that only your app can access

Those are MCPServer or FastMCPToolset problems, not MCPServerTool problems.

Constraint 2: You need a provider that supports the built-in tool

As of April 1, 2026, the Pydantic AI built-in tools docs list support for MCPServerTool on:

  • OpenAI Responses
  • Anthropic
  • xAI

The same docs list these as unsupported:

  • Google
  • Groq
  • OpenAI Chat Completions
  • Bedrock
  • Mistral
  • Cohere
  • HuggingFace

That OpenAI split is easy to miss. If you are on OpenAI, this is a Responses API feature, not a Chat Completions feature.

Step 3: Wire the Simplest Working Example First

I would start with the smallest possible remote server example before touching auth or connectors.

The official docs use DeepWiki as the minimal public example:

from pydantic_ai import Agent, MCPServerTool

agent = Agent(
    "openai-responses:gpt-5.2",
    builtin_tools=[
        MCPServerTool(
            id="deepwiki",
            url="https://mcp.deepwiki.com/mcp",
        )
    ],
)

result = agent.run_sync("Tell me about the pydantic/pydantic-ai repo.")
print(result.output)

If you prefer Anthropic, the same docs show the same pattern with a Claude model:

from pydantic_ai import Agent, MCPServerTool

agent = Agent(
    "anthropic:claude-sonnet-4-6",
    builtin_tools=[
        MCPServerTool(
            id="deepwiki",
            url="https://mcp.deepwiki.com/mcp",
        )
    ],
)

result = agent.run_sync("Tell me about the pydantic/pydantic-ai repo.")
print(result.output)

That is the key thing to notice: the transport details are not in your app. You are just declaring a remote MCP server as a provider-native tool.

Step 4: Use id Like It Actually Matters

The id field is not decorative.

According to the API reference, MCPServerTool uses id as the unique identifier for the server, and derives:

  • unique_id as mcp_server:<id>
  • label as MCP: <id>

That is a small detail, but it is worth treating seriously. Give each server a stable, descriptive id, especially if you plan to register more than one built-in MCP server.

Good examples:

  • deepwiki
  • github
  • google-calendar
  • billing-docs

Bad examples:

  • server1
  • test
  • foo

You may not care on day one. You will care once traces, logs, or debugging screenshots start piling up.

Step 5: Lock Down Auth and Tool Scope Early

The next step is where MCPServerTool gets more interesting.

The docs show that you can configure:

  • authorization_token
  • allowed_tools
  • description
  • headers

Here is the official GitHub-style example pattern:

import os

from pydantic_ai import Agent, MCPServerTool

agent = Agent(
    "openai-responses:gpt-5.2",
    builtin_tools=[
        MCPServerTool(
            id="github",
            url="https://api.githubcopilot.com/mcp/",
            authorization_token=os.getenv("GITHUB_ACCESS_TOKEN"),
            allowed_tools=["search_repositories", "list_commits"],
            description="GitHub MCP server",
            headers={"X-Custom-Header": "custom-value"},
        )
    ],
)

This is a much better starting point than exposing the entire server surface by default.

I would treat allowed_tools as the first real safety lever:

  • keep the list tight at the start
  • only expose the tools your prompt actually needs
  • widen later if logs show the agent is boxed in

That is not just good security hygiene. It also reduces tool-selection noise.

Parameter support is not identical across providers

The built-in tools docs include a parameter support table for MCPServerTool:

ParameterOpenAI ResponsesAnthropicxAI
authorization_tokenYesYesYes
allowed_toolsYesYesYes
descriptionYesNoYes
headersYesNoYes

That means two easy mistakes to avoid:

  • do not rely on headers if you need Anthropic
  • do not assume description is portable across every supported provider

If you need the broadest compatibility, stick to id, url, authorization_token, and allowed_tools.

Step 6: Use OpenAI Connectors When the Server URL Is Really a Connector

This is where the OpenAI route becomes more specialized.

The Pydantic AI docs say OpenAI Responses can use connectors by passing a special URL in this format:

x-openai-connector:<connector_id>

Example:

import os

from pydantic_ai import Agent, MCPServerTool

agent = Agent(
    "openai-responses:gpt-5.2",
    builtin_tools=[
        MCPServerTool(
            id="google-calendar",
            url="x-openai-connector:connector_googlecalendar",
            authorization_token=os.getenv("GOOGLE_API_KEY"),
        )
    ],
)

result = agent.run_sync("What do I have on my calendar today?")
print(result.output)

This is OpenAI-specific. It is not a generic MCP URL trick.

If you are already using OpenAI-managed connectors, this can be the cleanest reason to pick MCPServerTool over agent-side MCP. Your app stays thin, and the provider handles the remote tool bridge directly.

Step 7: Add Dynamic Built-in Configuration When One Server Is Not Always Needed

The generic built-in tools docs say builtin_tools can accept a function that receives RunContext and returns an AbstractBuiltinTool or None.

That section is shown with WebSearchTool, but the API is generic. So the same pattern can be applied to MCPServerTool. This is an inference from the built-in tool API, not a separate MCPServerTool-specific example in the docs.

Here is a practical version:

from pydantic_ai import Agent, MCPServerTool, RunContext


async def prepare_github_mcp(ctx: RunContext[dict]) -> MCPServerTool | None:
    if not ctx.deps.get("enable_repo_search"):
        return None

    token = ctx.deps.get("github_token")
    if not token:
        return None

    return MCPServerTool(
        id="github",
        url="https://api.githubcopilot.com/mcp/",
        authorization_token=token,
        allowed_tools=["search_repositories", "list_commits"],
    )


agent = Agent(
    "openai-responses:gpt-5.2",
    builtin_tools=[prepare_github_mcp],
    deps_type=dict,
)

I like this pattern when:

  • some users have connector access and others do not
  • you only want the MCP server available for a specific workflow
  • you want to skip the tool entirely when auth is missing

That keeps the agent prompt cleaner than registering every possible remote server all the time.

Step 8: Know What You Are Giving Up

This is the part that trips people up.

The docs say MCPServerTool does not support many of the advanced features of Pydantic AI’s agent-side MCP support. They do not frame it as a universal replacement for MCPServer.

So if I know I need any of the following, I stop and reach for the standard client path first:

  • localhost or stdio servers
  • private infrastructure only my app can reach
  • explicit agent-side transport control
  • richer MCP client behavior such as sampling or elicitation

For things like resource access, custom TLS control, or agent-side tool-call hooks, the standard MCPServer docs are the richer documented path. That is an inference from the documented feature split across the two systems, and in practice it is the safer way to choose.

In other words, MCPServerTool is excellent when the provider should own the remote exchange. It is not the tool I would pick if MCP behavior itself is part of my application’s contract.

Step 9: Choose MCPServerTool for the Right Reasons

Here is when I think MCPServerTool is genuinely the better answer:

  • your MCP server already lives at a public remote URL
  • your provider supports built-in MCP tools
  • you want less app-side plumbing
  • you want the provider to handle context packing and caching directly
  • you are using OpenAI connectors and want the shortest path to them

And here is when I would not force it:

  • your server is local
  • your team needs full agent-side control
  • you expect interactive MCP features to matter
  • you are still on an unsupported provider

This is why the three Pydantic AI MCP paths exist in the first place. They are not cosmetic variations. They solve different deployment shapes.

Step 10: The Fast Decision Rule

If you want a quick rule you can use in code review, use this:

  • choose MCPServerTool when the provider should talk to a public remote MCP server directly
  • choose MCPServer when your app should remain the MCP client
  • choose FastMCPToolset when you still want agent-side execution but prefer FastMCP ergonomics

That is the real map.

Common Mistakes

Using toolsets= instead of builtin_tools=

If you register MCPServerTool like a toolset, you are mixing two different Pydantic AI integration layers.

Pointing to localhost

http://localhost:3001/mcp may be reachable from your machine. That says nothing about whether OpenAI or Anthropic can reach it.

Using OpenAI Chat Completions

The built-in tools docs are explicit: MCPServerTool support is on OpenAI Responses, not Chat Completions.

Assuming all config parameters work everywhere

They do not. description and headers are not supported on Anthropic according to the current docs.

Reaching for it just because it sounds newer

Provider-side execution is not automatically better. Sometimes it is simpler. Sometimes it is just less controllable.

Final Takeaway

MCPServerTool makes sense once you stop thinking of it as “another MCP client wrapper” and start thinking of it as “provider-native remote MCP access.”

That is why it shines in a narrow set of cases:

  • public remote servers
  • supported providers
  • lighter app integration
  • connector-style workflows

Outside that lane, MCPServer is usually the more capable tool. And that is fine. Pydantic AI is giving you three MCP paths because real deployments are messy, not because the docs wanted extra nouns.

Pick the one that matches where the connection should live.

References

Spread The Article

Share this guide

Send this article to your network or keep a copy of the direct link.

X Facebook LinkedIn Reddit Telegram

Discussion

Leave a comment

No comments yet

Be the first to start the conversation.