Migrate from Composio to Scalekit
Map Composio concepts to Scalekit AgentKit equivalents and update your agent code step by step.
This guide maps Composio concepts to their Scalekit AgentKit equivalents and walks through each migration step: SDK setup, authentication, tool execution, and MCP. Use it as a reference while porting your agent code.
Concept mapping
Section titled “Concept mapping”| Composio | Scalekit | Notes |
|---|---|---|
Toolkit (e.g. GITHUB) | Connector (e.g. github) | Scalekit uses lowercase slugs |
Tool (e.g. GITHUB_CREATE_ISSUE) | Tool (e.g. github_create_issue) | Same concept, lowercase naming |
| Auth config | Connection | OAuth app credentials, scopes, redirect URIs |
| Connected account | Connected account | Per-user credential record |
user_id / entity ID | identifier | Your app’s unique user ID, passed per API call |
| Connect Link | Authorization link | OAuth redirect URL for user consent |
Session (composio.create()) | No equivalent | Scalekit is stateless — pass identifier per call |
Provider package (composio_openai) | No equivalent | Scalekit uses a single SDK for all frameworks |
session.tools() | listScopedTools() | Get tools a user is authorized to call |
session.tools.execute() | executeTool() | Execute a tool on behalf of a user |
session.mcp.url | MCP instance URL | Per-user MCP endpoint |
| Custom tool (in-memory) | Custom tool (API Proxy) | Defined in your app code using actions.request() |
executeToolRequest (proxy) | actions.request() | Proxied REST API call |
| Trigger | No equivalent | Scalekit does not support event-driven triggers |
COMPOSIO_SEARCH_TOOLS | No equivalent | Use listScopedTools with connection name filters |
COMPOSIO_REMOTE_WORKBENCH | No equivalent | No remote sandbox execution |
1. Set up Scalekit
Section titled “1. Set up Scalekit”-
Create a Scalekit account
Sign up at app.scalekit.com and copy your API credentials from Dashboard > Developers > Settings > API Credentials.
-
Set environment variables
Terminal window SCALEKIT_CLIENT_ID=your_client_idSCALEKIT_CLIENT_SECRET=your_client_secretSCALEKIT_ENV_URL=https://your-env.scalekit.com -
Install the SDK
Terminal window pip install scalekit-sdk-pythonTerminal window npm install @scalekit-sdk/node -
Initialize the client
Scalekit uses a single client instance. There is no session object — you pass
identifieron each API call.import osimport scalekit.clientscalekit_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.actionsimport { ScalekitClient } from '@scalekit-sdk/node';const scalekit = new ScalekitClient({clientId: process.env.SCALEKIT_CLIENT_ID!,clientSecret: process.env.SCALEKIT_CLIENT_SECRET!,envUrl: process.env.SCALEKIT_ENV_URL!,});
2. Configure connections
Section titled “2. Configure connections”In Composio, auth configs are created programmatically or via the dashboard. In Scalekit, you configure connections in the dashboard.
For each Composio toolkit your agent uses (Gmail, Slack, GitHub, etc.), create a corresponding connection in Dashboard > AgentKit > Connections > Add connection. See Configure a connection for the full walkthrough.
| Composio auth type | Scalekit equivalent |
|---|---|
| OAuth 2.0 (Composio managed) | OAuth 2.0 (use Scalekit credentials to start, then bring your own) |
| OAuth 2.0 (custom) | OAuth 2.0 (bring your own credentials) |
| API key | API key (user provides during connected account creation) |
| Bearer token | Bearer token |
| Basic auth | Basic auth |
3. Migrate authentication
Section titled “3. Migrate authentication”Both platforms create per-user records (connected accounts) and generate OAuth links. The SDK methods differ.
Create a connected account and authorize
Section titled “Create a connected account and authorize”Before (Composio):
# Composio handles auth in-chat or via connect linksession = composio.create(user_id="user_123")# Auth is triggered automatically when a tool requires itAfter (Scalekit):
# Create or retrieve the connected accountresponse = actions.get_or_create_connected_account( connection_name="gmail", identifier="user_123",)connected_account = response.connected_account
# Generate an authorization link if the account is not yet activeif connected_account.status != "ACTIVE": link_response = actions.get_authorization_link( connection_name="gmail", identifier="user_123", ) auth_url = link_response.link # Redirect or send auth_url to the userBefore (Composio):
// Composio handles auth in-chat or via connect linkconst session = await composio.create("user_123");// Auth is triggered automatically when a tool requires itAfter (Scalekit):
// Create or retrieve the connected accountconst response = await scalekit.actions.getOrCreateConnectedAccount({ connectionName: 'gmail', identifier: 'user_123',});
const connectedAccount = response.connectedAccount;
// Generate an authorization link if the account is not yet activeif (connectedAccount?.status !== 'ACTIVE') { const linkResponse = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123', }); const authUrl = linkResponse.link; // Redirect or send authUrl to the user}Key difference: Composio can trigger auth in-chat automatically. With Scalekit, your app explicitly creates the connected account and sends the authorization link to the user. Once the user completes the OAuth flow, the connected account becomes ACTIVE and your agent can execute tools.
Check connected account status
Section titled “Check connected account status”Composio tracks two statuses (ACTIVE and INACTIVE). Scalekit uses more granular states:
| Scalekit status | Meaning |
|---|---|
PENDING | User hasn’t completed authentication |
ACTIVE | Credentials valid, ready for tool calls |
EXPIRED | Credentials expired or invalidated, re-authentication required |
REVOKED | User revoked access or credentials were invalidated |
ERROR | Authentication or configuration error |
Check status before executing tools. If the account is not ACTIVE, generate a new authorization link.
4. Migrate tool calls
Section titled “4. Migrate tool calls”List available tools
Section titled “List available tools”Before (Composio):
session = composio.create(user_id="user_123")tools = session.tools() # all tools the user is authorized forAfter (Scalekit):
tools_response = scalekit_client.actions.tools.list_scoped_tools( identifier="user_123", filter={"connection_names": ["gmail"]}, # optional; omit for all connectors page_size=100,)Before (Composio):
const session = await composio.create("user_123");const tools = await session.tools(); // all tools the user is authorized forAfter (Scalekit):
const { tools } = await scalekit.tools.listScopedTools('user_123', { filter: { connectionNames: ['gmail'] }, // optional; omit for all connectors pageSize: 100,});Execute a tool
Section titled “Execute a tool”Before (Composio):
session = composio.create(user_id="user_123")tools = session.tools()# Framework handles execution via the agent loop, or:# composio.tools.execute(tool_name="GMAIL_FETCH_MAILS", params={...})After (Scalekit):
result = actions.execute_tool( tool_name="gmail_fetch_mails", identifier="user_123", connection_name="gmail", tool_input={"query": "is:unread", "max_results": 5},)print(result.data)Before (Composio):
const session = await composio.create("user_123");const tools = await session.tools();// Framework handles execution via the agent loopAfter (Scalekit):
const result = await scalekit.actions.executeTool({ toolName: 'gmail_fetch_mails', identifier: 'user_123', connectionName: 'gmail', toolInput: { query: 'is:unread', max_results: 5 },});console.log(result.data);Key differences:
- Composio tool names are uppercase (
GMAIL_FETCH_MAILS); Scalekit uses lowercase (gmail_fetch_mails) - Composio’s session model means you don’t pass
user_idon each call. With Scalekit, passidentifierandconnection_nameon everyexecuteToolcall - Both return structured, LLM-ready output
Map tool names
Section titled “Map tool names”Composio and Scalekit may name tools differently for the same connector. Browse the connector’s tool list in the Scalekit connector catalog to find the exact tool names. Common patterns:
| Composio tool name | Scalekit tool name |
|---|---|
GMAIL_FETCH_MAILS | gmail_fetch_mails |
SLACK_SEND_MESSAGE | slack_send_message |
GITHUB_CREATE_ISSUE | github_create_issue |
NOTION_CREATE_PAGE | notion_create_page |
Tool input schemas may also differ. Check each tool’s parameters in the connector catalog and update your agent’s tool input accordingly.
5. Migrate MCP
Section titled “5. Migrate MCP”Both platforms support MCP (Model Context Protocol) for framework-agnostic tool discovery and execution.
Before (Composio):
{ "mcpServers": { "composio": { "url": "https://backend.composio.dev/v3/mcp/{SERVER_ID}?user_id={USER_ID}", "headers": { "x-api-key": "<COMPOSIO_API_KEY>" } } }}After (Scalekit):
In Scalekit, MCP requires a two-step setup:
- Create an MCP config — define which connections and tools the server exposes (one-time)
- Generate a per-user MCP URL — each user gets a unique, pre-authenticated endpoint
See Configure an MCP server and Generate user MCP URLs for the full setup.
Once you have the per-user URL:
{ "mcpServers": { "scalekit": { "url": "<PER_USER_MCP_URL>" } }}Key difference: Composio uses a single URL with the user ID as a query parameter. Scalekit generates a unique, pre-authenticated URL per user — no API key in the client config.
6. Migrate custom tools
Section titled “6. Migrate custom tools”In Composio, custom tools are defined in code with decorators and stored in memory — they’re lost on restart. In Scalekit, custom tools use API Proxy mode (actions.request). The proxy is available out of the box for every connector with no extra configuration. You define the tool contract in your application code and call the provider’s REST endpoint through Scalekit, which injects the user’s credentials automatically.
| Composio approach | Scalekit approach |
|---|---|
@composio.tools.custom_tool decorator | Define the tool in your app code |
| In-memory, lost on restart | Lives in your codebase |
executeToolRequest for authenticated API calls | actions.request() — works out of the box for every connector |
response = actions.request( connection_name="gmail", identifier="user_123", method="GET", path="/gmail/v1/users/me/messages",)const response = await scalekit.actions.request({ connectionName: 'gmail', identifier: 'user_123', method: 'GET', path: '/gmail/v1/users/me/messages',});7. Add custom connectors
Section titled “7. Add custom connectors”If your agent connects to an API or MCP server that isn’t in Scalekit’s built-in catalog, you can add your own connector. Custom connectors support OAuth 2.0, API keys, bearer tokens, and other auth types. Once created, they work exactly like built-in connectors — same connected account flow, same actions.request() proxy, same MCP tool calling.
This goes beyond what Composio offers with in-memory custom tools: Scalekit custom connectors are persistent, support any SaaS API, partner system, or internal service, and keep all credential handling centralized.
See Add your own connector for the full walkthrough.