MCP server
A Model Context Protocol endpoint that exposes MentionFlow's reads as tools an AI agent can call. The setup, the protocol, and all sixteen tools.
The MCP server offers the same reads as the REST API, as tools an AI agent can call over the Model Context Protocol. It is stateless and runs the identical computations, so an MCP answer and a dashboard number never disagree. Every tool is a read except run_fact_check, which triggers the same on-demand check as the dashboard's fact-check card.
Endpoint and setup
The quickest way in is the app: the MCP server page in the sidebar prints a paste-ready config for Claude Desktop, Claude Code, Cursor, or any MCP client, and the key you mint there is filled in for you. The rest of this page is the same setup, written out.
- Endpoint:
POST https://mentionflow.ai/api/mcp(Streamable HTTP). AGETreturns405withAllow: POST. - Auth: the same bearer key as REST (
Authorization: Bearer mf_…). Aningest-scoped key is rejected with403. See Authentication.
Configure an MCP client with an HTTP transport:
{
"type": "http",
"url": "https://mentionflow.ai/api/mcp",
"headers": { "Authorization": "Bearer mf_your_key_here" }
}
Protocol
- JSON-RPC 2.0. Supported methods:
initialize,ping,tools/list,tools/call. - Protocol versions offered:
2025-06-18,2025-03-26,2024-11-05. The server echoes the version you ask for if it supports it, otherwise the newest. - Server identity:
{ "name": "mentionflow", "version": "1.0.0" }, advertising atoolscapability. - A batch may hold at most 10 messages (see Limits).
Every tool returns one text content block. Its text is the JSON payload, in the same shape as the matching REST resource. A tool that runs and fails, say on an unknown brand, returns a normal result flagged isError: true, not a protocol error. Check that flag. See Errors.
The brand argument
Every tool except list_brands takes one optional argument:
{ "brand_id": "<id from list_brands; defaults to your first brand>" }
Omit brand_id to use your first brand. An unknown id, or one outside your scope, returns {"error":"Unknown brand id: <id>"}.
Tools
Payload shapes and scales match the Resource reference and Conventions.
| Tool | Argument | Returns | Cap |
|---|---|---|---|
list_brands | none | your brands (id, name, domain) | — |
get_overview | brand_id? | the visibility scorecard | — |
list_prompts | brand_id? | tracked prompts with per-prompt presence, visibility, average position | all active |
list_tag_groups | brand_id? | the brand's named tag groups over the free-text prompt tags. Same data as the tag_groups block on /api/v1/prompts; [] = no groups defined, not no tags | all groups |
list_competitors | brand_id? | the competitor leaderboard, your brand's row included | all entities |
list_sources | brand_id? | cited domains with counts and classification | 20 |
list_urls | brand_id? | URL-level citation rows, the pages behind list_sources; see /api/v1/urls | 50 |
list_answers | brand_id? | recent runs: engine, model, region, ordered mentions, citations | 50 |
list_shopping_products | brand_id? | the shopping product leaderboard | 30 |
get_shopping_trend | brand_id? | the daily shopping-carousel time series | 7-day |
get_metrics_history | metric (required), brand_id?, days?/from?+to?, engine?, competitors? | daily metric time series (visibility, share-of-voice fraction, citation share, sentiment); see /api/v1/metrics/history | 366 days |
get_crawler_analytics | brand_id?, days? (7/14/28) | AI-agent activity on the brand's own site, plus robots.txt verdicts, with the honest-null rules in the description; see /api/v1/crawlers. Growth+ plans, the same gate as the /crawlers page | all known agents |
list_ads | brand_id?, days? (7/14/28/56) or from?+to?, engine? | captured advertiser units (engine-stated sponsored placements) with run and prompt linkage, plus verbatim creatives; see /api/v1/ads. Observable on ChatGPT only today, capture began July 2026 | 200 |
get_sentiment | brand_id?, days? (7/14/28/56), engine? | tone per entity (you and every tracked rival) and per engine, the counts behind each index, and the verbatim quotes the tone came from, worst first; see /api/v1/sentiment | 40 quotes |
get_fact_check | brand_id? | the cached knowledge-base fact check; see /api/v1/fact-check. fact_check: null = never checked, not clean | single slot |
run_fact_check | brand_id?, force? | runs the on-demand check (metered, about $0.01 to $0.02, spend reported as cost_usd); see below | single slot; 24 runs/brand/day |
list_answers returns 50 rows over MCP. The REST /api/v1/answers returns 200. Everything else matches its REST counterpart.
What to ask it
The setup is the easy half. The half people get stuck on is knowing what to type. Ask for the thing you want to know, in normal words. The client picks the tool.
Start with this one. It proves the connection and shows you the shape of the rest:
Use the MentionFlow tools. Which brands can you see, and how visible are we in AI answers right now?
Those first four words matter in a client that can also read files or run commands, such as Claude Code or Cursor. Without a named source, a question about "our data" is ambiguous, and an agent sitting in a repository will answer from the repository. Say "use the MentionFlow tools" and it asks the server. If nothing comes back at all, restart the client: tools load at startup.
Then, by job:
| Ask | What comes back | Tool |
|---|---|---|
| How visible are we in AI answers this week, and did it move? | Visibility, share of voice, sentiment and citation share, with the change | get_overview |
| Show our visibility for the last 28 days and tell me which days we dropped. | The daily series. Days with no collection come back null, never zero | get_metrics_history |
| Compare ChatGPT and Perplexity for us over the last 28 days. | The same series per engine, so you can see which one is cold on you | get_metrics_history |
| Who beats us in AI answers, and by how much? | The leaderboard: every tracked rival, their share, and where you sit | list_competitors |
| What do the engines say about us that is negative? Quote it. | The tone score, the counts behind it, and the sentences it was read from | get_sentiment |
| Do the engines say anything wrong about our pricing or features? | The cached fact check: claims that clash with your brand knowledge | get_fact_check |
| Which sites do the engines cite when they answer about our category? | Cited domains and pages, how often each is used, and whether it is yours | list_sources |
| Which of our prompts never mention us? Give me the answers as proof. | Presence per prompt, plus the answers behind it, word for word | list_prompts |
| Which AI bots crawl our site, and does any of it turn into citations? | Hits per bot, the pages they fetch, and how much gets cited back | get_crawler_analytics |
Three habits make the answers better:
- Name the window. Say "this week" or "the last 28 days". With no window the tools use 7 days.
- Name the brand when the workspace holds several. Otherwise the first one is used.
- Ask for the quote. Add "quote it" and you get the sentence an engine actually wrote, with its run id. That is the difference between a claim and proof.
What it will not do: change anything (every tool reads, except run_fact_check), reach a brand the key was not scoped to, or fill a gap. A null means the number was not measured, not that it is zero. Each tool's description carries that rule, so a well-behaved agent repeats it instead of rounding it away.
The same list, with copy buttons, sits on the MCP server page in the app.
Tag groups
list_tag_groups reads the brand's named tag groups, the ones you create on /prompts beside the tag filter. It serves the same tag_groups block GET /api/v1/prompts carries, through the same loader, so the two can never disagree.
Groups are brand-level metadata keyed by the literal tag string. Prompt tags stay free text. A tag in no group is simply ungrouped, the automatic state of every tag. tag_groups: [] means the brand has defined no groups, not that it has no tags.
Member tags are limited to tags currently on the brand's active prompts, so a stored member whose tag no prompt carries anymore is left out. An empty group is real: created, waiting for members. The tool is read-only. Groups are created and edited in the dashboard.
Fact-check tools
get_fact_check reads the brand's single cached fact-check result. Each run overwrites the last. null means no check has ever run, so read it as "never checked", not "no discrepancies". Field meanings match GET /api/v1/fact-check, including the 7-day staleness rule and the honest-null cost_usd.
run_fact_check is the one tool here that is not a read. It triggers the exact path behind the dashboard's "Run fact check" button: a metered LLM call, about $0.01 to $0.02 per run, with the real spend returned as cost_usd. It compares the newest answer per engine against the brand's knowledge base, up to 8 answers, and only ones that mention the brand.
Two guards keep the cost down. A cached result fresher than the 7-day staleness rule comes back with ran: false instead of spending. Pass force: true to run anyway. Back-to-back runs on the same brand are refused for a few seconds.
Each brand is capped at 24 metered runs per UTC day, force included. Only runs that spend count: a cached ran: false return, or a refusal such as a missing knowledge base, hands its slot back. Past the cap the tool returns an honest daily cap reached (24/day) error until UTC midnight, while get_fact_check and the cached read keep working. The shared rate limit applies on top.
The check needs the brand to have a knowledge base. Without one it returns an honest error, not an empty result.
Sentiment tool
get_sentiment is the sentiment tracker for agents, through the query definition GET /api/v1/sentiment uses. Its description carries the rules: sentiment_index is 0 to 100 with 50 neutral, null means no scored mention and never neutral, unscored mentions are reported but excluded, and quotes are verbatim spans tied to a run id, so the agent can cite the answer instead of paraphrasing the number. Filter quotes on entity to see what the engines hold against a competitor. See the REST resource.
Ads tool
list_ads returns the captured advertiser units behind the Ads intelligence page, through the query definition GET /api/v1/ads uses. Field meanings, the window grammar (days preset or from/to, engine list), the 200-row cap and the note rules all match the REST resource.
Its description carries the honesty contract. Ad presence is engine-stated and observable on ChatGPT only today (engines_observable). Structured capture began July 2026, so an empty earlier window means "not captured", never "no ads ran". A unit with no stated name or link is "not stated", never guessed. There are no spend estimates, by design.
The shopping tools embed their contract the same way, so an agent reading them gets the rules in context. list_shopping_products says that totals.carousels = 0 with an empty product list means no carousels were captured this window, and that you report it as absence of data, never as shopping presence. get_shopping_trend says that own_avg_position is null on days the brand was not on the shelf, since null is not zero, and that fewer than two observed days is a snapshot, not a trend. list_shopping_products also covers channel_coverage: status parses-today means the engine's payloads carry parseable product data, awaiting-payload means extraction is wired but the vendor sends no product fields yet, and carousels is null when unobservable, either because the engine was not sampled or the payload is missing. Null is NOT zero.
Related
- Resource reference: the field tables these tools return.
- Conventions: scales, null handling, and
notefields. - Limits, Errors, Authentication.