---
title: "MCP"
description: "Connect an MCP client to Arbol. The server URL, sign-in, the tools you see, and how answers are kept short."
---

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

# MCP

Arbol's MCP server offers the API's operations as tools to AI clients. It runs at the API's own URL, `https://api.getarbol.com`, over Streamable HTTP. Its former address, `https://mcp.getarbol.com`, redirects there.

A tool call is the REST request its operation describes, sent with your credential. The same scopes decide it and the same errors come back, so everything in [Authentication](/en/developers/authentication/) and [Concepts](/en/developers/concepts/) applies.

## Add the server to your client

Add `https://api.getarbol.com` to your client as a remote server. Each client has its own configuration file and field names, so check its documentation. A common shape:

### Sign in

```json
{
  "mcpServers": {
    "arbol": {
      "url": "https://api.getarbol.com"
    }
  }
}
```

A client that supports MCP authorization signs you in the first time it connects. See [Sign-in](#sign-in).

### API key

```json
{
  "mcpServers": {
    "arbol": {
      "url": "https://api.getarbol.com",
      "headers": {
        "Authorization": "Bearer arb_live_…"
      }
    }
  }
}
```

Use an API key for an unattended agent, or with a client that can't sign in. Give the key only the scopes the agent needs, and keep the file out of version control.

A plain `GET https://api.getarbol.com/`, as from a browser, answers the API's index rather than MCP. Clients send their MCP requests to the same URL with `POST`.

## Sign-in

Without a valid credential, the server answers `401` with a challenge that names the [protected resource metadata](/en/developers/authentication/#oauth-discovery) and the scopes its tools require:

```http
WWW-Authenticate: Bearer resource_metadata="https://api.getarbol.com/.well-known/oauth-protected-resource", scope="account:api-keys:read account:api-keys:write …"
```

1. The client reads the metadata, which names Arbol's authorization server, `https://auth.getarbol.com/`.
2. It signs you in there for the resource `https://api.getarbol.com`, with one of your organizations selected.
3. It connects again with the access token.

The token acts in the organization you selected. It holds the scopes the client asked for, as far as your roles grant them, so a client that asks for no scopes gets no tools.

> **If sign-in fails**
>
> Arbol's authorization server matches the resource exactly as the metadata gives it, `https://api.getarbol.com`, without a trailing slash, and every token must carry an organization. If your client can't complete sign-in, connect with an API key instead.

## The tools you see

The server lists only the tools your credential may use: the operation must accept your kind of caller (a person or a machine), your credential must hold one of its scopes, and an API key's restrictions must allow it. Calling a tool still goes through the same checks as REST.

Each tool is named after its operation: `account.organization.get` is the tool `account_organization_get`. Its annotations come from the operation's Effect: `readOnlyHint` for a read, `destructiveHint` for a delete, and `idempotentHint` when it's idempotent. See [Retries](/en/developers/concepts/retries/).

Not every operation is a tool. Each operation's page in the API reference names its MCP tool, or says it isn't offered on MCP; those are REST only.

## When you may use more than 40 tools

A long list is hard for a model to choose from, so when your credential may use more than 40 tools, the server lists these instead:

| Tool | What it does |
| --- | --- |
| `search_tools` | Finds the tools you may call, by what they do. |
| `run_read_tool` | Runs a tool that only reads. |
| `run_write_tool` | Runs a tool that creates or changes something. |
| `run_delete_tool` | Runs a tool that deletes something. |

A runner is listed only when you have tools with its effect. Since each effect has its own runner, a client's approval of `run_read_tool` never covers a write or a delete.

`search_tools` takes a `query` in English, such as `"list appointments"`, and optionally a `service` and a `limit` (10 by default, up to 50). Each match comes back in short: its name, effect, runner, what it does, its input as a signature and, for a read, the fields it returns. Before calling a tool whose input you don't know in full, a write above all, ask for it by `names`, up to five at a time, to get its whole input schema.

Then call the runner with the tool's name and its input. As the parameters of an MCP `tools/call` request:

```json
{
  "name": "run_read_tool",
  "arguments": {
    "name": "account_organization_get",
    "arguments": {}
  }
}
```

## Short answers

A model reads every answer in full, on every step, so read tools can answer less than REST does:

- **`fields`.** Every read tool takes `fields` besides its own input: up to 50 field names. Each record then comes back with only those fields, and always its `id`. The value never reaches the service.
- **`omittedFields`.** A list over 16 KB, asked for without `fields`, leaves out its items' largest fields, those over 512 bytes per item on average, and names them in `omittedFields`. Ask for them with `fields`, or read one record.

For example, a call to `account_api_keys_list` that asks only for each key's name and scopes:

```json
{
  "name": "account_api_keys_list",
  "arguments": { "limit": 100, "fields": ["name", "scopes"] }
}
```

REST answers are never shaped this way. One operation, [`nueva-eps.affiliations.lookup`](/api/nueva-eps/affiliations/lookup/), defines its own `fields`, which works as its reference describes.

## Errors

A refused call comes back as a tool result with `isError: true`. Its text is the same error object REST answers, with `code`, `message`, `retryable` and `data`: see [Responses and errors](/en/developers/concepts/responses-and-errors/). A tool called through the wrong runner is refused with `INVALID_INPUT`, and the error's `data.runner` names the right one.

## Integrations

Integration operations are tools too, such as `sura_appointments_create` or `adres_affiliations_lookup`, with the same input as their REST operation and the same checks: the integration active in your organization and your credential's restrictions. Some take `agentMode` to answer concise Spanish text: see [Text answers for AI agents](/en/developers/concepts/responses-and-errors/#text-answers-for-ai-agents) and, for ADRES, Sisbén and Policía Colombia, [Colombian registries](/en/developers/integrations/#colombian-registries).

Source: https://docs.getarbol.com/en/developers/mcp/index.mdx
