Skip to main content
Glama
AEO Copilot MCP Server

AEO Copilot MCP Server

README.md
# AEO Copilot MCP Server

Connect [AEO Copilot](https://aeo-copilot.com) to Claude or any MCP-compatible assistant. Ask your AI how ChatGPT, Claude, Perplexity, Gemini and Google AI Overviews answer about your brand, then work through the fixes AEO Copilot finds (Actions) without switching tabs.

## What is AEO Copilot?

AI search engines are eating into traditional search traffic. When someone asks ChatGPT "What's the best tool for X?", your brand either shows up or it doesn't. Unlike Google, there's no ranking page to check.

[AEO Copilot](https://aeo-copilot.com) runs prompts against 4 engines of your choice out of ChatGPT, Claude, Perplexity, Gemini, and Google AI Overviews, and records whether your brand got mentioned, where it ranked, how it was described, and which competitors showed up instead. This MCP server puts that data inside your AI assistant.

## New in 2.1.0

Your agent can now read and act on Site audit > Content, to improve the pages your prompts point to.

- `get_content_audit`: every audited page with its quality, substance, trust and copy scores, and the average over time.
- `get_content_audit_page`: one page's full report (failed checks, copy tells, fixes), its score history, the prompts that point to it and its open actions.
- `set_content_audit_pages` and `run_content_audit`: choose which pages are audited, and rescore them after you edit.

These need the new version of AEO Copilot on the brand.

## New in 2.0.0

Recommendations are now Actions, in the app and here.

- `get_recommendations` is removed, along with `GET /api/v1/brands/:id/recommendations`. Use `list_actions` to read what to fix and `update_action` to accept, dismiss or mark it done.
- `get_insights` keeps its `recommendations` field. It now holds your 3 most urgent open actions.

On 1.x, `get_recommendations` returns a 404. `npx aeo-copilot-mcp` picks up 2.0.0 on its own; if you pinned a version, move to `aeo-copilot-mcp@2`.

## Tools

| Tool | Description |
|------|-------------|
| `list_brands` | List all brands on your account |
| `list_topics` | List topics for a brand (e.g. "Product Comparisons", "Pricing Questions") |
| `get_results` | Per-prompt results for each engine the account tracks (ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews): mention status, position, sentiment, sources, competitors, and the full answer text. Set `engine` to read just one LLM's answers (e.g. Claude) |
| `get_insights` | Overview metrics: % of AI answers that name your brand (per engine, with the change since the last run), share of voice, what changed, who's named instead, reputation, cited sources, topics |
| `list_actions` | Your brand's actions: page fixes, pages to create, sources to win, site fixes, each tied to the prompts it affects, with before/after for done ones |
| `update_action` | Accept, dismiss, mark done or reopen an action; done actions are measured on the next runs of their prompts |
| `get_reputation` | Reputation brands: answers that get your brand wrong (wrong product, outdated, contradicting your facts, engine doesn't know you), by engine, with the quote and the fact it conflicts with |
| `draft_brand_facts` | Draft brand facts from your website for review (nothing is saved) |
| `set_brand_facts` | Save the brand facts answers are checked against, then re-check the latest answers |
| `check_reputation` | Re-check the latest answers against the saved brand facts |
| `create_brand` | Create a new brand (subject to your plan's brand limit) |
| `create_topic` | Create a topic cluster for a brand |
| `add_prompts` | Bulk-add prompts to a brand under a topic (subject to your plan's monthly prompt limit) |
| `run_brand_prompts` | Run all prompts for a brand (or one topic) across every enabled LLM |
| `scan_brand` | Run the technical audit on the brand's website and return the full scan result |
| `get_content_audit` | Site audit > Content: each audited page's quality, substance, trust and copy scores, the last change, prompts pointing to it, and the average over time |
| `get_content_audit_page` | One page's content report (failed checks, copy tells, fixes), score history, matched prompts and open actions, to improve that page |
| `set_content_audit_pages` | Replace the pages added to the content audit (up to 20); new pages are scored right away |
| `run_content_audit` | Rescore the content audit pages now, for example after editing a page |
| `create_index` | Create an industry index (brand-agnostic — every cited entity is captured) |
| `list_indexes` | List all industry indexes on your account |
| `add_index_topic` | Add a topic cluster to an index |
| `add_index_prompts` | Bulk-add prompts to a topic in an index |
| `run_index_prompts` | Run all index prompts on the account's selected engines and store full per-LLM results |
| `get_index_results` | Raw per-prompt results for an index across all LLMs |
| `get_index_share_of_voice` | Ranked entity list by citation frequency + concentration score (top-1 share, HHI) |
| `get_index_sources` | Domains ranked by citation frequency across every LLM response |
| `get_index_whitespace` | Prompts/topics where no entity is consistently cited — opportunity gaps |

## Setup

### 1. Get your API key

1. Log in to [aeo-copilot.com](https://aeo-copilot.com)
2. Go to **Settings → API**
3. Click **Create API key**
4. Copy the key — it starts with `aeo_`

Keep it somewhere safe; you won't be able to see the full key again after closing the dialog.

### 2. Add to Claude Code

```bash
claude mcp add aeo-copilot -e AEO_COPILOT_API_KEY=aeo_your_key_here -- npx aeo-copilot-mcp
```

### 3. Add to Claude Desktop

Edit `claude_desktop_config.json`:

- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "aeo-copilot": {
      "command": "npx",
      "args": ["aeo-copilot-mcp"],
      "env": {
        "AEO_COPILOT_API_KEY": "aeo_your_key_here"
      }
    }
  }
}
```

Restart Claude Desktop after saving.

## What you can ask

- "What's my brand's AI visibility score?"
- "Show me exactly what Claude said about my brand"
- "Which prompts mention my competitors but not me?"
- "Show me my visibility trend for the last 30 days"
- "What topics are performing best in AI search?"
- "What should I fix to improve my AI visibility?"
- "Find my lowest-scoring page in the content audit, fix its copy on our site, then rescore it"
- "Go through my new actions, accept the page fixes worth doing, and make them on our site"
- "Which of the actions I finished last month actually got us named more often?"
- "How does my brand compare to [competitor] in AI-generated answers?"
- "What's the sentiment breakdown for my brand mentions?"
- "Draft brand facts for my Reputation brand from our website, and show me what to correct"
- "Which AI answers describe the wrong product, and where did they get it from?"

## API reference

### `list_brands`
```
GET /api/v1/brands
```
Returns all brands on your account: name, website, industry, products, competitors.

### `list_topics`
```
GET /api/v1/brands/:id/topics
```
Topics group related prompts. Each topic has a name, description, target pages, and keywords.

### `get_results`
```
GET /api/v1/brands/:id/results
```
Per-prompt results. Each entry includes mention status, position, sentiment, sources cited, and competitors — broken down by AI engine. Every engine block also carries `response`: the **full answer text** that engine returned for the prompt.

Optional filters:

| Parameter | Type | Description |
|-----------|------|-------------|
| `topicId` | string | Filter by topic |
| `engine` | string | Return only one engine's answers: `chatgpt`, `claude`, `perplexity`, `googleAio`, or `gemini`. Each result is flattened to that engine's block (including its `response` text) and prompts where it wasn't run are omitted. Omit to get every engine |
| `from` | ISO date | Start date, e.g. `2025-01-01` |
| `to` | ISO date | End date |
| `limit` | number | Max results (default 100, max 500) |

> The API has no server-side `engine` filter — it always returns a block per engine (null when that engine didn't run). The MCP server applies the `engine` filter client-side so you get a focused, smaller payload when you only want one LLM (e.g. exactly what Claude said).

### `get_insights`
```
GET /api/v1/brands/:id/insights
```
The same numbers as the Overview page:

- `visibility`: % of answers that name your brand (1 answer = 1 prompt on 1 engine, latest run of each active prompt), with `visibilityDelta` in points and the split by engine
- `shareOfVoice`: your mentions as a share of all mentions of you and your tracked competitors
- `changes`: prompts where an engine stopped or started naming you, and who was named instead
- `competitors`: you and your competitors ranked on the same metric
- `reputation`, `sources`, `topics`
- `recommendations`: your 3 most urgent open actions (id, priority, category, type, title, description, target). `list_actions` returns them all
- Legacy fields kept: sentiment, competitiveShare, visibilityTrend, topTopics, mentionVolume, competitorBreakdown

### `get_reputation`
```
GET /api/v1/brands/:id/reputation
```
For Reputation brands: every answer checked against your saved brand facts. Returns `status`, problems by type and engine, `fixes` (quote, conflicting fact, prompts, engine, cited sources), a prompts × engines `matrix`, `tone` on answers with no problem, `changes`, `sources` and the saved `facts`. "No problem found" means nothing conflicts with your facts, not that the answer is verified.

### `draft_brand_facts`
```
POST /api/v1/brands/:id/brand-facts/draft
```
Drafts aliases and 5 to 8 facts from your website, each with the page it came from. Nothing is saved.

### `set_brand_facts`
```
PUT /api/v1/brands/:id/brand-facts
{ "aliases": ["generic name"], "facts": [{ "id": "f1", "statement": "...", "kind": "identity", "source": null }] }
```
Replaces the facts (the version goes up by 1) and re-checks the latest answers. `kind` is one of identity, indication, regulatory, pricing, availability, other. Needs editor access. Accuracy checks run on paid plans.

### `check_reputation`
```
POST /api/v1/brands/:id/reputation/check
```
Re-checks the latest answers against the current facts in the background. Read the result with `get_reputation`.

### `list_actions`
```
GET /api/v1/brands/:id/actions?status=triage|accepted|done|dismissed
```
Actions for a Visibility-mode brand, high priority and most prompts first. Each has a `type` (`cited_not_named`, `content_gap`, `page_structure`, `content_quality`, `source_opportunity`, `site`), a `target` (page URL, topic, domain or site check), what's wrong (`summary`), what to do (`detail`), `evidence`, and the `prompts` it affects. Done actions carry `baseline` (at accept) and `result` (measured on runs after the change, `measuredAt`). `enabled: false` means Actions isn't switched on for the account yet.

### `update_action`
```
PATCH /api/v1/actions/:id   { "status": "accepted" }
```
Moves: triage → accepted or dismissed; accepted → done or triage; done → accepted; dismissed → triage. A skipped step returns 409. Needs editor access.

### `create_brand`
```
POST /api/v1/brands
```
Create a new brand. Body: `name` (required), `website`, `industry`, `products[]`, `competitors[]`. Returns 402 if you've hit your plan's brand limit.

### `create_topic`
```
POST /api/v1/brands/:id/topics
```
Create a topic cluster. Body: `name` (required), `description`, `pages[]`, `keywords[]`.

### `add_prompts`
```
POST /api/v1/brands/:id/prompts
```
Bulk-add prompts under a topic. Body: `topicId` (required), `prompts[]` (required, array of strings). Returns 402 if adding these prompts would exceed your plan's monthly prompt limit.

### `run_brand_prompts`
```
POST /api/v1/brands/:id/run
```
Run all prompts across every enabled LLM. Optional query param `topicId` to scope to a single topic. Returns the count of prompts run.

### `scan_brand`
```
POST /api/v1/brands/:id/scan
```
Run the technical audit on the brand's website. Returns the full scan result (schema markup, sitemap, llms.txt, etc.) — same data the dashboard's technical scan view shows.

### `get_content_audit`
```
GET /api/v1/brands/:id/content-audit
```
Audited pages with their scores (`quality`, `substance`, `trust`, `copy`, 0-100), the pages added by URL list (`addedUrls`), the average quality and its history by day. `processing` is true while pages are being scored. `enabled: false` when the brand is not on the new version.

### `get_content_audit_page`
```
GET /api/v1/brands/:id/content-audit/page?url=
```
One page: `page` (scores), `report` (the slop detector's copy and quality reports), `history`, `prompts` pointing to the page, and `actions` about it. 404 when the page hasn't been scored.

### `set_content_audit_pages`
```
PUT /api/v1/brands/:id/content-audit/pages   { "urls": [...] }
```
Replaces the added pages (up to 20, on the brand's site). Returns `saved` and `refused` with the reason. Editor access.

### `run_content_audit`
```
POST /api/v1/brands/:id/content-audit/run
```
Rescores the content audit pages in the background (202). Editor access.

## Industry indexes

Indexes are brand-agnostic: instead of tracking how *your* brand is mentioned, an index tracks **every entity** cited across an industry's prompts. Useful for category mapping, competitive whitespace, and seeing which sources the LLMs lean on.

### `create_index`
```
POST /api/v1/indexes
```
Create an industry index. Body: `name` (required), `industry` (required), `description`.

### `list_indexes`
```
GET /api/v1/indexes
```
List all indexes on your account.

### `add_index_topic`
```
POST /api/v1/indexes/:id/topics
```
Add a topic cluster. Body: `name` (required), `description`.

### `add_index_prompts`
```
POST /api/v1/indexes/:id/prompts
```
Bulk-add prompts under a topic. Body: `topicId` (required), `prompts[]` (required, array of strings).

### `run_index_prompts`
```
POST /api/v1/indexes/:id/run
```
Run every prompt on the engines the account has selected (up to 4 of ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews). All extracted entities are stored as competitors — no brand filter.

### `get_index_results`
```
GET /api/v1/indexes/:id/results
```
Raw per-prompt results across all LLMs. Same shape as `/brands/:id/results` minus the brand-mention fields.

### `get_index_share_of_voice`
```
GET /api/v1/indexes/:id/share-of-voice
```
Ranked entity list by citation frequency, plus a concentration score:

- `top1Share`: the % of mentions held by the most-cited entity
- `hhi`: an HHI-style index (sum of squared shares × 10,000) showing how concentrated mentions are. Higher = more dominated by a few entities.

### `get_index_sources`
```
GET /api/v1/indexes/:id/sources
```
Domains ranked by citation frequency across every LLM response in the index.

### `get_index_whitespace`
```
GET /api/v1/indexes/:id/whitespace
```
Prompts and topics where **no entity is consistently cited** — i.e. fewer than 1 consistent entity appears across at least 50% of runs. These are the gaps where a brand can establish authority before the category solidifies.

## Development

```bash
git clone https://github.com/sofianbettayeb/aeo-copilot-mcp
cd aeo-copilot-mcp
npm install
AEO_COPILOT_API_KEY=aeo_your_key npm run dev
```

To run against another instance, such as a local AEO Copilot dev server, set `AEO_COPILOT_BASE_URL` (default `https://aeo-copilot.com`):

```bash
AEO_COPILOT_BASE_URL=http://localhost:3000 AEO_COPILOT_API_KEY=aeo_your_key npm run dev
```

## License

MIT

TDQS

A3.5/5.0

Scored across 25 tools

Disambiguation4/5

Tools are mostly distinct thanks to consistent brand/index prefixes and clear resource nouns, but update_prompt and update_prompts overlap functionally since the bulk variant can also handle a single prompt. Overall, descriptions resolve most ambiguity and misselection risk is low.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern with predictable verbs: list, create, get, add, update, delete, restore, run, scan. Brand/index distinctions are systematically encoded, e.g. run_brand_prompts vs run_index_prompts and get_results vs get_index_results.

Tool Count3/5

25 tools sits at the heavy end of the borderline range for a single MCP server. The domain is broad enough that most tools serve a purpose, but several bulk/parallel variants (e.g. update_prompt vs update_prompts, brand vs index families) make the surface feel larger than necessary.

Completeness3/5

Prompt lifecycle coverage is strong: list, add, update, delete, restore, and run are all present. However, brands, topics, and indexes have create/add/list/get operations but no corresponding update or delete tools, and index prompts cannot be listed or removed outside of results, leaving notable dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues