> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# MCP

> Connect any MCP client to Dial — hosted over OAuth, or local over stdio with your saved CLI key. Same tools, two transports.

Dial speaks the [Model Context Protocol](https://modelcontextprotocol.io) two ways, so an
agent can reach Dial's capabilities as MCP tools without writing any HTTP code:

* **Local (Recommended)** — `npx @getdial/cli mcp`, a stdio server you run on your own
  machine. It reuses the API key already saved by
  [`dial auth verify-otp`](/documentation/cli/install-and-onboarding), and `npx` runs it
  without a global install. Use it when the agent runs on the same machine as your Dial
  setup — for example, [Claude Code](/integrations/agent-clients/coding-agent/claude-code).
* **Remote** — a hosted server at `https://getdial.ai/mcp`. Point any MCP client that
  supports remote servers at that URL and authorize in the browser — no install, no API key
  to copy. Use it when the agent runs off your machine, like a web or desktop client — for
  example, Claude Chat or Claude Cowork.

The remote server connects an **existing** Dial account. If you don't have one yet, the
browser authorization walks you through creating it — including verifying a phone number —
before the connection completes.

Both expose the **same operational tools under the same names** (`send_message`,
`place_call`, `wait_for_event`, …), each mirroring a `dial` CLI command. The Local server is
a strict **superset**: everything Remote has, plus enhanced inbound capabilities the hosted
server can't offer (a persistent listen daemon, local event fan-out, and onboarding).

## Which one?

|                        | Local                                                 | Remote                              |
| ---------------------- | ----------------------------------------------------- | ----------------------------------- |
| **Command / endpoint** | `npx @getdial/cli mcp`                                | `https://getdial.ai/mcp`            |
| **Transport**          | stdio                                                 | Streamable HTTP                     |
| **Auth**               | Saved CLI key (`~/.local/share/dial/auth.v1.json`)    | OAuth 2.1, browser consent          |
| **Install**            | None — `npx` fetches the CLI on demand                | None — hosted                       |
| **Where it runs**      | The machine that owns the Dial setup                  | Anywhere — agent can be off-machine |
| **Tool surface**       | Operational tools **+ enhanced inbound capabilities** | Operational tools                   |

Pick **Local** when the agent runs on the same machine that owns the Dial setup and you want
onboarding, the background listen daemon, or local event fan-out. Pick **Remote** when you
want browser auth and the agent runs off-machine.

## Connect

Add Dial as an MCP server in your client. The two transports take different config — both
expose the same tools:

```json title="MCP client config (Local)"
{
  "mcpServers": {
    "dial": {
      "command": "npx",
      "args": ["-y", "@getdial/cli", "mcp"]
    }
  }
}
```

```json title="MCP client config (Remote)"
{
  "mcpServers": {
    "dial": {
      "url": "https://getdial.ai/mcp"
    }
  }
}
```

**Local** runs the CLI's stdio server through `npx` — no global install. It authenticates
with the key already at `~/.local/share/dial/auth.v1.json` (no OAuth, no config), so install
the CLI and sign in once first (see
[Install & onboarding](/documentation/cli/install-and-onboarding)) — or let the `auth_login`,
`auth_register_number`, and `auth_verify_otp` tools bootstrap a fresh machine from inside the
agent. The server speaks JSON-RPC on stdout and logs to stderr.

**Remote** points at the hosted server over **Streamable HTTP** at that single endpoint —
there is no SSE or stdio variant. On first connect the client opens a browser to authorize:

### The client requests access

It registers itself with Dial automatically (OAuth 2.1 dynamic client registration) and
opens Dial's consent page.

### You sign in

If you're signed out, Dial emails you a one-time code. If you don't have a Dial account
yet, a new one is created for you — with no phone number until you ask for one.

### You grant access

Approve the request on the consent screen, and Dial issues the client an access token
scoped to your account.

Tokens are scoped per account: a tool only ever sees your own numbers, messages, and calls.

## Tools

The operational tools are identical on both servers; the enhanced inbound capabilities run
only under the local server. See the [CLI command reference](/documentation/cli/commands) for
the underlying semantics.

| Tool                    | Purpose                                                                                  | Remote | Local |
| ----------------------- | ---------------------------------------------------------------------------------------- | :----: | :---: |
| `get_account_status`    | Account and phone-number readiness                                                       |    ✓   |   ✓   |
| `list_numbers`          | List your phone numbers                                                                  |    ✓   |   ✓   |
| `purchase_number`       | Provision an additional number                                                           |    ✓   |   ✓   |
| `set_number_properties` | Update a number's properties (inbound instruction, language, voice, nickname)            |    ✓   |   ✓   |
| `send_message`          | Send a message — to a number or a group, on the number's default channel or one you name |    ✓   |   ✓   |
| `list_messages`         | List recent messages, optionally filtered to one group                                   |    ✓   |   ✓   |
| `list_groups`           | List the [group conversations](/documentation/capabilities/groups) your lines are in     |    ✓   |   ✓   |
| `start_typing`          | Show a typing indicator from one of your numbers                                         |    ✓   |   ✓   |
| `stop_typing`           | Clear it                                                                                 |    ✓   |   ✓   |
| `place_call`            | Place an outbound AI voice call                                                          |    ✓   |   ✓   |
| `list_calls`            | List recent calls                                                                        |    ✓   |   ✓   |
| `get_call`              | Fetch one call (status, duration, transcript)                                            |    ✓   |   ✓   |
| `wait_for_event`        | Block until a matching account event arrives                                             |    ✓   |   ✓   |
| `auth_login`            | Start signup or sign-in (email OTP)                                                      |    —   |   ✓   |
| `auth_verify_otp`       | Verify an email or SMS code                                                              |    —   |   ✓   |
| `auth_register_number`  | Send an SMS code to the owner's phone number                                             |    —   |   ✓   |
| `listen_install`        | Install the background event daemon                                                      |    —   |   ✓   |
| `listen_uninstall`      | Remove the daemon                                                                        |    —   |   ✓   |
| `listen_status`         | Daemon health                                                                            |    —   |   ✓   |
| `add_url_target`        | Fan events to a loopback URL                                                             |    —   |   ✓   |
| `add_command_target`    | Fan events to a spawned handler                                                          |    —   |   ✓   |
| `remove_local_target`   | Remove a local target                                                                    |    —   |   ✓   |
| `list_local_targets`    | List local targets                                                                       |    —   |   ✓   |

When a tool that sends from a number omits `fromNumberId`, Dial uses your primary number. A `send_message` addressed with `groupId` is the exception: a group already belongs to one of your lines, so Dial sends from that one and never consults the primary number.

A couple of tools behave slightly differently per server: `wait_for_event` reads the local
[listen service](/documentation/cli/listen-service) log when the daemon is running (and falls
back to the REST API otherwise) on the Local server, while the Remote server always long-polls
the REST API; `get_account_status` on the Local server reflects the local `doctor` view of the
machine.

## Enhanced inbound capabilities

Running on your machine, the local server can handle inbound events in ways the hosted server
fundamentally can't — it keeps a persistent listener alive and routes inbound calls and
messages straight to your machine:

* **The [listen service](/documentation/cli/listen-service)** — an always-on background daemon
  that captures inbound calls and messages even while no agent is connected.
* **[Local-target](/documentation/cli/commands#local-target-add-url) fan-out** — deliver inbound
  events to a loopback URL or spawn a local handler as they arrive.
* **Sign-up and onboarding** — bootstrap a fresh machine from inside the agent (the hosted
  server replaces these with its browser consent flow).

The hosted server can't reach your machine, so these are exposed only by the local server. For
any of them, run `npx @getdial/cli mcp` (or the CLI) on the machine that needs them.