Skip to content
Scalekit Docs

Anthropic

Build an Anthropic agent with Scalekit-authenticated tools. Scalekit returns tool schemas in Anthropic's native format; no conversion needed.

Build an agent using Anthropic’s Claude that reads a user’s Gmail inbox. Scalekit returns tool schemas with input_schema, the exact format Anthropic’s tool use API expects.

Terminal window
pip install scalekit-sdk-python anthropic

For Node.js, save the code in a .mts file, such as agent.mts, and run it with npx tsx agent.mts. The .mts extension makes the file an ES module, so it can use top-level await.

import os
import scalekit.client
import anthropic
from google.protobuf.json_format import MessageToDict
scalekit_client = scalekit.client.ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
actions = scalekit_client.actions
client = anthropic.Anthropic()
# Connect the user's Gmail account, and wait until it's ACTIVE before calling tools
connection_name = "gmail"
identifier = "user_123" # your app's unique user ID
response = actions.get_or_create_connected_account(
connection_name=connection_name, identifier=identifier
)
if response.connected_account.status != "ACTIVE":
link = actions.get_authorization_link(
connection_name=connection_name, identifier=identifier
)
print("Authorize Gmail:", link.link)
input("Press Enter after authorizing...")
# Fetch the account again to pick up the new status
response = actions.get_or_create_connected_account(
connection_name=connection_name, identifier=identifier
)
if response.connected_account.status != "ACTIVE":
raise RuntimeError(
f"Gmail is {response.connected_account.status}, not ACTIVE. Authorize it and run again."
)

See Authorize a user for production auth handling.

Fetch tools scoped to this user, then run the full Claude tool-use loop:

# Fetch tools scoped to this user
scoped_response, _ = actions.tools.list_scoped_tools(
identifier="user_123",
filter={"connection_names": ["gmail"]},
page_size=100, # fetch beyond the default page so no connector tools are missed
)
llm_tools = [
{
"name": MessageToDict(t.tool).get("definition", {}).get("name"),
"description": MessageToDict(t.tool).get("definition", {}).get("description", ""),
"input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}),
}
for t in scoped_response.tools
]
# Run the agent loop
messages = [{"role": "user", "content": "Fetch my last 5 unread emails and summarize them"}]
while True:
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=llm_tools,
messages=messages,
)
if response.stop_reason == "end_turn":
print(response.content[0].text)
break
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = actions.execute_tool(
tool_name=block.name,
identifier="user_123",
connection_name="gmail",
tool_input=block.input,
)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(result.data),
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})

The Messages API can connect to a Scalekit Virtual MCP Server through Anthropic’s MCP connector (beta). Anthropic’s API calls the MCP server for you, so there’s no tool loop to write. Pass the server URL and a session token for this user.

from datetime import timedelta
# Returned by create_config when you created the Virtual MCP Server (see Set up and connect)
config_id = os.environ["SCALEKIT_MCP_CONFIG_ID"]
mcp_url = os.environ["SCALEKIT_MCP_SERVER_URL"]
# Mint a fresh session token for this user before each agent run
mcp_token = actions.mcp.create_session_token(
mcp_config_id=config_id,
identifier="user_123",
expiry=timedelta(hours=1),
).token
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Fetch my last 5 unread emails and summarize them"}],
mcp_servers=[
{"type": "url", "url": mcp_url, "name": "scalekit", "authorization_token": mcp_token}
],
tools=[{"type": "mcp_toolset", "mcp_server_name": "scalekit"}],
betas=["mcp-client-2025-11-20"],
)
print("".join(block.text for block in response.content if block.type == "text"))

Other MCP hosts, such as Claude Code, can connect to the same URL. Send the session token as an Authorization: Bearer header, and mint a new token when it expires (at most 24 hours). See Set up and connect to create the server and check that the user’s connections are active before you mint a token.