> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anycrm.anyreach.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview & Setup

> Connecting an MCP client (Claude Code, Claude Desktop, or your own agent) to the AnyCRM backend

AnyCRM exposes a [Model Context Protocol](https://modelcontextprotocol.io) server at **`/mcp`**, on the same origin and port as the REST API. It's a tool-calling surface over the same data — every tool enforces the same [scopes](/authentication#scopes) as the equivalent REST endpoint, isolated to the same organization by the same row-level security. If you're wiring up an agent rather than a script, MCP is usually the more convenient integration point; if you're calling the API directly from code, use the [REST reference](/api-reference/contacts/list-contacts) instead.

<Note>MCP and the REST API are two views of the same backend, not two different products. A tool call and the equivalent `curl` request run through the same authorization checks and hit the same database rows.</Note>

## Transport

The server speaks **streamable HTTP** (not stdio, not SSE) and is stateless — there's no session handshake or sticky routing to worry about; any request can be served by any backend process. The endpoint is:

```
https://crm-api.anyreach.ai/mcp
```

## Connect with Claude Code

Create an **organization API key** (`ak_…`) — see [Create an organization API key](/api-reference/pats/create-org-key) — then register the server:

```bash theme={null}
claude mcp add --transport http anycrm https://crm-api.anyreach.ai/mcp \
  --header "Authorization: Bearer ak_..."
```

The key is shown **exactly once**, at creation — only an Argon2id hash is stored server-side, so a lost key can't be recovered. Delete it and create a new one if that happens.

### Using a personal access token instead

A user personal access token (`pat_…`) also works, but it isn't bound to one organization — you must tell the server which org it's acting for on every connection with an `X-Anyreach-Org` header:

```bash theme={null}
claude mcp add --transport http anycrm https://crm-api.anyreach.ai/mcp \
  --header "Authorization: Bearer pat_..." \
  --header "X-Anyreach-Org: <logto-organization-id>"
```

Omit the header and the connection is rejected outright — a `pat_` credential is refused before any tool call is attempted if there's no org context to run it in. Because a `pat_` token is valid for every organization its owner belongs to, **`ak_` is the better default for an unattended agent**: an org API key's organization is a fixed column on its own database row, so nothing the client sends can move it. A `pat_` credential's org, by contrast, is whatever the client claims in that header on that request — Logto still refuses to mint a token for an org the user isn't a member of, but the token doesn't have a single, fixed home the way an `ak_` key does.

To disconnect: `claude mcp remove anycrm`.

## Connect with another MCP client

Any client that supports the streamable-HTTP transport with custom headers works the same way — point it at `https://crm-api.anyreach.ai/mcp` with an `Authorization: Bearer ak_...` header (and `X-Anyreach-Org` if you're using a `pat_` token instead). There's no OAuth discovery flow to configure: the server expects a bearer token handed to it directly, not one discovered through a protected-resource metadata endpoint.

## What the server tells a connecting client

On `initialize`, the server describes itself with a short system-level brief that orients a model to AnyCRM's data model:

> AnyCRM — a B2B sales CRM. Accounts are companies, deals are opportunities on an account, and contacts are people. Contacts use a single funnel stage: `target` (added, no reply) → `lead` (responded) → `contact` (converted). There is no separate "lead" record — filter contacts by stage instead. Prefer resolving records by name; tools accept either a name or a UUID and will tell you when a name is ambiguous rather than guessing.

That last point matters operationally: most tools accept a plain name in place of a UUID and resolve it server-side, refusing to guess if the name is ambiguous — see [Name and ID resolution](/mcp/safety-and-errors#name-and-id-resolution).

## Configuration reference

These are deployment-level settings — you can't change them from a client, but they explain what a given AnyCRM deployment will and won't let an MCP client do:

| Variable                | Default                   | Effect                                                                                                                                                                               |
| ----------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `MCP_ALLOW_WRITE_TOOLS` | `true`                    | When `false`, every write tool (create/update/archive/delete) is never registered — the server becomes read-only, and those tools simply don't appear in the tool list.              |
| `MCP_ALLOW_COST_TOOLS`  | `true`                    | When `false` (or when `MCP_ALLOW_WRITE_TOOLS` is `false`), tools that spend real money on external providers (Customer Intelligence runs and regenerations) are never registered.    |
| `MCP_TOOL_TIMEOUT_S`    | `20`                      | Per-call budget. A slow dependency returns a structured `timeout` error well before typical MCP client timeouts (\~60s) instead of leaving the connection hanging.                   |
| `MCP_MAX_RESULT_BYTES`  | `49152` (48 KiB)          | A result over this size is withheld and replaced with a `too_large` error rather than serialized — narrow your filter or lower `limit` rather than expecting a partial payload.      |
| `MCP_ALLOWED_HOSTS`     | `localhost:*,127.0.0.1:*` | DNS-rebinding protection allowlist. Must include the real public hostname in any non-local deployment — an unlisted `Host` header gets a bare `421` with no MCP code running at all. |

There is no `MCP_ENABLED` switch — the `/mcp` mount itself is always present; these variables only shape which tools it advertises.

See [Available Tools](/mcp/tools) for the full tool inventory, or [Safety, Scopes & Errors](/mcp/safety-and-errors) for how permissions, idempotency, and error reporting work.
