> **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/)

---

# Connect AI agents to the Vapi MCP server

The Vapi MCP connector routes your AI agent's tool calls to Vapi's own MCP server through Scalekit. Each user connects their own Vapi access token once, and Scalekit sends it with every call, so your agent never handles credentials. It comes with 13 tools.

**Authentication:** Bearer Token
**Categories:** Communication, AI
**Tools:** 13: 8 read, 5 write, 0 destructive
**Users sign in with:** Access token
**Built by:** Vendor MCP
**Try it:** [Playground in the Scalekit dashboard](https://app.scalekit.com/ws/signup?sk_intent=playground&provider=VAPIMCP)

## What you can do

- **Manage voice assistants**: create, update, and review voice AI assistants and their model and voice settings
- **Place outbound calls**: start or schedule calls with a chosen assistant and phone number
- **Review calls**: list calls and fetch a call's status, duration, and other details
- **Manage assistant tools**: create, update, and list tools that extend what assistants can do on calls
- **Look up phone numbers**: list the account's phone numbers and fetch details for a specific one

## Setup

1. ### Install the SDK

   **Node.js**

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

   **Python**

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

2. ### Set your credentials

   Add your Scalekit credentials to your `.env` file. Find values in **[app.scalekit.com](https://app.scalekit.com)** > **Developers** > **API Credentials**.

   ```sh title=".env"
   SCALEKIT_ENVIRONMENT_URL=<your-environment-url>
   SCALEKIT_CLIENT_ID=<your-client-id>
   SCALEKIT_CLIENT_SECRET=<your-client-secret>
   ```

3. ### Create the Vapi MCP connection

   In **AgentKit > Connections**, create a Vapi MCP connection. The name you give it is the `connection_name` your code passes. See [Configure connections](/agentkit/connections/).

   **Console steps with screenshots:**

   Register your Vapi API key with Scalekit so it can authenticate and proxy requests to the Vapi MCP server on behalf of your users. Vapi MCP uses bearer token authentication. Scalekit sends the key as `Authorization: Bearer <token>` to the Vapi MCP endpoint at `https://mcp.vapi.ai/mcp`.

   1. ## Get a Vapi API key

      - Go to [dashboard.vapi.ai/org/api-keys](https://dashboard.vapi.ai/org/api-keys) and sign in or create an account.

      - Under **API Keys**, copy your **Private Key**. Use the private key — it authorizes server-side calls to the Vapi API.

      - Treat this key as a secret. Anyone with it can manage your assistants, calls, and phone numbers.

   2. ## Create a connection in Scalekit

      - In the [Scalekit dashboard](https://app.scalekit.com), go to **AgentKit** > **Connections**. Find **Vapi MCP** and click **Create**.

      - Note the **Connection name** — you use this as `connection_name` in your code (for example, `vapimcp`).

   3. ## Add a connected account

      Connected accounts link a specific user identifier in your system to a Vapi API key. Add one in the dashboard to test. In production, each user adds their own through the authorization link: they enter their credentials on the page it opens.

      **In the dashboard, to test**

      - Open the connection you created and click the **Connected Accounts** tab → **Add account**.

      - Fill in:
        - **Your User's ID** — a unique identifier for this user in your system (for example, `user_123`)
        - **Vapi API key** — the private key you copied in step 1

      - Click **Save**.

      **From your backend, if your app already has the credentials**

      For example, when users enter them on a settings page in your app:

        **Node.js**

        ```typescript
        import { ConnectorStatus } from '@scalekit-sdk/node'

        const authorizationDetails = {
          details: {
            case: 'staticAuth',
            value: { details: { token: process.env.VAPI_API_KEY } },
          },
        };

        let { connectedAccount } = await scalekit.actions.upsertConnectedAccount({
          connectionName: 'vapimcp',
          identifier: 'user_123',       // your user's unique ID
          authorizationDetails,
        });

        // Make sure the account is ACTIVE before the first tool call.
        if (connectedAccount?.status !== ConnectorStatus.ACTIVE) {
          ({ connectedAccount } = await scalekit.actions.upsertConnectedAccount({
            connectionName: 'vapimcp',
            identifier: 'user_123',
            authorizationDetails,
          }));
        }
        ```

        **Python**

        ```python
        authorization_details = {"static_auth": {"token": os.environ["VAPI_API_KEY"]}}

        response = scalekit_client.actions.upsert_connected_account(
            connection_name="vapimcp",
            identifier="user_123",
            authorization_details=authorization_details,
        )

        # Make sure the account is ACTIVE before the first tool call.
        if response.connected_account.status != "ACTIVE":
            response = scalekit_client.actions.upsert_connected_account(
                connection_name="vapimcp",
                identifier="user_123",
                authorization_details=authorization_details,
            )
        ```

4. ### Authorize a user and make your first call

   **Node.js** (`quickstart.mts`)

   ```typescript
   import { ScalekitClient } from '@scalekit-sdk/node'
   import 'dotenv/config'
   import { createInterface } from 'node:readline/promises'

   const scalekit = new ScalekitClient(
     process.env.SCALEKIT_ENVIRONMENT_URL,
     process.env.SCALEKIT_CLIENT_ID,
     process.env.SCALEKIT_CLIENT_SECRET,
   )
   const actions = scalekit.actions

   const connector = 'vapimcp'
   const identifier = 'user_123'

   // Generate an authorization link for the user
   const { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })
   console.log('Authorize Vapi MCP:', link)
   const rl = createInterface({ input: process.stdin, output: process.stdout })
   await rl.question('Press Enter after authorizing...')
   rl.close()

   // Make your first call
   const result = await actions.executeTool({
     connector,
     identifier,
     toolName: 'vapimcp_list_assistants',
     toolInput: { rationale: 'YOUR_RATIONALE' },
   })
   console.log(result)
   ```

   ```bash
   npx tsx quickstart.mts
   ```

   **Python** (`quickstart.py`)

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

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

   connection_name = "vapimcp"
   identifier = "user_123"

   # Generate an authorization link for the user
   link_response = actions.get_authorization_link(
       connection_name=connection_name,
       identifier=identifier,
   )
   print("Authorize Vapi MCP:", link_response.link)
   input("Press Enter after authorizing...")

   # Make your first call
   result = actions.execute_tool(
       tool_input={"rationale":"YOUR_RATIONALE"},
       tool_name="vapimcp_list_assistants",
       connection_name=connection_name,
       identifier=identifier,
   )
   print(result)
   ```

   ```bash
   python quickstart.py
   ```

   Each user opens the link once and enters their Vapi MCP server credentials there. If your app already has a user's credentials, add the account from your backend instead, as the console steps above show. See [Authorize a user](/agentkit/tools/authorize/) for the full flow and statuses.

## Tools

Pass the exact name to `execute_tool`, with an input like each tool's example. To ask for a tool that's missing, use the [request form](https://scalekitsupport.portal.usepylon.com/forms/request-a-connector-tool).

**Node.js**

```typescript
const result = await actions.executeTool({
  toolName: 'vapimcp_get_assistant',
  toolInput: {
    assistantId: '<assistantId>',
    rationale: '<rationale>',
  },
  connector: 'vapimcp',
  identifier: 'user_123',
})
```

**Python**

```python
result = actions.execute_tool(
    tool_name="vapimcp_get_assistant",
    tool_input={
        "assistantId": "<assistantId>",
        "rationale": "<rationale>",
    },
    connection_name="vapimcp",
    identifier="user_123",
)
```

`result.data` is the app's response as JSON, and `result.execution_id` (`executionId` in Node.js) is the ID of the call.

### `vapimcp_get_assistant`

Get assistant · Read-only

Retrieves the full configuration of a specific Vapi assistant by ID, including its LLM, voice, transcription settings, tools, and first message.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `assistantId` (`string`, required): ID of the assistant to retrieve
- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"assistantId":"<assistantId>","rationale":"<rationale>"}`

### `vapimcp_get_call`

Get call · Read-only

Retrieves detailed information about a specific Vapi call by ID, including its status, duration, transcript, recording URL, and associated assistant.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `callId` (`string`, required): ID of the call to retrieve
- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"callId":"<callId>","rationale":"<rationale>"}`

### `vapimcp_get_phone_number`

Get phone number · Read-only

Retrieves details of a specific Vapi phone number by ID, including its number, provider, and any assistant or squad configuration attached to it.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `phoneNumberId` (`string`, required): ID of the phone number to retrieve
- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"phoneNumberId":"<phoneNumberId>","rationale":"<rationale>"}`

### `vapimcp_get_tool`

Get tool · Read-only

Retrieves the full configuration of a specific Vapi tool by ID, including its type (SMS, transfer call, function, or API request) and associated settings.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `toolId` (`string`, required): ID of the Vapi tool to retrieve

Example input: `{"rationale":"<rationale>","toolId":"<toolId>"}`

### `vapimcp_list_assistants`

List assistants · Read-only

Lists all Vapi assistants configured in the account. Returns a list of assistant objects including their IDs, names, configurations, and settings.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"rationale":"<rationale>"}`

### `vapimcp_list_calls`

List calls · Read-only

Lists all Vapi calls in the account. Returns call records including their IDs, status, duration, associated assistant, and transcript metadata.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"rationale":"<rationale>"}`

### `vapimcp_list_phone_numbers`

List phone numbers · Read-only

Lists all phone numbers provisioned in the Vapi account. Returns phone number objects including their IDs, numbers, provider, and associated assistant configurations.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"rationale":"<rationale>"}`

### `vapimcp_list_tools`

List tools · Read-only

Lists all Vapi tools configured in the account. Vapi tools extend assistant capabilities — types include SMS, transfer call, custom functions, and API request tools.

Read only: yes. Destructive: no. Idempotent (safe to retry): yes.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool

Example input: `{"rationale":"<rationale>"}`

### `vapimcp_create_assistant`

Create assistant · Write

Creates a new Vapi voice AI assistant with the specified configuration. Configure the assistant's LLM provider, voice, transcription engine, first message, and any tools it should have access to.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `name` (`string`, required): Name of the assistant
- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `firstMessage` (`string`, optional): First message the assistant says when a call starts
- `firstMessageMode` (`string`, optional): Whether the assistant speaks first or waits for the user
- `instructions` (`string`, optional): System instructions for the assistant. Defaults to 'You are a helpful assistant.'
- `llm` (`string`, optional): LLM configuration. Defaults to OpenAI gpt-4o.
- `toolIds` (`string`, optional): IDs of Vapi tools to attach to this assistant
- `transcriber` (`string`, optional): Transcription configuration. Defaults to Deepgram nova-3.
- `voice` (`string`, optional): Voice configuration. Defaults to ElevenLabs 'sarah'.

Example input: `{"name":"<name>","rationale":"<rationale>"}`

### `vapimcp_create_call`

Create call · Write

Initiates or schedules an outbound Vapi call. Specify the assistant and phone number to use, the customer's phone number, and optionally a scheduled time. Use assistantOverrides.variableValues to inject dynamic data into the assistant's prompts.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `assistantId` (`string`, optional): ID of the Vapi assistant to use for the call
- `assistantOverrides` (`string`, optional): Runtime overrides for the assistant configuration
- `customer` (`string`, optional): Customer contact information for the outbound call
- `phoneNumberId` (`string`, optional): ID of the Vapi phone number to call from
- `scheduledAt` (`string`, optional): ISO 8601 datetime to schedule the call (e.g. 2025-03-25T22:39:27.771Z). Omit to call immediately.

Example input: `{"rationale":"<rationale>"}`

### `vapimcp_create_tool`

Create tool · Write

Creates a new Vapi tool that can be attached to assistants. Supports four tool types: 'sms' for sending text messages, 'transferCall' for transferring calls to destinations, 'function' for custom server-side functions, and 'apiRequest' for HTTP API integrations.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `type` (`string`, required): Type of tool to create. One of: `sms`, `transferCall`, `function`, `apiRequest`.
- `apiRequest` (`string`, optional): API request tool configuration — provide when type is 'apiRequest'
- `description` (`string`, optional): Description of what the tool does
- `function` (`string`, optional): Function tool configuration — provide when type is 'function'
- `name` (`string`, optional): Name of the tool
- `sms` (`string`, optional): SMS configuration — provide when type is 'sms'
- `transferCall` (`string`, optional): Transfer call configuration — provide when type is 'transferCall'

Example input: `{"rationale":"<rationale>","type":"sms"}`

### `vapimcp_update_assistant`

Update assistant · Write

Updates an existing Vapi assistant's configuration. Only fields you provide will be changed; omitted fields retain their current values.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `assistantId` (`string`, required): ID of the assistant to update
- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `firstMessage` (`string`, optional): New first message the assistant says when a call starts
- `firstMessageMode` (`string`, optional): New first message mode
- `instructions` (`string`, optional): New system instructions for the assistant
- `llm` (`string`, optional): New LLM configuration
- `name` (`string`, optional): New name for the assistant
- `toolIds` (`string`, optional): New list of Vapi tool IDs for the assistant
- `transcriber` (`string`, optional): New transcription configuration
- `voice` (`string`, optional): New voice configuration

Example input: `{"assistantId":"<assistantId>","rationale":"<rationale>"}`

### `vapimcp_update_tool`

Update tool · Write

Updates an existing Vapi tool's configuration. Only fields you provide will be changed. Supports all tool types: sms, transferCall, function, and apiRequest.

Read only: no. Destructive: no. Idempotent (safe to retry): no.

Inputs:

- `rationale` (`string`, required): Always provide a brief explanation of why you are calling this tool
- `toolId` (`string`, required): ID of the Vapi tool to update
- `apiRequest` (`string`, optional): Updated API request tool configuration
- `description` (`string`, optional): New description for the tool
- `function` (`string`, optional): Updated function tool configuration
- `name` (`string`, optional): New name for the tool
- `sms` (`string`, optional): Updated SMS configuration
- `transferCall` (`string`, optional): Updated transfer call configuration

Example input: `{"rationale":"<rationale>","toolId":"<toolId>"}`

## Workflows

**Tool calling**

- Use `vapimcp_list_assistants` to discover existing assistants, then `vapimcp_get_assistant` to read a specific assistant's full configuration before changing it.
- Use `vapimcp_create_assistant` to provision a new voice AI assistant, and `vapimcp_update_assistant` to change only the fields you pass — omitted fields keep their current values.
- Use `vapimcp_list_phone_numbers` and `vapimcp_get_phone_number` to find the phone number to call from.
- Use `vapimcp_create_call` to place an outbound call with a chosen assistant and phone number, then `vapimcp_get_call` to read its status, duration, and transcript.
- Use `vapimcp_create_tool` to add SMS, transfer-call, function, or API-request tools, and attach them to an assistant with `vapimcp_update_assistant`.

  **Node.js**

  ```typescript
  const toolResponse = await actions.executeTool({
    connector: 'vapimcp',
    identifier: 'user_123',
    toolName: 'vapimcp_create_call',
    toolInput: {
      assistantId: 'YOUR_ASSISTANT_ID',
      phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
      customer: { number: '+15551234567' },
    },
  });
  console.log('Call started:', toolResponse.data);
  ```

  **Python**

  ```python
  tool_response = actions.execute_tool(
      connection_name='vapimcp',
      identifier='user_123',
      tool_name='vapimcp_create_call',
      tool_input={
          "assistantId": "YOUR_ASSISTANT_ID",
          "phoneNumberId": "YOUR_PHONE_NUMBER_ID",
          "customer": {"number": "+15551234567"},
      },
  )
  print("Call started:", tool_response)
  ```

## Related

Other Communication connectors ([all 57](/agentkit/connectors/?category=communication)):

- [Gmail](/agentkit/connectors/gmail/): Scalekit connector, OAuth, 48 tools
- [Google Calendar](/agentkit/connectors/googlecalendar/): Scalekit connector, OAuth, 30 tools
- [Slack](/agentkit/connectors/slack/): Scalekit connector, OAuth, 96 tools


---

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