AgentKit Frameworks: Framework-specific AgentKit examples — LangChain, Vercel AI, Anthropic, OpenAI, Google ADK, Mastra, Claude Managed Agents --- # DOCUMENT BOUNDARY --- # Overview > Learn how AgentKit works: tool calling with pre-built connectors and authentication for AI agents acting on behalf of users. AgentKit gives your AI agents authenticated access to third-party apps: sending emails, reading calendars, creating tickets, querying databases, and more. Your agent calls a tool; Scalekit handles the OAuth flow, token storage, and API call. ## Authentication [Section titled “Authentication”](#authentication) **Connections** are configurations you create once in the Scalekit Dashboard. A connection holds the credentials Scalekit needs to authenticate with a connector (OAuth app credentials, API keys, or service account details). One connection serves all your users. **Connected accounts** are per-user instances of a connection. When a user authorizes, Scalekit creates a connected account that stores their tokens and tracks their auth state. Your agent uses a connected account to act on that specific user’s behalf. Scalekit supports OAuth 2.0, API keys, RSA key pairs, and service accounts across all connectors. ## Tool calling [Section titled “Tool calling”](#tool-calling) **Connectors** are the pre-built integrations your agent can use: Gmail, Slack, Salesforce, Snowflake, GitHub, and many others. Each connector exposes a library of tools ready for your agent to call. **Tools** are connector-specific actions: `gmail_fetch_emails`, `salesforce_create_record`, `slack_send_message`. Scalekit provides the tool schemas and handles the authenticated API call. Your agent passes inputs; Scalekit injects the user’s credentials and returns structured output. ## How they fit together [Section titled “How they fit together”](#how-they-fit-together) You configure connections once. Your users authenticate to create connected accounts. Your agent calls tools; Scalekit handles the rest. ## Works with your framework [Section titled “Works with your framework”](#works-with-your-framework) AgentKit is framework-agnostic. Tool schemas work with any LLM API. Native adapters are available for [LangChain](/agentkit/examples/langchain/), [Google ADK](/agentkit/examples/google-adk/), and [MCP-compatible environments](/agentkit/mcp/configure-mcp-server/). ## Get started [Section titled “Get started”](#get-started) [Quickstart ](/agentkit/quickstart)Build a working agent with authenticated tool calls in minutes. [Configure a connection ](/agentkit/connections)Set up your first connection in the Scalekit Dashboard. [Connectors ](/agentkit/connectors/)Browse the pre-built connectors and their tool libraries. [Examples ](/agentkit/examples/)Full working examples for LangChain, Google ADK, Anthropic, OpenAI, and more. --- # DOCUMENT BOUNDARY --- # AgentKit: Connect my agent to apps > Build a working agent that makes authenticated tool calls on behalf of users, using Gmail as the example connector. ![Architecture diagram: an AI agent connects through Scalekit MCP Gateway with delegated auth, scoped permissions, and tool calls to SaaS apps such as Gmail, Slack, and Salesforce.](/_astro/agentkit.CAuIPwfK.svg) By the end of this guide, you’ll have a working agent that fetches a user’s last 5 unread Gmail messages (authenticated with their real account). Scalekit manages the OAuth flow, token storage, and API proxy so you focus on agent logic. ## Before you start [Section titled “Before you start”](#before-you-start) Complete these steps in the Scalekit dashboard before writing any code: 1. **Create a Scalekit account** at [app.scalekit.com](https://app.scalekit.com). 2. **Configure a Gmail connector** at Dashboard → **AgentKit** > **Connections** > **Create Connection** → select **Gmail**. Create the connection in the dashboard before running any code. Then copy the exact **Connection name** from that connection and use that value in your code. It must match the dashboard exactly, and it is not always the provider slug `gmail`. Gmail is enabled by default in new Scalekit environments. To connect to other services, create a connection for each app under **AgentKit** > **Connections** > **Create Connection**. 3. **Copy your API credentials** at Dashboard → **Developers → Settings → API Credentials**. Save these three values as environment variables: * `SCALEKIT_CLIENT_ID` * `SCALEKIT_CLIENT_SECRET` * `SCALEKIT_ENV_URL` * `GMAIL_CONNECTION_NAME` (copy the exact Connection name from **AgentKit** > **Connections**) ## Build your agent [Section titled “Build your agent”](#build-your-agent) * Using a coding agent Install the Scalekit Auth Stack for your coding agent, complete the browser authorization when prompted, then paste the implementation prompt. The agent scaffolds connected account setup, the OAuth flow, and tool execution. * Claude Code Terminal ```bash claude plugin marketplace add scalekit-inc/claude-code-authstack && claude plugin install agent-auth@scalekit-auth-stack ``` Installing the plugin sets up Scalekit’s MCP server and triggers an OAuth authorization flow in your browser. Complete the authorization before continuing. This gives Claude Code direct access to your Scalekit environment to search docs, manage connections, and check connected account status. Then paste the prompt below. * Codex Terminal ```bash curl -fsSL https://raw.githubusercontent.com/scalekit-inc/codex-authstack/main/install.sh | bash ``` Restart Codex → Plugin Directory → **Scalekit Auth Stack** → install **agent-auth**. If a browser authorization prompt appears, complete the OAuth flow before continuing. Then paste the prompt below. * GitHub Copilot CLI Terminal ```bash copilot plugin marketplace add scalekit-inc/github-copilot-authstack copilot plugin install agent-auth@scalekit-auth-stack ``` If a browser authorization prompt appears, complete the OAuth flow before continuing. Then run: Terminal ```bash copilot "Configure Scalekit agent authentication for Gmail. Provide code to create a connected account, generate an authorization link, and fetch the last 5 unread emails using Scalekit's tool API." ``` * Cursor Terminal ```bash curl -fsSL https://raw.githubusercontent.com/scalekit-inc/cursor-authstack/main/install.sh | bash ``` Reload Cursor → **Settings → Plugins** → enable **Agent Auth**. If a browser authorization prompt appears, complete the OAuth flow before continuing. Open chat (Cmd+L / Ctrl+L) and paste the prompt below. * 40+ agents Terminal ```bash npx skills add scalekit-inc/skills --skill integrating-agent-auth ``` Then ask your agent: “Configure Scalekit agent authentication for Gmail, create a connected account, generate an authorization link, and fetch the last 5 unread emails using Scalekit’s tool API.” Implementation prompt ```md Configure Scalekit agent authentication for Gmail. Provide code to create a connected account, generate an authorization link, and, once the user authorizes, fetch the last 5 unread emails using Scalekit's tool API. ``` Review generated code before deploying Verify that token validation logic, error handling, and environment variable references match your application’s requirements. * Step by step Terminal ```bash claude plugin marketplace add scalekit-inc/claude-code-authstack && claude plugin install agent-auth@scalekit-auth-stack ``` Installing the plugin sets up Scalekit’s MCP server and triggers an OAuth authorization flow in your browser. Complete the authorization before continuing. This gives Claude Code direct access to your Scalekit environment to search docs, manage connections, and check connected account status. Then paste the prompt below. * Claude Code Terminal ```bash curl -fsSL https://raw.githubusercontent.com/scalekit-inc/codex-authstack/main/install.sh | bash ``` Restart Codex → Plugin Directory → **Scalekit Auth Stack** → install **agent-auth**. If a browser authorization prompt appears, complete the OAuth flow before continuing. Then paste the prompt below. * Codex Terminal ```bash copilot plugin marketplace add scalekit-inc/github-copilot-authstack copilot plugin install agent-auth@scalekit-auth-stack ``` If a browser authorization prompt appears, complete the OAuth flow before continuing. Then run: Terminal ```bash copilot "Configure Scalekit agent authentication for Gmail. Provide code to create a connected account, generate an authorization link, and fetch the last 5 unread emails using Scalekit's tool API." ``` * GitHub Copilot CLI Terminal ```bash curl -fsSL https://raw.githubusercontent.com/scalekit-inc/cursor-authstack/main/install.sh | bash ``` Reload Cursor → **Settings → Plugins** → enable **Agent Auth**. If a browser authorization prompt appears, complete the OAuth flow before continuing. Open chat (Cmd+L / Ctrl+L) and paste the prompt below. * Cursor Terminal ```bash npx skills add scalekit-inc/skills --skill integrating-agent-auth ``` Then ask your agent: “Configure Scalekit agent authentication for Gmail, create a connected account, generate an authorization link, and fetch the last 5 unread emails using Scalekit’s tool API.” * 40+ agents ### 1. Set up your environment [Section titled “1. Set up your environment”](#1-set-up-your-environment) Install the Scalekit SDK and initialize the client with your API credentials: * Python ```sh pip install scalekit-sdk-python python-dotenv requests ``` * Node.js ```sh npm install @scalekit-sdk/node ``` - Python ```python import scalekit.client import os import requests from dotenv import load_dotenv load_dotenv() 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.actions connection_name = os.getenv("GMAIL_CONNECTION_NAME") # must match the Connection name in the dashboard exactly ``` - Node.js ```typescript import { ScalekitClient } from '@scalekit-sdk/node'; import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET ); const actions = scalekit.actions; const connectionName = process.env.GMAIL_CONNECTION_NAME!; // must match the Connection name in the dashboard exactly ``` ### 2. Create a connected account [Section titled “2. Create a connected account”](#2-create-a-connected-account) Scalekit tracks each user’s third-party connection as a connected account. This is the record that holds their OAuth tokens. Creating it tells Scalekit to start managing the user’s Gmail access on your behalf. This step fails if the Gmail connection has not been created in **AgentKit** > **Connections** yet, or if `connection_name` / `connectionName` does not match the dashboard exactly. * Python ```python # Create or retrieve the user's connected Gmail account response = actions.get_or_create_connected_account( connection_name=connection_name, identifier="user_123" # Replace with your system's unique user ID ) connected_account = response.connected_account print(f'Connected account created: {connected_account.id}') ``` * Node.js ```typescript // Create or retrieve the user's connected Gmail account const response = await actions.getOrCreateConnectedAccount({ connectionName, identifier: 'user_123', // Replace with your system's unique user ID }); const connectedAccount = response.connectedAccount; console.log('Connected account created:', connectedAccount?.id); ``` ### 3. Authenticate the user [Section titled “3. Authenticate the user”](#3-authenticate-the-user) Your agent can’t act on behalf of a user until they authorize access. Generate an authorization link, send it to the user, and Scalekit handles the rest: token exchange, storage, and automatic refresh. Once they complete the flow, the connected account status becomes `ACTIVE`. * Python ```python # Generate authorization link if user hasn't authorized or token is expired if(connected_account.status != "ACTIVE"): print(f"Gmail is not connected: {connected_account.status}") link_response = actions.get_authorization_link( connection_name=connection_name, identifier="user_123" ) print(f"🔗 click on the link to authorize Gmail", link_response.link) input(f"⎆ Press Enter after authorizing Gmail...") # In production, redirect user to this URL to complete OAuth flow ``` * Node.js ```typescript // Generate authorization link if user hasn't authorized or token is expired if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { console.log('gmail is not connected:', connectedAccount?.status); const linkResponse = await actions.getAuthorizationLink({ connectionName, identifier: 'user_123', }); console.log('🔗 click on the link to authorize gmail', linkResponse.link); // In production, redirect user to this URL to complete OAuth flow } ``` Open the link in a browser and authorize the Gmail connection. Once complete, the connected account status updates to `ACTIVE` and your agent can act on the user’s behalf. ### 4. Fetch emails via tool call [Section titled “4. Fetch emails via tool call”](#4-fetch-emails-via-tool-call) Pass the tool name and your inputs to Scalekit. It handles the request to Gmail and returns a structured response your agent can reason over directly: no endpoint URLs, auth headers, or response parsing required. * Python ```python response = actions.execute_tool( tool_name="gmail_fetch_mails", identifier="user_123", tool_input={ "query": "is:unread", "max_results": 5, }, ) print(response) ``` * Node.js ```typescript const toolResponse = await actions.executeTool({ toolName: 'gmail_fetch_mails', connectedAccountId: connectedAccount?.id, toolInput: { query: 'is:unread', max_results: 5, }, }); console.log('Recent emails:', toolResponse.data); ``` * Python ```sh pip install scalekit-sdk-python python-dotenv requests ``` * Node.js ```sh npm install @scalekit-sdk/node ``` * Python ```python import scalekit.client import os import requests from dotenv import load_dotenv load_dotenv() 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.actions connection_name = os.getenv("GMAIL_CONNECTION_NAME") # must match the Connection name in the dashboard exactly ``` * Node.js ```typescript import { ScalekitClient } from '@scalekit-sdk/node'; import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET ); const actions = scalekit.actions; const connectionName = process.env.GMAIL_CONNECTION_NAME!; // must match the Connection name in the dashboard exactly ``` * Python ```python # Create or retrieve the user's connected Gmail account response = actions.get_or_create_connected_account( connection_name=connection_name, identifier="user_123" # Replace with your system's unique user ID ) connected_account = response.connected_account print(f'Connected account created: {connected_account.id}') ``` * Node.js ```typescript // Create or retrieve the user's connected Gmail account const response = await actions.getOrCreateConnectedAccount({ connectionName, identifier: 'user_123', // Replace with your system's unique user ID }); const connectedAccount = response.connectedAccount; console.log('Connected account created:', connectedAccount?.id); ``` * Python ```python # Generate authorization link if user hasn't authorized or token is expired if(connected_account.status != "ACTIVE"): print(f"Gmail is not connected: {connected_account.status}") link_response = actions.get_authorization_link( connection_name=connection_name, identifier="user_123" ) print(f"🔗 click on the link to authorize Gmail", link_response.link) input(f"⎆ Press Enter after authorizing Gmail...") # In production, redirect user to this URL to complete OAuth flow ``` * Node.js ```typescript // Generate authorization link if user hasn't authorized or token is expired if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { console.log('gmail is not connected:', connectedAccount?.status); const linkResponse = await actions.getAuthorizationLink({ connectionName, identifier: 'user_123', }); console.log('🔗 click on the link to authorize gmail', linkResponse.link); // In production, redirect user to this URL to complete OAuth flow } ``` * Python ```python response = actions.execute_tool( tool_name="gmail_fetch_mails", identifier="user_123", tool_input={ "query": "is:unread", "max_results": 5, }, ) print(response) ``` * Node.js ```typescript const toolResponse = await actions.executeTool({ toolName: 'gmail_fetch_mails', connectedAccountId: connectedAccount?.id, toolInput: { query: 'is:unread', max_results: 5, }, }); console.log('Recent emails:', toolResponse.data); ``` ## Verify it works [Section titled “Verify it works”](#verify-it-works) Run your agent and confirm: * The connected account status is `ACTIVE` after the user completes the Gmail OAuth flow. * The tool response contains structured email data (subject, sender, snippet, and timestamp) ready for your agent to process. If the connected account stays in a `non-ACTIVE` state, the user has not completed the OAuth flow. Regenerate the authorization link and try again. ## Next steps [Section titled “Next steps”](#next-steps) * [Secure user verification](/agentkit/user-verification/): Confirm the OAuth identity matches your logged-in user before activating a connected account. Required for production. * [Connected accounts](/agentkit/connected-accounts/): Manage user connections across multiple providers. * [Tool calling](/agentkit/tools/scalekit-optimized-tools/): Use Scalekit’s optimized tools to call APIs without managing endpoints yourself. --- # DOCUMENT BOUNDARY --- # AgentKit code samples > Full working examples showing how to integrate AgentKit with popular AI frameworks and agent platforms. Each example builds a working agent that reads a user’s Gmail inbox using Scalekit-authenticated tools. ## No agent loop to build [Section titled “No agent loop to build”](#no-agent-loop-to-build) These platforms manage the agent harness for you. Pass a Scalekit MCP URL, describe the task, and the platform handles tool discovery, execution, and session state. [Claude Managed Agents ](/agentkit/examples/claude-managed-agents/)Anthropic runs the agent loop. Pass a Scalekit MCP URL, describe a task, and Claude handles tool discovery, execution, and retries. [OpenClaw ](/agentkit/openclaw/)Conversational agent platform. No code required to connect 50+ services including Gmail, Slack, Notion, and LinkedIn. ## Build your own agent loop [Section titled “Build your own agent loop”](#build-your-own-agent-loop) These integrations give you full control. Fetch Scalekit tool schemas, wire them into your framework, and run the tool-use loop yourself. | Framework | Language | Integration | Notes | | ---------------------------------------------- | --------------- | -------------------- | -------------------------------------------------------------------------------- | | [LangChain](/agentkit/examples/langchain/) | Python | SDK, native adapter | Scalekit returns native LangChain tool objects. No schema reshaping needed. | | [Google ADK](/agentkit/examples/google-adk/) | Python | SDK, native adapter | Scalekit returns native ADK tool objects. No schema reshaping needed. | | [Anthropic](/agentkit/examples/anthropic/) | Python, Node.js | SDK, direct | Tool schemas use `input_schema`, which matches Anthropic’s format exactly. | | [OpenAI](/agentkit/examples/openai/) | Python, Node.js | SDK, direct | Rename `input_schema` to `parameters` to match OpenAI’s function format. | | [Vercel AI SDK](/agentkit/examples/vercel-ai/) | Node.js | SDK, `tool()` helper | Wrap tools with `tool()` and `jsonSchema()`. No manual schema conversion needed. | | [Mastra](/agentkit/examples/mastra/) | Node.js | MCP | Native MCP support via `@mastra/mcp`. Tool discovery is automatic. | ## Working examples on GitHub [Section titled “Working examples on GitHub”](#working-examples-on-github) ### [Connect LangChain agents to Gmail](https://github.com/scalekit-inc/sample-langchain-agent) [Securely connect a LangChain agent to Gmail using Scalekit for authentication. Python example for tool authorization.](https://github.com/scalekit-inc/sample-langchain-agent) ### [Connect Google GenAI agents to Gmail](https://github.com/scalekit-inc/google-adk-agent-example) [Build a Google ADK agent that securely accesses Gmail tools. Python example demonstrating Scalekit auth integration.](https://github.com/scalekit-inc/google-adk-agent-example) ### [Connect agents to Slack tools](https://github.com/scalekit-inc/python-connect-demos/tree/main/direct) [Authorize Python agents to use Slack tools with Scalekit. Direct integration example for secure tool access.](https://github.com/scalekit-inc/python-connect-demos/tree/main/direct) ### [Browse all agent auth examples](https://github.com/scalekit-developers/agent-auth-examples) [A curated collection of working examples showing how to build agents that authenticate and access tools using Scalekit.](https://github.com/scalekit-developers/agent-auth-examples) --- # DOCUMENT BOUNDARY --- # 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”](#install) * Python ```sh 1 pip install scalekit-sdk-python anthropic ``` * Node.js ```sh 1 npm install @scalekit-sdk/node @anthropic-ai/sdk ``` ## Initialize [Section titled “Initialize”](#initialize) * Python ```python 1 import os 2 import scalekit.client 3 import anthropic 4 from google.protobuf.json_format import MessageToDict 5 6 scalekit_client = scalekit.client.ScalekitClient( 7 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 8 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 9 env_url=os.getenv("SCALEKIT_ENV_URL"), 10 ) 11 actions = scalekit_client.actions 12 client = anthropic.Anthropic() ``` * Node.js ```typescript 1 import { ScalekitClient } from '@scalekit-sdk/node'; 2 import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; 3 import Anthropic from '@anthropic-ai/sdk'; 4 5 const scalekit = new ScalekitClient( 6 process.env.SCALEKIT_ENV_URL!, 7 process.env.SCALEKIT_CLIENT_ID!, 8 process.env.SCALEKIT_CLIENT_SECRET!, 9 ); 10 const anthropic = new Anthropic(); ``` ## Connect the user to Gmail [Section titled “Connect the user to Gmail”](#connect-the-user-to-gmail) * Python ```python 1 response = actions.get_or_create_connected_account( 2 connection_name="gmail", 3 identifier="user_123", 4 ) 5 if response.connected_account.status != "ACTIVE": 6 link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") 7 print("Authorize Gmail:", link.link) 8 input("Press Enter after authorizing...") ``` * Node.js ```typescript 1 const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ 2 connectionName: 'gmail', 3 identifier: 'user_123', 4 }); 5 if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { 6 const { link } = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123' }); 7 console.log('Authorize Gmail:', link); 8 } ``` See [Authorize a user](/agentkit/tools/authorize/) for production auth handling. ## Run the agent [Section titled “Run the agent”](#run-the-agent) Fetch tools scoped to this user, then run the full Claude tool-use loop: * Python ```python 1 # Fetch tools scoped to this user 2 scoped_response, _ = actions.tools.list_scoped_tools( 3 identifier="user_123", 4 filter={"connection_names": ["gmail"]}, 5 page_size=100, # fetch beyond the default page so no connector tools are missed 6 ) 7 llm_tools = [ 8 { 9 "name": MessageToDict(t.tool).get("definition", {}).get("name"), 10 "description": MessageToDict(t.tool).get("definition", {}).get("description", ""), 11 "input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}), 12 } 13 for t in scoped_response.tools 14 ] 15 16 # Run the agent loop 17 messages = [{"role": "user", "content": "Fetch my last 5 unread emails and summarize them"}] 18 19 while True: 20 response = client.messages.create( 21 model="claude-sonnet-4-6", 22 max_tokens=1024, 23 tools=llm_tools, 24 messages=messages, 25 ) 26 if response.stop_reason == "end_turn": 27 print(response.content[0].text) 28 break 29 30 tool_results = [] 31 for block in response.content: 32 if block.type == "tool_use": 33 result = actions.execute_tool( 34 tool_name=block.name, 35 identifier="user_123", 36 tool_input=block.input, 37 ) 38 tool_results.append({ 39 "type": "tool_result", 40 "tool_use_id": block.id, 41 "content": str(result.data), 42 }) 43 44 messages.append({"role": "assistant", "content": response.content}) 45 messages.append({"role": "user", "content": tool_results}) ``` * Node.js ```typescript 1 // Fetch tools scoped to this user 2 const { tools } = await scalekit.tools.listScopedTools('user_123', { 3 filter: { connectionNames: ['gmail'] }, 4 pageSize: 100, // fetch beyond the default page so no connector tools are missed 5 }); 6 const llmTools = tools.map(t => ({ 7 name: t.tool.definition.name, 8 description: t.tool.definition.description, 9 input_schema: t.tool.definition.input_schema, 10 })); 11 12 // Run the agent loop 13 const messages: Anthropic.MessageParam[] = [ 14 { role: 'user', content: 'Fetch my last 5 unread emails and summarize them' }, 15 ]; 16 17 while (true) { 18 const response = await anthropic.messages.create({ 19 model: 'claude-sonnet-4-6', 20 max_tokens: 1024, 21 tools: llmTools, 22 messages, 23 }); 24 25 if (response.stop_reason === 'end_turn') { 26 const text = response.content.find(b => b.type === 'text'); 27 if (text?.type === 'text') console.log(text.text); 28 break; 29 } 30 31 const toolResults: Anthropic.ToolResultBlockParam[] = []; 32 for (const block of response.content) { 33 if (block.type === 'tool_use') { 34 const result = await scalekit.actions.executeTool({ 35 toolName: block.name, 36 identifier: 'user_123', 37 toolInput: block.input as Record, 38 }); 39 toolResults.push({ type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(result.data) }); 40 } 41 } 42 messages.push({ role: 'assistant', content: response.content }); 43 messages.push({ role: 'user', content: toolResults }); 44 } ``` ## Use MCP instead [Section titled “Use MCP instead”](#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: ```json 1 { 2 "mcpServers": { 3 "scalekit": { 4 "transport": "streamable-http", 5 "url": "your-scalekit-mcp-url" 6 } 7 } 8 } ``` For programmatic use, connect via any MCP client library and pass tools to `anthropic.messages.create`. See [Connect an MCP client](/agentkit/mcp/connect-mcp-client/) for setup details and [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/) to get the URL. --- # DOCUMENT BOUNDARY --- # Claude Managed Agents > Connect a Claude Managed Agent to Scalekit-authenticated tools via MCP. Anthropic runs the agent loop; you describe the task, Claude handles the rest. Beta Claude Managed Agents is in public beta. All API requests require the `managed-agents-2026-04-01` beta header, which the Anthropic SDK sets automatically. API behavior may change between releases. Connect a Claude Managed Agent to Scalekit-authenticated Gmail tools via MCP. You generate a Scalekit MCP URL, pass it to the agent, and describe a task. Anthropic manages the agent loop: tool discovery, execution, retries, and session state. Compare this to the [Anthropic SDK example](/agentkit/examples/anthropic/): that approach uses the Messages API and requires you to fetch tool schemas, build a tool-use loop, and feed results back manually. Here, none of that exists in your code. ## Prerequisites [Section titled “Prerequisites”](#prerequisites) * A Scalekit account with a Gmail connection configured. See [Configure a connection](/agentkit/connections/). * A Scalekit MCP config and a per-user instance URL already created. See [Configure an MCP server](/agentkit/mcp/configure-mcp-server/) and [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/). * An [Anthropic API key](https://platform.anthropic.com/settings/keys). ## Install [Section titled “Install”](#install) ```sh 1 pip install anthropic scalekit-sdk-python ``` ## Get a Scalekit MCP URL [Section titled “Get a Scalekit MCP URL”](#get-a-scalekit-mcp-url) Generate a per-user MCP URL from your existing MCP config. This URL is pre-authenticated; it encodes the user’s identity and their authorized connections. ```python 1 import os 2 import scalekit.client 3 4 scalekit_client = scalekit.client.ScalekitClient( 5 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 6 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 7 env_url=os.getenv("SCALEKIT_ENV_URL"), 8 ) 9 actions = scalekit_client.actions 10 11 inst_response = actions.mcp.ensure_instance( 12 config_name="email-assistant", # your MCP config name 13 user_identifier="user_123", # your app's unique user ID 14 ) 15 mcp_url = inst_response.instance.url ``` Keep the MCP URL server-side The MCP URL is pre-authenticated. Never expose it in client-side code or browser requests. Pass it directly to the Managed Agent from your backend. Before passing the URL to the agent, confirm the user has authorized all connections the config requires. See [Check auth state](/agentkit/mcp/generate-user-urls/#check-auth-state). ## Create the agent [Section titled “Create the agent”](#create-the-agent) Define the agent once and reuse it across sessions. Pass the Scalekit MCP URL as an MCP server; no vault or additional auth configuration needed, because the URL is already authenticated. ```python 1 from anthropic import Anthropic 2 3 client = Anthropic() 4 5 agent = client.beta.agents.create( 6 name="Gmail Assistant", 7 model="claude-opus-4-7", 8 system="You are a helpful assistant with access to the user's Gmail account.", 9 mcp_servers=[ 10 { 11 "type": "url", 12 "name": "scalekit", 13 "url": mcp_url, 14 }, 15 ], 16 tools=[ 17 { 18 "type": "mcp_toolset", 19 "mcp_server_name": "scalekit", 20 "default_config": {"permission_policy": {"type": "always_allow"}}, 21 }, 22 ], 23 ) ``` Save `agent.id`. You reference it in every session; no need to recreate the agent per user. ## Create an environment [Section titled “Create an environment”](#create-an-environment) An environment is the cloud container the agent runs in. Create one and reuse it. ```python 1 environment = client.beta.environments.create( 2 name="gmail-agent-env", 3 config={ 4 "type": "cloud", 5 "networking": {"type": "unrestricted"}, 6 }, 7 ) ``` ## Run a session [Section titled “Run a session”](#run-a-session) Start a session, send a task, and stream results. No `vault_ids` needed; the Scalekit MCP URL handles authentication. ```python 1 session = client.beta.sessions.create( 2 agent=agent.id, 3 environment_id=environment.id, 4 title="Gmail session", 5 ) 6 7 with client.beta.sessions.events.stream(session.id) as stream: 8 client.beta.sessions.events.send( 9 session.id, 10 events=[ 11 { 12 "type": "user.message", 13 "content": [ 14 { 15 "type": "text", 16 "text": "Fetch my last 5 unread emails and summarize them.", 17 } 18 ], 19 }, 20 ], 21 ) 22 23 for event in stream: 24 match event.type: 25 case "agent.message": 26 for block in event.content: 27 print(block.text, end="") 28 case "agent.tool_use": 29 print(f"\n[{event.name}]") 30 case "session.status_idle": 31 print("\n") 32 break ``` The agent discovers available Gmail tools from the Scalekit MCP server, executes them using the user’s pre-authorized credentials, and streams results back. You don’t manage any of that loop. --- # DOCUMENT BOUNDARY --- # Google ADK > Build a Google ADK agent with Scalekit-authenticated Gmail tools. Scalekit returns native ADK tool objects; no schema reshaping needed. Build a Google ADK agent that reads a user’s Gmail inbox. Scalekit handles OAuth, token storage, and returns tools as native ADK tool objects compatible with any ADK agent. [Full code on GitHub ](https://github.com/scalekit-inc/google-adk-agent-example) ## Install [Section titled “Install”](#install) ```sh 1 pip install scalekit-sdk-python google-adk ``` ## Initialize [Section titled “Initialize”](#initialize) ```python 1 import os 2 import asyncio 3 import scalekit.client 4 5 scalekit_client = scalekit.client.ScalekitClient( 6 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 7 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 8 env_url=os.getenv("SCALEKIT_ENV_URL"), 9 ) 10 actions = scalekit_client.actions ``` ## Connect the user to Gmail [Section titled “Connect the user to Gmail”](#connect-the-user-to-gmail) ```python 1 response = actions.get_or_create_connected_account( 2 connection_name="gmail", 3 identifier="user_123", 4 ) 5 if response.connected_account.status != "ACTIVE": 6 link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") 7 print("Authorize Gmail:", link.link) 8 input("Press Enter after authorizing...") ``` See [Authorize a user](/agentkit/tools/authorize/) for production auth handling. ## Build and run the agent [Section titled “Build and run the agent”](#build-and-run-the-agent) `actions.google.get_tools()` returns native ADK tool objects. Pass them directly to a Google ADK `Agent`: ```python 1 from google.adk.agents import Agent 2 from google.adk.runners import Runner 3 from google.adk.sessions import InMemorySessionService 4 from google.genai import types 5 6 tools = actions.google.get_tools( 7 identifier="user_123", 8 connection_names=["gmail"], 9 page_size=100, # avoid missing tools when a connector has more than the default page 10 ) 11 12 agent = Agent( 13 name="gmail_assistant", 14 model="gemini-2.0-flash", 15 instruction="You are a helpful Gmail assistant.", 16 tools=tools, 17 ) 18 19 async def main(): 20 session_service = InMemorySessionService() 21 runner = Runner(agent=agent, app_name="gmail_app", session_service=session_service) 22 session = await session_service.create_session(app_name="gmail_app", user_id="user_123") 23 24 message = types.Content( 25 role="user", 26 parts=[types.Part(text="Fetch my last 5 unread emails and summarize them")], 27 ) 28 async for event in runner.run_async( 29 user_id="user_123", 30 session_id=session.id, 31 new_message=message, 32 ): 33 if event.is_final_response(): 34 print(event.response.text) 35 36 asyncio.run(main()) ``` ## Use MCP instead [Section titled “Use MCP instead”](#use-mcp-instead) Google ADK supports MCP via `MCPToolset`. Connect to a Scalekit-generated MCP URL to skip tool setup: ```python 1 from google.adk.agents import Agent 2 from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StreamableHTTPConnectionParams 3 4 agent = Agent( 5 name="gmail_assistant", 6 model="gemini-2.0-flash", 7 instruction="You are a helpful Gmail assistant.", 8 tools=[ 9 MCPToolset( 10 connection_params=StreamableHTTPConnectionParams(url=mcp_url) 11 ) 12 ], 13 ) ``` See [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/) to get `mcp_url`. --- # DOCUMENT BOUNDARY --- # LangChain > Build a LangChain agent with Scalekit-authenticated Gmail tools. Scalekit returns native LangChain tool objects; no schema reshaping needed. Build a LangChain agent that reads a user’s Gmail inbox. Scalekit handles OAuth, token storage, and returns tools in native LangChain format. Your agent code needs no Scalekit-specific logic beyond initialization. [Full code on GitHub ](https://github.com/scalekit-inc/sample-langchain-agent) ## Install [Section titled “Install”](#install) ```sh 1 pip install scalekit-sdk-python langchain-openai ``` ## Initialize [Section titled “Initialize”](#initialize) ```python 1 import os 2 import scalekit.client 3 4 scalekit_client = scalekit.client.ScalekitClient( 5 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 6 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 7 env_url=os.getenv("SCALEKIT_ENV_URL"), 8 ) 9 actions = scalekit_client.actions ``` ## Connect the user to Gmail [Section titled “Connect the user to Gmail”](#connect-the-user-to-gmail) ```python 1 response = actions.get_or_create_connected_account( 2 connection_name="gmail", 3 identifier="user_123", 4 ) 5 if response.connected_account.status != "ACTIVE": 6 link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") 7 print("Authorize Gmail:", link.link) 8 input("Press Enter after authorizing...") ``` See [Authorize a user](/agentkit/tools/authorize/) for production auth handling. ## Build and run the agent [Section titled “Build and run the agent”](#build-and-run-the-agent) `actions.langchain.get_tools()` returns native `StructuredTool` objects. Bind them to your LLM and run the tool-calling loop: ```python 1 from langchain_openai import ChatOpenAI 2 from langchain_core.messages import HumanMessage, ToolMessage 3 4 tools = actions.langchain.get_tools( 5 identifier="user_123", 6 connection_names=["gmail"], 7 page_size=100, # avoid missing tools when a connector has more than the default page 8 ) 9 tool_map = {t.name: t for t in tools} 10 11 llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) 12 messages = [HumanMessage("Fetch my last 5 unread emails and summarize them")] 13 14 while True: 15 response = llm.invoke(messages) 16 messages.append(response) 17 if not response.tool_calls: 18 print(response.content) 19 break 20 for tc in response.tool_calls: 21 result = tool_map[tc["name"]].invoke(tc["args"]) 22 messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"])) ``` ## Use MCP instead [Section titled “Use MCP instead”](#use-mcp-instead) LangChain supports MCP via `langchain-mcp-adapters`. Install it, then connect to a Scalekit-generated MCP URL: ```sh 1 pip install langchain-mcp-adapters ``` ```python 1 import asyncio 2 from langchain_mcp_adapters.client import MultiServerMCPClient 3 from langchain_openai import ChatOpenAI 4 from langchain_core.messages import HumanMessage, ToolMessage 5 6 async def run(mcp_url: str): 7 async with MultiServerMCPClient( 8 {"scalekit": {"transport": "streamable_http", "url": mcp_url}} 9 ) as client: 10 tools = client.get_tools() 11 tool_map = {t.name: t for t in tools} 12 llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) 13 messages = [HumanMessage("Fetch my last 5 unread emails and summarize them")] 14 15 while True: 16 response = await llm.ainvoke(messages) 17 messages.append(response) 18 if not response.tool_calls: 19 print(response.content) 20 break 21 for tc in response.tool_calls: 22 result = await tool_map[tc["name"]].ainvoke(tc["args"]) 23 messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"])) 24 25 asyncio.run(run(mcp_url)) ``` See [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/) to get `mcp_url`. --- # DOCUMENT BOUNDARY --- # Mastra > Connect a Mastra agent to Scalekit-authenticated tools using MCP. Mastra's native MCP client connects directly to a Scalekit-generated MCP URL. Connect a Mastra agent to Scalekit tools using MCP. Mastra has native MCP support via `@mastra/mcp`. Pass a Scalekit-generated URL and Mastra handles tool discovery automatically. ## Install [Section titled “Install”](#install) ```sh 1 npm install @scalekit-sdk/node @mastra/core @mastra/mcp @ai-sdk/openai ``` ## Get a per-user MCP URL [Section titled “Get a per-user MCP URL”](#get-a-per-user-mcp-url) Generate a Scalekit MCP URL for the user. This requires the Python SDK. Call this from your backend and pass the URL to your Mastra application: ```python 1 # Backend (Python): generate once per user session 2 inst_response = actions.mcp.ensure_instance( 3 config_name="your-mcp-config", 4 user_identifier="user_123", 5 ) 6 mcp_url = inst_response.instance.url 7 # Pass mcp_url to your Mastra app (e.g. via environment variable or API response) ``` See [Configure an MCP server](/agentkit/mcp/configure-mcp-server/) and [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/) to set up the config and generate the URL. ## Build the agent [Section titled “Build the agent”](#build-the-agent) Pass the MCP URL to `MCPClient`. Mastra fetches the tool list and schemas automatically: ```typescript 1 import { Agent } from '@mastra/core/agent'; 2 import { MCPClient } from '@mastra/mcp'; 3 import { openai } from '@ai-sdk/openai'; 4 5 const mcpUrl = process.env.SCALEKIT_MCP_URL!; // set from your backend 6 7 const mcp = new MCPClient({ 8 servers: { 9 scalekit: { url: new URL(mcpUrl) }, 10 }, 11 }); 12 13 const tools = await mcp.getTools(); 14 15 const agent = new Agent({ 16 name: 'gmail_assistant', 17 instructions: 'You are a helpful Gmail assistant.', 18 model: openai('gpt-4o'), 19 tools, 20 }); 21 22 const result = await agent.generate('Fetch my last 5 unread emails and summarize them'); 23 console.log(result.text); 24 25 await mcp.disconnect(); ``` --- # DOCUMENT BOUNDARY --- # OpenAI > Build an OpenAI agent with Scalekit-authenticated tools. Convert Scalekit's tool schemas to OpenAI's function calling format in one step. Build an agent using OpenAI’s GPT models that reads a user’s Gmail inbox. Scalekit’s tool schemas use `input_schema`: rename it to `parameters` and wrap it in OpenAI’s function format. ## Install [Section titled “Install”](#install) * Python ```sh 1 pip install scalekit-sdk-python openai ``` * Node.js ```sh 1 npm install @scalekit-sdk/node openai ``` ## Initialize [Section titled “Initialize”](#initialize) * Python ```python 1 import os, json 2 import scalekit.client 3 from openai import OpenAI 4 from google.protobuf.json_format import MessageToDict 5 6 scalekit_client = scalekit.client.ScalekitClient( 7 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 8 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 9 env_url=os.getenv("SCALEKIT_ENV_URL"), 10 ) 11 actions = scalekit_client.actions 12 client = OpenAI() ``` * Node.js ```typescript 1 import { ScalekitClient } from '@scalekit-sdk/node'; 2 import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; 3 import OpenAI from 'openai'; 4 5 const scalekit = new ScalekitClient( 6 process.env.SCALEKIT_ENV_URL!, 7 process.env.SCALEKIT_CLIENT_ID!, 8 process.env.SCALEKIT_CLIENT_SECRET!, 9 ); 10 const openai = new OpenAI(); ``` ## Connect the user to Gmail [Section titled “Connect the user to Gmail”](#connect-the-user-to-gmail) * Python ```python 1 response = actions.get_or_create_connected_account( 2 connection_name="gmail", 3 identifier="user_123", 4 ) 5 if response.connected_account.status != "ACTIVE": 6 link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") 7 print("Authorize Gmail:", link.link) 8 input("Press Enter after authorizing...") ``` * Node.js ```typescript 1 const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ 2 connectionName: 'gmail', 3 identifier: 'user_123', 4 }); 5 if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { 6 const { link } = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123' }); 7 console.log('Authorize Gmail:', link); 8 } ``` See [Authorize a user](/agentkit/tools/authorize/) for production auth handling. ## Run the agent [Section titled “Run the agent”](#run-the-agent) Fetch tools scoped to this user, convert to OpenAI’s function format, then run the tool-calling loop: * Python ```python 1 # Fetch and convert tools to OpenAI format 2 scoped_response, _ = actions.tools.list_scoped_tools( 3 identifier="user_123", 4 filter={"connection_names": ["gmail"]}, 5 page_size=100, # fetch beyond the default page so no connector tools are missed 6 ) 7 llm_tools = [ 8 { 9 "type": "function", 10 "function": { 11 "name": MessageToDict(t.tool).get("definition", {}).get("name"), 12 "description": MessageToDict(t.tool).get("definition", {}).get("description", ""), 13 "parameters": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}), 14 }, 15 } 16 for t in scoped_response.tools 17 ] 18 19 # Run the agent loop 20 messages = [{"role": "user", "content": "Fetch my last 5 unread emails and summarize them"}] 21 22 while True: 23 response = client.chat.completions.create( 24 model="gpt-4o", 25 tools=llm_tools, 26 messages=messages, 27 ) 28 message = response.choices[0].message 29 if not message.tool_calls: 30 print(message.content) 31 break 32 33 messages.append(message) 34 for tc in message.tool_calls: 35 result = actions.execute_tool( 36 tool_name=tc.function.name, 37 identifier="user_123", 38 tool_input=json.loads(tc.function.arguments), 39 ) 40 messages.append({ 41 "role": "tool", 42 "tool_call_id": tc.id, 43 "content": str(result.data), 44 }) ``` * Node.js ```typescript 1 // Fetch and convert tools to OpenAI format 2 const { tools } = await scalekit.tools.listScopedTools('user_123', { 3 filter: { connectionNames: ['gmail'] }, 4 pageSize: 100, // fetch beyond the default page so no connector tools are missed 5 }); 6 const llmTools: OpenAI.ChatCompletionTool[] = tools.map(t => ({ 7 type: 'function', 8 function: { 9 name: t.tool.definition.name, 10 description: t.tool.definition.description, 11 parameters: t.tool.definition.input_schema, 12 }, 13 })); 14 15 // Run the agent loop 16 const messages: OpenAI.ChatCompletionMessageParam[] = [ 17 { role: 'user', content: 'Fetch my last 5 unread emails and summarize them' }, 18 ]; 19 20 while (true) { 21 const response = await openai.chat.completions.create({ 22 model: 'gpt-4o', 23 tools: llmTools, 24 messages, 25 }); 26 const message = response.choices[0].message; 27 if (!message.tool_calls?.length) { 28 console.log(message.content); 29 break; 30 } 31 messages.push(message); 32 for (const tc of message.tool_calls) { 33 const result = await scalekit.actions.executeTool({ 34 toolName: tc.function.name, 35 identifier: 'user_123', 36 toolInput: JSON.parse(tc.function.arguments), 37 }); 38 messages.push({ role: 'tool', tool_call_id: tc.id, content: JSON.stringify(result.data) }); 39 } 40 } ``` ## Use the Responses API [Section titled “Use the Responses API”](#use-the-responses-api) OpenAI’s [Responses API](https://platform.openai.com/docs/api-reference/responses) is a stateful alternative to Chat Completions. Instead of managing conversation history yourself, you pass `previous_response_id` to continue a session. The tool schema format is the same. * Python ```python 1 response = client.responses.create( 2 model="gpt-4o", 3 input="Fetch my last 5 unread emails and summarize them", 4 tools=llm_tools, 5 ) 6 7 while any(item.type == "function_call" for item in response.output): 8 tool_results = [ 9 { 10 "type": "function_call_output", 11 "call_id": item.call_id, 12 "output": str(actions.execute_tool( 13 tool_name=item.name, 14 identifier="user_123", 15 tool_input=json.loads(item.arguments), 16 ).data), 17 } 18 for item in response.output 19 if item.type == "function_call" 20 ] 21 response = client.responses.create( 22 model="gpt-4o", 23 previous_response_id=response.id, 24 input=tool_results, 25 tools=llm_tools, 26 ) 27 28 for item in response.output: 29 if item.type == "message": 30 print(item.content[0].text) ``` * Node.js ```typescript 1 let response = await openai.responses.create({ 2 model: 'gpt-4o', 3 input: 'Fetch my last 5 unread emails and summarize them', 4 tools: llmTools, 5 }); 6 7 while (response.output.some(item => item.type === 'function_call')) { 8 const toolResults = await Promise.all( 9 response.output 10 .filter(item => item.type === 'function_call') 11 .map(async item => { 12 const result = await scalekit.actions.executeTool({ 13 toolName: item.name, 14 identifier: 'user_123', 15 toolInput: JSON.parse(item.arguments), 16 }); 17 return { 18 type: 'function_call_output' as const, 19 call_id: item.call_id, 20 output: JSON.stringify(result.data), 21 }; 22 }) 23 ); 24 response = await openai.responses.create({ 25 model: 'gpt-4o', 26 previous_response_id: response.id, 27 input: toolResults, 28 tools: llmTools, 29 }); 30 } 31 32 const message = response.output.find(item => item.type === 'message'); 33 if (message?.type === 'message') console.log(message.content[0].text); ``` ## Use MCP instead [Section titled “Use MCP instead”](#use-mcp-instead) If you prefer the MCP approach, connect your OpenAI agent via the [Vercel AI SDK + MCP](/agentkit/examples/vercel-ai#use-mcp-instead) or LangChain’s MCP client with a Scalekit-generated URL. See [Connect an MCP client](/agentkit/mcp/connect-mcp-client/) for the URL setup. --- # DOCUMENT BOUNDARY --- # Vercel AI SDK > Build a Vercel AI SDK agent with Scalekit-authenticated tools using the tool() helper and jsonSchema() adapter. Build an agent using the Vercel AI SDK that reads a user’s Gmail inbox. Use `tool()` and `jsonSchema()` from the `ai` package to wrap Scalekit tools. No manual schema conversion needed. ## Install [Section titled “Install”](#install) ```sh 1 npm install @scalekit-sdk/node ai @ai-sdk/openai ``` ## Initialize [Section titled “Initialize”](#initialize) ```typescript 1 import { ScalekitClient } from '@scalekit-sdk/node'; 2 import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; 3 4 const scalekit = new ScalekitClient( 5 process.env.SCALEKIT_ENV_URL!, 6 process.env.SCALEKIT_CLIENT_ID!, 7 process.env.SCALEKIT_CLIENT_SECRET!, 8 ); ``` ## Connect the user to Gmail [Section titled “Connect the user to Gmail”](#connect-the-user-to-gmail) ```typescript 1 const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ 2 connectionName: 'gmail', 3 identifier: 'user_123', 4 }); 5 if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { 6 const { link } = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123' }); 7 console.log('Authorize Gmail:', link); 8 } ``` See [Authorize a user](/agentkit/tools/authorize/) for production auth handling. ## Run the agent [Section titled “Run the agent”](#run-the-agent) ```typescript 1 import { generateText, jsonSchema, stepCountIs, tool } from 'ai'; 2 import { openai } from '@ai-sdk/openai'; 3 4 const { tools: scopedTools } = await scalekit.tools.listScopedTools('user_123', { 5 filter: { connectionNames: ['gmail'] }, 6 pageSize: 100, // fetch beyond the default page so no connector tools are missed 7 }); 8 9 const tools = Object.fromEntries( 10 scopedTools.map(t => [ 11 t.tool.definition.name, 12 tool({ 13 description: t.tool.definition.description, 14 parameters: jsonSchema(t.tool.definition.input_schema ?? { type: 'object', properties: {} }), 15 execute: async (args) => { 16 const result = await scalekit.actions.executeTool({ 17 toolName: t.tool.definition.name, 18 identifier: 'user_123', 19 toolInput: args, 20 }); 21 return result.data; 22 }, 23 }), 24 ]), 25 ); 26 27 const { text } = await generateText({ 28 model: openai('gpt-4o'), 29 tools, 30 stopWhen: stepCountIs(5), 31 prompt: 'Fetch my last 5 unread emails and summarize them', 32 }); 33 console.log(text); ``` ## Use MCP instead [Section titled “Use MCP instead”](#use-mcp-instead) The Vercel AI SDK supports MCP via `experimental_createMCPClient`. Pass a Scalekit-generated MCP URL to connect without any tool schema setup: ```typescript 1 import { experimental_createMCPClient, generateText } from 'ai'; 2 import { openai } from '@ai-sdk/openai'; 3 4 const mcpClient = await experimental_createMCPClient({ 5 transport: { 6 type: 'sse', 7 url: mcpUrl, // from actions.mcp.ensure_instance() 8 }, 9 }); 10 11 const tools = await mcpClient.tools(); 12 13 const { text } = await generateText({ 14 model: openai('gpt-4o'), 15 tools, 16 stopWhen: stepCountIs(5), 17 prompt: 'Fetch my last 5 unread emails and summarize them', 18 }); 19 await mcpClient.close(); 20 console.log(text); ``` See [Generate user MCP URLs](/agentkit/mcp/generate-user-urls/) to get `mcpUrl`. --- # DOCUMENT BOUNDARY --- # Node.js SDK reference > Complete API reference for the Scalekit Node.js SDK: actions client and tools client. `scalekit.actions` is the primary interface for AgentKit. It handles connected account management, tool execution, and proxied API calls. `scalekit.tools` exposes raw tool schemas for building custom adapters. ## Install and initialize [Section titled “Install and initialize”](#install-and-initialize) ```bash 1 npm install @scalekit-sdk/node ``` ```ts 1 import { ScalekitClient } from '@scalekit-sdk/node'; 2 3 const scalekit = new ScalekitClient({ 4 clientId: process.env.SCALEKIT_CLIENT_ID!, 5 clientSecret: process.env.SCALEKIT_CLIENT_SECRET!, 6 envUrl: process.env.SCALEKIT_ENV_URL!, 7 }); ``` *** ## Actions client [Section titled “Actions client”](#actions-client) ### Authentication [Section titled “Authentication”](#authentication) #### getAuthorizationLink [Section titled “getAuthorizationLink”](#getauthorizationlink) Generates a time-limited OAuth magic link to authorize a user’s connection. Input schema NameTypeRequiredDescription connectionNamestringoptionalConnector slug (e.g. gmail) identifierstringoptionalUser's identifier (e.g. email) connectedAccountIdstringoptionalDirect connected account ID (ca\_...) organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users statestringoptionalOpaque value passed through to the redirect URL userVerifyUrlstringoptionalYour app's redirect URL for user verification Response schema GetMagicLinkForConnectedAccountResponse Field Type Description link string OAuth magic link URL. Redirect the user here to start the authorization flow. Example ```ts 1 const { link } = await scalekit.actions.getAuthorizationLink({ 2 connectionName: 'gmail', 3 identifier: 'user@example.com', 4 userVerifyUrl: 'https://your-app.com/verify', 5 }); 6 // Redirect the user to link ``` #### verifyConnectedAccountUser [Section titled “verifyConnectedAccountUser”](#verifyconnectedaccountuser) Verifies the user after OAuth callback. Call this from your redirect URL handler. Input schema NameTypeRequiredDescription authRequestIdstringrequiredToken from the redirect URL query params identifierstringrequiredCurrent user's identifier Response schema VerifyConnectedAccountUserResponse Field Type Description postUserVerifyRedirectUrl string URL to redirect the user to after successful verification Example ```ts 1 await scalekit.actions.verifyConnectedAccountUser({ 2 authRequestId: req.query.auth_request_id as string, 3 identifier: 'user@example.com', 4 }); ``` *** ### Connected accounts [Section titled “Connected accounts”](#connected-accounts) #### getOrCreateConnectedAccount [Section titled “getOrCreateConnectedAccount”](#getorcreateconnectedaccount) Fetches an existing connected account or creates one if none exists. Use this as the default when setting up a user. Input schema NameTypeRequiredDescription connectionNamestringrequiredConnector slug identifierstringrequiredUser's identifier authorizationDetailsobjectoptionalOAuth token or static auth details organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users apiConfigRecord\optionalConnector-specific options (for example scopes or static auth fields) Response schema CreateConnectedAccountResponse Field Type Description connectedAccount.id string Account ID (ca\_...) connectedAccount.identifier string User's identifier connectedAccount.provider string Provider slug connectedAccount.status string ACTIVE, INACTIVE, or PENDING connectedAccount.authorizationType string OAuth, API\_KEY, etc. connectedAccount.tokenExpiresAt string ISO 8601 OAuth token expiry Example ```ts 1 const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ 2 connectionName: 'gmail', 3 identifier: 'user@example.com', 4 }); 5 console.log(connectedAccount.id); ``` #### getConnectedAccount [Section titled “getConnectedAccount”](#getconnectedaccount) Fetches auth details for a connected account. Returns sensitive credentials. Protect access to this method. Requires `connectedAccountId` **or** `connectionName` + `identifier`. Input schema NameTypeRequiredDescription connectionNamestringoptionalConnector slug. Use with identifier when you do not pass connectedAccountId. identifierstringoptionalEnd-user or workspace identifier. Use with connectionName. connectedAccountIdstringoptionalConnected account ID (ca\_...) when resolving by ID instead of name + identifier organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users Response schema GetConnectedAccountByIdentifierResponse Field Type Description connectedAccount.id string Account ID (ca\_...) connectedAccount.identifier string User's identifier connectedAccount.provider string Provider slug connectedAccount.status string ACTIVE, INACTIVE, or PENDING connectedAccount.authorizationType string OAuth, API\_KEY, etc. connectedAccount.authorizationDetails object Credential payload (access token, API key, etc.) connectedAccount.tokenExpiresAt string ISO 8601 OAuth token expiry connectedAccount.lastUsedAt string Last time this account was used connectedAccount.updatedAt string Last update timestamp #### listConnectedAccounts [Section titled “listConnectedAccounts”](#listconnectedaccounts) Input schema NameTypeRequiredDescription connectionNamestringoptionalFilter by connector identifierstringoptionalFilter by user identifier providerstringoptionalFilter by provider organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users pageSizenumberoptionalMaximum accounts per page (server default if omitted) pageTokenstringoptionalOpaque cursor from a previous list response querystringoptionalFree-text search Response schema ListConnectedAccountsResponse Field Type Description connectedAccounts array List of ConnectedAccountForList objects (excludes authorizationDetails) totalSize number Total number of matching accounts nextPageToken string Token for the next page, if any prevPageToken string Token for the previous page, if any #### createConnectedAccount [Section titled “createConnectedAccount”](#createconnectedaccount) Creates a connected account with explicit auth details. Input schema NameTypeRequiredDescription connectionNamestringrequiredConnector slug. Must match a connection configured in your environment. identifierstringrequiredStable ID for this end user or workspace (email, user\_id, or custom string) authorizationDetailsobjectrequiredOAuth token payload, API key, or other credentials for this connector organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users apiConfigRecord\optionalConnector-specific options (for example scopes or static auth fields) Returns CreateConnectedAccountResponse. Same shape as `getOrCreateConnectedAccount`. #### updateConnectedAccount [Section titled “updateConnectedAccount”](#updateconnectedaccount) Requires `connectedAccountId` **or** `connectionName` + `identifier`. Input schema NameTypeRequiredDescription connectionNamestringoptionalConnector slug. Use with identifier when you do not pass connectedAccountId. identifierstringoptionalEnd-user or workspace identifier. Use with connectionName. connectedAccountIdstringoptionalConnected account ID (ca\_...) when updating by ID instead of name + identifier authorizationDetailsobjectoptionalReplace or merge stored credentials (OAuth tokens, API keys, etc.) organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users apiConfigobjectoptionalConnector-specific configuration to persist on the account Returns UpdateConnectedAccountResponse. #### deleteConnectedAccount [Section titled “deleteConnectedAccount”](#deleteconnectedaccount) Deletes a connected account and revokes its credentials. Requires `connectedAccountId` **or** `connectionName` + `identifier`. Input schema NameTypeRequiredDescription connectionNamestringoptionalConnector slug. Use with identifier when you do not pass connectedAccountId. identifierstringoptionalEnd-user or workspace identifier. Use with connectionName. connectedAccountIdstringoptionalConnected account ID (ca\_...) when deleting by ID instead of name + identifier organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users Returns DeleteConnectedAccountResponse. *** ### Tool execution [Section titled “Tool execution”](#tool-execution) #### executeTool [Section titled “executeTool”](#executetool) Executes a named tool via Scalekit. Input schema NameTypeRequiredDescription toolNamestringrequiredTool name (e.g. gmail\_fetch\_emails) toolInputRecord\requiredParameters the tool expects identifierstringoptionalUser's identifier connectedAccountIdstringoptionalDirect connected account ID connectorstringoptionalConnector slug organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users Response schema ExecuteToolResponse Field Type Description data object Tool's structured output executionId string Unique ID for this execution Example ```ts 1 const result = await scalekit.actions.executeTool({ 2 toolName: 'gmail_fetch_emails', 3 toolInput: { maxResults: 5, label: 'UNREAD' }, 4 identifier: 'user@example.com', 5 }); 6 const emails = result.data; ``` *** ### Proxied API calls [Section titled “Proxied API calls”](#proxied-api-calls) #### request [Section titled “request”](#request) Makes a REST API call on behalf of a connected account. Scalekit injects the user’s OAuth token automatically. Input schema NameTypeRequiredDescription connectionNamestringrequiredConnector slug identifierstringrequiredUser's identifier pathstringrequiredAPI path (e.g. /gmail/v1/users/me/messages) methodstringoptionalHTTP method. Default: GET queryParamsRecord\optionalURL query parameters appended to path bodyunknownoptionalJSON-serializable body for POST, PUT, PATCH, or similar methods formDataRecord\optionalMultipart form fields when the upstream API expects form data instead of JSON headersRecord\optionalExtra HTTP headers merged with Scalekit-injected auth headers timeoutMsnumberoptionalDefault: 30000 Returns `AxiosResponse`. Use `.data`, `.status`, and standard Axios response attributes. Example ```ts 1 const response = await scalekit.actions.request({ 2 connectionName: 'gmail', 3 identifier: 'user@example.com', 4 path: '/gmail/v1/users/me/messages', 5 queryParams: { maxResults: 5, q: 'is:unread' }, 6 }); 7 const messages = response.data.messages; ``` *** ## Tools client [Section titled “Tools client”](#tools-client) `scalekit.tools` gives access to raw tool schemas. Use this when building a custom framework adapter or passing schemas directly to an LLM API (e.g. Anthropic, OpenAI). #### listTools [Section titled “listTools”](#listtools) Lists all tools available in your workspace. Input schema NameTypeRequiredDescription filterFilteroptionalFilter by provider, identifier, or tool name pageSizenumberoptionalMaximum tools per page (server default if omitted) pageTokenstringoptionalOpaque cursor from a previous list response Response schema ListToolsResponse Field Type Description tools array List of tool schemas (name, description, input schema) nextPageToken string Token for the next page, if any #### listScopedTools [Section titled “listScopedTools”](#listscopedtools) Lists tools scoped to a specific user. Use this for tool discovery because it returns pagination metadata such as `nextPageToken` and `totalSize`. Input schema NameTypeRequiredDescription identifierstringrequiredUser's connected account identifier filterScopedToolFilteroptionalFilter by providers, tool names, or connection names pageSizenumberoptionalMaximum tools per page. Use 100 for discovery so connectors with more than the default page are not truncated. pageTokenstringoptionalOpaque cursor from a previous list response Response schema ListScopedToolsResponse Field Type Description tools array List of tool schemas tools\[].name string Tool name tools\[].description string Tool description tools\[].inputSchema object JSON Schema for tool inputs. Pass directly to LLM API. nextPageToken string Token for the next page, if any Example ```ts 1 const { tools } = await scalekit.tools.listScopedTools('user@example.com', { 2 filter: { connectionNames: ['gmail'] }, 3 pageSize: 100, 4 }); 5 // Pass tools to your LLM's tool call API ``` #### listAvailableTools [Section titled “listAvailableTools”](#listavailabletools) Lists tools available for a given identifier. These tools can be activated but may not yet be scoped to the user. Input schema NameTypeRequiredDescription identifierstringrequiredUser's connected account identifier pageSizenumberoptionalMaximum tools per page (server default if omitted) pageTokenstringoptionalOpaque cursor from a previous list response Response schema ListAvailableToolsResponse Field Type Description tools array List of available tool schemas nextPageToken string Token for the next page, if any #### executeTool [Section titled “executeTool”](#executetool-1) Low-level tool execution. Prefer `scalekit.actions.executeTool` for most use cases. Input schema NameTypeRequiredDescription toolNamestringrequiredRegistered tool name to execute identifierstringoptionalEnd-user or workspace identifier used to resolve the connected account paramsRecord\optionalTool arguments matching the tool input schema connectedAccountIdstringoptionalConnected account ID (ca\_...) when you already know it connectorstringoptionalConnector slug when the tool name exists on more than one connector organizationIdstringoptionalOrganization tenant ID when your app scopes auth and accounts by org userIdstringoptionalYour application user ID when you map Scalekit accounts to internal users Returns ExecuteToolResponse. Same shape as `scalekit.actions.executeTool`. *** ## Error handling [Section titled “Error handling”](#error-handling) ```ts 1 import { 2 ScalekitNotFoundException, 3 ScalekitServerException, 4 } from '@scalekit-sdk/node'; 5 6 try { 7 const account = await scalekit.actions.getConnectedAccount({ 8 connectionName: 'gmail', 9 identifier: 'user@example.com', 10 }); 11 } catch (err) { 12 if (err instanceof ScalekitNotFoundException) { 13 // Account does not exist: create it or redirect to auth 14 } else if (err instanceof ScalekitServerException) { 15 // Network or server error 16 console.error(err); 17 } 18 } ``` | Exception | When raised | | ------------------------------- | -------------------------------- | | `ScalekitNotFoundException` | Resource not found | | `ScalekitUnauthorizedException` | Invalid credentials | | `ScalekitForbiddenException` | Insufficient permissions | | `ScalekitServerException` | Base class for all server errors | --- # DOCUMENT BOUNDARY --- # Python SDK reference > Complete API reference for the Scalekit Python SDK: actions client, MCP server provisioning, framework adapters, tools client, and modifiers. `scalekit_client.actions` is the primary interface for AgentKit. It handles connected account management, MCP server provisioning, tool execution, and framework integrations. ## Install and initialize [Section titled “Install and initialize”](#install-and-initialize) ```bash 1 pip install scalekit-sdk-python ``` ```python 1 import os 2 import scalekit.client 3 4 scalekit_client = scalekit.client.ScalekitClient( 5 client_id=os.getenv("SCALEKIT_CLIENT_ID"), 6 client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), 7 env_url=os.getenv("SCALEKIT_ENV_URL"), 8 ) 9 10 actions = scalekit_client.actions ``` *** ## Actions client [Section titled “Actions client”](#actions-client) ### Authentication [Section titled “Authentication”](#authentication) #### get\_authorization\_link [Section titled “get\_authorization\_link”](#get_authorization_link) Generates a time-limited OAuth magic link to authorize a user’s connection. Input schema NameTypeRequiredDescription identifierstroptionalUser identifier (e.g. email) connection\_namestroptionalConnector slug (e.g. gmail) connected\_account\_idstroptionalDirect connected account ID (ca\_...) statestroptionalOpaque value passed through to the redirect URL user\_verify\_urlstroptionalApp redirect URL for user verification Response schema MagicLinkResponse Field Type Description link str OAuth magic link URL. Redirect the user here to start the authorization flow. expiry datetime Link expiry timestamp Example ```python 1 magic_link = actions.get_authorization_link( 2 identifier="user@example.com", 3 connection_name="gmail", 4 user_verify_url="https://your-app.com/verify", 5 ) 6 # Redirect the user to magic_link.link ``` #### verify\_connected\_account\_user [Section titled “verify\_connected\_account\_user”](#verify_connected_account_user) Verifies the user after OAuth callback. Call this from your redirect URL handler. Input schema NameTypeRequiredDescription auth\_request\_idstrrequiredToken from the redirect URL query params identifierstrrequiredCurrent user identifier Response schema VerifyConnectedAccountUserResponse Field Type Description post\_user\_verify\_redirect\_url str URL to redirect the user to after successful verification Example ```python 1 result = actions.verify_connected_account_user( 2 auth_request_id=request.args["auth_request_id"], 3 identifier="user@example.com", 4 ) 5 # Redirect to result.post_user_verify_redirect_url ``` *** ### Connected accounts [Section titled “Connected accounts”](#connected-accounts) #### get\_or\_create\_connected\_account [Section titled “get\_or\_create\_connected\_account”](#get_or_create_connected_account) Fetches an existing connected account or creates one if none exists. Use this as the default when setting up a user. Input schema NameTypeRequiredDescription connection\_namestrrequiredConnector slug identifierstrrequiredUser's identifier authorization\_detailsdictoptionalOAuth token or static auth details organization\_idstroptionalOrganization tenant ID when your app scopes auth and accounts by org user\_idstroptionalYour application user ID when you map Scalekit accounts to internal users api\_configdictoptionalConnector-specific options (for example scopes or static auth fields) Response schema CreateConnectedAccountResponse Field Type Description connected\_account.id str Account ID (ca\_...) connected\_account.identifier str User's identifier connected\_account.provider str Provider slug connected\_account.status str ACTIVE, INACTIVE, or PENDING connected\_account.authorization\_type str OAuth, API\_KEY, etc. connected\_account.token\_expires\_at datetime OAuth token expiry Example ```python 1 account = actions.get_or_create_connected_account( 2 connection_name="gmail", 3 identifier="user@example.com", 4 ) 5 print(account.connected_account.id) ``` #### get\_connected\_account [Section titled “get\_connected\_account”](#get_connected_account) Fetches auth details for a connected account. Returns sensitive credentials. Protect access to this method. Use this when you know the connected account already exists and you need its credential payload. For first-time setup or general application flows, prefer `get_or_create_connected_account` so new users do not hit a not-found error. Requires `connected_account_id` **or** `connection_name` + `identifier`. Input schema NameTypeRequiredDescription connection\_namestroptionalConnector slug. Use with identifier when you do not pass connected\_account\_id. identifierstroptionalEnd-user or workspace identifier. Use with connection\_name. connected\_account\_idstroptionalConnected account ID (ca\_...) when resolving by ID instead of name + identifier Response schema GetConnectedAccountAuthResponse Field Type Description connected\_account.id str Account ID (ca\_...) connected\_account.identifier str User's identifier connected\_account.provider str Provider slug connected\_account.status str ACTIVE, INACTIVE, or PENDING connected\_account.authorization\_type str OAuth, API\_KEY, etc. connected\_account.authorization\_details dict Credential payload (access token, API key, etc.) connected\_account.token\_expires\_at datetime OAuth token expiry connected\_account.last\_used\_at datetime Last time this account was used connected\_account.updated\_at datetime Last update timestamp #### list\_connected\_accounts [Section titled “list\_connected\_accounts”](#list_connected_accounts) Input schema NameTypeRequiredDescription connection\_namestroptionalFilter by connector identifierstroptionalFilter by user identifier providerstroptionalFilter by provider Response schema ListConnectedAccountsResponse Field Type Description connected\_accounts list List of ConnectedAccountForList objects (excludes authorization\_details and api\_config) total\_count int Total number of matching accounts next\_page\_token str Token for the next page, if any previous\_page\_token str Token for the previous page, if any #### create\_connected\_account [Section titled “create\_connected\_account”](#create_connected_account) Creates a connected account with explicit auth details. Input schema NameTypeRequiredDescription connection\_namestrrequiredConnector slug. Must match a connection configured in your environment. identifierstrrequiredStable ID for this end user or workspace (email, user\_id, or custom string) authorization\_detailsdictrequiredOAuth token payload, API key, or other credentials for this connector organization\_idstroptionalOrganization tenant ID when your app scopes auth and accounts by org user\_idstroptionalYour application user ID when you map Scalekit accounts to internal users api\_configdictoptionalConnector-specific options (for example scopes or static auth fields) Returns CreateConnectedAccountResponse. Same shape as `get_or_create_connected_account`. #### update\_connected\_account [Section titled “update\_connected\_account”](#update_connected_account) Requires `connected_account_id` **or** `connection_name` + `identifier`. Input schema NameTypeRequiredDescription connection\_namestroptionalConnector slug. Use with identifier when you do not pass connected\_account\_id. identifierstroptionalEnd-user or workspace identifier. Use with connection\_name. connected\_account\_idstroptionalConnected account ID (ca\_...) when updating by ID instead of name + identifier authorization\_detailsdictoptionalReplace or merge stored credentials (OAuth tokens, API keys, etc.) organization\_idstroptionalOrganization tenant ID when your app scopes auth and accounts by org user\_idstroptionalYour application user ID when you map Scalekit accounts to internal users api\_configdictoptionalConnector-specific configuration to persist on the account Returns UpdateConnectedAccountResponse. #### delete\_connected\_account [Section titled “delete\_connected\_account”](#delete_connected_account) Deletes a connected account and revokes its credentials. Requires `connected_account_id` **or** `connection_name` + `identifier`. Input schema NameTypeRequiredDescription connection\_namestroptionalConnector slug. Use with identifier when you do not pass connected\_account\_id. identifierstroptionalEnd-user or workspace identifier. Use with connection\_name. connected\_account\_idstroptionalConnected account ID (ca\_...) when deleting by ID instead of name + identifier Returns DeleteConnectedAccountResponse. *** ### Tool execution [Section titled “Tool execution”](#tool-execution) #### execute\_tool [Section titled “execute\_tool”](#execute_tool) Executes a named tool via Scalekit. Pre- and post-modifiers run automatically if registered. Input schema NameTypeRequiredDescription tool\_namestrrequiredTool name (e.g. gmail\_fetch\_emails) tool\_inputdictrequiredParameters the tool expects identifierstroptionalUser's identifier connected\_account\_idstroptionalDirect connected account ID Response schema ExecuteToolResponse Field Type Description data dict Tool structured output execution\_id str Unique ID for this execution Example ```python 1 result = actions.execute_tool( 2 tool_name="gmail_fetch_emails", 3 tool_input={"max_results": 5, "label": "UNREAD"}, 4 identifier="user@example.com", 5 ) 6 emails = result.data ``` *** ### Proxied API calls [Section titled “Proxied API calls”](#proxied-api-calls) #### request [Section titled “request”](#request) Makes a REST API call on behalf of a connected account. Scalekit injects the user’s OAuth token automatically. Input schema NameTypeRequiredDescription connection\_namestrrequiredConnector slug identifierstrrequiredUser's identifier pathstrrequiredAPI path (e.g. /gmail/v1/users/me/messages) methodstroptionalHTTP method. Default: GET query\_paramsdictoptionalURL query parameters appended to path bodyanyoptionalJSON-serializable body for POST, PUT, PATCH, or similar methods form\_datadictoptionalMultipart form fields when the upstream API expects form data instead of JSON headersdictoptionalExtra HTTP headers merged with Scalekit-injected auth headers Returns `requests.Response`. Use `.json()`, `.status_code`, and standard response attributes. Example ```python 1 response = actions.request( 2 connection_name="gmail", 3 identifier="user@example.com", 4 path="/gmail/v1/users/me/messages", 5 query_params={"maxResults": 5, "q": "is:unread"}, 6 ) 7 messages = response.json()["messages"] ``` *** ## MCP server provisioning [Section titled “MCP server provisioning”](#mcp-server-provisioning) `actions.mcp` generates per-user MCP-compatible server URLs. Any MCP-compatible agent framework (LangChain, Google ADK, Anthropic, OpenAI, and others) can connect to these URLs directly. **Two-step model:** Create a **config** once (defines which connectors and tools to expose), then call `ensure_instance` per user to get their personal MCP server URL. ### Configs [Section titled “Configs”](#configs) #### actions.mcp.create\_config [Section titled “actions.mcp.create\_config”](#actionsmcpcreate_config) Input schema NameTypeRequiredDescription namestrrequiredConfig name descriptionstroptionalHuman-readable summary of what this MCP config exposes connection\_tool\_mappingslistoptionalList of McpConfigConnectionToolMapping objects Response schema CreateMcpConfigResponse Field Type Description config.id str Config ID config.name str Config name config.connection\_tool\_mappings list Connector-to-tools mappings Example ```python 1 from scalekit.actions.types import McpConfigConnectionToolMapping 2 3 config = actions.mcp.create_config( 4 name="email-agent", 5 connection_tool_mappings=[ 6 McpConfigConnectionToolMapping( 7 connection_name="gmail", 8 tools=["gmail_fetch_emails", "gmail_send_email"], 9 ) 10 ], 11 ) ``` #### actions.mcp.list\_configs [Section titled “actions.mcp.list\_configs”](#actionsmcplist_configs) Input schema NameTypeRequiredDescription page\_sizeintoptionalMaximum configs per page (server default if omitted) page\_tokenstroptionalOpaque cursor from a previous list response filter\_namestroptionalFilter by exact name filter\_providerstroptionalFilter by provider slug searchstroptionalFree-text search on name Returns ListMcpConfigsResponse. #### actions.mcp.update\_config [Section titled “actions.mcp.update\_config”](#actionsmcpupdate_config) Input schema NameTypeRequiredDescription config\_idstrrequiredMCP config ID from create\_config or list\_configs descriptionstroptionalNew human-readable description for this config connection\_tool\_mappingslistoptionalReplaces existing mappings Returns UpdateMcpConfigResponse. #### actions.mcp.delete\_config [Section titled “actions.mcp.delete\_config”](#actionsmcpdelete_config) Input schema NameTypeRequiredDescription config\_idstrrequiredMCP config ID to delete Returns DeleteMcpConfigResponse. ### Instances [Section titled “Instances”](#instances) #### actions.mcp.ensure\_instance [Section titled “actions.mcp.ensure\_instance”](#actionsmcpensure_instance) Creates an MCP instance for this user if one doesn’t exist, or returns the existing one. Call this on every session; it’s idempotent. The `instance.url` field is the MCP server URL to give to the user’s agent or IDE. Input schema NameTypeRequiredDescription config\_namestrrequiredName of the config to instantiate user\_identifierstrrequiredUser identifier (e.g. email) namestroptionalDisplay name for the instance Response schema EnsureMcpInstanceResponse Field Type Description instance.url str MCP server URL for agent or IDE instance.id str Instance ID instance.name str Display name instance.user\_identifier str User identifier instance.config object The config this instance was created from instance.last\_used\_at datetime Last usage timestamp instance.updated\_at datetime Last update timestamp Example ```python 1 instance = actions.mcp.ensure_instance( 2 config_name="email-agent", 3 user_identifier="user@example.com", 4 ) 5 mcp_url = instance.instance.url 6 # Give mcp_url to the user's agent or IDE ``` #### actions.mcp.get\_instance\_auth\_state [Section titled “actions.mcp.get\_instance\_auth\_state”](#actionsmcpget_instance_auth_state) Returns authorization status per connector. Use `include_auth_links=True` to generate fresh auth links for connections that need authorization or re-authorization. Input schema NameTypeRequiredDescription instance\_idstrrequiredInstance ID include\_auth\_linksbooloptionalGenerate auth links for unauthorized connections Response schema GetMcpInstanceAuthStateResponse Field Type Description connections list List of McpInstanceConnectionAuthState, one per configured connector connections\[].connection\_id str Connection ID connections\[].connection\_name str Connector slug connections\[].provider str Provider slug connections\[].connected\_account\_id str Connected account ID, if authorized connections\[].connected\_account\_status str ACTIVE, INACTIVE, or PENDING connections\[].authentication\_link str Auth link to send to the user when status is not ACTIVE Example ```python 1 auth_state = actions.mcp.get_instance_auth_state( 2 instance_id=instance.instance.id, 3 include_auth_links=True, 4 ) 5 for conn in auth_state.connections: 6 if conn.connected_account_status != "ACTIVE": 7 # Send conn.authentication_link to the user to authorize 8 print(f"{conn.connection_name}: {conn.authentication_link}") ``` #### actions.mcp.get\_instance [Section titled “actions.mcp.get\_instance”](#actionsmcpget_instance) Input schema NameTypeRequiredDescription instance\_idstrrequiredMCP instance ID from ensure\_instance or list\_instances Returns GetMcpInstanceResponse. #### actions.mcp.list\_instances [Section titled “actions.mcp.list\_instances”](#actionsmcplist_instances) Input schema NameTypeRequiredDescription page\_sizeintoptionalMaximum instances per page (server default if omitted) page\_tokenstroptionalOpaque cursor from a previous list response filter\_user\_identifierstroptionalFilter by user filter\_config\_namestroptionalFilter by config name filter\_namestroptionalFilter by MCP instance display name filter\_idstroptionalFilter by MCP instance ID Returns ListMcpInstancesResponse. #### actions.mcp.update\_instance [Section titled “actions.mcp.update\_instance”](#actionsmcpupdate_instance) At least one of `name` or `config_name` is required. Input schema NameTypeRequiredDescription instance\_idstrrequiredMCP instance ID to update namestroptionalNew display name for this instance config\_namestroptionalSwitch the instance to a different config by name Returns UpdateMcpInstanceResponse. #### actions.mcp.delete\_instance [Section titled “actions.mcp.delete\_instance”](#actionsmcpdelete_instance) Input schema NameTypeRequiredDescription instance\_idstrrequiredMCP instance ID to delete Returns DeleteMcpInstanceResponse. *** ## Framework adapters [Section titled “Framework adapters”](#framework-adapters) Pre-built integrations for LangChain and Google ADK. Use these when your agent runs in one of these frameworks and you prefer native tool objects over an MCP URL. ### LangChain [Section titled “LangChain”](#langchain) ```bash 1 pip install langchain ``` #### actions.langchain.get\_tools [Section titled “actions.langchain.get\_tools”](#actionslangchainget_tools) Input schema NameTypeRequiredDescription identifierstrrequiredUser connected account identifier providerslistoptionalFilter by provider (e.g. \["google"]) tool\_nameslistoptionalFilter by tool name connection\_nameslistoptionalFilter by connection name page\_sizeintoptionalMaximum tools per page. Use 100 for discovery so connectors with more than the default page are not truncated. page\_tokenstroptionalOpaque cursor from a previous list response Response schema List\[StructuredTool] Field Type Description \[].name str Tool name \[].description str Tool description \[].args\_schema object Pydantic schema for the tool inputs Example ```python 1 from langchain.agents import create_react_agent 2 3 tools = actions.langchain.get_tools( 4 identifier="user@example.com", 5 page_size=100, # avoid missing tools when a connector has more than the default page 6 ) 7 agent = create_react_agent(llm=llm, tools=tools, prompt=prompt) ``` ### Google ADK [Section titled “Google ADK”](#google-adk) ```bash 1 pip install google-adk ``` #### actions.google.get\_tools [Section titled “actions.google.get\_tools”](#actionsgoogleget_tools) Same parameters as `actions.langchain.get_tools`. Returns `List[ScalekitGoogleAdkTool]`. Pass it directly to a Google ADK agent. Example ```python 1 tools = actions.google.get_tools( 2 identifier="user@example.com", 3 page_size=100, # avoid missing tools when a connector has more than the default page 4 ) ``` *** ## Tools client [Section titled “Tools client”](#tools-client) `scalekit_client.actions.tools` gives access to raw tool schemas. Use this when building a custom adapter or passing schemas directly to an LLM API (e.g. Anthropic, OpenAI). #### actions.tools.list\_tools [Section titled “actions.tools.list\_tools”](#actionstoolslist_tools) Input schema NameTypeRequiredDescription filterFilteroptionalFilter by provider, identifier, or tool name page\_sizeintoptionalMaximum tools per page. Use 100 for discovery so connectors with more than the default page are not truncated. page\_tokenstroptionalOpaque cursor from a previous list response Response schema ListToolsResponse Field Type Description tools list List of tool schemas (name, description, input schema) next\_page\_token str Token for the next page, if any #### actions.tools.list\_scoped\_tools [Section titled “actions.tools.list\_scoped\_tools”](#actionstoolslist_scoped_tools) Lists tools scoped to a specific user. Use this method for tool discovery because it returns pagination metadata such as `next_page_token` and `total_size`; framework `get_tools()` helpers return framework-ready tool objects and do not expose that metadata. Input schema NameTypeRequiredDescription identifierstrrequiredUser connected account identifier filterScopedToolFilteroptionalFilter by providers, tool names, or connection names page\_sizeintoptionalMaximum tools per page. Use 100 for discovery so connectors with more than the default page are not truncated. page\_tokenstroptionalOpaque cursor from a previous list response Response schema ListScopedToolsResponse Field Type Description tools list List of tool schemas (name, description, input\_schema) tools\[].name str Tool name tools\[].description str Tool description tools\[].input\_schema object JSON Schema for tool inputs. Pass directly to LLM API. next\_page\_token str Token for the next page, if any Example ```python 1 tools_response = scalekit_client.actions.tools.list_scoped_tools( 2 identifier="user@example.com", 3 page_size=100, 4 ) 5 # Pass tools_response.tools to your LLM's tool call API ``` #### actions.tools.execute\_tool [Section titled “actions.tools.execute\_tool”](#actionstoolsexecute_tool) Low-level tool execution. Bypasses modifiers. Prefer `actions.execute_tool` in most cases. Input schema NameTypeRequiredDescription tool\_namestrrequiredRegistered tool name to execute identifierstrrequiredEnd-user or workspace identifier used to resolve the connected account paramsdictoptionalTool arguments matching the tool input schema connected\_account\_idstroptionalConnected account ID (ca\_...) when you already know it Returns ExecuteToolResponse. Same shape as `actions.execute_tool`. *** ## Modifiers [Section titled “Modifiers”](#modifiers) Modifiers intercept tool calls to transform inputs or outputs, useful for validation, enrichment, or logging. ```python 1 @actions.pre_modifier(tool_names=["gmail_fetch_emails"]) 2 def add_default_label(tool_input): 3 tool_input.setdefault("label", "UNREAD") 4 return tool_input 5 6 @actions.post_modifier(tool_names=["gmail_fetch_emails"]) 7 def filter_attachments(tool_output): 8 tool_output["emails"] = [e for e in tool_output["emails"] if not e.get("has_attachment")] 9 return tool_output ``` | Decorator | Receives | Returns | | ------------------------------------ | -------- | --------------- | | `@actions.pre_modifier(tool_names)` | `dict` | Modified `dict` | | `@actions.post_modifier(tool_names)` | `dict` | Modified `dict` | `tool_names` accepts a string or a list of strings. Multiple modifiers for the same tool chain in registration order. *** ## Error handling [Section titled “Error handling”](#error-handling) ```python 1 from scalekit.common.exceptions import ScalekitNotFoundException, ScalekitServerException 2 3 try: 4 account = actions.get_connected_account( 5 connection_name="gmail", 6 identifier="user@example.com", 7 ) 8 except ScalekitNotFoundException: 9 # Account does not exist: create it or redirect to auth 10 pass 11 except ScalekitServerException as e: 12 print(e.error_code, e.http_status) ``` | Exception | When raised | | ------------------------------- | -------------------------------- | | `ScalekitNotFoundException` | Resource not found | | `ScalekitUnauthorizedException` | Invalid credentials | | `ScalekitForbiddenException` | Insufficient permissions | | `ScalekitServerException` | Base class for all server errors |