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

> ## Agent Instructions
> Use the public API base URL: https://api.teamfollowup.ai/api.
> Authenticate public API requests with Authorization: Bearer YOUR_API_KEY.
> Use product-owned terms: agents, calls, campaigns, contacts, phone numbers, billing, and configuration.

# MCP action tools

> Let AI agents call the TFUAI public API through a scoped remote MCP server.

TFUAI has two separate MCP interfaces. They solve different jobs.

| Interface                | URL                                        | Purpose                             |
| ------------------------ | ------------------------------------------ | ----------------------------------- |
| Documentation search MCP | `https://teamfollowupai.mintlify.site/mcp` | Search and read these docs          |
| API action MCP           | `https://api.teamfollowup.ai/api/mcp`      | Call published TFUAI API operations |

Mintlify provides the documentation search MCP. It does not turn OpenAPI
operations into callable action tools. Use the API action MCP when an agent
needs live TFUAI data.

## Connect

| Setting        | Value                                 |
| -------------- | ------------------------------------- |
| Transport      | Streamable HTTP                       |
| Server URL     | `https://api.teamfollowup.ai/api/mcp` |
| Authentication | OAuth 2.1, or a bearer API key        |

The endpoint accepts either credential. Pick by how the client runs:

* **OAuth** suits hosted assistants such as Claude, ChatGPT, and Gemini. The
  user signs in and approves the scopes in a browser, so no secret is ever
  pasted into a chat. Most clients only need the server URL.
* **API keys** suit scripts, backend jobs, and self-hosted clients where no
  person is present to approve a browser prompt.

### OAuth

Point the client at `https://api.teamfollowup.ai/api/mcp` and let it run
discovery. An unauthenticated request returns `401` with the pointer that
starts the flow:

```http theme={"dark"}
WWW-Authenticate: Bearer realm="TFUAI MCP",
  resource_metadata="https://api.teamfollowup.ai/.well-known/oauth-protected-resource/api/mcp"
```

From there the client reads the metadata, registers itself, and opens the
consent screen. The endpoints exist if you need them directly:

| Endpoint                                        | Purpose                                           |
| ----------------------------------------------- | ------------------------------------------------- |
| `/.well-known/oauth-protected-resource/api/mcp` | Which authorization server protects this endpoint |
| `/.well-known/oauth-authorization-server`       | Authorization server metadata                     |
| `/register`                                     | Dynamic client registration                       |
| `/authorize`                                    | Authorization request and consent                 |
| `/token`                                        | Token issue and refresh                           |
| `/revoke`                                       | Token revocation                                  |

What to expect during the flow:

* PKCE is required, `S256` only. A request without a code challenge is refused.
* The consent screen lists the exact scopes the client asked for. Anything the
  user does not grant is not issued.
* Access tokens last 1 hour. Refresh tokens last 30 days and rotate on every
  use, so a refresh token is only ever valid once.
* Reusing a spent refresh token or authorization code revokes that whole token
  family. This is the standard response to a stolen token, and it means the
  client must store the newest refresh token it received.

Revoke a connection at any time from the dashboard, or by calling `/revoke`.

### API keys

Send the key as a bearer token:

```http theme={"dark"}
Authorization: Bearer YOUR_API_KEY
```

Create a narrowly scoped key from the **API Keys** page in the dashboard. Do
not put a key in a prompt, repository, browser bundle, screenshot, or support
message.

Tool results can contain contact details, call records, billing data, and other
tenant information. Connect the MCP only to clients approved to receive that
data, request only the modules needed for the task, and avoid broad exports
when a narrower read answers the question.

You can verify the connection with an MCP initialize request:

```bash theme={"dark"}
curl --request POST \
  --url https://api.teamfollowup.ai/api/mcp \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Accept: application/json, text/event-stream" \
  --header "Content-Type: application/json" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": { "name": "my-agent", "version": "1.0.0" }
    }
  }'
```

The negotiated protocol version in the response can be newer than the version
in this example.

## Tool visibility

`tools/list` returns only tools that meet both conditions:

1. The operation is enabled for the current MCP release.
2. The credential carries the operation's required scope.

This applies the same way to an API key's scopes and to the scopes a user
granted an OAuth client. A module write scope also covers its matching read
scope. Public read operations can appear for any valid credential.

Filtering is not only cosmetic. A tool the credential lacks the scope for is
hidden from `tools/list` and refused if called by name.

For broad credentials, narrow the advertised catalog with a comma-separated
module filter. Module names are lowercase tag slugs:

```text theme={"dark"}
https://api.teamfollowup.ai/api/mcp?modules=contacts,calls
```

This reduces the number and size of tool definitions sent to the agent. An
unknown module returns HTTP `400` with the valid module names.

## Reads and writes

The MCP advertises every published read operation, plus the write operations
whose effect stays inside the platform. A credential with `agents:write` can
create, update and delete agents; one with `campaign_workflows:write` can edit
workflows.

Write tools carry standard MCP annotations so your client knows when to ask
before running one:

| Annotation              | Meaning                                                  |
| ----------------------- | -------------------------------------------------------- |
| `readOnlyHint: true`    | The tool only reads                                      |
| `destructiveHint: true` | The call overwrites or removes existing state            |
| `idempotentHint: true`  | Repeating the call has the same effect as making it once |

A create is annotated `destructiveHint: false`. An update or delete is
`destructiveHint: true`.

<Warning>
  Most operations do not accept an `Idempotency-Key`. If a tool call times out,
  a retry can repeat the write. Prefer reading current state back before
  retrying a create.
</Warning>

## Operations the MCP does not expose

Some published operations are deliberately absent from `tools/list`, no matter
how broad the key is. They place calls to real people, spend money, or cannot
be undone, and the consequence of a model getting one wrong does not stay
inside the platform:

| Area                                           | Why it is withheld                                                          |
| ---------------------------------------------- | --------------------------------------------------------------------------- |
| `calls:write`                                  | Places real outbound calls                                                  |
| `power_dialer:write`                           | Starts or changes live dialling of a lead list                              |
| `phone_numbers:write`, `phone_numbers:release` | Buys numbers, and releasing one is irreversible                             |
| `projects:write`, `projects:delete`            | Overwrites or destroys a project                                            |
| Clearing a contact's do-not-call flag          | Can produce a call that should not be placed. Setting the flag is available |
| Enrolling existing leads into a campaign       | Puts contacts in line to be dialled                                         |

Call these through the REST API, where a person is making the request. The
tools stay withheld rather than being scope-gated because the risk is about who
is deciding, not about what the key is allowed to do.

## Tool arguments

Tool schemas preserve the original OpenAPI parameter locations:

```json theme={"dark"}
{
  "path": {},
  "query": {},
  "headers": {},
  "body": {}
}
```

Only groups used by an operation appear in that tool's schema, and each schema
lists the groups it actually requires. A group the schema does not require can
be left out entirely rather than sent as an empty object. For example, deleting
an agent skill takes only `path`, because the optional `expectedVersion` in its
body is the sole thing a body would carry.

A contact call-history read can accept:

```json theme={"dark"}
{
  "path": {
    "phoneNumber": "+14155551234"
  },
  "query": {
    "projectName": "Riverside Clinic",
    "contactId": "contact_123"
  }
}
```

The server validates arguments before the API request. It controls the request
URL and authentication header, so an agent cannot supply an arbitrary URL or
forward arbitrary headers.

## Results

* Every operation published today answers with JSON, which returns as both MCP
  text content and structured content.
* Public API errors return tool results with `isError: true` and the original
  safe error body. The HTTP status is on the result as
  `_meta["tfuai/httpStatus"]`.
* Network failures, timeouts, and oversized responses fail as tool errors.

CSV exports and logo reads are not part of the published surface, so no tool
returns text or image content. If a module publishing either is added later, the
adapter already carries them through as MCP text and image content.

Every tool call goes through the same public REST route as a direct API call.
Credential validation, scopes, tenant access, role checks, rate limits, and
public response projections still apply.

## Common connection errors

| Result                           | Meaning                                                                                                                                                                      |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP `401` before JSON-RPC       | Missing, invalid, expired, or revoked credential. The `WWW-Authenticate` header names the authorization server, so an OAuth client can recover by refreshing or reconnecting |
| `invalid_grant` on refresh       | The refresh token was already spent. Reconnect through the consent screen                                                                                                    |
| Tool is absent from `tools/list` | Missing scope or operation not enabled for MCP                                                                                                                               |
| Tool result has HTTP `403`       | The public route rejected role, tenant, project, or scope access                                                                                                             |
| Tool result has HTTP `429`       | A public API rate limit was reached                                                                                                                                          |

Use the [Authentication](/authentication) page for scopes and key management.
