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. Compatible clients include:- Claude.ai (web and mobile) — add as a connector
- ChatGPT — via developer-mode connectors
- Grok — via custom MCP connectors
- Gemini Spark — via custom Connected Apps
- Microsoft 365 Copilot agents and Microsoft Copilot Studio
- Claude Desktop and Claude Code
- Cursor
- Windsurf, Perplexity Enterprise, Mistral, and other MCP-compatible clients
How authentication works
The Searchable MCP server uses OAuth 2.1 with PKCE. It supports the current MCP client-metadata discovery flow, plus Dynamic Client Registration for clients that still require it. Public clients use PKCE; compatible enterprise clients can use a dynamically issued client secret. This means a new standards-compatible assistant can connect without Searchable adding a provider-specific OAuth integration first. 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:- You add the server URL to your client (
https://app.searchable.com/api/mcp-server/mcp). - On first use, the client opens Searchable in your browser and asks you to log in (or reuses your existing session).
- 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.
- You click Authorize. Your client receives an OAuth access token scoped to exactly what you approved and uses it for subsequent requests.
Setup
https://app.searchable.com/api/mcp-server/mcp — the same address for every
client below.Step 1: Add the server to your client
- Claude.ai
- ChatGPT
- Claude Code
- Claude Desktop
- Cursor
- Windsurf
- Open Claude.ai → Settings → Connectors.
- Click Add custom connector.
- Enter URL:
https://app.searchable.com/api/mcp-server/mcp - Claude opens the Searchable sign-in and consent page — continue with Step 2.
https://app.searchable.com/api/mcp-server/mcp. Searchable publishes OAuth discovery metadata, so choose OAuth
or automatic authentication when the host asks. The exact menu name and availability are controlled
by the host product.
Step 2: Log in and authorize
The first time your client connects, Searchable opens in your browser:- Log in to Searchable (or continue with your existing session).
- On the consent screen, choose which projects the client may access and whether it gets Read-only (default) or Read & write access.
- Click Authorize. Your browser returns to the client, now connected — no API key to copy or paste.
Step 3: Verify the connection
Once connected, ask: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 samesea_ key the REST API accepts.
Create an API key
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.Send it as a bearer token
Authorization: Bearer sea_... on every request to
https://app.searchable.com/api/mcp-server/mcp. No login or consent screen is involved on this
path.Available tools
The Searchable MCP exposes 30 primary tools — 27 read-only and 3 write (32 with the Associated Sources feature enabled), plus 4 deprecated names kept callable through their sunset window (see Deprecated tool names). Every read tool is annotatedreadOnlyHint: true. Every tool that operates on a project takes a required projectId (get IDs from list_projects), and most read tools also accept an optional response_format — "concise" (default, summary + capped rows) or "detailed" (fuller rows, same shape).
Five tools exist purely to make assistants reliable, and are worth calling early in a session:
get_current_date— the server’s UTC date plus pre-computed window starts (7/30/90/365 days). Call it before interpreting relative time like “last month” so date math is never guessed.whoami— who this connection is authenticated as, its read/write scopes, and the project roster it can see. Call it when unsure what the connection can access.search_docs/read_doc— full-text search and retrieval over this documentation, so questions like “how is the visibility score calculated?” are answered in-chat, from the source.get_page_metrics— the per-URL rollup: one page’s citations, AI-referral sessions, and AI-crawler hits as daily buckets, in one call.
searchable://glossary (compact index) and searchable://glossary/full (complete definitions) — metric and concept definitions with the tools that read each one, for hosts that attach resources as reference context.
get_visibility, get_share_of_voice, and get_sentiment additionally accept compare: "previous_period" | "previous_year" — the response gains a comparison block with the previous window’s metrics and current-minus-previous deltas, so period-over-period questions are one tool call.
from and to (inclusive, UTC) as an
alternative to the relative days — from: "2026-03-01", to: "2026-03-31" answers “how did March
go” without arithmetic against today. Both bounds are required together, and they are mutually
exclusive with days: sending both is an invalid_argument error rather than a silent
precedence rule. Bare YYYY-MM-DD and full ISO timestamps are both accepted (the UTC day is what
counts). An over-long days is clamped to the tool’s maximum, but an over-long explicit range is
rejected — narrowing a range you spelled out would answer a different question than the one
you asked. Supported on get_visibility (every group_by), get_share_of_voice,
get_sentiment, get_topic_analysis, and get_ai_traffic (every report), plus the matching
REST endpoints. Tools not in that list — get_competitors, get_shopping_visibility, get_ads,
get_page_metrics, get_query_fanout, get_prompt_answers, and the source reads — still take
days only. (get_gsc_performance has always had its own startDate / endDate.)appliedFilters object: the platform / brand /
topic / location filters that call actually narrowed by, or {} when it was unfiltered. That
covers get_visibility, get_share_of_voice, get_competitors, get_topic_analysis,
list_prompts, get_sentiment (every view), get_source_trends, and get_shopping_visibility
(summary view). All of them except get_topic_analysis also return availableFilters (the
project’s topics and countries) so a client can offer the next filter without a second round-trip
— on get_visibility that rides along on the summary and platform views. Use appliedFilters
to state what a number covers rather than presenting a filtered figure as the whole picture.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.Diagnostics
investigate
question="visibility_drop" (default) returns the score trend with the largest single-day fall,
per-platform movement against the previous window, the share-of-voice shift with which
competitors gained, and the weakest topics. "competitive_position" returns your standing with
ranks and deltas plus the topics where a rival currently leads. "citation_gap" returns your
citation trend, the domains AI answers actually cite in your space, and per-engine citation share.Takes the usual narrowing arguments — days or from/to, platform, topicId, unbranded /
branded, country / locationId.It reports measurements, never a cause. It will tell you ChatGPT fell 38 points while Gemini
held; it will not tell you why, because the reason is usually outside the data — a rebrand, a
campaign ending, a competitor launch. Every response carries an interpretation list naming what
the numbers cannot settle. A signal whose upstream failed appears in unavailable with a reason
rather than as a zero, so missing data is never mistaken for a finding.Each question has a companion recipe explaining how to read the result and when it misleads:
visibility drop, competitive position,
citation gap. Load one in-chat with
read_doc("recipes/visibility-drop").Projects
list_projects
projectId.Parameters: response_format (optional)Visibility & share of voice
get_visibility
group_by selects the view: summary (overall visibility score), platform (per ChatGPT/Claude/Gemini/Perplexity breakdown), prompt (per-prompt breakdown, paginated), location (per country/city), or date (the per-report time series — trend, uplift, before/after analysis; default 90-day window). The unbranded/branded, topicId, country and locationId filters work on every view except date, which accepts only unbranded/branded; the platform filter is restricted 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" | "prompt" | "location" | "date", default summary), days (default 30, or 90 for group_by=date; 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)get_topic_analysis
get_visibility (group_by:"topic"). An interactive Topic Analysis card also renders automatically beside the answer on Apps-capable clients — see below.view="prompts" drills into ONE topic (topicId required): every prompt assigned to it with your average rank, its visibility, and which competitors outrank you — the “which specific questions are we losing” view behind a weak topic. A prompt you never appeared for reports rank: null, never 0.view="heatmap" returns average brand position per topic x AI platform — where you’re strong on one engine and absent on another. There is deliberately no platform filter on this view: the platform axis is the answer.Parameters: projectId (required), view (topics default, prompts, heatmap — platform is rejected on heatmap, whose axis IS platform), topicId (required for view=prompts; rejected on the default view, which lists every topic), days (default 30, max 365), from/to, limit, platform, unbranded, branded (all optional except projectId)get_visibility_history
get_visibility with group_by: "date" instead (same data, same parameters). This name keeps answering with an identical payload until its removal date; see Deprecated tool names.Parameters: projectId (required), days (default 90, max 365), unbranded, branded (all optional except projectId)get_share_of_voice
mentions/citations aren’t part of this view (mirrors the in-app Share of Voice sheet) — use get_competitors for those. An interactive Share of Voice card also renders automatically beside the answer on Apps-capable clients — see below.group_by="date" returns the daily share series instead — your share and your top competitors’, one point per day. That is the “is our share growing?” view; include="annotations" adds the dated markers explaining any jump. compare is not supported there (the series already shows the movement), and the interactive card hides itself on it.Parameters: projectId (required), group_by (summary default, or date), days (default 30, max 365), from/to, include, platform, topicId, unbranded, branded, country, locationId, compare (all optional except projectId)Competitors
get_competitors
brand block carrying the same metrics for the project itself so the two sit on one ruler. Pass competitorId for a head-to-head against one competitor instead: headToHead.brand vs headToHead.competitor, each with visibility %, share of voice %, sentiment (0–100) and average position (a rank — lower is better), plus the phrases each is known for; for the competitor it also returns its rank, per-day history, and up to 10 recent prompts it was mentioned in. competitorId accepts either the competitor’s ID or its name exactly as the list shows it (competitorId: "Nike"), so you can drill in straight from the list — response_format: "detailed" adds an id column if you want the exact key. A null metric means unmeasured in that window, not zero. visibility/sov/sentimentScore/avgPosition honor the filters; the list view’s mentions is all-time and ignores them. On the head-to-head, citations (inline citations on responses mentioning the competitor) and history[].domainSources (source URLs — pages used for generation, not inline citations — on the competitor’s own domain) are different metrics. An interactive Competitor Ranking card also renders automatically beside the answer on Apps-capable clients, in whichever shape matches the call — see below.Parameters: projectId (required), competitorId (optional — ID or name; switches to the head-to-head 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)Sources & citations
search_sources
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)get_source_detail
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)get_source_trends
projectId (required), days (window; default 30 — pass 7/90/365 for a different one), platform, topicId, sourceType, unbranded, branded, country, locationId (all optional except projectId)Sentiment
get_sentiment
view selects: summary (default) — overall score + positive/neutral/negative split + per-platform breakdown, plus analysis (the weekly brand-perception write-up for the platform that mentions you most, or the one you filter to with platform) and analyses (every platform’s write-up); history — the daily sentiment trend (default 90-day window); competitors — head-to-head vs competitors, the brand flagged by isBrand. topicId is not accepted on competitors, and compare only on summary. The interactive Sentiment Profile card renders on summary answers only.Parameters: projectId (required), view ("summary" | "history" | "competitors", default summary), days (default 30, or 90 for view=history; max 365), platform, topicId, limit (view=competitors, default 10, max 50), unbranded, branded, country, locationId, response_format (all optional except projectId)get_sentiment_history
get_sentiment with view: "history" instead (same data, same parameters). Keeps answering identically until its removal date; see Deprecated tool names.Parameters: projectId (required), days (default 90, max 365), platform, topicId, unbranded, branded, country, locationId, response_format (all optional except projectId)get_sentiment_competitors
get_sentiment with view: "competitors" instead (same data, same parameters). Keeps answering identically until its removal date; see Deprecated tool names.Parameters: projectId (required), days (default 30, max 365), platform, limit (default 10, max 50), unbranded, branded, country, locationId, response_format (all optional except projectId)Query fanout
get_query_fanout
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)Brand profile & authority
get_brand_profile
include: "domain_authority" to also get the Moz domain-authority block (latest DA/PA/spam/linking-domains snapshot + roughly-monthly 365-day history) in the same call. Call this first for brand context in any analysis. profile is null until onboarding creates one; facts come from the weekly sentiment job.Parameters: projectId (required), platform, verificationStatus ("unverified" | "pass" | "fail"), include ("domain_authority"), response_format (all optional except projectId)get_domain_authority
get_brand_profile with include: "domain_authority" instead (same data; the REST endpoint keeps custom days windows). Keeps answering identically until its removal date; see Deprecated tool names.Parameters: projectId (required), days (default 365, max 1095) (all optional except projectId)Prompts
list_prompts
status="suggested" — proposals from research runs and the agent that nobody has accepted or rejected yet, each with the reason it was proposed). Configuration data, not performance — use get_visibility group_by=prompt for per-prompt visibility scores. The summary always reports all three counts, so pending suggestions surface from any call. An interactive Prompts card also renders automatically beside the answer on Apps-capable clients.Parameters: projectId (required), status ("tracked" | "untracked" | "suggested" | "all", default tracked), topicId, limit (default 50, max 200), offset, days (metrics window, default 30, max 365), sortBy (prompt | volume | difficulty | branded | intent | recency, default recency — performance columns like visibility/position/sentiment are computed per page and are not server-sortable), sortDir ("asc" | "desc", default desc), unbranded, branded, response_format (all optional except projectId)get_prompt_answers
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)Site health & audits
get_site_health
view="pages" (default) = the monitored-page inventory, one server-paginated page at a time (audited pages first) — every page (audited or not) with its latest technical/AEO scores, open-issue count, and last-audited date, plus pagination.total; page with limit/offset, filter server-side with search (URL/slug/title), reorder with sortBy, and omit the header aggregates with includeSummary=false; view="audits" = per-page technical/AEO scores for audited pages + averages; view="issues" = issues grouped by severity (filter status); view="issue_details" = issues grouped by type with fix guidance (filter issueType). An interactive Site Audit card renders beside the answer on Apps-capable clients: pages/audits show the inventory with a search box + Prev/Next paging (both server-side), a per-page Audit button (calls trigger_audit for that page), and a Sync website button (calls refresh_sitemap); issues/issue_details show the findings ranked by severity, each expanding to its fix guidance. Clicking a page row on the inventory drills into that page’s own issues.Parameters: projectId (required), view ("pages" | "audits" | "issues" | "issue_details", default pages), status (view=issues: "open" | "resolved" | "all", default open), pageId (view=issues: scope to one monitored page — the card’s page → issues drill-down), issueType (view=issue_details: "technical" | "content"), includeIssues (view=audits, boolean), search (view=pages: server-side filter by URL / slug / title), sortBy (view=pages: "audited" | "technical" | "aeo" | "issues", default audited-first), includeSummary (view=pages, boolean, default true), limit (view=pages default 12, max 100; view=issues default 1000, max 5000), offset (view=pages / view=issues) (all optional except projectId)Content & articles
list_articles
projectId (required), status ("draft" | "published" | "editing" | "all", default all), limit (default 50, max 100) (all optional except projectId)get_article
articleId (required)Opportunities
get_opportunities
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)GA4 / Traffic
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.get_ga4_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)Search Console (GSC)
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.get_gsc_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)AI Traffic
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.get_ai_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, and an unrecognized value returns an error rather than a silent empty result: crawlers and referrals accept all eight platform IDs (openai, anthropic, google, perplexity, microsoft, deepseek, xai, meta), while top_cited_pages accepts only the first five. overview ignores platform entirely — it always returns every platform, so filter with crawlers or referrals instead. Long-tail vendors that can appear in output rows (e.g. amazon, you.com) are deliberately not filterable.overview, crawlers, and correlation take groupBy="platform" | "botCategory" | "botName". This extends the same tool rather than adding traffic tools. Omitting it preserves the legacy response; botCategory adds byCategory, botName adds byBot (name, ID, vendor, and category), and platform adds correlation’s per-page byPlatform crawl split. Overview and crawlers keep their existing byPlatform arrays with every grouping.The public bot categories are ai_training, ai_search, ai_assistant, ai_agent, and search_engine. ai_assistant is the distinct user-triggered class for ChatGPT-User, Claude-User, and Perplexity-User. A per-page ai_training → ai_search → ai_assistant view is therefore possible, but ai_search means retrieval/search crawling — actual answer citation remains a separate visibility metric.Five further reports cover the rest of the AI Traffic surface:sitemap_coverage— per bot (named, with vendor and category): how often it fetched your sitemap, how many listed pages it discovered, and the median lag from publish to first crawl. It answers how fast and how completely each crawler is picking your sitemap up; it does not enumerate individual uncrawled URLs.human— real human sessions that arrived FROM an AI assistant, split by platform. The conversion half of the funnel the crawler reports open. ChecksummarySource: site-wide totals come from the first-party tracker while the AI figures fall back to GA4 when no tracker is installed — in that split state everysummaryfield andpercentOfTotalarenull(not0), and a failed GA4 read surfaces asaiReferral.sourceErrorrather than as zeroes.correlation— per page, crawls and AI-referred sessions over the same window, joined by path. Its optional grouping classifies the crawl side only. This is co-occurrence, not attribution: nothing establishes that a session followed a crawl or came from a named bot. Ranked by sessions, but the ranked population is the upstream union of the top-500 crawled and top-500 human-traffic pages —pagesConsideredis a floor, andpopulationTruncatedtells you when pages are certainly missing.attribution— traffic by UTM tuple, referrer domain, and bot category.logs— the raw request feed, filterable bypath,statusCode,botsOnly, andhost, cursor-paginated: pass a page’snextCursorback as bothcursorTimestampandcursorEventId(half a cursor is rejected rather than silently re-serving page one). Row-capped (25 default, 100 max) because it is the one row-level report.ip_addressanduser_agentare never returned — the IP is personal data with no analytical value oncecountryis present, and the user-agent is superseded by the resolved bot identity.
host narrows any report to specific hostnames (comma-separated) — useful on multi-domain projects where “blog versus docs” is the question.Parameters: projectId (required), report (default overview), days (default 30, max 365), from/to, host, platform (required for top_cited_pages), groupBy (overview/crawlers/correlation only), limit, plus path / statusCode / botsOnly for report=logs (all optional except projectId)Shopping visibility
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.get_shopping_visibility
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. The summary view accepts the brand / topic / location filters and echoes appliedFilters + availableFilters. An interactive Shopping Shelf card also renders automatically beside the answer on the summary view for Apps-capable clients — see below.Parameters: projectId (required), days (default 30, max 365), platform, productId (optional — switches to detail view), view ("summary" | "timeseries", default summary), limit (summary view, default 50, max 100), offset (summary view), topicId, unbranded, branded, country, locationId (all optional except projectId)AI ads
topicId, locationId and
promptId take IDs, not names. An unrecognized value is dropped from its filter; only when none
of a filter’s values resolve does that filter match nothing rather than being ignored — a mixed
list silently returns just the recognized subset. Retry without filters before reporting that a
project has no ad data, and state that the retried figures are unfiltered. adCount/appearances
count ads we scraped in AI answers, not ad-platform impressions, and commercial ad libraries don’t
publish spend, so there are no cost or impression figures.get_ads
view="advertisers" (default): who is running ads, ranked by ad volume with share % and a competitor flag, plus your own brand’s ad share-of-voice and rank. view="creatives": the individual ad creatives (advertiser, headline, appearances, prompts) — narrow with advertiserKey, promptId, or search. view="prompts": which tracked prompts surface the most ads, with ad coverage %. view="timeseries": per-advertiser ad-frequency trend.Parameters: projectId (required), view ("advertisers" | "creatives" | "prompts" | "timeseries", default advertisers), days (default 30, max 365), filter ("all" | "competitors", view=advertisers), advertiserKey (view=creatives/timeseries), promptId + search (view=creatives), sortBy (promptText|adUnits|coveragePct|engines|totalResponses, default adUnits) + sortDir (view=prompts), limit (advertisers default 20/max 100, creatives 25/200, prompts 50/500), platform, topicId, locationId, unbranded, branded, response_format (all optional except projectId)Write actions
confirm: true — omit it and the tool returns a dry-run preview (what would happen, current quota state)
with no side effect.generate_report
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)trigger_audit
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)refresh_sitemap
get_site_health (view="pages"). Blocked for pitch projects.Parameters: projectId (required), confirm (optional)Removed tool names
Earlier iterations of this MCP shipped 35 individual tools. When those were consolidated, 26 of the old names stayed callable as deprecated aliases. Those aliases were removed in August 2026 — calling one of the names below now returns an unknown-tool error. Use the replacement.list_projects, list_articles, get_article, get_opportunities, get_sentiment, and get_query_fanout; the other three (get_visibility_history, get_sentiment_history, get_sentiment_competitors) were folded into selector views in August 2026 and are now deprecated names — see the next section.
get_source_* breakdown rows above are the one case where the removed name did something
no MCP tool now does: breakdown (and get_source_trend’s group) were arguments only those
aliases accepted. get_source_trends returns the top-source-domain trend directly and has no
breakdown argument. For the content-type, source-type, or article-type breakdown, use the REST
endpoint.Deprecated tool names
The August 2026 family-grid consolidation folded four reads into selector parameters on their family’s primary tool. Unlike the removed aliases above, these four names still work — same handler, byte-identical payload — so existing scripts and scheduled jobs keep running. They are scheduled for removal after 2026-10-15 (the same ~60-day window the removed aliases got); move to the replacement call before then. The REST endpoints behind these reads (GET /visibility/history, GET /sentiment/history, GET /sentiment/competitors,
GET /domain-authority) are not deprecated — the 12-month REST deprecation
policy governs those, and nothing REST-side is scheduled for
removal.
Interactive cards
get_visibility hides its card on a platform-filtered call and on group_by=prompt|location,
where the card’s numbers would misrepresent the answer. Hosts without MCP Apps support just see the
normal text/JSON answer. Cards are dark/light aware and have an Expand button for a fullscreen view.
Where a card has a period control you switch window inside the card rather than sending another
message — the card queries the tool itself and remembers each window it has already loaded, so
returning to one is instant.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:
- Call
get_visibilitywithgroup_by: "prompt"(defaults:limit100,offset0). - While
pagination.hasMoreistrue, call again withoffset=pagination.nextOffset. - Stop when
pagination.hasMoreisfalse.
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
Site audit
Content
Use cases
Automated issue fixing
Pair the MCP with a coding assistant to retrieve AEO/SEO issues and apply fixes in your codebase: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
Connection failed or 403 Forbidden
Connection failed or 403 Forbidden
- Confirm the server URL is exactly
https://app.searchable.com/api/mcp-server/mcp(browser-sentOriginheaders are validated against an allowlist — hosted connectors normally 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.
The browser consent page won't complete
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.
Legacy API key rejected (401)
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.
No projects returned
No projects returned
- Confirm you have projects in your Searchable account. - Check that the API key belongs to the correct workspace.
get_ga4_traffic fails with 'ga4_not_connected'
get_ga4_traffic fails with 'ga4_not_connected'
- The project has no GA4 property linked, so the tool call returns a
409error withcode: "ga4_not_connected". - Connect Google Analytics 4 under Settings → Integrations in your Searchable dashboard (the error’showToFixfield carries the direct link), then retry the tool call.
get_gsc_performance fails with 'gsc_not_connected'
get_gsc_performance fails with 'gsc_not_connected'
- The project has no Google Search Console site linked, so the tool call returns a
409error withcode: "gsc_not_connected". - Connect Google Search Console under Settings → Integrations in your Searchable dashboard (the error’showToFixfield carries the direct link), then retry the tool call.
get_ai_traffic fails with 'traffic_not_connected'
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
409error withcode: "traffic_not_connected". - Connect a source under AI Traffic → Setup in your Searchable dashboard (the error’showToFixfield carries the direct link), then retry the tool call.
get_shopping_visibility fails with 'plan_upgrade_required'
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 withcode: "plan_upgrade_required". - This is different fromavailable: false— that’s a normal 200 response meaning the project just has no shopping data yet, not a plan restriction. If you’re seeingavailable: falseinstead of this error, no upgrade is needed. - Upgrade to a plan with Shopping Analytics in Settings → Billing, then retry.
A tool returns 'rate_limited' or 'query_timeout'
A tool returns 'rate_limited' or 'query_timeout'
rate_limited means another heavy
read for the same project is still running — the limit is per project, not per key, so wait a
moment and retry, and avoid firing many project-wide tools in parallel for one project.
query_timeout means the aggregation ran past the server-side limit — reduce the days window or
add filters (platform, topicId, country), then retry.A write tool (generate_report, trigger_audit, refresh_sitemap) returns 'missing_scope'
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.
Tools not appearing
Tools not appearing
- Restart your MCP client.
- Verify the server URL and JSON config syntax.
- Check the client’s MCP logs for errors.
Security
Read-only by default, write tools scope-gated
Every tool except the 3 write tools is annotatedreadOnlyHint: 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
The server validates browserOrigin 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
Rate limits
Searchable does not enforce a per-key request-rate limit today, but two server-side controls can make a call fail retryably:- Per-project concurrency. Heavy aggregation reads take a per-project lock, so a second heavy call for the same project while the first is still running is rejected rather than queued. On the REST API that’s a
429with aRetry-Afterheader; MCP tools have no header channel, so the tool returns the error coderate_limitedwith retry guidance inhowToFix. Wait a moment and retry — the limit is per project, not per key. - Query timeout. Long aggregations are bounded by a server-side timeout, returning
query_timeoutwith a hint to narrow thedayswindow or add filters.

