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

# MCP Integration

> Connect Searchable to Claude.ai, Claude Desktop, Cursor, and other MCP-compatible assistants to query your AI visibility, site audits, and content.

## What is MCP?

The **Model Context Protocol (MCP)** is an open standard that lets AI assistants connect to external tools and data sources. Searchable's MCP server lets you ask AI assistants questions about your AI visibility, site audits, and content — without leaving the assistant.

Supported clients:

* **Claude.ai** (web and mobile) — add as a connector
* **ChatGPT** — via developer-mode connectors
* **Claude Desktop** and **Claude Code**
* **Cursor**
* **Windsurf** and any other MCP-compatible client

<Info>
  Ask questions like *"What's my brand's visibility score on ChatGPT?"* or *"What critical AEO issues does my site have?"* and the assistant will query Searchable for live data.
</Info>

<Note>
  **Plan requirement:** MCP integration requires a paid Searchable plan. Both connection methods — signing in with OAuth and API keys — are unavailable on the Free plan.
</Note>

## How authentication works

The Searchable MCP server uses **OAuth 2.1 with PKCE and Dynamic Client Registration**. You do **not** paste an API key into your MCP client's config — you sign in and approve access, just like connecting any other app:

1. You add the server URL to your client (`https://mcp.searchable.com/mcp`).
2. On first use, the client opens Searchable in your browser and asks you to **log in** (or reuses your existing session).
3. A **consent screen** shows which application is connecting and lets you choose:
   * **Which projects** it can access — pick specific ones, or leave all selected (all also covers projects you create later).
   * **Read-only** (default) or **Read & write** access.
4. You click **Authorize**. Your client receives an OAuth access token scoped to exactly what you approved and uses it for subsequent requests.

The token can never exceed what you granted on the consent screen — a read-only, single-project grant stays read-only and single-project.

<Warning>
  Only connect the Searchable MCP from trusted clients. Grant the narrowest access you need — read-only, and only the projects the assistant should see.
</Warning>

## Setup

### Step 1: Add the server to your client

<Tabs>
  <Tab title="Claude.ai">
    1. Open Claude.ai → **Settings → Connectors**.
    2. Click **Add custom connector**.
    3. Enter URL: `https://mcp.searchable.com/mcp`
    4. Claude opens the Searchable sign-in and consent page — continue with Step 2.
  </Tab>

  <Tab title="ChatGPT">
    ChatGPT connects through developer-mode connectors (available on ChatGPT Plus and Pro):

    1. Open ChatGPT → **Settings → Apps & Connectors → Advanced settings** and enable **Developer mode**.
    2. Back in **Apps & Connectors**, click **Create** to add a connector.
    3. Enter URL: `https://mcp.searchable.com/mcp` and choose **OAuth** authentication.
    4. ChatGPT opens the Searchable sign-in and consent page — continue with Step 2.

    In a chat, enable the Searchable connector from the composer's tools menu, then ask away.
  </Tab>

  <Tab title="Claude Code">
    Add the server from your terminal:

    ```bash theme={null}
    claude mcp add searchable --transport http https://mcp.searchable.com/mcp
    ```

    Then inside a session run `/mcp`, pick **searchable → Authenticate** — your browser opens the Searchable sign-in and consent page. Continue with Step 2.
  </Tab>

  <Tab title="Claude Desktop">
    Add to `~/.claude/mcp.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "searchable": {
          "url": "https://mcp.searchable.com/mcp"
        }
      }
    }
    ```

    Restart Claude Desktop. On first use it opens the Searchable sign-in and consent page in your browser — continue with Step 2.
  </Tab>

  <Tab title="Cursor">
    Click to install with one step — Cursor opens, shows the server, and you confirm:

    <a href="cursor://anysphere.cursor-deeplink/mcp/install?name=searchable&config=eyJ1cmwiOiJodHRwczovL21jcC5zZWFyY2hhYmxlLmNvbS9tY3AifQ==">
      <img className="block dark:hidden" src="https://cursor.com/deeplink/mcp-install-dark.png" alt="Add searchable MCP server to Cursor" style={{ maxHeight: 32 }} noZoom />

      <img className="hidden dark:block" src="https://cursor.com/deeplink/mcp-install-light.png" alt="Add searchable MCP server to Cursor" style={{ maxHeight: 32 }} noZoom />
    </a>

    Or add manually to `.cursor/mcp.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "searchable": {
          "url": "https://mcp.searchable.com/mcp"
        }
      }
    }
    ```

    Either way, Cursor discovers OAuth automatically (the server supports Dynamic Client Registration) — no manual `auth` block needed. On first use it opens the Searchable sign-in and consent page in your browser — continue with Step 2.
  </Tab>

  <Tab title="Windsurf">
    Add to your Windsurf MCP configuration:

    ```json theme={null}
    {
      "mcpServers": {
        "searchable": {
          "url": "https://mcp.searchable.com/mcp"
        }
      }
    }
    ```
  </Tab>
</Tabs>

### Step 2: Log in and authorize

The first time your client connects, Searchable opens in your browser:

1. **Log in** to Searchable (or continue with your existing session).
2. On the **consent screen**, choose which projects the client may access and whether it gets **Read-only** (default) or **Read & write** access.
3. Click **Authorize**. Your browser returns to the client, now connected — no API key to copy or paste.

<Note>
  Your login is the identity for this flow. To connect a script or a client that only accepts a static bearer token, use the legacy API-key path below instead.
</Note>

### Step 3: Verify the connection

Once connected, ask:

```
List my Searchable projects
```

You should see a list of your projects with their names and domains.

### Connect with an API key (legacy)

The OAuth login flow above is the recommended path for interactive MCP clients. For scripts, headless clients, or any client that only accepts a static bearer token, a Searchable **API key** works as a bearer token directly — the same `sea_` key the [REST API](/advanced/api-usage) accepts.

<Steps>
  <Step title="Create an API key">
    In **Settings → Workspace → Integrations**, click **Create API Key**, name it, and copy the key (starts with `sea_`). Store it securely — you won't see it again. A key can be scoped to a single project and to read or read-and-write, mirroring the consent options above.
  </Step>

  <Step title="Send it as a bearer token">
    Configure your client to send `Authorization: Bearer sea_...` on every request to `https://mcp.searchable.com/mcp`. No login or consent screen is involved on this path.
  </Step>
</Steps>

## Available tools

The Searchable MCP exposes **22 primary tools** — 19 read-only and 3 write. Every read tool (and every deprecated alias below) is annotated `readOnlyHint: true`. Every tool that operates on a project takes a required `projectId` (get IDs from `list_projects`), and every read tool except `get_article` also accepts an optional `response_format` — `"concise"` (default, summary + capped rows) or `"detailed"` (fuller rows, same shape).

<Note>
  Write actions **are** MCP tools too: `generate_report`, `trigger_audit`, and `refresh_sitemap` are available to keys/grants with the **write** scope, and each requires an explicit `confirm: true` argument — without it the tool returns a dry-run preview and changes nothing. The REST equivalents (e.g. `POST /api/mcp/projects/{projectId}/reports`) remain available; see [Advanced API Usage](/advanced/api-usage).
</Note>

### Projects

<CardGroup cols={2}>
  <Card title="list_projects" icon="folder">
    List all projects this connection can access — names, domains, and IDs. Call this FIRST: every other tool needs a `projectId`.

    **Parameters:** `response_format` (optional)
  </Card>
</CardGroup>

### Visibility & share of voice

<CardGroup cols={2}>
  <Card title="get_visibility" icon="chart-line">
    AI visibility for a project. `group_by` selects the view: `summary` (overall score + mention rate), `platform` (per ChatGPT/Claude/Gemini/Perplexity breakdown), `topic` (per topic-area category), `prompt` (per-prompt breakdown, paginated), or `location` (per country/city). `platform`/`topicId` filters only apply to `group_by=prompt|location`. An interactive Visibility Snapshot card also renders automatically beside the answer on Apps-capable clients — see below.

    **Parameters:** `projectId` (required), `group_by` (`"summary"` | `"platform"` | `"topic"` | `"prompt"` | `"location"`, default summary), `days` (default 30; max 365, or 180 for `group_by=prompt`), `unbranded`, `branded`, `platform`, `topicId`, `limit` (`group_by=prompt`, default 100, max 500), `offset` (`group_by=prompt`), `country`, `locationId` (all optional except `projectId`)
  </Card>

  <Card title="get_visibility_history" icon="timeline">
    Historical AI-visibility time series — per-report score, mentions, citations, and an improving/declining/stable trend. Useful for uplift and before/after analysis.

    **Parameters:** `projectId` (required), `days` (default 90, max 365), `unbranded`, `branded` (all optional except `projectId`)
  </Card>

  <Card title="get_share_of_voice" icon="chart-pie">
    Brand vs competitor share of voice — mention-share percentage and rank among all tracked entities, plus each entity's day-over-day (today vs yesterday) point change. `mentions`/`citations` aren't part of this view (mirrors the in-app Share of Voice sheet) — use `get_competitors` for those.

    **Parameters:** `projectId` (required), `days` (default 30, max 365), `platform`, `topicId`, `unbranded`, `branded`, `country`, `locationId` (all optional except `projectId`)
  </Card>
</CardGroup>

### Competitors

<CardGroup cols={2}>
  <Card title="get_competitors" icon="users">
    The project's real/tracked competitors (list, sorted by mention volume) — share of voice, all-time mention count, and sentiment score. Pass `competitorId` to get one competitor's full detail instead: per-day history plus up to 10 recent prompts it was mentioned in. `sov`/`sentimentScore` honor the filters; the list view's `mentions` is all-time and ignores them. Detail carries two distinct metrics: `citations` (inline citations on responses mentioning the competitor) vs `history[].domainSources` (source URLs — pages used for generation, not inline citations — on the competitor's own domain).

    **Parameters:** `projectId` (required), `competitorId` (optional — switches to detail view), `days` (default 30, max 365), `platform`, `topicId`, `unbranded`, `branded`, `country`, `locationId`, `limit` (list view, default 20, max 100), `offset` (list view) (all optional except `projectId`)
  </Card>
</CardGroup>

### Sources & citations

<CardGroup cols={2}>
  <Card title="search_sources" icon="globe">
    Top cited source domains from AI answers — rank, citation counts, usage %, models, and top content types. Paginated and sortable. Use to find which external sites AI models cite most; drill in with `get_source_detail`.

    **Parameters:** `projectId` (required), `sort` (e.g. `"-citations"`), `limit` (default 20, max 100), `offset`, `days`, `platform`, `topicId`, `sourceType`, `unbranded`, `branded`, `country`, `locationId`, `response_format` (all optional except `projectId`)
  </Card>

  <Card title="get_source_detail" icon="building">
    Drill into cited sources. `level="domain"` (+ `domain`): domain summary, or `include="urls"` (cited URLs on it) / `include="responses"` (AI responses citing it). `level="url"`: with `url` → single-page citation analytics, or `include="content"` → cached page markdown + entity mentions (never triggers a live scrape); without `url` → all cited URLs across the project (optionally filtered by `contentType`).

    **Parameters:** `projectId` (required), `level` (`"domain"` | `"url"`, default domain), `include` (`"urls"` | `"responses"` | `"content"`), `domain` (required for `level=domain`), `url` (`level=url`), `contentType`, `limit`, `offset`, `cursor`, `days`, `platform`, `topicId`, `sourceType`, `unbranded`, `branded`, `country`, `locationId` (all optional except `projectId`)
  </Card>

  <Card title="get_source_trends" icon="arrow-trend-up">
    Source distributions and trends. `breakdown="content-types"` (Blog/Product/How-to citation rates), `"source-types"` (editorial/social/forum share), `"article-types"` (URL-count breakdown), or `"trend"` (citation time-series; `group="brand"|"competitors"|"top-domains"`).

    **Parameters:** `projectId` (required), `breakdown` (`"content-types"` | `"source-types"` | `"article-types"` | `"trend"`, default trend), `group` (`breakdown=trend` only: `"brand"` | `"competitors"` | `"top-domains"`, default top-domains), `days`, `platform`, `topicId`, `sourceType`, `unbranded`, `branded`, `country`, `locationId` (all optional except `projectId`)
  </Card>
</CardGroup>

### Sentiment

<CardGroup cols={2}>
  <Card title="get_sentiment" icon="face-smile">
    Brand sentiment across AI platforms. `view="summary"` (default) = overall score + positive/neutral/negative split + per-platform breakdown; `view="history"` = daily trend; `view="competitors"` = head-to-head sentiment vs competitors.

    **Parameters:** `projectId` (required), `view` (`"summary"` | `"history"` | `"competitors"`, default summary), `days` (default 30, or 90 for history; max 365), `platform`, `topicId`, `limit` (`view=competitors`, default 10, max 50), `unbranded`, `branded`, `country`, `locationId` (all optional except `projectId`)
  </Card>
</CardGroup>

### Query fanout

<CardGroup cols={2}>
  <Card title="get_query_fanout" icon="magnifying-glass">
    The sub-queries AI models generate when answering tracked prompts. Without `prompt_id`: the project aggregate (most frequent fanout queries, per-prompt counts, per-model stats; paginated). With `prompt_id`: every deduped sub-query for that one prompt, with per-query frequency and query type. Paid feature — returns `plan_upgrade_required` if not entitled.

    **Parameters:** `projectId` (required), `prompt_id` (optional — note the snake\_case; omit for the project aggregate), `days` (default 30, max 180), `platform`, `topicId`, `unbranded`, `branded`, `limit` (aggregate, default 50, max 50), `offset` (aggregate), `topQueriesLimit` (aggregate, default 50, max 200) (all optional except `projectId`)
  </Card>
</CardGroup>

### Prompt answers

<CardGroup cols={2}>
  <Card title="get_prompt_answers" icon="comments">
    Raw, per-response AI-answer data for one prompt (Profound-parity) — platform, response date, response text, whether the brand was mentioned, competitors mentioned, and the source URLs the engine consulted (`sources[]` — pages used for generation, not inline citations), one entry per AI response. Not an aggregate — use `get_visibility` or `get_share_of_voice` for scores/rankings. Response text is hard-truncated at 2000 characters server-side; the markdown table shows a short snippet (120 characters, 500 in `detailed` format).

    **Parameters:** `projectId` (required), `promptId` (required — note the camelCase, unlike `get_query_fanout`'s `prompt_id`), `days` (default 30, max 365), `platform`, `limit` (default 10, max 50) (all optional except `projectId` and `promptId`)
  </Card>
</CardGroup>

### Site health & audits

<CardGroup cols={2}>
  <Card title="get_site_health" icon="heart-pulse">
    Technical + AEO site health. `view="audits"` (default) = per-page technical/AEO scores + averages; `view="issues"` = issues grouped by severity (filter `status`); `view="pages"` = monitored pages + open-issue counts; `view="issue_details"` = issues grouped by type with fix guidance (filter `issueType`).

    **Parameters:** `projectId` (required), `view` (`"audits"` | `"issues"` | `"pages"` | `"issue_details"`, default audits), `status` (`view=issues`: `"open"` | `"resolved"` | `"all"`, default open), `issueType` (`view=issue_details`: `"technical"` | `"content"`), `includeIssues` (`view=audits`, boolean), `limit` (`view=issues`, default 1000, max 5000), `offset` (`view=issues`) (all optional except `projectId`)
  </Card>
</CardGroup>

### Content & articles

<CardGroup cols={2}>
  <Card title="list_articles" icon="newspaper">
    List articles / content pieces for a project (merges content-v2 + legacy). Shows title, status, type, word count, and source.

    **Parameters:** `projectId` (required), `status` (`"draft"` | `"published"` | `"editing"` | `"all"`, default all), `limit` (default 50, max 100) (all optional except `projectId`)
  </Card>

  <Card title="get_article" icon="file-lines">
    Full article content — HTML/markdown body, outline, FAQs, images, schema markup, internal/external links, and all metadata.

    **Parameters:** `articleId` (required)
  </Card>
</CardGroup>

### Opportunities

<CardGroup cols={2}>
  <Card title="get_opportunities" icon="lightbulb">
    Actionable opportunities Searchable surfaced for the project — prioritized fix / write / audit suggestions derived from visibility, sentiment, sources, traffic, prompts, site health, and articles. Returned in the product's priority order (status, then impact, then newest). Defaults to active opportunities; blocked for active pitch projects.

    **Parameters:** `projectId` (required), `status` (`"active"` | `"completed"` | `"dismissed"` | `"auto_resolved"`, default active only), `includeResolved`, `source` (e.g. `"visibility"`, `"sentiment"`, `"sources"`, `"traffic"`, `"prompts"`, `"site_health"`, `"articles"`), `impact` (`"critical"` | `"high"` | `"medium"` | `"low"`), `limit` (default 100, max 500), `offset` (all optional except `projectId`)
  </Card>
</CardGroup>

### GA4 / Traffic

<Note>
  This tool requires a linked GA4 property. When the project has none, the backing endpoint returns a `409` error with `{ code: "ga4_not_connected", message, howToFix }` — the `howToFix` field points at **Settings → Integrations** in Searchable, where you can connect GA4 and then retry.
</Note>

<CardGroup cols={2}>
  <Card title="get_ga4_traffic" icon="robot">
    Google Analytics 4 website traffic. `report="ai_referrals"` (default; per-LLM-host AI Source Visitors from ChatGPT/Copilot/Gemini/Perplexity/DeepSeek and more — use for AI-referral attribution), `"trend"` (daily users/sessions/pageviews), `"top_pages"` (top landing pages by sessions), or `"sources"` (channel-group + source breakdown).

    **Parameters:** `projectId` (required), `report` (`"ai_referrals"` | `"trend"` | `"top_pages"` | `"sources"`, default ai\_referrals), `weeks` (default 12, max 52), `limit` (`top_pages`/`sources`, default 20, max 100) (all optional except `projectId`)
  </Card>
</CardGroup>

### Search Console (GSC)

<Note>
  This tool requires a linked Google Search Console site. When the project has none, the backing endpoint returns a `409` error with `{ code: "gsc_not_connected", message, howToFix }` — the `howToFix` field points at **Settings → Integrations** in Searchable, where you can connect GSC and then retry.
</Note>

<CardGroup cols={2}>
  <Card title="get_gsc_performance" icon="magnifying-glass-chart">
    Live Google Search Console organic performance. `report="overview"` (default): clicks/impressions/CTR/average position plus a prior-period comparison. `"top_queries"` / `"top_pages"` / `"countries"` / `"devices"`: ranked rows for that dimension. `"trend"`: daily timeseries with window totals. `"opportunities"`: quick-win queries (ranking position 4-15, ≥100 impressions, under 5% CTR). `"position_buckets"`: query-count distribution across top 3 / page 1 / page 2 / beyond 20. Pass `period` (`"7d"`|`"28d"`|`"30d"`|`"90d"`|`"16m"`, default `"30d"`) or an explicit `startDate`+`endDate` (`YYYY-MM-DD`) window — GSC data lags \~3 days.

    **Parameters:** `projectId` (required), `report` (default overview), `period`, `startDate`, `endDate`, `limit` (`top_queries`/`top_pages`/`countries`/`opportunities` only; defaults 25/25/100/20) (all optional except `projectId`)
  </Card>
</CardGroup>

### AI Traffic

<Note>
  First-party AI-traffic measurement from the tracker/CDN pipeline — Searchable's flagship differentiator, distinct from GA4 above (which reads Google's own analytics). This tool requires a crawler-log, CDN, or Searchable-tracker source connected. When none is connected, the backing endpoint returns a `409` error with `{ code: "traffic_not_connected", message, howToFix }` — the `howToFix` field points at **AI Traffic → Setup** in Searchable, where you can connect a source and then retry.
</Note>

<CardGroup cols={2}>
  <Card title="get_ai_traffic" icon="server">
    First-party AI-crawler and AI-referral traffic. `report="overview"` (default): crawler + AI-referral totals by platform, plus the top crawled pages. `"crawlers"`: per-page AI-crawler activity, capped by `limit` (no deep pagination at the tool layer — use the REST endpoint's `offset` for that). `"referrals"`: daily AI-referral session timeseries by platform. `"top_cited_pages"`: top pages driving AI-referral traffic for one platform — `platform` is **required** for this report. `platform` is validated strictly against `openai`/`anthropic`/`google`/`perplexity`/`microsoft` (`crawlers`/`referrals`/`overview` also accept `deepseek`/`xai`/`meta`) — an unrecognized value returns an `invalid_argument` error, never a silent empty result.

    **Parameters:** `projectId` (required), `report` (`"overview"` | `"crawlers"` | `"referrals"` | `"top_cited_pages"`, default overview), `days` (default 30, max 365), `platform` (required only for `top_cited_pages`), `limit` (default 20 for crawlers / 10 for top\_cited\_pages, max 100) (all optional except `projectId`)
  </Card>
</CardGroup>

### Shopping visibility

<Note>
  Requires a plan with **Shopping Analytics** (Scale or higher). `get_shopping_visibility` returns `available: false` (not an error) when the project simply has no shopping/product data yet — that's a data-presence state, not a plan or connection problem, and needs no setup step. The plan gate only surfaces once there's data to fetch.
</Note>

<CardGroup cols={2}>
  <Card title="get_shopping_visibility" icon="cart-shopping">
    AI shopping/product visibility (Peec-parity) — products surfaced in AI shopping/product-carousel responses. `view="summary"` (default): ranked product list (rank, mentions, dominant platform) plus an activation-rate summary. `view="timeseries"`: daily activation-rate/product-count trend. Pass `productId` (the `id` from a summary row — the product's title) for full detail on one product instead: occurrences, vendor/pricing rows, a real per-platform breakdown, and up to 50 recent responses that surfaced it — `productId` overrides `view`.

    **Parameters:** `projectId` (required), `days` (default 30, max 365), `platform`, `productId` (optional — switches to detail view), `view` (`"summary"` | `"timeseries"`, default summary) (all optional except `projectId`)
  </Card>
</CardGroup>

### Write actions

<Note>
  All three require a grant/key with the **write** scope. None of them execute without `confirm: true` — omit it and the tool returns a dry-run preview (what would happen, current quota state) with no side effect.
</Note>

<CardGroup cols={2}>
  <Card title="generate_report" icon="share-nodes">
    Generate + publish a shareable report and return its public URL. `reportType`=`sentiment`|`visibility`|`combined` (default sentiment). Note the `Only` suffix on the brand filters here — `unbrandedOnly`/`brandedOnly` — unlike every read tool's `unbranded`/`branded`.

    **Parameters:** `projectId` (required), `reportType`, `timeRange` (`"7d"`|`"30d"`|`"90d"`|`"365d"`, default 30d), `platforms`, `topicIds`, `locationIds`, `unbrandedOnly`, `brandedOnly`, `title`, `status` (`"published"`|`"draft"`, default published), `whiteLabel` (requires a white-label-entitled plan), `confirm` (all optional except `projectId`)
  </Card>

  <Card title="trigger_audit" icon="clipboard-check">
    Start a technical + AEO site audit for the project's pages (all tracked pages by default, or the given `pageIds`); returns the job id. Results land on `get_site_health` (`view="audits"`). Consumes the monthly audit quota and is blocked for pitch projects.

    **Parameters:** `projectId` (required), `pageIds` (optional — omit to audit every tracked page), `confirm` (optional)
  </Card>

  <Card title="refresh_sitemap" icon="sitemap">
    Re-sync the project's configured sitemap — re-discovers it and reconciles monitored pages (add/update/remove) in the background; returns the job id. Read the result with `get_site_health` (`view="pages"`). Blocked for pitch projects. The only write tool with `idempotentHint: true`.

    **Parameters:** `projectId` (required), `confirm` (optional)
  </Card>
</CardGroup>

### Deprecated aliases

Earlier iterations of this MCP shipped 35 individual tools. **28 of those old names still work** — each is registered as a deprecated alias that forwards to the consolidated tool above with the equivalent arguments filled in automatically (for example, `get_visibility_summary` calls `get_visibility` with `group_by: "summary"`). An alias returns the identical data its replacement would for the same inputs. They'll keep working — Searchable removes an alias only after 60 days of zero telemetry on it. New integrations should call the primary tool names directly.

| Deprecated tool               | Use instead                                                   |
| ----------------------------- | ------------------------------------------------------------- |
| `get_visibility_summary`      | `get_visibility` (`group_by: "summary"`)                      |
| `get_visibility_details`      | `get_visibility` (`group_by: "platform"`)                     |
| `get_visibility_by_topic`     | `get_visibility` (`group_by: "topic"`)                        |
| `get_visibility_by_prompt`    | `get_visibility` (`group_by: "prompt"`)                       |
| `get_visibility_by_location`  | `get_visibility` (`group_by: "location"`)                     |
| `get_prompt_topics`           | `get_visibility` (`group_by: "topic"`)                        |
| `get_sources`                 | `search_sources`                                              |
| `get_source_domain`           | `get_source_detail` (`level: "domain"`)                       |
| `get_source_domain_urls`      | `get_source_detail` (`level: "domain", include: "urls"`)      |
| `get_source_domain_responses` | `get_source_detail` (`level: "domain", include: "responses"`) |
| `get_source_urls`             | `get_source_detail` (`level: "url"`)                          |
| `get_source_page`             | `get_source_detail` (`level: "url"`, with `url`)              |
| `get_source_page_content`     | `get_source_detail` (`level: "url", include: "content"`)      |
| `get_source_content_types`    | `get_source_trends` (`breakdown: "content-types"`)            |
| `get_source_types`            | `get_source_trends` (`breakdown: "source-types"`)             |
| `get_source_article_types`    | `get_source_trends` (`breakdown: "article-types"`)            |
| `get_source_trend`            | `get_source_trends` (`breakdown: "trend"`)                    |
| `get_sentiment_history`       | `get_sentiment` (`view: "history"`)                           |
| `get_sentiment_competitors`   | `get_sentiment` (`view: "competitors"`)                       |
| `get_prompt_query_fanout`     | `get_query_fanout` (use `prompt_id`, not `promptId`)          |
| `get_ga4_ai_referrals`        | `get_ga4_traffic` (`report: "ai_referrals"`)                  |
| `get_ga4_traffic_trend`       | `get_ga4_traffic` (`report: "trend"`)                         |
| `get_ga4_top_pages`           | `get_ga4_traffic` (`report: "top_pages"`)                     |
| `get_ga4_traffic_sources`     | `get_ga4_traffic` (`report: "sources"`)                       |
| `get_website_issues`          | `get_site_health` (`view: "issues"`)                          |
| `get_page_audits`             | `get_site_health` (`view: "audits"`)                          |
| `get_monitored_pages`         | `get_site_health` (`view: "pages"`)                           |
| `get_issue_details`           | `get_site_health` (`view: "issue_details"`)                   |

The seven other pre-consolidation names — `list_projects`, `get_visibility_history`, `list_articles`, `get_article`, `get_opportunities`, `get_sentiment`, and `get_query_fanout` — kept their exact original name as a primary tool, so they need no alias.

## Interactive visibility card

<Info>
  On **Apps-capable** MCP hosts (Claude.ai, ChatGPT, Goose, VS Code), `get_visibility` also renders an interactive snapshot card beside its answer — brand name, AI visibility score with trend, a per-platform breakdown, and the report date range, with an **Open in Searchable** link back to your dashboard. Hosts without MCP Apps support just see the normal text/JSON answer.
</Info>

## Pagination

Tools that return lists are paginated so you can read complete datasets without silent truncation.

### Per-prompt visibility

`get_visibility` with `group_by: "prompt"` is fully paginated (the deprecated `get_visibility_by_prompt` alias maps to the same call). Every response includes a `pagination` object that tells you whether more prompts exist and exactly how to fetch the next page:

```json theme={null}
{
  "pagination": {
    "limit": 100,
    "offset": 0,
    "returnedCount": 100,
    "totalCount": 740,
    "hasMore": true,
    "nextOffset": 100
  }
}
```

Loop until you've read every prompt:

1. Call `get_visibility` with `group_by: "prompt"` (defaults: `limit` 100, `offset` 0).
2. While `pagination.hasMore` is `true`, call again with `offset` = `pagination.nextOffset`.
3. Stop when `pagination.hasMore` is `false`.

`limit` accepts 1–500 prompts per page. The total number of prompts you can page through is unbounded — paging in fixed-size chunks scales to projects with thousands of prompts.

### Other list tools

Other list-returning tools paginate too: `get_opportunities`, `search_sources`, `get_source_detail` (`include: "responses"`), and `get_query_fanout` (per-prompt list) use `limit` + `offset`, while `get_source_detail` (`include: "urls"`, or `level: "url"` for the flat cross-project listing) is cursor-based (pass the `cursor` from the previous response until none is returned). `get_prompt_answers` also returns the standard `limit`/`offset`/`hasMore`/`nextOffset` pagination shape, but the tool layer only exposes `limit` (max 50) — use the REST endpoint's `offset` for deep pagination.

## Example prompts

### Visibility analysis

```
What's my brand's AI visibility score for the last 30 days?
```

```
How does my brand perform on ChatGPT vs Claude vs Perplexity?
```

```
Which topics have the weakest visibility? Show me the top 5.
```

### Site audit

```
What critical AEO issues does my site have and how do I fix them?
```

```
Show me the pages with the lowest AEO scores.
```

### Content

```
List all my draft articles.
```

```
Get the full content of my latest published article for review.
```

## Use cases

### Automated issue fixing

Pair the MCP with a coding assistant to retrieve AEO/SEO issues and apply fixes in your codebase:

```
Get all critical issues for my project and propose fixes in this repo
```

The assistant fetches issues from Searchable (missing meta descriptions, alt text, heading structure, etc.), locates the relevant files, and proposes or applies fixes.

### For developers

* Query AEO/SEO issues while debugging frontend code
* Check if code changes would impact page audit scores
* Review article content without leaving your IDE

### For AEO/SEO teams

* Pull visibility summaries during standups
* Extract audit data for reports
* Track issue resolution progress

### For content teams

* Review article status and metadata
* Pull full article content for editing
* Track content coverage across topics

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connection failed or 403 Forbidden">
    * Confirm the server URL is exactly `https://mcp.searchable.com/mcp` (browser-sent `Origin` headers are validated against an allowlist — connectors like Claude.ai and ChatGPT call server-side without one, so they're unaffected).
    * Check your API key starts with `sea_` and is enabled for MCP in Searchable settings.
    * Restart your MCP client after config changes.
  </Accordion>

  <Accordion title="The browser consent page won't complete">
    * Make sure you're logged in to Searchable in the same browser, then retry the connection from your client.
    * The authorization link is single-use and expires after a few minutes — if you left it open, restart the connection from your client to get a fresh one.
    * On the consent screen, select at least one project (or leave all selected) before clicking **Authorize**.
  </Accordion>

  <Accordion title="Legacy API key rejected (401)">
    * Confirm the key starts with `sea_` and hasn't been revoked in **Settings → Integrations**.
    * Confirm the key's workspace is on a paid Searchable plan — MCP is unavailable on the Free plan.
  </Accordion>

  <Accordion title="No projects returned">
    * Confirm you have projects in your Searchable account.
    * Check that the API key belongs to the correct workspace.
  </Accordion>

  <Accordion title="get_ga4_traffic fails with 'ga4_not_connected'">
    * The project has no GA4 property linked, so the tool call returns a `409` error with `code: "ga4_not_connected"`.
    * Connect Google Analytics 4 under **Settings → Integrations** in your Searchable dashboard (the error's `howToFix` field carries the direct link), then retry the tool call.
  </Accordion>

  <Accordion title="get_gsc_performance fails with 'gsc_not_connected'">
    * The project has no Google Search Console site linked, so the tool call returns a `409` error with `code: "gsc_not_connected"`.
    * Connect Google Search Console under **Settings → Integrations** in your Searchable dashboard (the error's `howToFix` field carries the direct link), then retry the tool call.
  </Accordion>

  <Accordion title="get_ai_traffic fails with 'traffic_not_connected'">
    * The project has no crawler-log, CDN, or Searchable-tracker source connected, so the tool call returns a `409` error with `code: "traffic_not_connected"`.
    * Connect a source under **AI Traffic → Setup** in your Searchable dashboard (the error's `howToFix` field carries the direct link), then retry the tool call.
  </Accordion>

  <Accordion title="get_shopping_visibility fails with 'plan_upgrade_required'">
    * The workspace's plan doesn't include **Shopping Analytics** (Scale or higher), and the project has shopping data to fetch, so the tool call returns a `403`-equivalent error with `code: "plan_upgrade_required"`.
    * This is different from `available: false` — that's a normal 200 response meaning the project just has no shopping data yet, not a plan restriction. If you're seeing `available: false` instead of this error, no upgrade is needed.
    * Upgrade to a plan with Shopping Analytics in **Settings → Billing**, then retry.
  </Accordion>

  <Accordion title="A write tool (generate_report, trigger_audit, refresh_sitemap) returns 'missing_scope'">
    * The connected grant or API key only has **read** access. Write tools require the **write** scope.
    * Re-authorize with **Read & write** selected on the consent screen, or create/edit an API key with read-and-write access in **Settings → Integrations**.
  </Accordion>

  <Accordion title="Tools not appearing">
    * Restart your MCP client.
    * Verify the server URL and JSON config syntax.
    * Check the client's MCP logs for errors.
  </Accordion>
</AccordionGroup>

## Security

### Read-only by default, write tools scope-gated

19 of the 22 primary tools — plus all 28 deprecated aliases — are annotated `readOnlyHint: true`: they can only list and read data. The 3 write tools (`generate_report`, `trigger_audit`, `refresh_sitemap`) additionally require a grant or key with the **write** scope, and each still needs an explicit `confirm: true` on the individual call before it does anything — a read-only connection can't invoke them at all (the call fails with `missing_scope`), and even a read-and-write connection gets a no-op dry-run preview until it passes `confirm: true`.

### Token & key handling

* The OAuth login flow issues your client an access token scoped to exactly the projects and read/write access you approved on the consent screen — no API key is created or stored for this path.
* Every request is re-checked against the server-side authorization grant, so a revoked grant stops working immediately — the token in the client's hands can't outlive the consent it came from.
* Tokens refresh silently while the connection is in use; active connections persist, and an idle connection expires about 60 days after its last use, after which you simply re-authorize.
* On the legacy API-key path, the `sea_` key **is** the bearer token — treat it as a secret, scope it narrowly, and revoke it in **Settings → Integrations** if it's exposed.

### Origin validation

Both the edge worker and the in-app host validate browser `Origin` headers against an allowlist (`claude.ai`, `claude.com`, plus dev hosts) to prevent cross-site abuse. Requests without an `Origin` header are allowed through — that covers native clients (Claude Desktop, Cursor, curl) **and** hosted connectors like Claude.ai and ChatGPT, which call from their servers rather than a browser. This is defense-in-depth; bearer-token auth is the primary control.

### Best practices

* **Rotate keys regularly** — generate new keys periodically and revoke old ones.
* **Use per-use-case keys** — separate keys for separate clients makes revocation targeted.
* **Revoke unused keys** — remove keys you're no longer using from Searchable settings.

## API reference

### Server details

| Property       | Value                                      |
| -------------- | ------------------------------------------ |
| Endpoint       | `https://mcp.searchable.com/mcp`           |
| Transport      | Streamable HTTP                            |
| Protocol       | MCP 1.0                                    |
| Authentication | OAuth 2.1 with Dynamic Client Registration |

### Rate limits

Searchable does not enforce per-key or per-project rate limits today. Heavy aggregation queries (visibility, sentiment) are instead bounded by a server-side query timeout, which surfaces as a retryable error rather than `429`. Per-key rate limits are coming with the hardening release — once live, clients should handle `429 Too Many Requests` responses by honouring the `Retry-After` header and backing off before retrying. Normal interactive usage from Claude, Cursor, or similar clients is not expected to hit a limit.

## Support

<CardGroup cols={2}>
  <Card title="All integrations" icon="book" href="/integrations/overview">
    Browse the integrations directory
  </Card>

  <Card title="Contact support" icon="headset" href="mailto:support@searchable.com">
    Email our team
  </Card>
</CardGroup>
