Endpoint
Authentication
The OtterlyAI MCP server authenticates with OAuth 2.0. You do not pass an API key. When you add the server to a compatible client, the client walks you through a standard browser sign-in to OtterlyAI and obtains an access token on your behalf. Permissions and workspace scoping match your OtterlyAI account.The
oai_live_ API keys documented under
Authentication are for the REST Public API only. The
MCP server does not accept them — it is OAuth-only.401 with a
WWW-Authenticate header pointing at the protected-resource metadata, which is
the client’s cue to start the OAuth flow.
Quick sanity check
You don’t need a token to confirm the server is up and correctly OAuth-gated. An unauthenticated request returns401 with a WWW-Authenticate header:
HTTP/1.1 401 and a header of the form
WWW-Authenticate: Bearer error="invalid_token", resource_metadata="https://data.otterly.ai/.well-known/oauth-protected-resource/mcp".
Fetching that metadata document returns the resource and its authorization
server:
Claude.ai
In Customize → Connectors, choose Add connector / ”+” sign, search for OtterlyAI, and click Connect:Claude Code
claude mcp list — you should see
otterly: ... - ✓ Connected. Tools are then available as
mcp__otterly__<tool_name>.
Claude Code holds the resulting token itself, so it never shares credentials
with another client on your machine.
Claude Desktop
Add a remote connector pointing at the endpoint; Claude Desktop runs the OAuth flow in your browser on first connect. If your version launches stdio servers only, use themcp-remote bridge — it
performs the OAuth handshake for you, so no static Authorization header is
needed. Add the following to
~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
Cursor
In Cursor → Settings → MCP, add a new server using the samemcp-remote
bridge (the OAuth flow opens in your browser on first use):
Running more than one client on one machine
Themcp-remote bridge stores every credential in ~/.mcp-auth, keyed by
server URL, regardless of which client started it. Two clients pointed at the
same URL therefore share a single login: whichever one authorizes last evicts
the other, which then opens its own browser tab to authorize and evicts the
first. The symptom is an authorization tab that keeps reappearing and a client
that reports no connection to OtterlyAI.
Separate application folders do not separate these credentials — two Claude
Desktop profiles hit this too. Give each client its own store and its own
callback port.
Claude Desktop:
MCP_REMOTE_CONFIG_DIR; ~ is not expanded. Then quit
every client, delete the shared ~/.mcp-auth, and authorize one client at a
time.
This is also how you connect two different OtterlyAI accounts on one machine —
with one shared store both clients end up on whichever account authorized last.
Available tools
Every tool has a counterpart in the Public API and returns the same data shapes. Each tool also advertises anoutputSchema (JSON Schema) in
tools/list and returns its result as structuredContent conforming to that
schema, with the same JSON mirrored in the text block — so clients can type
and validate responses at the protocol level. Required arguments are listed per
tool; optional arguments below the tables.
Account
Workspaces & engines
Brand reports
Agent analytics
AI crawler and agent traffic hitting the brand report’s own domains — the inverse of citations, which are what the engines said about your brand. Same data as the Agent Analytics tab in the app.
Unlike the other brand-report tools,
startDate and endDate are optional
here and default to the last 14 days (UTC) — the window the app shows by
default. There is no country argument: crawler traffic is attributed to a URL
and a user-agent, and neither carries a country.
get_brand_report_agent_stats speaks one engine vocabulary throughout —
chatgpt, claude, copilot, perplexity, google (Gemini included),
other. That holds for both the summary (topEngine, per-engine totals) and the
trend series, whose rows are { dayId, engine, bot, visitCount }. bot is the
raw crawler name (GPTBot, Google-Extended), so one engine can appear across
several bots on a day — e.g. google for both GoogleOther and
Google-Extended.
Every response carries an availability field. Check it before reading the
numbers:
Treating
not_connected as zero is the mistake worth avoiding: it reads as “no
AI crawler visited this site” when the truth is that nobody is measuring.
GEO audits
Query fan-outs
Write tools (write permission only)
These tools are only registered when your account has
write permission; with
read-only access they are not advertised by the server.
Common arguments
- Dates:
startDateandendDateare inclusive. AcceptYYYY-MM-DDor a full ISO timestamp; only the date portion is used. - Country:
countryis a lowercase ISO 3166-1 alpha-2 code (e.g.us,de). Useukfor the United Kingdom. - Engines:
engines(multi-value) andengine(single-value) acceptchatgpt,claude,google,perplexity,copilot,google_ai_mode,gemini. Calllist_enginesto see which engines are available in which countries. - Engines on the agent-analytics tools: single-value —
chatgpt,claude,copilot,perplexity,google,other.googlecovers the whole Google family (Gemini included), unlike the app which lists Gemini separately. Passengine=otherto match every AI crawler outside the named engines (Amazon, Meta, xAI, ByteDance, Common Crawl, and so on).otheralso appears in the response breakdown, so it means the same thing in and out. The agent name inlist_brand_report_agentsis always exact, soothernever hides which crawler it was. - Pagination: every list tool pages,
with
limitdefaulting to25(max100). Thepagingobject has the same shape as the Public API endpoint behind the tool, but only the shape: several Public API endpoints return the whole list in one response where MCP pages it. Cursor lists (list_workspaces,list_workspace_tags,list_workspace_prompts,list_brand_reports,list_brand_report_recommendations,list_brand_report_annotations,list_crawlability_checks,list_content_checks,list_query_fan_outs) acceptcursorandlimitand returnpaging: { nextCursor, hasMore }; passnextCursorback ascursorfor the next page.list_brand_report_prompt_ai_responsesis cursor-paged too, withcursoronly. Offset lists (list_brand_report_citations,list_brand_report_prompts,list_brand_report_citation_prompts,list_brand_report_agent_pages,list_brand_report_agents) acceptlimitandoffset(a multiple oflimit) and returnpaging: { limit, offset, hasMore }, the agent-analytics lists addingtotalCount; addlimittooffsetfor the next page. Either way, stop whenhasMoreisfalse. The formerpageandpageSizearguments are no longer accepted: a list tool rejects them, like any unknown argument, with a validation error rather than ignoring them. - Extra filters on
list_brand_report_promptsandlist_brand_report_citations:engines,tagId,search,sortBy,sortOrder. searchon the agent-analytics list tools is a case-insensitive substring match, applied server-side across the whole result set. It is matched literally —%and_are not wildcards.
Typical conversation flow
get_account_info→ your plan and how many MCP tool calls remain this period. Free, so it is safe to call first.list_workspaces→ pick aworkspaceId(optional).list_brand_reports→ pick areportId.list_brand_report_promptsorlist_brand_report_citationswithreportId, a date range, and a country code (e.g.us,uk,de).- Drill into
get_brand_report_stats,get_brand_report_citation_stats,list_brand_report_recommendations, or the GEO audit tools as needed. - To ask about AI crawlers on your own site rather than what the engines said,
start at
get_brand_report_agent_statswith just thereportId, then drill intolist_brand_report_agent_pagesorlist_brand_report_agents.
Troubleshooting
The authorization tab keeps reopening, or the client reports no connection to OtterlyAI. Two clients are sharing onemcp-remote credential store — see
Running more than one client.
Reconnecting repairs one client and breaks the other, so the loop survives any
number of reconnects.
“state already in use”. A connection link is single-use and retrying the
same one lands here. Wait about ten minutes, then start the connection again
from the client rather than reloading the page.
The wrong OtterlyAI account got connected. Approval is granted by whichever
account the browser is already signed into; the client has no say in it. To
connect a specific account, sign that account in first — a separate browser
profile per account is the reliable way — and then authorize.
401 from a tool call. The OAuth token is missing or expired; reconnect to
refresh it. If reconnecting works and then fails again within a day, it is the
shared-credential case above rather than an expiry.
403 from a tool call. Your account lacks permission for the requested
workspace.
Things to know
- Most tools are read-only. The tools in the Write tools section above
are only available to accounts with the
writepermission. - Workspace scoping matches your OtterlyAI account. See
Troubleshooting for
401and403responses. - Every tool call except
get_account_infocounts against your plan’s MCP tool-call limit. Once it is exhausted, calls fail withRequest limit exceeded for this billing perioduntil the next period. - Each tool’s
outputSchemais the contract for its result. The shapes are the Public API response shapes, paging included, so the OpenAPI spec doubles as a field reference.