> **Building with AI coding agents?** Install the authstack plugin with one command. This equips your agent with accurate Scalekit implementation patterns.
>
> **Recommended** (the `-y` flags skip prompts, so the command runs without an interactive terminal):
> ```bash
> npx -y @scalekit-inc/cli setup -y
> ```
>
> Global:
> ```bash
> npm install -g @scalekit-inc/cli
> scalekit setup -y
> ```
>
> Supports Claude Code, Cursor, GitHub Copilot, Codex + skills for other Agent Skills-compatible agents in `~/.agents/skills`.
> Skills: integrate-agentkit, implement-saaskit, add-mcp-oauth, implement-sso, implement-scim.
> [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Migrate from Composio to Scalekit

Move an agent from Composio to Scalekit AgentKit: map concepts, recreate connections, have users re-authorize, then move tool calls, MCP and custom tools.
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.

> note: Users must re-authorize
>
> OAuth refresh tokens are bound to the OAuth client that issued them. After migration, each user must complete the OAuth consent flow once through Scalekit to create a new connected account. Existing Composio tokens cannot be transferred.

## 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_issue_create`) | 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()`) | **`identifier`** on each call | No session to create: each call names the user |
| Provider package (`composio_openai`) | `@scalekit-sdk/node` or `scalekit-sdk-python` | One SDK works with every framework |
| `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` | **Virtual MCP server URL + session token** | Static server URL with a short-lived bearer token per agent run |
| 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 | Your own scheduler or the app's webhooks | Run `executeTool()` on a schedule, or subscribe to the app's webhooks |
| `COMPOSIO_SEARCH_TOOLS` | `searchTools()` | Rank tools by relevance to a task, or filter `listScopedTools()` by connection name |
| `COMPOSIO_REMOTE_WORKBENCH` | Your own runtime | Run code where your agent runs |

## 1. Set up Scalekit

1. **Create a Scalekit account**

   Sign up at [app.scalekit.com](https://app.scalekit.com) and copy your API credentials from **Dashboard > Developers > Settings > API Credentials**.

2. **Set environment variables**

   Add them to a `.env` file that you don't commit. The code in step 4 loads it.

   ```bash title=".env"
   SCALEKIT_CLIENT_ID=your_client_id
   SCALEKIT_CLIENT_SECRET=your_client_secret
   SCALEKIT_ENVIRONMENT_URL=https://your-env.scalekit.com
   ```

3. **Install the SDK**

     **Python**

     ```bash
     pip install scalekit-sdk-python python-dotenv
     ```

     **Node.js**

     ```bash
     npm install @scalekit-sdk/node dotenv
     ```

4. **Initialize the client**

   Scalekit uses a single client instance. There is no session object — you pass `identifier` on each API call.

     **Python**

     ```python
     import os
     from scalekit import ScalekitClient
     from dotenv import load_dotenv

     load_dotenv()  # reads .env into the environment

     scalekit_client = ScalekitClient(
         client_id=os.getenv("SCALEKIT_CLIENT_ID"),
         client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
         env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
     )
     actions = scalekit_client.actions
     ```

     **Node.js**

     ```typescript
     import 'dotenv/config'; // reads .env into process.env
     import { ScalekitClient } from '@scalekit-sdk/node';

     const scalekit = new ScalekitClient(
       process.env.SCALEKIT_ENVIRONMENT_URL!,
       process.env.SCALEKIT_CLIENT_ID!,
       process.env.SCALEKIT_CLIENT_SECRET!
     );
     ```

## 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 **AgentKit** > **Connections** > **Add connection**. See [Configure a connection](/agentkit/connections/) 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 |

> tip: Scalekit credentials for quick testing
>
> Many OAuth connectors offer a **Use Scalekit credentials** option that lets you skip OAuth app registration, in development and in production. Switch to your own credentials when you want your app's name on the consent screen. See [Bring your own OAuth](/agentkit/advanced/bring-your-own-oauth/).

## 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

  **Python**

  **Before (Composio):**
  ```python
  # Composio handles auth in-chat or via connect link
  session = composio.create(user_id="user_123")
  # Auth is triggered automatically when a tool requires it
  ```

  **After (Scalekit):**
  ```python
  # Create or retrieve the connected account
  response = 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 active
  if 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 user
  ```

  **Node.js**

  **Before (Composio):**
  ```typescript
  // Composio handles auth in-chat or via connect link
  const session = await composio.create("user_123");
  // Auth is triggered automatically when a tool requires it
  ```

  **After (Scalekit):**
  ```typescript
  import { ConnectorStatus } from '@scalekit-sdk/node';

  // Create or retrieve the connected account
  const response = await scalekit.actions.getOrCreateConnectedAccount({
    connectionName: 'gmail',
    identifier: 'user_123',
  });

  const connectedAccount = response.connectedAccount;

  // Generate an authorization link if the account is not yet active
  if (connectedAccount?.status !== ConnectorStatus.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

Composio tracks two statuses (`ACTIVE` and `INACTIVE`). Scalekit uses more granular states:

| Scalekit status | Meaning |
|---|---|
| `PENDING_AUTH` | User hasn't completed authentication |
| `PENDING_VERIFICATION` | Authentication complete; user verification still required |
| `ACTIVE` | Credentials valid, ready for tool calls |
| `EXPIRED` | Credentials expired or were revoked; re-authentication required |
| `DISCONNECTED` | Account was disconnected |

Check status before executing tools. If the account is not `ACTIVE`, generate a new authorization link.

## 4. Migrate tool calls

#### List available tools

  **Python**

  **Before (Composio):**
  ```python
  session = composio.create(user_id="user_123")
  tools = session.tools()  # all tools the user is authorized for
  ```

  **After (Scalekit):**
  ```python
  tools_response, _ = scalekit_client.actions.tools.list_scoped_tools(
      identifier="user_123",
      # Required: list every connection whose tools the agent should see
      filter={"connection_names": ["gmail"]},
      page_size=100,
  )
  ```

  **Node.js**

  **Before (Composio):**
  ```typescript
  const session = await composio.create("user_123");
  const tools = await session.tools();  // all tools the user is authorized for
  ```

  **After (Scalekit):**
  ```typescript
  const { tools } = await scalekit.tools.listScopedTools('user_123', {
    // Required: list every connection whose tools the agent should see
    filter: { connectionNames: ['gmail'] },
    pageSize: 100,
  });
  ```

#### Execute a tool

  **Python**

  **Before (Composio):**
  ```python
  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):**
  ```python
  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)
  ```

  **Node.js**

  **Before (Composio):**
  ```typescript
  const session = await composio.create("user_123");
  const tools = await session.tools();
  // Framework handles execution via the agent loop
  ```

  **After (Scalekit):**
  ```typescript
  const result = await scalekit.actions.executeTool({
    toolName: 'gmail_fetch_mails',
    identifier: 'user_123',
    connector: '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_id` on each call. With Scalekit, pass `identifier` and the connection name on every `executeTool` call: `connection_name` in Python, `connector` in Node.js
- Both return structured, LLM-ready output

### 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](/agentkit/connectors/) 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_issue_create` |
| `NOTION_CREATE_PAGE` | `notion_page_create` |

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

Both platforms support MCP (Model Context Protocol) for framework-agnostic tool discovery and execution.

**Before (Composio):**
```json
{
  "mcpServers": {
    "composio": {
      "url": "https://backend.composio.dev/v3/mcp/{SERVER_ID}?user_id={USER_ID}",
      "headers": {
        "x-api-key": "<COMPOSIO_API_KEY>"
      }
    }
  }
}
```

**After (Scalekit):**

Scalekit MCP uses Virtual MCP servers:

1. **Create a Virtual MCP server** — define which connections and tools the server exposes (one-time). This gives you a static `mcp_server_url`.
2. **Mint a session token** — before each agent run, call `create_session_token` for the user. Pass it as a bearer auth header.

See [Virtual MCP servers](/agentkit/mcp/overview/) for the full setup.

```json
{
  "mcpServers": {
    "scalekit": {
      "url": "<MCP_SERVER_URL>",
      "headers": {
        "Authorization": "Bearer <SESSION_TOKEN>"
      }
    }
  }
}
```

**Key difference:** Composio embeds the user ID in the URL. Scalekit uses a static server URL shared across all users, with a short-lived session token per agent run for authentication.

## 6. Migrate custom tools

In Scalekit, custom tools use **API Proxy mode** (`actions.request`). The proxy works out of the box for most connectors, with no extra configuration. If a call returns `proxy not enabled for provider`, see [Call any API](/agentkit/tools/custom-tools/#proxy-not-enabled-for-provider). 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 most connectors |

  **Python**

  ```python
  response = actions.request(
      connection_name="gmail",
      identifier="user_123",
      method="GET",
      path="/gmail/v1/users/me/messages",
  )
  ```

  **Node.js**

  ```typescript
  const response = await scalekit.actions.request({
    connectionName: 'gmail',
    identifier: 'user_123',
    method: 'GET',
    path: '/gmail/v1/users/me/messages',
  });
  ```

## 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.

See [Add your own connector](/agentkit/bring-your-own-connector/overview/) for the full walkthrough.

## Checklist

- [ ] Scalekit account created, API credentials saved as environment variables
- [ ] Scalekit SDK installed
- [ ] Connections created in the Scalekit Dashboard for each connector
- [ ] Connected account creation and authorization link flow ported
- [ ] Tool names updated from uppercase to lowercase
- [ ] `executeTool` calls updated with `identifier` and the connection name (`connection_name` in Python, `connector` in Node.js)
- [ ] Tool input schemas verified against the Scalekit connector catalog
- [ ] Virtual MCP server created and session token flow implemented (if using MCP)
- [ ] Custom tools ported to `actions.request()` (if applicable)
- [ ] Agent tested end-to-end with a test user
- [ ] Users re-authorized through Scalekit's OAuth flow

## Next

  - [Quickstart](/agentkit/quickstart/): Make your first tool call as a user.
  - [Choose a framework](/agentkit/examples/): Build the same agent in another framework.

## API reference

The endpoints this page's code calls, with every field and the SDK method for each:

- `POST` [Create a connected account](https://docs.scalekit.com/agentkit/reference/connected-accounts/create-a-connected-account.md)
- `POST` [Get an authorization link](https://docs.scalekit.com/agentkit/reference/authorization/get-an-authorization-link.md)
- `POST` [Execute a tool](https://docs.scalekit.com/agentkit/reference/tools/execute-a-tool.md)
- `GET` [List a user's scoped tools](https://docs.scalekit.com/agentkit/reference/tools/list-scoped-tools.md)


---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
