WEIR

Pydantic AI MCP Client: Connect a Remote MCP Server in v2

Connect a Pydantic AI agent to a remote MCP server with the MCP capability or MCPToolset: headers, tool filters, and what replaced MCPServerStreamableHTTP.


Published · Updated · 7 min read

Cover image: X search in a Pydantic AI agent

The Pydantic AI MCP client is the MCP capability in version 2: pass a URL and headers, then add it to your agent.

This guide connects a Pydantic AI agent to Weir's remote MCP server for public X (Twitter) data. You'll limit its tools and see the agent answer with search_x. Many guides online still use version 1 class names, which fail on 2.x. We run Weir.

import os
from pydantic_ai import Agent
from pydantic_ai.capabilities import MCP

weir = MCP(
    url="https://api.weirapp.io/mcp",
    headers={"Authorization": f"Bearer {os.environ['WEIR_API_KEY']}"},
    allowed_tools=["search_x"],
)
agent = Agent("anthropic:claude-sonnet-5-5", capabilities=[weir])

How to connect Pydantic AI to a remote MCP server

You need the slim package with two extras, a Weir key and a model key. The Weir key rides in a header on every request, so there's no sign-in step. That suits scripts, scheduled jobs and servers.

  1. Installpip install "pydantic-ai-slim[anthropic,mcp]" in a virtual environment.
  2. Get a Weir keyCreate one under API keys in your Weir dashboard. Keep it in WEIR_API_KEY.
  3. Set a model keyAnthropic models read ANTHROPIC_API_KEY from the environment.
  4. Run the agentUse async with agent, then agent.run(), as in the script below.

As of 22 October 2026, PyPI lists pydantic-ai-slim 2.59.0, which needs Python 3.11 or later. The mcp extra pulled in FastMCP's client and the official mcp SDK on our install.

Skip the anthropic extra and the agent fails to start, with an ImportError that names it. Swap it for your provider's extra if you use another model.

Pydantic AI MCP client example: ask X a question

The script is 22 lines. Part one builds the capability and the agent:

import asyncio, os
from pydantic_ai import Agent
from pydantic_ai.capabilities import MCP

weir = MCP(
    url="https://api.weirapp.io/mcp",
    headers={"Authorization": f"Bearer {os.environ['WEIR_API_KEY']}"},
    allowed_tools=["search_x", "get_x_post"],
)
agent = Agent(
    "anthropic:claude-sonnet-5-5",
    capabilities=[weir],
    instructions="Search X with limit 5 or less. Link every post you cite.",
)

Part two opens the connection and asks:

async def main(question: str) -> None:
    async with agent:
        result = await agent.run(question)
    print(result.output)
    print(result.usage)

asyncio.run(main("What has @pydantic posted about MCP lately?"))

Swap the model string for any provider Pydantic AI supports. The MCP part stays the same.

Three things happen that you don't see:

  • allowed_tools hides the rest. Weir serves over 40 tools, Reddit included. The model gets only the two you name.
  • async with agent holds one connection. It opens the MCP session before the run and closes it after.
  • Weir's own advice comes along. The capability adds the server's instructions to the agent's, so the model reads Weir's rules on small limits and 402 errors.

What does the agent get back?

The model calls search_x with a handle and a keyword. We made that call through Weir's MCP server on 22 October 2026:

→ search_x {"fromUsers": ["pydantic"], "query": "MCP -filter:nativeretweets", "limit": 3}
← 3 posts · 4 credits · nextCursor set
  2026-09-30  26 likes  "Your coding agent knows your code by heart and has never
                         seen a production request. The Logfire MCP server fixes that..."
  2026-09-17  20 likes  a post about AGNTCon + MCPCon Europe in Amsterdam
  2026-09-16   2 likes  a one-line reply

The tool result reaches the model as JSON, with each post's url, text and counts. Our stub replayed this response, so the run above saw the same three posts.

The reply also carries meta.nextCursor, so the model can ask for page two. Weir's docs say only a null cursor marks the end. If one page is enough, say so in your instructions.

Weir bills 1 credit per call plus 1 per X post, and failed calls are free:

4credits for the search above
11credits for a 10-post search
1credit for a search that finds nothing
5,000free Weir credits every month

Each post costs a credit, so the limit in your instructions is a spending cap too.

Paid packs start at $5 for 25,000 credits and never expire, as of October 2026. Your model tokens are billed by your provider. Every Weir rate is on our pricing page.

What replaced MCPServerStreamableHTTP?

MCPToolset did, in Pydantic AI 2.0.0, which PyPI dates to 23 June 2026. On 2.59.0, the old import raises ImportError.

Here's what changed, from Pydantic AI's migration table:

Version 1 Version 2
MCPServerStreamableHTTP MCPToolset
MCPServerSSE, MCPServerStdio MCPToolset
Agent(mcp_servers=[...]) Agent(toolsets=[...])
agent.run_mcp_servers() async with agent:
MCP(url=...) ran remotely MCP(url=..., native=True)

Watch the last row. In version 1, MCP(url=...) handed the URL to your model provider. In version 2, your own process connects unless you set native=True.

Which one should you use? Pick the MCP capability for one server and a fixed list of tools. Pick MCPToolset to filter with code, prefix the names or share one connection between agents:

import os
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset

weir = MCPToolset(
    "https://api.weirapp.io/mcp",
    headers={"Authorization": f"Bearer {os.environ['WEIR_API_KEY']}"},
    include_instructions=True,
)
x_only = weir.filtered(lambda ctx, tool: tool.name.startswith(("search_x", "get_x_")))
agent = Agent("anthropic:claude-sonnet-5-5", toolsets=[x_only.prefixed("weir")])

The filter keeps every X tool, then .prefixed("weir") renames search_x to weir_search_x. The prefix stops clashes when two servers share a tool name. Note that include_instructions is off by default here, unlike on the capability.

To check a connection without a model, call the free get_usage tool directly:

async def check() -> None:
    async with weir:
        print(await weir.direct_call_tool("get_usage", {}))

asyncio.run(check())

If it doesn't work

  • MCPError: Server returned an error response at connect. Pydantic AI hides the HTTP status. In our test it was Weir's 401 for a missing key. Weir's free /v1/whoami endpoint tells you if a key works.
  • The handshake times out. MCPToolset waits 5 seconds by default. Build one with init_timeout=30.
  • 401 with authorization_token. We saw it send the raw key, with no Bearer. Put the full header in headers instead.
  • cannot import name 'MCPServerStreamableHTTP'. You're on version 2. Switch to MCPToolset or the MCP capability.
  • headers and http_client together fail. They're mutually exclusive. Set headers on your own httpx2.AsyncClient instead.
  • A tool returns 402. Your Weir credits ran out, and retrying won't help.

When not to use Weir

  • Your agent has to post or DM on X. Weir is read-only.
  • You want private data. Weir reads public posts, not bookmarks, DMs or home timelines.
  • Price per post matters most. TwitterAPI.io lists $0.15 per 1,000 tweets as of October 2026, less than our $5 pack.
  • You need a guarantee. Weir isn't licensed by X or affiliated with it, so access can change.

FAQ

Does Pydantic AI support MCP?

Yes. Pydantic AI's docs list three ways in: the MCP capability, the lower-level MCPToolset, and MCPServerTool for a provider's own MCP support. For a remote server with a key, start with the capability.

How do I pass headers to an MCP server in Pydantic AI?

Pass headers={...} to MCP or MCPToolset. Both send them on every request. If you also need custom TLS or pooling, build an httpx2.AsyncClient with the headers and pass it as http_client.

Can the model provider call the MCP server instead of my code?

Yes, with MCP(url=..., native=True). Pydantic AI's docs say it falls back to running the server locally when the model doesn't support native MCP. We tested only the local mode.

Is there a Pydantic AI MCP client without an agent?

Yes. MCPToolset works on its own inside async with. Call list_tools() to see what the server offers and direct_call_tool() to run one. Our MCP Python client guide shows the same calls with the bare mcp SDK.

Sources