Anthropic Python SDK
The Anthropic Python SDK takes a base_url on the client constructor, so pointing it at an LLM Registry entry needs no wrapper and no proxy configuration. It can also send custom headers, which is how the Agent Access Key travels when an entry requires one.
Which setup do you need?
| What you get | Use it when | |
|---|---|---|
| LLM Registry entry | The model, governed | You only need model access |
| Agent Persona | The model and the persona's MCP tools, in the same request | You want the model to call tools as well |
Which credentials you send depends on the entry's credential mode. If you haven't read which credentials your entry needs, start there.
Connect to an LLM Registry entry
Pick the credential mode on the entry's Provider Credential panel. All three are verified working against an Anthropic entry.
- API Key
- Passthrough (Agent Access Key Required)
- Passthrough (No Agent Access Key)
The gateway stores the Anthropic credential, so no Anthropic key leaves your machine. api_key carries your Agent Access Key instead.
import anthropic
client = anthropic.Anthropic(
base_url="https://<gateway-host>/llm/<url-prefix>",
api_key="<your-agent-access-key>"
)
response = client.messages.create(
model="<model-id>",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
print(response)
The SDK sends api_key as x-api-key, which the gateway accepts as your credential on this mode. It then attaches the stored Anthropic credential on the outbound side.
Two credentials travel on every call, in two separate places: your own Anthropic key in api_key, and the Agent Access Key in a custom header.
import anthropic
client = anthropic.Anthropic(
base_url="https://<gateway-host>/llm/<url-prefix>",
api_key="<your-anthropic-api-key>",
default_headers={"X-Agent-Key": "<your-agent-access-key>"}
)
response = client.messages.create(
model="<model-id>",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
print(response)
What each argument does:
api_keycarries your own Anthropic key, which the gateway forwards to Anthropic unchanged.default_headerscarries the Agent Access Key onX-Agent-Key, which identifies you to the gateway. It applies to every request the client makes.max_tokensis required by Anthropic's Messages API. The SDK supplies no default.
To set the header per call rather than per client, client.messages.create(..., extra_headers={"X-Agent-Key": "<your-agent-access-key>"}) works the same way.
Without a custom header
If setting a header is awkward in your setup, both credentials can travel in api_key instead, combined provider key first and separated by two colons:
client = anthropic.Anthropic(
base_url="https://<gateway-host>/llm/<url-prefix>",
api_key="<your-anthropic-api-key>::<your-agent-access-key>"
)
The gateway splits the value apart before authenticating, exactly as it does for clients with only one credential field.
With Require an agent access key off, only your Anthropic key travels and no headers are needed.
import anthropic
client = anthropic.Anthropic(
base_url="https://<gateway-host>/llm/<url-prefix>",
api_key="<your-anthropic-api-key>"
)
response = client.messages.create(
model="<model-id>",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
print(response)
Connect through an Agent Persona
The SDK reaches a persona differently from a terminal client. Rather than registering an MCP server locally, it names the persona's tools socket in the request itself, using Anthropic's MCP connector. Anthropic then connects to that socket on your behalf and the model can call the persona's tools within the same request.
Two things change from the setups above:
base_urlbecomes the persona-scoped route,https://<gateway-host>/p/<persona-id>/llm/<registry-entry-id>.- The request moves to
client.beta.messages.createand addsmcp_servers, pointing athttps://<gateway-host>/p/<persona-id>.
One Agent Access Key covers both. It authenticates the model route and, as authorization_token, the tools socket.
Because Anthropic's servers open the connection to the tools socket, the persona endpoint has to be reachable from the public internet. This differs from Claude Code or Gemini CLI, where your own machine connects to it.
Two separate settings are in play here, and only one of them changes the code below.
- The entry's credential mode — API Key or Passthrough — decides which credentials you send. This is what the tabs below switch between, exactly as on the route above.
- The persona's own Inbound Authentication method — Interactive or Passthrough — decides how the persona identifies you. Either way an Agent Access Key is issued, and neither changes the configuration below.
Because a persona always identifies you by an Agent Access Key, the entry's third mode — Passthrough (No Agent Access Key) — has no tab here. It applies to the LLM Registry entry route only.
- API Key
- Passthrough (Agent Access Key Required)
import anthropic
client = anthropic.Anthropic(
base_url="https://<gateway-host>/p/<persona-id>/llm/<registry-entry-id>",
api_key="<your-agent-access-key>"
)
response = client.beta.messages.create(
model="<model-id>",
max_tokens=1024,
messages=[{"role": "user", "content": "What is my GitLab profile?"}],
mcp_servers=[
{
"type": "url",
"url": "https://<gateway-host>/p/<persona-id>",
"name": "<persona-name>",
"authorization_token": "<your-agent-access-key>",
}
],
extra_headers={"anthropic-beta": "mcp-client-2025-04-04"},
)
print(response.content)
The Agent Access Key appears twice on purpose: in default_headers for the model route, and as authorization_token for the tools socket.
import anthropic
client = anthropic.Anthropic(
base_url="https://<gateway-host>/p/<persona-id>/llm/<registry-entry-id>",
api_key="<your-anthropic-api-key>",
default_headers={"X-Agent-Key": "<your-agent-access-key>"}
)
response = client.beta.messages.create(
model="<model-id>",
max_tokens=1024,
messages=[{"role": "user", "content": "What is my GitLab profile?"}],
mcp_servers=[
{
"type": "url",
"url": "https://<gateway-host>/p/<persona-id>",
"name": "<persona-name>",
"authorization_token": "<your-agent-access-key>",
}
],
extra_headers={"anthropic-beta": "mcp-client-2025-04-04"},
)
print(response.content)
What the extra arguments do:
mcp_serversnames the persona's tools socket.nameis any short label;authorization_tokenis the Agent Access Key, which Anthropic presents when it connects.extra_headersenables Anthropic's MCP connector. Without it,mcp_serversis rejected.client.beta.messages.createis required because the connector is a beta feature.client.messages.createdoes not acceptmcp_servers.
Troubleshooting
anthropic.AuthenticationError: missing API key
The gateway received no Agent Access Key on an entry that requires one. It looks for the key in the X-Agent-Key header and nowhere else on a passthrough entry, so this means default_headers is absent, misspelled, or carrying an empty value.
It does not mean your Anthropic key is wrong. That key is never examined when the Agent Access Key is missing, so the error names the credential that actually failed rather than the one that didn't.
The model answers but never calls a tool
Check the mcp_servers URL. It is the persona root, /p/<persona-id>, with no /llm/... suffix. The model route and the tools socket are different endpoints on the same persona.
Where to find each value
| Placeholder | Where to find it |
|---|---|
<gateway-host> | Host from the entry's Overview tab, for example gw.aigateway.example.com |
<url-prefix> | The URL prefix field on the entry's Overview tab |
<persona-id> | The persona's ID on the Agent Persona page |
<persona-name> | Any short label you want to give the tools socket in your code |
<registry-entry-id> | The LLM Registry entry's ID in the entry's URL |
<model-id> | A model identifier from the entry's Allowed Models list, for example claude-opus-5 |
<your-agent-access-key> | Generate from the entry's Agent Access Keys step, or the persona's Connect flow. Plaintext is shown once. |
<your-anthropic-api-key> | Your own Anthropic API key, needed only in the passthrough modes |
Tips
- Keep credentials out of your source. The snippets inline the values so the shape is clear, but read them from environment variables or a secret store in anything you commit.
base_urltakes no suffix. Paste the endpoint exactly as the Connect flow shows it. The SDK appends/v1/messagesitself.max_tokensis not optional. Anthropic rejects a Messages API call without it, whether or not the gateway is in the path.- Working in a different SDK? There are sibling guides for the OpenAI Python SDK and Google ADK.
- Want a full worked example? Code Review Agent with the Anthropic Python SDK builds on the persona setup above with a real GitLab MCP tool and a code-review skill attached.
Cequence AI Gateway