Locus product guide · Updated
Pydantic AI MCP tools: MCPToolset with a spend cap
Pydantic AI uses MCP servers as toolsets. Create an MCPToolset with the Locus Pro URL https://api.paywithlocus.com/api/credits/mcp and auth set to an agent key, then pass it to Agent(toolsets=[...]). A process_tool_call hook can force a max_credits ceiling onto every paid call. A Hunter email lookup through Locus Pro costs 1 to 10.1 credits, at most about $0.01.
Setup, step by step
Step 1
Create an agent key
In the Locus Pro dashboard, open Connect, then API keys, then An agent. Choose the tools, a credit cap per call and an expiry. Store the lcac_ key in your secret manager.
export LOCUS_AGENT_CONNECTION="lcac_..." # agent key, from your secret store export LOCUS_MCP_URL="https://api.paywithlocus.com/api/credits/mcp"
Step 2
Install Pydantic AI with MCP support
Install pydantic-ai, or pydantic-ai-slim with the mcp group. The mcp group installs FastMCP 4, which is built on httpx2, so build any custom auth or HTTP client objects with httpx2.
pip install "pydantic-ai-slim[mcp]"
Step 3
Connect with a price ceiling on every paid call
auth takes a bearer token string. process_tool_call runs before each call, so it can rewrite execute arguments. Here it caps max_credits at 15 whatever the model asked for. tool_error_behavior="failed" records a refused call as a failed result instead of asking the model to retry.
import os from typing import Any from pydantic_ai import Agent, RunContext from pydantic_ai.mcp import CallToolFunc, MCPToolset, ToolResult CAP = 15 # credits async def cap_paid_calls( ctx: RunContext[None], call_tool: CallToolFunc, name: str, tool_args: dict[str, Any] ) -> ToolResult: if name == "execute": asked = float(tool_args.get("max_credits") or CAP) tool_args = {**tool_args, "max_credits": min(asked, CAP)} return await call_tool(name, tool_args) locus = MCPToolset( os.environ["LOCUS_MCP_URL"], auth=os.environ["LOCUS_AGENT_CONNECTION"], process_tool_call=cap_paid_calls, tool_error_behavior="failed", ) agent = Agent("openai:gpt-6.1-sol", toolsets=[locus])Step 4
Run a first paid call
Use any model string your Pydantic AI setup supports in place of the one shown. The execute result reports credits_charged and credits_balance.
result = await agent.run( "Find the work email for Tim Cook at apple.com with hunter/email-finder and report the credits charged." ) print(result.output)Step 5
Check the balance for free
get_balance and catalog searches cost nothing, so a balance check is a safe way to prove the connection before any paid call.
result = await agent.run("What is my Locus balance?")
MCPToolset or the MCP capability: which should I use?
Pydantic AI recommends the MCP capability for most cases. It takes a URL, runs the connection in your process by default and can switch to the model provider’s native MCP support with native=True. With native MCP, the provider calls Locus, so your key goes to the provider.
Use MCPToolset when you want the process_tool_call hook, a shared toolset across agents, or direct control of the client. This guide uses it because the hook is the cleanest way to force a ceiling on paid calls.
| Option | Where the connection runs | Who sees your key | Best for |
|---|---|---|---|
| MCPToolset | Your process | Locus only | Hooks, shared toolsets, custom clients |
| MCP('url') | Your process by default | Locus, unless native is on | Most agents, per-run credentials |
| MCP('url', native=True) | The model provider, where supported | The provider and Locus | Letting the provider run the tool calls |
How do I force a price ceiling on every paid call?
The max_credits argument on execute is written by the model, so a model can raise it. The process_tool_call hook above sits between the model and the server and rewrites the argument before the call leaves your process. A call priced above the ceiling fails with nothing charged.
Keep the agent key’s per-call cap as well. Locus enforces it on its side, so it still holds if the hook has a bug. A call over that cap fails with agent_connection_call_limit_exceeded.
Should a refused Locus call retry, fail or raise?
tool_error_behavior sets one behavior for every server-reported error on a toolset. retry is the default and sends the error back to the model as a retry. failed records a tool result with outcome failed and lets the model decide. error raises the MCP exception and ends the run.
For paid calls, retry invites the model to resend with a higher ceiling or the same arguments. failed suits paid tools better: the model sees the refusal once and decides what to tell the user. Structured error content reaches the model as JSON, so Locus hints such as retryAfter stay readable.
| Locus error | Meaning | What to do |
|---|---|---|
| charge_ceiling_exceeded | Price above max_credits; nothing charged | Let the model report it, which failed allows |
| tenant_rate_limited | Plan limit hit: 5 paid calls a minute on Free, 15 on Plus | Wait retryAfter seconds, then resend |
| Insufficient credits | Balance below the price | Stop and add credits from your code |
| credential_endpoint_denied | Endpoint not on the key’s list | Add the endpoint to the agent key |
How do I give each user of my app their own Locus credential?
Pass a function as auth. Pydantic AI calls it with the run context at the start of each run, so it can read a per-user key from the run’s dependencies. Each run then opens its own MCP session, so users never share one.
Do not share one MCPToolset with a fixed auth across concurrent runs for different users. On the Enterprise plan, create an agent key per customer and bill each customer from their own balance at base price plus your markup.
What does lead enrichment cost through Locus Pro?
Prices come from the Locus catalog; 1,000 credits equal $1. Prices checked November 10, 2026.
Enriching 500 leads with 1 email lookup and 1 company lookup each costs at most 500 x 10.1 + 500 x 10.1 = 10,100 credits, about $10.10. With the 15-credit cap from the hook, no single call can cost more than $0.015.
| Endpoint | Locus price | Returns |
|---|---|---|
| hunter/email-finder | 1 to 10.1 credits, by request | The likely email for a name and domain |
| hunter/company-enrichment | 10.1 credits ($0.0101) | Company data from a domain |
| hunter/combined-enrichment | 20.2 credits ($0.0202) | Person and company data together |
| apollo/people-search | 2 credits ($0.00202) | People by title and company |
When does Locus Pro make sense for a Pydantic AI agent?
It makes sense when the agent calls several paid providers and you want one key, one balance and a hard ceiling per call. It also fits uneven workloads, since purchased credits do not expire and there is no plan minimum.
It is the wrong choice when one provider covers the job at steady volume, since that provider can cost less per call with your own account and API key. For logic in your own code, a plain Pydantic AI function tool is simpler.
Frequently asked questions
Can I load the Locus server from an mcp_config.json file?
Yes. load_mcp_toolsets reads url and headers for HTTP servers and expands ${VAR} references, so the Authorization header can read the key from the environment. You lose the per-toolset hook unless you build that toolset in code.
Do Locus tools get a name prefix in Pydantic AI?
Not by default. Wrap the toolset with prefixed, for example prefixed with locus, to get names like locus_execute when another server also has an execute tool.
Does Pydantic AI need FastMCP for MCP?
Yes. MCPToolset wraps the FastMCP client and supports FastMCP 3 and 4. The mcp install group pulls in FastMCP 4.
Implementation references
Use these first-party references for current request contracts and account requirements. Tool availability, prices, and negotiated terms can change.
Sources
Third-party details were checked on November 10, 2026. Vendors change pricing and features often, so confirm on their site before you decide.