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

# MCP server

> Connect Claude, Cursor or any MCP client to your campaigns — and add prompts just by asking.

The MCP server exposes your campaigns to AI clients that speak the
[Model Context Protocol](https://modelcontextprotocol.io) — Claude, Claude
Code, Cursor, and anything else supporting **Streamable HTTP**. Instead of
writing API calls, you ask questions in plain language and the client picks the
right tool.

> *"Which of my tracked prompts lost the most visibility this month, and what
> did ChatGPT actually say?"*

It's the same data as the [External API](/api/overview), over a different
transport, authenticated with the same personal API key.

<Note>
  Like the REST API, the MCP server is **not** read-only. It includes one write
  tool, `create_prompt`, which adds tracked prompts to a campaign. Any key that
  connects to MCP can use it — see [Permissions and scope](#permissions-and-scope).
</Note>

## Before you start

You need an API key. If you already have one from the REST API it works here —
the MCP server accepts the same tokens.

<Steps>
  <Step title="Create a key">
    In the app, go to **Settings → API** and choose **Create key**. Name it
    after the client you're connecting, e.g. `Claude Desktop`.
  </Step>

  <Step title="Copy it once">
    The full key is shown **only once**, right after creation. You can't view it
    again, only revoke it.
  </Step>

  <Step title="Copy your server URL">
    The same page shows your **MCP Server URL** under the **MCP SERVER**
    section:

    ```
    https://app.theaitracker.com/mcp
    ```
  </Step>
</Steps>

<Warning>
  Treat the key like a password. It grants read access to every campaign you
  own and the ability to add prompts to them.
</Warning>

## Connect a client

The server is a **Streamable HTTP** MCP server and supports two ways to
authenticate:

* **OAuth** — you click "Connect", sign in, and approve access. No key to copy.
  This is what browser-based clients such as claude.ai use, and it is the only
  option there, since they cannot send a static header.
* **Bearer token** — an API key sent as `Authorization: Bearer <your-key>`.
  Used by clients you configure yourself: Claude Code, Claude Desktop, Cursor.

<Tabs>
  <Tab title="Claude.ai (OAuth)">
    Go to **Settings → Connectors → Add custom connector** and enter the MCP
    server URL:

    ```
    https://app.theaitracker.com/mcp
    ```

    Leave the client id and secret blank — the connector registers itself
    automatically. You'll be sent to AI Tracker to sign in (if you aren't
    already) and asked to approve access, then returned to Claude with the
    connection live.

    <Note>
      No API key is involved here. If you're prompted for one, you're on the
      bearer-token path — clear the field and use the URL alone.
    </Note>
  </Tab>

  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add --transport http ai-tracker https://app.theaitracker.com/mcp \
      --header "Authorization: Bearer <your-key>"
    ```

    Verify it connected:

    ```bash theme={null}
    claude mcp list
    ```
  </Tab>

  <Tab title="Claude Desktop">
    Open **Settings → Connectors → Add custom connector**, then enter the MCP
    server URL and your bearer token.

    If your build uses a config file instead, add this to
    `claude_desktop_config.json` and restart the app:

    ```json theme={null}
    {
      "mcpServers": {
        "ai-tracker": {
          "type": "http",
          "url": "https://app.theaitracker.com/mcp",
          "headers": {
            "Authorization": "Bearer <your-key>"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Cursor">
    Add this to `.cursor/mcp.json` in your project (or the global
    `~/.cursor/mcp.json`), then reload:

    ```json theme={null}
    {
      "mcpServers": {
        "ai-tracker": {
          "url": "https://app.theaitracker.com/mcp",
          "headers": {
            "Authorization": "Bearer <your-key>"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Raw HTTP">
    Useful for debugging — this lists the available tools:

    ```bash theme={null}
    curl -X POST https://app.theaitracker.com/mcp \
      -H "Authorization: Bearer <your-key>" \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
    ```

    A missing or invalid key returns `401 Unauthorized`.
  </Tab>
</Tabs>

## Available tools

Start with `list_campaigns` to get a campaign `uuid`; every other tool takes
one.

| Tool | What it does |
| - | - |
| `list_campaigns` | Your campaigns — name, domain, platforms, status |
| `get_campaign` | One campaign by uuid, with its 30-day visibility summary |
| `get_visibility` | Overall score and trend for the last N days, plus a per-platform breakdown |
| `list_prompts` | Tracked prompts for a campaign, with each prompt's run count |
| `create_prompt` | **Writes.** Adds one or more tracked prompts to a campaign |
| `get_prompt_runs` | Raw per-platform runs — the actual AI answers and the sources cited |
| `get_sentiment` | Brand sentiment records and their mentions across AI platforms |
| `get_traffic` | Traffic — sessions by day, source and medium |

### Adding prompts

`create_prompt` accepts a single prompt or a list. To add several at once, put
one per line in `text`; numbered and bulleted markers are stripped for you, so
you can paste a list straight out of a chat:

```
1. What are the best running shoes for flat feet?
2. Which running shoe brands last longest?
3. Cheapest cushioned running shoes?
```

`topic`, `location_code` and `tags` apply to every prompt in the call.

<ParamField path="topic" type="string" required>
  Topic to file the prompts under. Matched case-insensitively against the
  campaign's existing topics; **created if there's no match** — so check your
  spelling, or you'll end up with a near-duplicate topic.
</ParamField>

<ParamField path="location_code" type="string" default="us">
  Two-letter market code the prompts are tracked in, e.g. `us`, `gb`.
</ParamField>

<ParamField path="tags" type="string[]">
  Up to 8 tags, max 24 characters each. Lowercased on save.
</ParamField>

The same limits as the app's **Add prompt** dialog apply:

* **2,000 characters** per prompt. Over-long ones are skipped and reported in
  the response; the rest of the batch is still created.
* **50 prompts** per call. Over that, the call is rejected and nothing is
  created.
* **The active-prompt cap.** A campaign only tracks a limited number of
  *active* prompts. Anything past the cap is saved but left **inactive** — it
  won't run until a slot frees up. The response returns `remaining_slots` so
  you can see where you stand.

<Note>
  A prompt that itself spans multiple lines would be split by the
  line-per-prompt rule. Pass a JSON array of strings instead — array elements
  are never split.
</Note>

## Permissions and scope

Every tool resolves campaigns through the key owner's own campaigns, so a key
can only ever reach data belonging to the user who created it. There is no way
to widen that scope, and no tool that reaches another account's data.

Revoking a key in **Settings → API** immediately cuts off any client using it.

## Rate limits

Two throttles apply, in this order:

| Limit | Scope |
| - | - |
| 120 requests/minute | Per IP, before authentication |
| 60 requests/minute | Per user, after authentication |

Exceeding either returns `429 Too Many Requests`. An AI client exploring your
data can be chatty — if you hit this, it's usually a client looping over
prompt runs rather than a genuine need for more throughput.

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    The key is missing, mistyped, or revoked. Check the header is exactly
    `Authorization: Bearer <your-key>` and that the key still appears in
    **Settings → API**. Keys can't be viewed after creation — if you've lost
    it, create a new one and revoke the old.
  </Accordion>

  <Accordion title="The client connects but lists no tools">
    Confirm the client is configured for **Streamable HTTP**, not stdio or SSE.
    A stdio-only entry connects to nothing.
  </Accordion>

  <Accordion title="'Campaign not found or not accessible'">
    The `campaign_uuid` doesn't belong to your account, or it's wrong. Call
    `list_campaigns` to get valid uuids — the tools deliberately don't
    distinguish "doesn't exist" from "isn't yours".
  </Accordion>

  <Accordion title="Prompts were added but aren't running">
    They were saved inactive because the campaign is at its active-prompt
    limit. Check `remaining_slots` in the response, then deactivate an existing
    prompt to free a slot. See
    [Managing prompts](/guides/prompts#the-active-prompt-cap).
  </Accordion>

  <Accordion title="A browser-based client says the redirect domain isn't permitted">
    Redirect URIs are restricted to an allow-list, which is what stops a rogue
    client registering an attacker-controlled callback. If you're connecting a
    legitimate client that isn't on it,
    [contact support](https://theaitracker.com/contact) with the client name.
  </Accordion>

  <Accordion title="The tools return no data at all">
    Check the campaign actually has results yet. A brand-new campaign has no
    prompt runs until its first daily run completes, and `get_traffic` returns
    nothing until an [integration is connected](/integrations/overview).
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.