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.
Install
Section titled “Install”pip install scalekit-sdk-python anthropicnpm install @scalekit-sdk/node @anthropic-ai/sdkInitialize
Section titled “Initialize”import osimport scalekit.clientimport anthropicfrom 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_ENV_URL"),)actions = scalekit_client.actionsclient = anthropic.Anthropic()import { ScalekitClient } from '@scalekit-sdk/node';import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb';import Anthropic from '@anthropic-ai/sdk';
const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!,);const anthropic = new Anthropic();Connect the user to Gmail
Section titled “Connect the user to Gmail”response = actions.get_or_create_connected_account( connection_name="gmail", identifier="user_123",)if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") print("Authorize Gmail:", link.link) input("Press Enter after authorizing...")const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ connectionName: 'gmail', identifier: 'user_123',});if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { const { link } = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123' }); console.log('Authorize Gmail:', link);}See Authorize a user for production auth handling.
Run the agent
Section titled “Run the agent”Fetch tools scoped to this user, then run the full Claude tool-use loop:
# Fetch tools scoped to this userscoped_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 loopmessages = [{"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", 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})// Fetch tools scoped to this userconst { tools } = await scalekit.tools.listScopedTools('user_123', { filter: { connectionNames: ['gmail'] }, pageSize: 100, // fetch beyond the default page so no connector tools are missed});const llmTools = tools.map(t => ({ name: t.tool.definition.name, description: t.tool.definition.description, input_schema: t.tool.definition.input_schema,}));
// Run the agent loopconst messages: Anthropic.MessageParam[] = [ { role: 'user', content: 'Fetch my last 5 unread emails and summarize them' },];
while (true) { const response = await anthropic.messages.create({ model: 'claude-sonnet-4-6', max_tokens: 1024, tools: llmTools, messages, });
if (response.stop_reason === 'end_turn') { const text = response.content.find(b => b.type === 'text'); if (text?.type === 'text') console.log(text.text); break; }
const toolResults: Anthropic.ToolResultBlockParam[] = []; for (const block of response.content) { if (block.type === 'tool_use') { const result = await scalekit.actions.executeTool({ toolName: block.name, identifier: 'user_123', toolInput: block.input as Record<string, unknown>, }); toolResults.push({ type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(result.data) }); } } messages.push({ role: 'assistant', content: response.content }); messages.push({ role: 'user', content: toolResults });}Use MCP instead
Section titled “Use MCP instead”Claude Desktop and other Anthropic-compatible MCP hosts connect directly to Scalekit MCP URLs. Add the URL to your MCP host config:
{ "mcpServers": { "scalekit": { "transport": "streamable-http", "url": "your-scalekit-mcp-url" } }}For programmatic use, connect via any MCP client library and pass tools to anthropic.messages.create. See Virtual MCP Servers for setup details and the URL.