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

---

# AgentKit: Connect my agent to apps

<img
  src={quickstartArchitecture.src}
  alt="Architecture diagram: an AI agent connects through Scalekit MCP Gateway with delegated auth, scoped permissions, and tool calls to SaaS apps such as GitHub, Gmail, Slack, and Salesforce."
  width={quickstartArchitecture.width}
  height={quickstartArchitecture.height}
  loading="eager"
  decoding="async"
/>

By the end of this guide, you'll have a working agent that stars a repository on GitHub on behalf of a user (authenticated with their real account). Scalekit manages the OAuth flow, token storage, and API proxy so you focus on agent logic.

<ProductAgentBlock skill="integrate-agentkit" />

## 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. **Confirm the GitHub connection** at Dashboard → **AgentKit** > **Connections**.

   New Scalekit environments include a default GitHub connection named `github-connect`, pre-configured with Scalekit's managed credentials and the `user:email`, `repo`, and `public_repo` scopes — no connector setup is needed for this quickstart.

   Copy the exact **Connection name** from that connection and use that value in your code. It must match the dashboard exactly; in older environments or renamed connections the value can differ from `github-connect`. 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 values as environment variables:
   - `SCALEKIT_CLIENT_ID`
   - `SCALEKIT_CLIENT_SECRET`
   - `SCALEKIT_ENVIRONMENT_URL`
   - `GITHUB_CONNECTION_NAME` (copy the exact Connection name from **AgentKit** > **Connections** — `github-connect` in new environments)

## Build your agent

Paste this prompt into your coding agent. It builds an agent that stars a GitHub repo on behalf of a user.

    <ProductAgentBlock skill="integrate-agentkit" hideLead />
**Review generated code before deploying:** Verify that token validation logic, error handling, and environment variable references match your application's requirements.

  ### 1. Set up your environment

    Install the Scalekit SDK and initialize the client with your API credentials:

    ```sh showLineNumbers=false frame="none"
        pip install scalekit-sdk-python python-dotenv
        ```
      ```sh showLineNumbers=false frame="none"
        npm install @scalekit-sdk/node
        ```
      ```python showLineNumbers=false frame="none" wrap
        import os
        from scalekit import ScalekitClient
        from dotenv import load_dotenv
        load_dotenv()

        # Constructor: env_url, client_id, client_secret
        scalekit_client = ScalekitClient(
            os.environ["SCALEKIT_ENVIRONMENT_URL"],
            os.environ["SCALEKIT_CLIENT_ID"],
            os.environ["SCALEKIT_CLIENT_SECRET"],
        )
        actions = scalekit_client.actions
        connection_name = os.getenv("GITHUB_CONNECTION_NAME")  # must match the Connection name in the dashboard exactly
        ```
      ```typescript showLineNumbers=false frame="none"
        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';

        // Constructor: envUrl, clientId, clientSecret
        const scalekit = new ScalekitClient(
          process.env.SCALEKIT_ENVIRONMENT_URL!,
          process.env.SCALEKIT_CLIENT_ID!,
          process.env.SCALEKIT_CLIENT_SECRET!
        );

        const actions = scalekit.actions;
        const connectionName = process.env.GITHUB_CONNECTION_NAME!; // must match the Connection name in the dashboard exactly
        ```
      ### 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 GitHub access on your behalf. This step fails if the GitHub connection does not exist in **AgentKit** > **Connections**, or if `connection_name` / `connectionName` does not match the dashboard exactly.

    ```python wrap {2} showLineNumbers=false frame="none"
        # Create or retrieve the user's connected GitHub 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}')
        ```
      ```typescript showLineNumbers=false frame="none"
        // Create or retrieve the user's connected GitHub account
        const response = await actions.getOrCreateConnectedAccount({
          connectionName,
          identifier: 'user_123',  // Replace with your system's unique user ID
        });

        let connectedAccount = response.connectedAccount;
        console.log('Connected account created:', connectedAccount?.id);
        ```
      ### 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 showLineNumbers=false frame="none" wrap
        # Generate authorization link if user hasn't authorized or token is expired.
        # Do not call tools until status is ACTIVE — wait for the user to finish OAuth first.
        if connected_account.status != "ACTIVE":
            print(f"GitHub is not connected: {connected_account.status}")
            link_response = actions.get_authorization_link(
                connection_name=connection_name,
                identifier="user_123",
            )
            print("🔗 click on the link to authorize GitHub", link_response.link)
            input("⎆ Press Enter after authorizing GitHub...")
            # Re-fetch so connected_account reflects ACTIVE status and a valid id
            response = actions.get_or_create_connected_account(
                connection_name=connection_name,
                identifier="user_123",
            )
            connected_account = response.connected_account
            # In production, redirect the user to this URL and resume after the OAuth callback

        if connected_account.status != "ACTIVE":
            raise RuntimeError(
                "GitHub is still not ACTIVE. Complete authorization and try again."
            )
        ```
      ```typescript showLineNumbers=false frame="none" wrap
        // Generate authorization link if user hasn't authorized or token is expired.
        // Do not call tools until status is ACTIVE — wait for the user to finish OAuth first.
        if (connectedAccount?.status !== ConnectorStatus.ACTIVE) {
          console.log('GitHub is not connected:', connectedAccount?.status);
          const linkResponse = await actions.getAuthorizationLink({
            connectionName,
            identifier: 'user_123',
          });
          console.log('🔗 click on the link to authorize GitHub', linkResponse.link);
          console.log('Press Enter after authorizing GitHub...');
          await new Promise<void>((resolve) => {
            process.stdin.resume();
            process.stdin.once('data', () => {
              process.stdin.pause();
              resolve();
            });
          });
          // Re-fetch so connectedAccount reflects ACTIVE status and a valid id
          const refreshed = await actions.getOrCreateConnectedAccount({
            connectionName,
            identifier: 'user_123',
          });
          connectedAccount = refreshed.connectedAccount;
          // In production, redirect the user to this URL and resume after the OAuth callback
        }

        if (connectedAccount?.status !== ConnectorStatus.ACTIVE) {
          throw new Error('GitHub is still not ACTIVE. Complete authorization and try again.');
        }
        ```
      Open the link in a browser and authorize the GitHub connection. Once complete, the connected account status updates to `ACTIVE` and your agent can act on the user's behalf. In CLI samples, wait for that step (for example with `input()` or stdin) before calling tools — otherwise the first run fails because the account is still inactive.

    ### 4. Star a repo via tool call

    Pass the tool name and your inputs to Scalekit. It handles the request to GitHub and returns a structured response your agent can reason over directly: no endpoint URLs, auth headers, or response parsing required. The example stars the Scalekit SDK repo for your language.

    ```python showLineNumbers=false frame="none" wrap
        # Prefer connected_account_id after authorize. If you use identifier instead,
        # also pass connection_name — the pair is required for account resolution.
        tool_response = actions.execute_tool(
            tool_name="github_repo_star",
            connected_account_id=connected_account.id,
            tool_input={
                "owner": "scalekit-inc",
                "repo": "scalekit-sdk-python",
            },
        )
        # Tool output lives under data
        print(tool_response.data)
        ```
      ```typescript showLineNumbers=false frame="none" wrap
        const toolResponse = await actions.executeTool({
          toolName: 'github_repo_star',
          connectedAccountId: connectedAccount?.id,
          toolInput: {
            owner: 'scalekit-inc',
            repo: 'scalekit-sdk-node',
          },
        });
        // Tool output lives under data
        console.log('Starred the repo:', toolResponse.data);
        ```
      ## Verify it works

Run your agent and confirm:

- The connected account status is `ACTIVE` after the user completes the GitHub OAuth flow.
- The tool call returns success and the star appears on the Scalekit SDK repo on GitHub. Starring is idempotent — GitHub returns success even if the repo is already starred — so re-runs are safe. To confirm programmatically, call `github_starred_repos_list` and check the repo is in the list.

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

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

---

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