# AthenaHQ (remote · api.athenahq.ai)

Track how AI assistants mention, cite, and rank your brand and competitors in AI search.

- Trust score: 66/100 (medium)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- remote · `api.athenahq.ai`: 66/100 (this document), [markdown](https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp.md), [page](https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp)

## Channel facts

- Endpoint: `https://api.athenahq.ai/api/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `1.0.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Endpoint Security**: 63/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation check failed: no authorisation is required to call this server, and it exposes a tool marked destructive (add_brand_facts).
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 34/100
  - 0% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 19329 tokens (~169/item across 114 items; 113 tools + 1 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 63/100
  - Stability check failed: schema churn in the 20 days we've observed: 4 tool removals, 0 breaking changes, 0 auth/transport breaks, 14 additions.
- **Tool Coverage**: 77/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 21% of tool parameters carry a description.
  - Structured output schemas are declared (99% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - All 10 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.
  - An AI judge read all 114 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.
  - Supports UI / widget rendering.

## Install

### How do I install the AthenaHQ MCP server?

AthenaHQ is a hosted endpoint at https://api.athenahq.ai/api/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http ai-athenahq-mcp 'https://api.athenahq.ai/api/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "ai-athenahq-mcp": {
      "url": "https://api.athenahq.ai/api/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "ai-athenahq-mcp": {
      "type": "http",
      "url": "https://api.athenahq.ai/api/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.ai-athenahq-mcp]
url = "https://api.athenahq.ai/api/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ai-athenahq-mcp": {
      "type": "remote",
      "url": "https://api.athenahq.ai/api/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ai-athenahq-mcp --url 'https://api.athenahq.ai/api/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  ai-athenahq-mcp:
    url: "https://api.athenahq.ai/api/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "ai-athenahq-mcp": {
      "Transport": "http",
      "Url": "https://api.athenahq.ai/api/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add ai-athenahq-mcp -t streamable-http -u 'https://api.athenahq.ai/api/mcp'
```

### Other

```json
{
  "mcpServers": {
    "ai-athenahq-mcp": {
      "type": "http",
      "url": "https://api.athenahq.ai/api/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-11-04 (score 66, +1)

- [cosmetic] “query_metrics” reworded the description of “compare”

### 2026-11-02 (score 65, +1)

No change was recorded against any check on this day. Stability & Change Management went from 49 to 53.

### 2026-10-30 (score 64, +1)

No change was recorded against any check on this day. Stability & Change Management went from 39 to 43.

### 2026-10-29 (score 63, 0)

- [security] New tool “remove_competitors”, which the server declares destructive
- [functional] New tool “add_competitors”

### 2026-10-28 (score 63, +1)

- [functional] New tool “list_api_keys”

### 2026-10-26 (score 62, +1)

No change was recorded against any check on this day. Stability & Change Management went from 26 to 29.

### 2026-10-24 (score 61, 0)

- [security] Tool “query_metrics” rewrote its description, which is the text the model reads
- [security] Tool “query_rows” rewrote its description, which is the text the model reads
- [functional regression] Schema quality: 144 → 169
- [cosmetic] “query_metrics” reworded the description of “from”
- [cosmetic] “query_rows” reworded the description of “from”

### 2026-10-23 (score 61, +1)

- [security] Tool “start_prompt_discovery” rewrote its description, which is the text the model reads
- [functional] New tool “find_more_prompt_discovery”

## MCP tools (113)

### `open_ai_access` (~37 tokens)

AI crawler access

Open the AthenaHQ AI crawler access panel. Enter a public HTTPS domain to inspect crawler responses and robots.txt permissions without an AthenaHQ account.

### `check_public_ai_access` (~87 tokens)

Check AI crawler access

Check HTTP responses to AI crawler user agents and robots.txt permissions for a public website. No AthenaHQ account required. Search, retrieval and training are separate. Requests originate from AthenaHQ, not verified crawler IPs. Unknown responses are inconclusive; this does not measure visibility or guarantee indexing, citations or real crawler access. Use nullable evidence and diagnostics.

Input parameters:

- `domain` (string, required)

Output parameters:

- `checkedAt` (string)
- `diagnostics` (object)
- `domain` (string)
- `evidence` (object)
- `log` (string)

### `get_prompt_schedules` (~130 tokens)

List the Default, custom and archived streaming schedules for a website. Use each row's selection value when filtering analytics or responses. Default includes all pre-cutover history and ad hoc runs; archived schedules retain results. To combine schedules, pass several selection values as an array in the schedule field of query_metrics and query_rows, or use a saved view that stores several schedules. Partner REST filters take one schedule. starts_on and ends_on bound a custom schedule's active period as UTC days (null means no bound); an active schedule outside its period does not run.

Input parameters:

- `website_id` (string, required)

Output parameters:

- `schedules` (array)

### `get_ai_search_value` (~55 tokens)

AI Search Value for a website: topic-market value, captured value range, headroom, coverage, value-weighted AI share of voice, per-topic detail, and modeled attributed contribution.

Input parameters:

- `website_id` (string, required)

Output parameters:

- `assumptions_version` (string|null)
- `captured` (object)
- `computed_at` (string|null)
- `contribution` (object)
- `forecast`
- `has_computed_valuations` (boolean)
- `headroom` (object)
- `is_stale_value` (boolean)
- `market` (object)
- `measured_responses` (number)
- `merge_suggestions` (array)
- `topics` (array)

### `get_prompts` (~52 tokens)

List prompts (search queries) tracked for a website

Input parameters:

- `prompt_tags` (array)
- `prompt_tags_operator` (string)
- `status` (string)
- `website_id` (string, required)

Output parameters:

- `prompts` (array)

### `get_prompt_tags` (~44 tokens)

List prompt tags for a website with per-tag prompt counts. Tag IDs can be used with the prompt_tags filter on the prompts endpoint.

Input parameters:

- `website_id` (string, required)

Output parameters:

- `prompt_tags` (array)

### `get_personas` (~47 tokens)

List personas configured for a website with per-persona prompt counts. Use it to resolve persona_id values returned by other tools to persona names and descriptions.

Input parameters:

- `website_id` (string, required)

Output parameters:

- `personas` (array)

### `get_topics` (~36 tokens)

List topics (groupings of prompts) for a website, with the count of prompts in each

Input parameters:

- `website_id` (string, required)

Output parameters:

- `topics` (array)

### `get_competitors` (~25 tokens)

List competitors tracked for a website

Input parameters:

- `website_id` (string, required)

Output parameters:

- `competitors` (array)

### `get_content_hub_sheets` (~85 tokens)

List the Content Hub tabs/sheets configured for a website. Use to discover available tabs (e.g. 1st-party content, 3rd-party placements, Reddit) before calling get_tracked_content with a specific sheet_id (metrics; excludes in-flight pipeline items) or list_content (every item including unpublished drafts).

Input parameters:

- `website_id` (string, required)

Output parameters:

- `sheets` (array)

### `get_tracked_content` (~250 tokens)

List tracked content (1st-party drafts, imported pages, 3rd-party placements) with citation, mention, and impression metrics for the supplied date range and filters. Supports pagination via page_num / page_size and optional filtering by Content Hub sheet_id or content_type. A sheet_id of a view-type tab (see get_content_hub_sheets sheet_type) lists the shared main pool: content not filed in any sheet. In-flight pipeline items (drafts, briefs, running generations) never appear here; enumerate those with list_content. A returned item can still lack a url (pipeline finished but not published anywhere yet).

Input parameters:

- `content_type` (string)
- `filters` (object, required)
- `mentioned` (boolean)
- `page_num` (integer)
- `page_size` (integer)
- `sheet_id` (string): Content Hub tab to list (get_content_hub_sheets). A sheet-type tab lists its own content; a view-type tab, the default tab included, lists the shared main pool (content not filed in any sheet), witho…
- `website_id` (string, required)

Output parameters:

- `content` (array)
- `pagination` (object)

### `list_content` (~470 tokens)

Enumerate every content item in a website's Content Hub, published or not: in-flight drafts, briefs, snipes, optimize and slice runs, scheduled and failed items, plus tracked pages. Returns identity fields only (id, title, type, stage, sheet, URL, timestamps, target prompt ids), no metrics. Uncached and Postgres-backed, so an item created by create_content is listable immediately. Filter by sheet_id, content_type, stage, or prompt_id. stage is the raw pipeline workflow state, not a publication flag: null = no pipeline record (most tracked external / imported pages), and manual editor items carry 'generated'. Treat an item as published only when its stage is done (or it is an external / imported page) AND it has a url; done without a url is an unpublished orphan. A sheet_id of a view-type tab (see get_content_hub_sheets sheet_type) lists the shared main pool without the view's saved filters. Use get_tracked_content for citation and impression metrics on published content; use this tool to discover what exists. Each row carries prompt_ids: the prompts that item was WRITTEN FOR (what create_content was given), capped at 25 with the true size in prompt_count — resolve the ids to text with get_prompts rather than calling get_content_detail per row, and drill in with get_content_detail where prompt_count exceeds the ids returned (that read carries up to 100; associations past 100 are not currently readable). prompt_ids includes soft-deleted prompts, which get_prompts does NOT list — an id that fails to resolve there is a deleted prompt, and get_content_detail returns its text and status: "deleted". Empty prompt_ids means no targeting was recorded, which is normal for imported or externally tracked pages. This is not the same as being cited for a prompt — see get_content_citation_prompts for that. Filter by prompt_id for the reverse question: which content already targets a given prompt (coverage gaps).

Input parameters:

- `content_type` (string)
- `page_num` (integer)
- `page_size` (integer)
- `prompt_id` (string)
- `sheet_id` (string)
- `stage` (string)
- `website_id` (string, required)

Output parameters:

- `content` (array)
- `pagination` (object)

### `get_content_detail` (~358 tokens)

Fetch the full detail of a single tracked content item — its brief and body text (drafts, optimize rewrites, snipes, authored and scraped pages), plus status, cited source URLs, and links. Use after get_tracked_content to read the actual text behind a content_id. A status of generated_brief means the brief is ready while the article is still being written. Pages registered via track_content_urls return a null body and null status until their page text is fetched from the app — a null body on an external page means not fetched yet, not missing content; citation tracking does not need the body. `prompts` lists the prompts this page was WRITTEN FOR (the same ids create_content takes), newest-linked last, capped at 100 with the true size in `prompts_total`. When prompts_total exceeds 100 the rest are not currently readable through any tool — report the total, do not imply the list is complete. Entries carry status active, paused or deleted: a deleted prompt is still part of what the page was written for and still shows in the Content Hub, but get_prompts will not list it, so use the text returned here. An empty array means the page has no prompt targeting, which is normal for imported or externally tracked pages. That is a different question from get_content_citation_prompts, which lists prompts whose AI responses CITED the page. To see the reworded variants actually asked of the models for these prompts, pass their ids to get_responses (each row carries base_prompt plus the variation as prompt) or query the responses cube via query_rows on the prompt_variation dimension.

Input parameters:

- `content_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `body` (string|null)
- `brief` (string|null)
- `brief_cited_urls`
- `brief_internal_links`
- `cited_urls`
- `content_id` (string)
- `created_at` (string)
- `facebook_post` (string|null)
- `instagram_post` (string|null)
- `internal_links`
- `linkedin_post` (string|null)
- `mark_as_done_time` (string|null)
- `meta_description` (string|null)
- `normalized_url` (string|null)
- `optimize_summary`
- `prompts` (array)
- `prompts_total` (integer)
- `reddit_post` (string|null)
- `sheet_id` (string|null)
- `status`
- `title` (string|null)
- `topic_name` (string|null)
- `type` (string|null)
- `updated_at` (string)
- `url` (string|null)
- `x_post` (string|null)

### `get_content_citation_prompts` (~184 tokens)

For a single tracked content item, list every prompt whose AI responses cited it — with citations, citation %, and estimated impressions. Use after get_tracked_content to drill into which prompts a given URL is appearing for. This is CITED-BY, measured over the requested date range, not the targeting the page was written for: an empty prompts array means no AI response cited this URL in that window, which is expected for new or never-cited pages and is not missing data. For the prompts a page was written to target, read `prompts` on get_content_detail (or prompt_ids on list_content) — those come from the content record itself and do not depend on any citation having happened.

Input parameters:

- `content_id` (string, required)
- `filters` (object, required)
- `mentioned` (boolean)
- `website_id` (string, required)

Output parameters:

- `content_id` (string)
- `content_normalized_url` (string|null)
- `content_url` (string|null)
- `prompts` (array)

### `list_websites` (~70 tokens)

List every website accessible to the calling session. Works with any API key (global or scoped) and with MCP/OAuth sessions. Call with an empty argument object `{}`. Each item includes `baseCountry`, the country market the website targets: use it to tell same-brand websites for different countries apart.

Output parameters:

- `websites` (array)

### `get_locations` (~25 tokens)

List geo-locations configured for a website

Input parameters:

- `website_id` (string, required)

Output parameters:

- `locations` (array)

### `get_date_range` (~94 tokens)

Get the earliest and latest response dates for a website

Input parameters:

- `prompt_status` (string)
- `schedule_id`: One schedule: "default" or a custom/archived schedule UUID. Omit for Default, which includes all pre-cutover history and ad hoc runs. The retired "manual" token is accepted as an alias of "default".…
- `website_id` (string, required)

Output parameters:

- `max_date` (string|null)
- `min_date` (string|null)

### `get_responses` (~243 tokens)

Get LLM responses for a website. Shows how AI models answer queries, with sources, sentiment, and ranking data. Filter by whether a model used search queries or by text within those queries. For a variation-level export at volume, pair filters.variation_filter with include_response: false and compact_sources: true. That keeps the prompt, its variation, the model, the mentioned/cited flags and the cited domains while dropping the answer text, cutting each row to roughly a tenth of its size.

Input parameters:

- `compact_sources` (boolean): Replace the per-source `sources` objects with `source_domains`, a deduped, sorted list of cited root domains. Defaults to false. Use when you need which domains were cited but not their exact URLs.
- `filters` (object, required)
- `include_response` (boolean): Include the full answer text on each row. Defaults to true. Set false to omit the `response` field entirely (the heaviest part of a row) when you only need which prompt/variation ran and how it score…
- `page_num` (number)
- `page_size` (number)
- `website_id` (string, required)

Output parameters:

- `has_more` (boolean)
- `notice` (string)
- `page_num` (number)
- `page_size` (number)
- `responses` (array)
- `total` (number)

### `get_response_streaming_status` (~57 tokens)

Read the latest (or a specific) response-streaming run's whole-run state and response-queue progress. Only completed means downstream analysis has finished

Input parameters:

- `website_id` (string, required)
- `workflow_id` (string)

Output parameters:

- `config` (object)
- `created_at` (string|null)
- `finish_reason`: Why a "failed" or "cancelled" run ended: credits_exhausted (no credits remaining), credits_paused (credit allocation paused by the partner), subscription_inactive, organization_deleted, entitlement_u…
- `is_scheduled` (boolean|null)
- `progress` (object): Response-queue completion only. These counts and percentage do not indicate downstream analysis readiness.
- `saved_response_progress`: Cached retained-response counts, separate from execution-queue progress. A missing completed_count_observed_at means the count is unmeasured, not zero. Initial fields preserve the last observed snaps…
- `state` (string): Whole-run state. Only "completed" means response collection and downstream analysis have finished; "running" can coexist with 100 percent response progress.
- `updated_at` (string|null)
- `workflow_id` (string|null)

### `get_response_detail` (~43 tokens)

Fetch a single LLM response by id with full sources, mentions, and rank details.

Input parameters:

- `response_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `response` (object)

### `get_saved_views` (~28 tokens)

List saved views (filter presets) for a website

Input parameters:

- `website_id` (string, required)

Output parameters:

- `saved_views` (array)

### `get_group_saved_views` (~35 tokens)

List group-level saved views (filter presets) shared across the websites in a group

Input parameters:

- `group_id` (string, required)

Output parameters:

- `group_saved_views` (array)

### `get_credits_organization` (~18 tokens)

Get credit balance for the organization

Output parameters:

- `total` (object)

### `get_credits_website` (~27 tokens)

Get credit balance for a specific website

Input parameters:

- `website_id` (string, required)

Output parameters:

- `credits` (object)

### `get_groups` (~65 tokens)

List all groups in the organization (global API key only)

Input parameters:

- `external_id` (string): Partner API keys only. Filter by the partner-issued external id mapped to a group. Non-partner API keys passing this field receive 403. Omit unless you are a partner integration.

Output parameters:

- `groups` (array)

### `get_group_detail` (~28 tokens)

Fetch a single group by id with its member websites.

Input parameters:

- `group_id` (string, required)

Output parameters:

- `group` (object)

### `get_share_of_voice_cumulative` (~66 tokens)

Get cumulative share of voice — overall SOV for each competitor across the date range. Each entry also includes relative_mention_rate: the share of responses mentioning any tracked brand that mention this entity.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_share_of_voice_time_series` (~71 tokens)

Get share of voice over time — how often the website is mentioned vs competitors, grouped by day. Each entry also includes relative_mention_rate: the share of that day's responses mentioning any tracked brand that mention this entity.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_citation_rate_cumulative` (~43 tokens)

Get cumulative citation rate — average citation rate for each competitor across the date range.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (object)

### `get_citation_rate_time_series` (~49 tokens)

Get citation rate over time — how often AI models cite (link to) the website, grouped by day.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_mention_rate_cumulative` (~67 tokens)

Get cumulative mention rate — average mention rate for each competitor across the date range. mention_rate is absolute (share of all responses); relative_mention_rate is the share of responses mentioning any tracked brand.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (object)

### `get_mention_rate_time_series` (~74 tokens)

Get mention rate over time — how often AI models mention the website by name, grouped by day. mention_rate is absolute (share of that day's responses); relative_mention_rate is the share of that day's responses mentioning any tracked brand.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_position_cumulative` (~40 tokens)

Get cumulative position — average ranking position for each competitor across the date range.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (object)

### `get_position_time_series` (~45 tokens)

Get ranking position over time — average position of the website in AI model responses, grouped by day.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_position_distribution` (~45 tokens)

Get position distribution: share of responses where the brand ranks top/middle/bottom across the date range.

Input parameters:

- `filters` (object, required)
- `website_id` (string, required)

Output parameters:

- `data` (object)

### `query_metrics` (~2137 tokens)

Query aggregated metrics for brand performance, competitors, sources, citations, and response trends. Use query_rows for individual records.

Mentions: from "response_mentions". Citations: from "citations". On either, where { is_website: true } selects the brand; { is_competitor: true } selects competitors; { entity_id: { eq: "<uuid>" } } selects one entity.
Filter/group models by model_category (display names like "ChatGPT", "Claude"), never "model". Dimensions vary by cube; source_mentions has no prompt/model dimensions.
Group by week (Monday start) or month wherever date groups. prompt_status is the paused flag (true = paused).

Measures: count, count_distinct, avg, sum, min, max; per-measure where enables conditional aggregation. Use compare for two date ranges.
When grouping by IDs, use alsoSelect for names: entity_id/entity_name, prompt_id/prompt_text, prompt_topic_id/topic_name (prompts uses topic_id).

Cited pages mentioning competitors but not the brand: from "sources", where { source_mentions_entity: { hasSome: [competitorIds], hasNone: [brandId] } }. Also works on "source_mentions". Checks all stored page mentions per URL/website. Date/model on sources scope AI responses; extracted page content may be older than the live page.

Content-hub attribution: on "sources", where { is_attributed_content: true }; by: ["content_id"], alsoSelect: ["content_title"]. Add content_type to by for type, or group by content_type alone. Read articles from "contents" via query_rows.

Schedule: select one "default" or custom/archived UUID from the catalog, or an array of them to combine schedules. Omit for caller default (current page in Ask Athena); explicit schedule overrides it. Top-level prompt_schedule_kind/id equality filters remain supported but must not conflict with schedule. Historical provenance is independent of current prompt membership; website-level cubes are unaffected.

Input parameters:

- `alsoSelect` (array): Label dimensions carried via any(). Must be determined by a by dim (cube's dependentDims). Example: entity_name when entity_id is in by.
- `by` (array): GROUP BY dimensions. Omit for scalar result.
- `compare` (object): Compare the same measures across two slices. Each base measure `m` expands to `m_<baseline.label>` and `m_<current.label>`; the result also gets `m_delta` (= current − baseline) and `m_pct_change` (=…
- `from` (string, required): Dataset to query. Cubes and their contracts: Each cube lists its selectable fields, then: filter-only (usable only in where), alsoSelect (name←id: group by the id, pass the name in alsoSelect), group…
- `having`: HAVING filter (after grouping). References measure aliases and by dims.
- `limit` (integer): Max rows to return.
- `measures` (object, required): Aggregate expressions keyed by output column name. Example: { total: { fn: 'count_distinct', of: 'response_id' } }
- `orderBy` (array): ORDER BY. Measure aliases and by dims allowed.
- `schedule`: One schedule from the catalog ("default" or a custom/archived UUID), or an array of them to combine their data. Omit to use the caller default. The retired "manual" token is accepted as a deprecated…
- `website_id` (string, required): The website to query. Must be a website your credentials can access.
- `where`: WHERE filter (before grouping).

Output parameters:

- `notice` (string)
- `rows` (array)

### `query_rows` (~1743 tokens)

Query individual analytics rows. Use for qualitative data like response text, specific identifiers, or individual mentions.

Schedule selection: pass schedule: "default" or a custom/archived UUID from the schedule catalog, or an array of them to combine schedules. Omit to use the caller default (Ask Athena uses the current page selection). Explicit selection overrides that default. Existing top-level equality predicates on prompt_schedule_kind/id remain supported, but cannot conflict with schedule. Historical provenance does not change with current prompt membership. Website-level cubes are unaffected.

Cubes (same set as query_metrics): attributes, citations, competitors, contents, prompts, response_mentions, responses, source_mentions, sources, topics, websites.
Returns { rows, nextCursor, hasMore }. Pass nextCursor back as "after" to paginate.
prompt_status is the prompt's paused flag (boolean, true = paused), not a status string.
On the responses cube, content is hydrated from Postgres and can only be selected. Do not filter or sort by content. Use search_terms_in_responses for text frequency analysis.
Use query_metrics for aggregates instead.

Input parameters:

- `after` (object): Last row from previous page for keyset pagination. Must include values for all orderBy dims.
- `fields` (array, required): Columns to SELECT.
- `from` (string, required): Dataset to query. Cubes and their contracts: Each cube lists its selectable fields, then: filter-only (usable only in where), alsoSelect (name←id: group by the id, pass the name in alsoSelect), group…
- `limit` (integer): Max rows to return.
- `orderBy` (array): ORDER BY. If omitted, uses cube default order.
- `schedule`: One schedule from the catalog ("default" or a custom/archived UUID), or an array of them to combine their data. Omit to use the caller default. The retired "manual" token is accepted as a deprecated…
- `website_id` (string, required): The website to query. Must be a website your credentials can access.
- `where`: WHERE filter.

Output parameters:

- `hasMore` (boolean)
- `nextCursor`
- `notice` (string)
- `rows` (array)

### `list_pitches` (~29 tokens)

List pitch workspace reports for the organization. Returns all non-deleted pitches with their status and metadata.

Output parameters:

- `pitches` (array)

### `get_pitch` (~45 tokens)

Get a pitch report by ID including competitors, prompts, attributes, top citing sources, and aggregate metrics (brand mentions, sentiment, response rate).

Input parameters:

- `pitch_id` (string, required)

Output parameters:

- `attributes` (array)
- `competitors` (array)
- `metrics` (object)
- `pitch` (object)
- `prompts` (array)
- `sources` (array)

### `get_sources` (~144 tokens)

List top cited sources (root domains) for a website with citation, mention, brand-mention, and impression metrics. Each row is classified as owned / competitor / partner / third_party. Supports filters (date range, models, prompts, competitors, locations, personas), sort, and pagination via page_num / page_size.

Input parameters:

- `competitors_mentioned` (string)
- `filters` (object, required)
- `mentioned` (string)
- `page_num` (integer)
- `page_size` (integer)
- `search` (string|null)
- `sort_direction` (string)
- `sort_field` (string)
- `website_id` (string, required)

Output parameters:

- `notice` (string)
- `pagination` (object)
- `sources` (array)

### `get_source_pages` (~153 tokens)

List individual cited URLs (pages) for a website with citation, mention, and impression metrics plus a per-URL daily sparkline. Each row is classified as owned / competitor / partner / third_party. Companion to get_sources (root-domain-level). Supports filters (date range, models, prompts, competitors, locations, personas), search, sort, and pagination.

Input parameters:

- `competitors_mentioned` (string)
- `filters` (object, required)
- `mentioned` (string)
- `page_num` (integer)
- `page_size` (integer)
- `search` (string|null)
- `sort_direction` (string)
- `sort_field` (string)
- `website_id` (string, required)

Output parameters:

- `notice` (string)
- `pages` (array)
- `pagination` (object)

### `get_attributes` (~112 tokens)

List the brand traits (called attributes in the API) tracked for a website: brand-perception keywords such as 'Affordable' or 'Slow Support'. Athena extracts these from AI model responses. Brand traits are direction-neutral; `positive` selects the directional series and defaults to true when omitted. Use this to discover attribute ids, then get_attribute_metrics for how often each is mentioned, or get_attribute_time_series for one attribute's trend over time.

Input parameters:

- `positive` (boolean)
- `website_id` (string, required)

Output parameters:

- `attributes` (array)

### `get_attribute_metrics` (~196 tokens)

Get cumulative brand trait (attribute) metrics: for each brand-perception keyword (e.g. 'Affordable', 'Slow Support'), how many AI responses mentioned it across the date range, and the percentage. `positive` selects the observation direction and defaults to true when omitted. `total_responses` is the denominator: responses in the date range that mention the brand AND had attribute extraction run on them. It is NOT every response for the website — responses that never mention the brand are excluded, and Athena samples which responses get extraction, so un-analyzed ones are excluded too. Compute rates from the returned `percentage` / `total_responses` rather than against a response count from another endpoint. Attributes nobody mentioned come back with response_count 0. Use get_competitor_attribute_metrics for the same breakdown per competitor.

Input parameters:

- `filters` (object, required)
- `positive` (boolean)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_competitor_attribute_metrics` (~187 tokens)

Get brand trait (attribute) metrics per tracked competitor: for each competitor and each brand-perception keyword (e.g. 'Affordable'), how many AI responses mentioned that keyword for that competitor, and the percentage. Use with get_attribute_metrics to compare the brand against competitors. `total_responses` is per-competitor: responses in the date range that mention THAT competitor and had attribute extraction run on them. Each competitor therefore has its own denominator, and none of them is the website's total response count. `positive` selects the observation direction and defaults to true when omitted. Returns one row per competitor per attribute, so results can be large — filter with competitor_ids. Competitors with no responses in the date range are omitted entirely rather than returned with zeros.

Input parameters:

- `filters` (object, required)
- `positive` (boolean)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_attribute_time_series` (~185 tokens)

Get the daily trend for ONE brand trait (attribute), brand and competitors side by side — how mentions of a keyword like 'Affordable' moved over time. Requires an attribute_id: call get_attributes first to discover ids. `positive` selects the observation direction and defaults to true when omitted. Days with no data are returned as zeros, so the series is gap-free and chartable. Denominators are per-side, not the day's whole response set: brand_percentage divides by that day's responses that mention the brand (and had attribute extraction run), and competitor_percentage by responses that mention the tracked competitors. brand_total and competitor_total return those denominators explicitly. Competitor figures aggregate all tracked competitors unless competitor_ids narrows them.

Input parameters:

- `attribute_id` (string, required)
- `filters` (object, required)
- `positive` (boolean)
- `website_id` (string, required)

Output parameters:

- `data` (array)

### `get_attribute_observations` (~429 tokens)

Get individual brand trait (attribute) observations: each row is one AI response describing one entity (the brand or a competitor) with one brand trait, including the response excerpt as `text_span`. `score` runs from -1 to 1 and its sign always matches `positive`; its magnitude (0.1 to 1.0) is how strongly the wording praises or criticizes. `score` is null when the observation was not scored (extracted before scoring existed, or no valid value was recorded); for direction only, use `score ?? (positive ? 1 : -1)`. Omit `positive` for both directions. `sort: "intensity"` (the default) returns the strongest observations first with unscored ones last; `sort: "recent"` returns the newest first. Narrow with entity_ids and attribute_ids (from get_attributes). Paginate with page_num and page_size; a page can hold fewer than page_size rows when an excerpt is no longer available, so use `has_more` to decide whether to fetch the next page. Use get_attribute_metrics for how often each trait is mentioned.

Input parameters:

- `attribute_ids` (array): Attribute UUIDs to filter to (from get_attributes), as an array even for one id. Omit for every active attribute.
- `entity_ids` (array): Entity UUIDs to filter to, as an array even for one id: the website_id for the brand itself, competitor ids from get_competitors for competitors. Omit for every entity.
- `filters` (object, required)
- `page_num` (integer): Zero-indexed page number. Defaults to 0.
- `page_size` (integer): Rows per page, 1 to 100. Defaults to 40.
- `positive` (boolean): true for favorable observations only, false for critical ones only. Omit for both directions.
- `sort` (string): "intensity" (default): strongest first, unscored last, then newest. "recent": newest first.
- `website_id` (string, required)

Output parameters:

- `data` (array)
- `has_more` (boolean)
- `notice` (string)
- `page_num` (integer)
- `page_size` (integer)

### `get_user_by_email` (~54 tokens)

Look up a user by email address, scoped to the caller's organization. Returns 404 when the email does not belong to a member of the organization or of one of its websites.

Input parameters:

- `email` (string, required)

Output parameters:

- `user` (object)

### `get_oracle_findings` (~482 tokens)

When grounding is present, use its complete team-confirmed statement and all supporting facts as joint evidence; the legacy fact ID/text are only a compatibility anchor. List Oracle accuracy findings for a website: places where an AI response contradicted a verified brand fact (type 'inaccuracy' or 'kb_issue', with quote, claim, and reason) or where two knowledge-base facts conflict ('kb_duplicate' / 'kb_contradiction', pairing fact_text with related_fact_text). Findings from every status are included by default (pending, acknowledged, ignored, ...), each row carrying its status — pass the status filter for pending items only. Filters (run_id, fact_id, lineage_id, response_id, prompt_id, source_url, type, kind, severity, status) AND-compose; source_url matches evidence URLs exactly after normalization (protocol and trailing slash ignored). 'total' is the pre-limit count. 'latest_run' is the newest scan of any kind and is null only when the website has never been scanned, so latest_run plus empty findings means it scanned clean, while latest_run null means never scanned, not clean. Archived findings from before the current scanner ARE included: their run carries 'is_imported': true and keeps its original started_at, so an import can be the newest run — say the history is archived rather than calling it a current scan. 'has_imported_history' is true when any such archived run exists, and every finding row carries 'run_is_imported' so archival and current rows stay distinguishable in one list. Returns status 'no_access' if the brand does not have Oracle v2; that response carries the status alone, with no counts or findings.

Input parameters:

- `fact_id` (string)
- `kind` (string)
- `limit` (integer)
- `lineage_id` (string)
- `model` (string): Filter to one AI model by product name (ChatGPT, Claude, Gemini, Perplexity, Copilot, Meta AI); raw identifiers also match exactly
- `prompt_id` (string)
- `response_id` (string)
- `run_id` (string)
- `severity` (string)
- `source_url` (string)
- `status` (string)
- `type` (string)
- `website_id` (string, required)

Output parameters:

- `findings` (array)
- `has_imported_history` (boolean)
- `latest_run`
- `notice` (string)
- `status` (string)
- `total` (integer)

### `get_oracle_finding` (~170 tokens)

When grounding is present, use its complete team-confirmed statement and all supporting facts as joint evidence; the legacy fact ID/text are only a compatibility anchor. Load one Oracle finding in full: the flagged claim with its verified fact and prompt text, the run it came from, a ~2000-character response excerpt centered on the quoted claim, the cited-page evidence captured during the run (url, quote, snippet, scrape_hash), and its lineage: sibling findings sharing its lineage_id across runs, newest first. Use after get_oracle_findings to interrogate a specific finding. Returns a not-found error for an unknown finding id, and status 'no_access' if the brand does not have Oracle v2.

Input parameters:

- `finding_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `finding`
- `status` (string)

### `list_api_keys` (~153 tokens)

List the organization's API key metadata, including creator and creation date, oldest first. Includes revoked keys so polling can detect keys revoked between checks. Never returns secrets or hashes. Requires a global API key or an organization admin's MCP connection. For polling, keep since/until fixed while paging, overlap successive windows and deduplicate by id. This is an inventory, not a durable event log; deleted creator accounts remove their keys.

Input parameters:

- `page_num` (integer)
- `page_size` (integer)
- `since` (string): Include keys created at or after this ISO 8601 timestamp.
- `until` (string): Include keys created at or before this ISO 8601 timestamp. Keep fixed while paging.

Output parameters:

- `api_keys` (array)
- `pagination` (object)

### `add_brand_facts` (~216 tokens)

Add brand facts to a website's Knowledge Base in bulk (1-50 per call). Each fact runs the full ingestion pipeline (deduplication, approval gates, pillar routing); there is no way to force-approve. Returns one outcome per fact (approved | pending | duplicate; extensible) with the created fact id and the pillar it was filed under. Facts without a pillar_id are routed automatically and may land unfiled. A fact similar to facts already in the Knowledge Base is not added: its outcome is duplicate and lists them under matches, and the response carries a match_token. To resolve, call again with those facts, the match_token, one decision per listed match (approve, optionally with new text, or delete) and save_submitted (true adds the facts as written, false only applies the decisions).

Input parameters:

- `decisions` (array)
- `facts` (array, required)
- `match_token` (string)
- `save_submitted` (boolean)
- `website_id` (string, required)

Output parameters:

- `match_token` (string)
- `outcomes` (array)
- `resolved` (object)

### `add_competitors` (~182 tokens)

Start tracking competitors on a website, 1 to 25 per call, under the same rules as the Competitors page. Each competitor needs a name and its website url, or no_website: true for a brand with no website of its own; identifiers and additional_urls are optional. Returns one result per competitor, in order: added, already_tracked (the website already tracks that url; nothing changes), or rejected with the reason (a url on the website's own domains, an invalid url, or the limit of 500 competitors per website). New AI responses count mentions of an added competitor right away. Past responses are reanalyzed only when someone runs the backfill on the Competitors page, which costs credits; this tool never starts it and costs no credits.

Input parameters:

- `competitors` (array, required)
- `website_id` (string, required)

Output parameters:

- `results` (array)

### `add_content` (~254 tokens)

Add an article that is already written (for example, one drafted in this conversation) to the website's Content Hub as an editable draft. Same as pasting it into the Content Hub's blank editor: no AI model runs and no content credits are spent. Use create_content instead when Athena should research and write the piece. body is the full article in Markdown and is stored as given, except that link and image destinations with an unsafe scheme (javascript:, data:) become #. The item is created with type manual at stage generated, and the body is recorded as version 1, so get_content_draft, edit_content, revise_content and get_content_versions work on it right away. Pass title, or it is taken from the body's first heading (else its first line). sheet_id must be a tab from get_content_hub_sheets: a sheet-type tab keeps the item, a view-type tab or no sheet_id puts it in the shared pool. The item is not published. Once it is live on the site, call publish_content with its URL to start citation tracking.

Input parameters:

- `body` (string)
- `sheet_id`
- `title` (string)
- `website_id` (string, required)

Output parameters:

- `content_id` (string)
- `sheet_id`
- `title` (string)
- `unsafe_links_removed` (integer)
- `version_number`

### `approve_brief` (~99 tokens)

Approve a content brief and start writing the article from it. Only valid while the piece is at status generated_brief. The article is generated from the brief exactly as it currently stands, including any revisions made with revise_brief or edits made in the app. Consumes content credits; poll get_content_status afterwards, then read the result with get_content_draft.

Input parameters:

- `content_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `content_id` (string)
- `status` (string)

### `create_content` (~452 tokens)

Generate an article or content brief in AthenaHQ. Fetches source URLs, sends source material to external AI providers, and consumes content credits. Obtain user approval before calling. Does not publish to a website or CMS. For draft mode, auto_approve defaults to true; set false to generate only a brief and wait for approve_brief. Poll get_content_status using each returned content_ids value. Slice mode returns slice_titles and an empty content_ids array; generated items appear in list_content. To save an already-written article without generation or credit use, call add_content.

Input parameters:

- `auto_approve` (boolean): Draft mode only. Defaults to true, which continues from brief generation to article generation. Set false to pause at generated_brief until approve_brief is called.
- `brand_kit_id` (string)
- `content_format_type` (string)
- `custom_instructions` (string)
- `fact_review` (object)
- `kb_mode` (string)
- `mode` (string, required): draft: generate a brief and optionally an article from tracked prompts. snipe: draft an article using a competitor URL as input. optimize: improve an existing page for AI search. slice: turn one sour…
- `pdf_file_name_or_r2_key` (string)
- `pinned_claim_ids` (array)
- `prompt_ids` (array): Existing tracked prompt UUIDs, up to 100. Required and nonempty for draft; omit for slice. Use IDs from the website's tracked prompt list; never invent them.
- `rec_id` (string)
- `rec_kind` (string)
- `scrape_additional_links` (boolean)
- `selected_topic_ids` (array)
- `sheet_id`
- `title` (string): Article title. Required for draft, snipe, and optimize modes.
- `url` (string): Source page URL. Required for snipe, optimize, and slice modes. A URL without a protocol, such as example.com/article, is accepted.
- `use_content_memories` (boolean)
- `use_kb_internal_links` (boolean)
- `website_id` (string, required)

Output parameters:

- `content_ids` (array)
- `slice_titles` (array)
- `status` (string)

### `create_location` (~45 tokens)

Create a location for a website

Input parameters:

- `country` (string, required)
- `location` (string, required)
- `prompt_ids` (array)
- `website_id` (string, required)

Output parameters:

- `country` (string)
- `id` (string)
- `location` (string)

### `create_pillar` (~85 tokens)

Create a Knowledge Base pillar (a subject area that groups brand facts) from a name and optional description. Get-or-create semantics: if a pillar with the same name already exists, it is returned with created: false instead of failing, so retries are idempotent.

Input parameters:

- `description` (string)
- `name` (string, required)
- `website_id` (string, required)

Output parameters:

- `created` (boolean)
- `pillar` (object)

### `create_prompt_tag` (~90 tokens)

Create a prompt tag on a website, or return the existing tag when its name matches case-insensitively. Trims surrounding whitespace and rejects reserved prompt-type names. Returns the tag ID and whether it was created. Use the returned ID to assign the tag to prompts; creating a tag does not assign it to any prompts.

Input parameters:

- `tag` (string, required)
- `website_id` (string, required)

Output parameters:

- `created` (boolean)
- `success` (boolean)
- `tag` (string)
- `tag_id` (string)

### `create_prompts` (~40 tokens)

Create one or more prompts on a website

Input parameters:

- `prompts` (array, required)
- `source` (string)
- `website_id` (string, required)

Output parameters:

- `count` (number)
- `prompt_ids` (array)
- `success` (boolean)

### `create_saved_view` (~367 tokens)

Create a saved view (filter preset) for a website. Saved views appear in the dashboard filter bar for every member of the website. filters is an object keyed by filter field key, each value shaped {"id": "<unique string>", "field": "<same field key>", "operator": "is_any_of", "values": [...]}. Common field keys: "models" (slugs like "chatgpt", "perplexity", "google_ai_overview"), "competitors", "prompts", "personas", "locations", "promptTags", "attributes" (arrays of UUIDs from the matching list tools), "countries", "sourceTag". "promptTags" also accepts the builtin tokens "type:high_intent" (branded prompts) and "type:discovery" (non-branded) alongside tag UUIDs. "sourceTag" values are the builtin categories "owned", "competitor", "partner", "third_party" or custom source tag UUIDs, not display labels; custom source tag ids appear on existing saved views (list the website's saved views to find them). When unsure, list the website's saved views and mirror their filter shapes. icon, when set, must be a supported Remix icon name (e.g. "RiStarLine"); invalid names are rejected with the full list. When talking to the user about a view or its filters, use the dashboard names (Branded / Non-branded prompts, Owned / Competitor / Partner / Third party sources), never internal tokens, field keys, operator strings, or icon identifiers.

Input parameters:

- `filters` (object, required)
- `icon`
- `name` (string, required)
- `olympus_layout` (object)
- `website_id` (string, required)

Output parameters:

- `created_at` (string|null)
- `created_by`
- `creator_has_access` (boolean|null)
- `filters` (object)
- `icon` (string|null)
- `id` (string)
- `name` (string)
- `olympus_layout`
- `updated_at` (string|null)
- `user_id` (string|null)
- `website_id` (string)

### `create_topic` (~46 tokens)

Create a topic on a website (returns the existing topic when the name is already taken)

Input parameters:

- `description`
- `name` (string, required)
- `website_id` (string, required)

Output parameters:

- `created` (boolean)
- `description` (string|null)
- `id` (string)
- `name` (string)

### `delete_brand_facts` (~92 tokens)

Permanently delete 1-50 brand facts from a website's Knowledge Base. There is no undo. Ids that do not exist on the website are reported in not_found_ids rather than failing the call, so retries are idempotent. Requires an admin; on OAuth connections the signed-in user must have the admin role.

Input parameters:

- `fact_ids` (array, required)
- `website_id` (string, required)

Output parameters:

- `deleted_count` (integer)
- `not_found_ids` (array)
- `success` (boolean)

### `delete_content` (~52 tokens)

Delete a content row. Destructive: physical row delete, no undo. Powers delete-and-retry. Bulk delete is out of scope.

Input parameters:

- `content_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `success` (boolean)

### `delete_location` (~31 tokens)

Delete a location from a website

Input parameters:

- `location_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `location` (string)
- `success` (boolean)

### `delete_pillars` (~113 tokens)

Permanently delete 1-20 Knowledge Base pillars and every fact filed under them. Facts are deleted, not unfiled; there is no undo. Ids that do not exist on the website are reported in not_found_ids rather than failing the call, so retries are idempotent; ids in failed_ids are untouched and safe to retry. Requires an admin; on OAuth connections the signed-in user must have the admin role.

Input parameters:

- `pillar_ids` (array, required)
- `website_id` (string, required)

Output parameters:

- `deleted_pillars` (array)
- `failed_ids` (array)
- `not_found_ids` (array)
- `success` (boolean)

### `delete_prompt` (~36 tokens)

Delete a prompt (soft when responses exist, hard otherwise)

Input parameters:

- `prompt_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `soft_deleted` (boolean)
- `success` (boolean)

### `delete_topic` (~46 tokens)

Delete a topic (soft delete; optionally also delete its prompts)

Input parameters:

- `delete_prompts` (string)
- `topic_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `deleted_prompt_count` (integer)
- `name` (string)
- `success` (boolean)

### `draft_outreach_message` (~228 tokens)

Draft a pitch email to the author of a cited page and save it as the page's Outreach draft, replacing any previous draft. Uses the website's team-wide Outreach custom instructions, the saved author name, and the sender's name. Costs 0.1 credits per draft written (billed in whole credits every 10 drafts); free when the page cannot be read. Show the draft to the user before they send it; nothing is sent.

Input parameters:

- `sender_name` (string): Name to sign the email with. Defaults to the signed-in user's profile name; required for API-key sessions that should sign with a name.
- `url` (string, required): Cited page URL, e.g. "example.com/blog/best-tools". A contact already saved under this exact URL (for example one the Outreach page saved for a query variant its URL rules list separately) is used fi…
- `website_id` (string, required)

Output parameters:

- `contact` (object)
- `created` (boolean): True when this call created the page's contact.

### `edit_content` (~217 tokens)

Apply exact find-and-replace edits to a content draft's article body. Deterministic, no AI model involved: your replacement text lands verbatim (use revise_content when you want an AI rewrite from an instruction). Each edit's find text must match the current body exactly once; zero or multiple matches fail the whole call and nothing is saved, so extend the find text until it is unique. Edits apply in order, later ones see earlier results, and the batch is recorded as one new version, recoverable via get_content_versions / restore_content_version. Pass expected_version_number from get_content_draft to fail with a conflict when a new version was recorded after your read (a revision, edit, or restore). An app autosave changes the body without recording a version; that drift is caught by the anchors themselves, since a moved or vanished find text fails the call.

Input parameters:

- `content_id` (string, required)
- `edits` (array, required)
- `expected_version_number` (integer)
- `website_id` (string, required)

Output parameters:

- `body` (string)
- `body_word_count` (integer)
- `content_id` (string)
- `previous_body_word_count` (integer)
- `version_id` (string)
- `version_number` (integer)

### `find_more_prompt_discovery` (~213 tokens)

Find more prompts for a finished Discover run: start the next round of its series with the same sources, effort level, country, language and custom instructions. The round skips every question the series already suggested and reads evidence earlier rounds did not use, so its prompts add to the same list. Invoke only after the user asks for more prompts from an existing run, and confirm with them first: each round runs the same paid research as a new run. A series takes one round at a time and at most two after the first run, and ends early after a round that found fewer than ten new prompts or nothing new to read; the tool then refuses with the reason. Returns the new round's run ID; poll the discovery history tool with it. Prompts are not added to tracking automatically. Requires prompt-management permission and the series' source entitlements.

Input parameters:

- `run_id` (string, required): A finished Discover run, or any finished round of its series, to continue.
- `website_id` (string, required)

Output parameters:

- `run_id` (string)
- `version` (string)

### `find_outreach_author` (~208 tokens)

Find who wrote a cited page and how to reach them, then save it to the page's Outreach contact. Reads the page's byline, the addresses the page publishes, and Hunter.io; when no author is found it returns the site's contact address and contact page instead. Every email comes with its source. Costs 0.1 credits when an author is found (billed in whole credits every 10 lookups); free otherwise. Overwrites the saved author fields. Obtain user confirmation before running it over many pages.

Input parameters:

- `url` (string, required): Cited page URL, e.g. "example.com/blog/best-tools". A contact already saved under this exact URL (for example one the Outreach page saved for a query variant its URL rules list separately) is used fi…
- `website_id` (string, required)

Output parameters:

- `author_found` (boolean)
- `contact` (object)
- `created` (boolean): True when this call created the page's contact.

### `get_brand_facts` (~145 tokens)

List a website's brand facts from the Knowledge Base, newest first, with offset paging. By default excludes facts generated by Oracle analysis; pass include_oracle=true to include them. Filters: pillar, review status (default approved), source type, and unfiled=true for facts not under any published pillar (unfiled and pillar_id are mutually exclusive).

Input parameters:

- `include_oracle` (string)
- `limit` (string)
- `offset` (string)
- `pillar_id` (string)
- `source_type` (string)
- `status` (string)
- `unfiled` (string)
- `website_id` (string, required)

Output parameters:

- `facts` (array)
- `total` (integer)

### `get_content_draft` (~118 tokens)

Read the current draft text of a content item — the article body as it stands right now, including every revision applied so far. Use this before revise_content to see what you are changing, and after it to confirm the result. A status of generated_brief means the brief is ready while the article is still being written, so body may still be empty. For the full record (cited urls, links, social posts) use get_content_detail instead.

Input parameters:

- `content_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `body` (string|null)
- `brief` (string|null)
- `content_id` (string)
- `latest_version_number`
- `meta_description` (string|null)
- `status` (string|null)
- `title` (string|null)

### `get_content_status` (~150 tokens)

Get the normalized pipeline status (running | succeeded | failed) for one content row, plus the raw stage behind it. Read-only. Poll once per contentId returned by create_content (content.pipeline.start). A stage of generated_brief with status running means the brief is ready and waiting — for a non-auto-approve draft it stays there until approve_brief is called, so do not treat running as always in progress. Not meaningful for tracked pages (track_content_urls / external rows): they have no generation pipeline and report running with a null stage forever — read them via get_tracked_content or get_content_detail instead.

Input parameters:

- `content_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `stage`
- `status` (string)

### `get_content_version` (~72 tokens)

Read the full text of one saved version of a content item. Use it to compare two passes (fetch both and diff them yourself) or to check what an earlier version said before restoring it.

Input parameters:

- `content_id` (string, required)
- `version_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `body` (string|null)
- `brief` (string|null)
- `change_type` (string|null)
- `created_at` (string)
- `label` (string|null)
- `meta_description` (string|null)
- `version_id` (string)
- `version_number` (integer)

### `get_content_versions` (~99 tokens)

List the saved versions of a content item, newest first. Each entry carries its version number, label, how it was produced, and who made it. Use it to see how a draft evolved, then get_content_version to read a specific one, or restore_content_version to go back to it.

Input parameters:

- `content_id` (string, required)
- `limit` (integer)
- `offset` (integer)
- `website_id` (string, required)

Output parameters:

- `total_count` (integer)
- `versions` (array)

### `get_credit_usage` (~258 tokens)

Read recorded organization credit consumption: total, hourly (24h) or daily trend, and charged website/group/organization pools. Use for spending trends and biggest charged pools; the credit-balance tools read current balances. For 'this month' or a specific spike, supply explicit UTC window boundaries; 30d is rolling, not a calendar month. State the returned interval. A group pool is not an originating website. The breakdown may exclude unattributed usage or be capped by the billing provider; totalCreditsUsed is authoritative, not the sum of displayed entities. Negative credits are refunds. Entities are paginated: continue with window and nextOffset while hasMore. Use credit-usage events to inspect recorded actions. Requires organization billing access on a signed-in connection, or a global organization API key. Website-scoped keys are not supported. Read-only.

Input parameters:

- `limit` (integer)
- `offset` (integer)
- `range` (string)
- `website_id` (string, required)
- `window` (object): Explicit UTC interval within recorded history, ending no later than now. For the current month or today, use the current UTC time as endAtUtc, not the next calendar boundary. Reuse both returned boun…

Output parameters:

- `breakdown_credits_used` (number)
- `breakdown_note` (string)
- `buckets` (array)
- `entities` (array)
- `has_more` (boolean)
- `next_offset` (number)
- `total_credits_used` (number)
- `window` (object)

### `get_credit_usage_events` (~272 tokens)

Read a page of recorded credit charges/refunds and action labels for the organization, optionally filtered by originatingWebsiteId. Use to inspect a usage spike or charges behind a total. Use credit-usage totals for complete period totals. Supply explicit UTC window for calendar months. Continue with returned window, originatingWebsiteId, and nextOffset while hasMore; never compute the next offset from returned row count. Limit bounds underlying operations, each may split into several charged-pool rows. One page is not a complete action breakdown. 'Not recorded' means unknown historical action/site attribution, never infer it. Unknown raw action tags are preserved. Negative credits are refunds. Requires organization billing access on a signed-in connection, or a global organization API key. Website-scoped keys are not supported. Read-only.

Input parameters:

- `limit` (integer)
- `offset` (integer)
- `originating_website_id` (string): Optional originating website in this organization; this is different from the charged group pool.
- `range` (string)
- `website_id` (string, required)
- `window` (object): Explicit UTC interval within recorded history, ending no later than now. For the current month or today, use the current UTC time as endAtUtc, not the next calendar boundary. Reuse both returned boun…

Output parameters:

- `attribution_note` (string)
- `events` (array)
- `has_more` (boolean)
- `limit` (number)
- `next_offset` (number)
- `offset` (number)
- `originating_website_id` (string|null)
- `window` (object)

### `get_identifiers` (~128 tokens)

Read the identifiers of the website's brand, or of one competitor: the names, aliases and domains Athena looks for in AI responses to count a mention. default_identifiers (the name and domain) are always matched and cannot be removed; identifiers lists every other value, as the Competitors page shows them. case_sensitive tells whether matching respects letter case. Read this before update_identifiers. Read-only.

Input parameters:

- `competitor_id` (string): The competitor to read or edit, from get_competitors. Omit it for the website's own brand.
- `website_id` (string, required)

Output parameters:

- `case_sensitive` (boolean)
- `default_identifiers` (array)
- `entity` (object)
- `identifiers` (array)

### `get_pillar_document` (~53 tokens)

Fetch a pillar's synthesized markdown document from the Knowledge Base. Returns document: null when the pillar exists but has no synthesized document yet.

Input parameters:

- `pillar_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `document` (string|null)
- `generated_at` (string|null)
- `name` (string)
- `pillar_id` (string)

### `get_pillars` (~50 tokens)

List a website's Knowledge Base pillars (excluding archived ones) with approved-fact counts, whether a synthesized document exists, and when each pillar was last researched.

Input parameters:

- `website_id` (string, required)

Output parameters:

- `pillars` (array)

### `get_prompt_discovery_runs` (~134 tokens)

Read Discover history and progress for a website, or supply the run ID returned by discovery launch to inspect one study. Distinguishes pending, running, completed, partial, failed and cancelled. limit bounds returned runs (default 10, maximum 20); has_more means older runs remain. This is read-only: it does not start research, monitor in the background or send notifications. Candidate results can be reviewed in the application's Discover page. Requires permission to view prompts; source visibility restrictions still apply.

Input parameters:

- `limit` (integer)
- `run_id` (string)
- `website_id` (string, required)

Output parameters:

- `has_more` (boolean)
- `runs` (array)

### `get_seo_rankings` (~61 tokens)

Read saved Google organic rankings by explicit market and device alongside observed AI visibility. Includes recent history, missing-data reasons, freshness and committed provider budget. Does not trigger collection.

Input parameters:

- `property_id` (string)
- `website_id` (string, required)

Output parameters:

- `billed_cost_usd` (number)
- `collection_enabled` (boolean)
- `committed_budget_usd` (number)
- `estimated_refresh_cost_usd` (number)
- `monthly_budget_usd` (number)
- `provider` (string)
- `refresh_cooldown_hours` (number)
- `requested_depth` (number)
- `rows` (array)
- `unknown_cost_jobs` (integer)

### `get_shopping_metrics` (~153 tokens)

Get the Shopping Insights dashboard for a website over a date range: how often the brand's products appear in AI shopping answers (product carousels) versus competitors, average position and price, the top own and competitor products, the competitor leaderboard, retailer (merchant) breakdown, rank distribution, price comparison, and a daily appearances trend. Rates are percentages 0-100; positions are 1-based (lower is better). Requires a paid plan.

Input parameters:

- `filters` (object, required)
- `top_products_limit` (integer): How many products to return in each of top_own_products and top_competitor_products, 1 to 50. Defaults to 10.
- `website_id` (string, required)

Output parameters:

- `data` (object)

### `list_outreach_contacts` (~150 tokens)

Read saved Outreach contacts: cited pages with their status, author, email and where the email came from, LinkedIn, contact page, and pitch draft. Only pages someone has triaged, enriched or drafted are listed; find other cited pages with the source-page analytics tools. Newest first; use offset for the next page. Read-only.

Input parameters:

- `limit` (integer): Contacts per page: 1 through 50, default 20.
- `offset` (integer)
- `statuses` (array): Only contacts in these statuses. Omit for all.
- `url` (string): Return only this page's contact. Omit to list all.
- `website_id` (string, required)

Output parameters:

- `contacts` (array)
- `has_more` (boolean)
- `total` (number)

### `merge_pillars` (~131 tokens)

Merge 1-20 source pillars into a published target pillar: every fact on the sources (any review status) re-files onto the target, page links carry over keeping the stronger signal, and the source pillars are then deleted. The target must be a published pillar and must not appear among the sources. Unlike the other Knowledge Base writes, retries are strict: missing source ids are rejected rather than skipped, so re-read the pillars before retrying a failed merge.

Input parameters:

- `source_pillar_ids` (array, required)
- `target_pillar_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `merged_pillars` (array)
- `moved_fact_count` (integer)
- `pillar` (object)
- `success` (boolean)

### `move_brand_facts` (~110 tokens)

File 1-50 brand facts under a published Knowledge Base pillar — works for unfiled facts and re-files facts from other pillars. Review status never changes, and only approved facts under a published pillar feed content generation, so moving is what puts approved facts to work. Missing ids are reported in not_found_ids rather than failing the call, so retries are idempotent.

Input parameters:

- `fact_ids` (array, required)
- `pillar_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `moved_count` (integer)
- `not_found_ids` (array)
- `pillar` (object)
- `success` (boolean)
- `unchanged_ids` (array)

### `move_content` (~233 tokens)

Move one or more content items to a different Content Hub sheet, or back to the shared pool. Sheet assignment is organizational metadata only: a move never changes an item's stage, brief, body, versions, URL, or metrics, and the item stays fully readable and revisable. targetSheetId must be a "sheet"-type tab from the Content Hub sheets list — view-type tabs (e.g. All content) are computed filters, not assignable; pass null to unassign back to the shared pool they display. Batch is all-or-nothing: if any contentIds entry does not belong to the website, nothing moves. Custom-column values follow each item when the target has a matching column (same name and type; missing columns are auto-created); values whose column conflicts by type are dropped, and multi-select selections whose option is missing on the matched target column are removed — both counts are reported. Each moved item is returned with its previous and new sheet id so no follow-up read is needed.

Input parameters:

- `content_ids` (array, required)
- `target_sheet_id` (required)
- `website_id` (string, required)

Output parameters:

- `cells_dropped` (integer)
- `cells_transferred` (integer)
- `moved` (array)
- `option_values_dropped` (integer)
- `target_sheet_id`
- `target_sheet_name` (string)

### `publish_content` (~246 tokens)

Record an already-published article's URL in AthenaHQ for citation and mention tracking. Does not upload or publish content to a website or CMS. Call only after the article is live. Sets the first publication time and moves the pipeline stage to done. A first publish requires a finished article (stage generated), with one exception: an optimize draft is created from a page that is already live and can be marked published while it waits at stage pending, as long as no Athena review is running on it. Briefs, still-generating or failed pieces, optimize drafts with a review in flight, and items with a scheduled CMS publish are rejected with the reason. Pass the exact public URL of the live page (a bare domain path like acme.com/blog/post is fine; the protocol is stripped on store). Calling it again on an already-published item (including external and imported pages, which are live by definition) updates the tracked URL only, keeping the original publish time. This is the only way to set a content URL over MCP; rename_content is deliberately title-only.

Input parameters:

- `content_id` (string, required)
- `url` (string, required)
- `website_id` (string, required)

Output parameters:

- `already_published` (boolean)
- `content_id` (string)
- `published_at` (string|null)
- `title` (string|null)
- `url` (string)

### `remove_competitors` (~153 tokens)

Stop tracking competitors on a website, 1 to 25 per call, by id from get_competitors, as the Competitors page's delete does. Returns one result per id, in order: removed, no_change (already removed), or not_found (not a competitor of this website). Past mentions and citations are kept, and a removed competitor can be restored on the Competitors page. Reanalyzing past responses happens only when someone runs the backfill on the Competitors page, which costs credits; this tool never starts it and costs no credits.

Input parameters:

- `competitor_ids` (array, required): The competitors to stop tracking, by id from get_competitors.
- `website_id` (string, required)

Output parameters:

- `results` (array)

### `rename_content` (~58 tokens)

Rename a content row's title. URL editing is not supported — URL is the content asset's stable identity and cannot be changed here.

Input parameters:

- `content_id` (string, required)
- `title` (string, required)
- `website_id` (string, required)

Output parameters:

- `success` (boolean)

### `restore_content_version` (~89 tokens)

Bring an earlier version's text back as the current draft — use it when a later pass came out worse than an earlier one. Nothing is deleted: the restored text is appended as a new version on top of the history, so the passes in between remain readable and restorable.

Input parameters:

- `content_id` (string, required)
- `version_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `body` (string)
- `content_id` (string)
- `restored_from_version_number` (integer)
- `version_id` (string)
- `version_number` (integer)

### `revise_brief` (~172 tokens)

Rewrite a content brief from a natural-language instruction (for example: 'add a section on pricing objections', 'cut the competitor comparison'). An AI model performs the rewrite server-side, so the result is generated text, not your literal wording. Records each pass as a version; iterate by calling it again, since each call starts from the current brief. Most useful while a piece waits at status generated_brief, where the brief still shapes what the article will say — call approve_brief once it reads right. It also works after the article exists, to correct the brief for a later regeneration; note that revising the brief does NOT rewrite an already-generated article, so use revise_content for that.

Input parameters:

- `content_id` (string, required)
- `instruction` (string, required)
- `website_id` (string, required)

Output parameters:

- `brief` (string)
- `content_id` (string)
- `version_id` (string)
- `version_number` (integer)

### `revise_content` (~204 tokens)

Rewrite an existing content draft from a natural-language instruction (for example: 'tighten the intro', 'add a section on pricing', 'remove the second half'). An AI model performs the rewrite server-side, so the result is generated text, not your literal wording; when you already have the exact replacement text, use edit_content instead. Applies the change to the whole article and records it as a new version, so earlier passes stay recoverable via get_content_versions / restore_content_version. Iterate by calling it again — each call starts from the current text, so no version id is needed. Use this instead of create_content to change a draft; it edits in place rather than generating a new piece. The returned body is always the complete replacement article, never just the edited passage; compare body_word_count with previous_body_word_count to confirm nothing unexpected was lost.

Input parameters:

- `content_id` (string, required)
- `instruction` (string, required)
- `website_id` (string, required)

Output parameters:

- `body` (string)
- `body_word_count` (integer)
- `content_id` (string)
- `previous_body_word_count` (integer)
- `version_id` (string)
- `version_number` (integer)

### `search_brand_facts` (~89 tokens)

Semantic search over a website's approved brand facts in the Knowledge Base. Reaches facts not filed under any pillar. Returns fact text with confidence, source URL and quote, and the published pillar it belongs to (null when unfiled).

Input parameters:

- `pillar_id` (string)
- `query` (string, required)
- `top_k` (string)
- `website_id` (string, required)

Output parameters:

- `facts` (array)

### `set_outreach_status` (~157 tokens)

Move cited pages to an Outreach pipeline status (New, Todo, In Progress, Done, Rejected), as the Outreach inbox and board do. Each change to an existing contact is recorded in its activity history. Pages without a contact get one at the new status, starting with no activity entries; "New" only resets existing contacts and creates none. "Rejected" removes pages from the active queue; "New" returns them to untriaged. Up to 100 pages per call. Obtain user confirmation before calling.

Input parameters:

- `status` (string, required): Pipeline status. "New" means untriaged; "Rejected" removes the page from the active queue.
- `urls` (array, required)
- `website_id` (string, required)

Output parameters:

- `updated` (number)

### `set_prompt_tags` (~99 tokens)

Replace all tag assignments on an existing prompt. For additions or removals, read the prompt's current tags with get_prompts, resolve tag IDs with get_prompt_tags, and pass the full resulting set. Existing assignments omitted from tag_ids are removed; an empty array clears all assignments. Tag definitions and the prompt itself are preserved.

Input parameters:

- `prompt_id` (string, required)
- `tag_ids` (array, required)
- `website_id` (string, required)

Output parameters:

- `success` (boolean)
- `tag_ids` (array)

### `set_prompts_status` (~43 tokens)

Pause or unpause multiple prompts in one transaction

Input parameters:

- `prompt_ids` (array, required)
- `status` (string, required)
- `website_id` (string, required)

Output parameters:

- `changed_count` (integer)
- `message` (string)
- `success` (boolean)
- `unchanged_count` (integer)

### `source_tags__create` (~264 tokens)

Create a custom source tag with a name, URL patterns and optionally an icon and colour. Read the tag listing first: built-in tags already cover media, social, government, e-commerce, review sites, PR wires, academic and wiki sources, and a host they miss is better added to the built-in tag than given a new one. Obtain user confirmation before calling. MCP executes immediately after authorization; Athena AI chat presents an approval card. Patterns support hosts (example.com), subtrees (*.example.com), path sections (example.com/blog), exact pages (example.com/blog$) and query constraints. Up to 500 patterns. These are source tags, not prompt tags.

Input parameters:

- `color` (string): Optional colour family: ochre, clay, brick, amber, olive, moss, teal, slate, ink, mauve or plum. Default ink.
- `icon` (string): Optional icon key from the curated set (for example newspaper, capsule, hospital, graduation-cap, building). Omit for a letter badge.
- `name` (string, required): Custom tag name. Names of built-in tags (Media, Social, Government, …) and of Owned and Competitor are reserved.
- `patterns` (array, required)
- `website_id` (string, required)

Output parameters:

- `analytics_refreshed` (boolean)
- `color` (string)
- `deletable` (boolean)
- `editable` (boolean)
- `icon` (string|null)
- `id` (string)
- `kind` (string)
- `name` (string)
- `patterns` (array)
- `removed_patterns` (array)
- `revision` (string)

### `source_tags__delete` (~170 tokens)

Permanently delete a custom source tag and all its pattern assignments; retain source records. Built-in tags and Owned/Competitor cannot be deleted; remove patterns from a built-in tag instead. Read the listing first and pass the tag's revision as expected-revision. Obtain explicit user confirmation identifying the tag and its patterns before calling. MCP executes immediately after authorization; Athena AI chat presents an approval card. If the tag changed, read again. Never retry a declined proposal unless asked. A false analytics-refresh result means the tag was deleted but filtered analytics may still be cached.

Input parameters:

- `expected_revision` (string, required): Revision returned by the source-tag listing tool for this tag.
- `tag_id` (string, required): Custom source tag ID returned by the source-tag listing tool.
- `website_id` (string, required)

Output parameters:

- `analytics_refreshed` (boolean)
- `color` (string)
- `deletable` (boolean)
- `editable` (boolean)
- `icon` (string|null)
- `id` (string)
- `kind` (string)
- `name` (string)
- `patterns` (array)
- `removed_patterns` (array)
- `revision` (string)

### `source_tags__get_sources` (~241 tokens)

List cited domains by tag coverage, most cited first with citation counts: either the domains one custom source tag matches (tag ID), or, with untagged true, the domains no tag covers at all. Built-in tags (platform) and Owned/Competitor (entity) are refused as tag IDs: their membership is automatic and not listable; add or remove patterns on them instead. Start from untagged when asked which domains still need tags or which new tags to suggest.

Input parameters:

- `days` (integer): Look-back window in days, default 90.
- `limit` (integer)
- `offset` (integer)
- `tag_id` (string): Custom tag ID from the listing tool. Built-in tags are refused. Omit and set untagged to list sources no tag covers.
- `untagged` (boolean): true lists cited domains that carry no tag at all: not Owned, not Competitor, no built-in tag, no custom tag. Use this to find what still needs tagging; then propose adding hosts to a built-in tag or…
- `website_id` (string, required)

Output parameters:

- `has_more` (boolean)
- `sources` (array)
- `total` (number)

### `source_tags__list` (~277 tokens)

Read every source tag this website sees: Owned and Competitor (entity), the built-in classes AthenaHQ classifies automatically (platform: Media, Social, Government, E-Commerce, Review sites, PR Wire, Academic and research, Wiki) and the website's custom tags. Built-in tags list only what this website added or removed, never the platform's own patterns; custom tags list their patterns. Read this before proposing, creating, editing or deleting tags, and prefer adding hosts to a built-in tag over creating a near-duplicate. To find sources no tag covers, call source_tags__get_sources with untagged true. Filter by name substring or tag ID; page tags with offset, page one tag's patterns with tag ID and pattern offset.

Input parameters:

- `limit` (integer): Tags per page: 1 through 50, default 20. Use offset for the next page.
- `offset` (integer)
- `pattern_limit` (integer): Patterns per tag: 1 through 500, default 50.
- `pattern_offset` (integer)
- `query` (string): Optional tag-name substring. Omit to list all names.
- `tag_id` (string): Actual UUID returned by this tool. Omit to list all tags; never use a placeholder.
- `website_id` (string, required)

Output parameters:

- `has_more` (boolean)
- `tags` (array)
- `total` (number)

### `source_tags__update` (~281 tokens)

Edit a source tag. Custom tag: rename, add patterns, remove exact patterns from the listing. Built-in tag (platform): add patterns to this website's copy so they carry the tag here, or remove patterns so they stop carrying it here; a removal is accepted only for a pattern the tag currently applies to (by a platform rule, by automatic classification, or by your own addition), and an addition is accepted only when the pattern does not already carry the tag. Owned and Competitor cannot be edited here; their patterns live in Brand Profile and Competitors. Read the listing first and pass the tag's revision as expected-revision. Obtain explicit user confirmation of the exact changes before calling; MCP executes immediately after authorization; Athena AI chat presents an approval card. If the tag changed, read again. Never retry a declined proposal unless asked. Up to 500 additions and 500 removals. A false analytics-refresh result means the edit saved but filtered analytics may still be cached.

Input parameters:

- `add_patterns` (array)
- `expected_revision` (string, required)
- `name` (string): Custom tag name. Names of built-in tags (Media, Social, Government, …) and of Owned and Competitor are reserved.
- `remove_patterns` (array)
- `tag_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `added` (array)
- `analytics_refreshed` (boolean)
- `before` (object)
- `color` (string)
- `deletable` (boolean)
- `editable` (boolean)
- `icon` (string|null)
- `id` (string)
- `kind` (string)
- `name` (string)
- `patterns` (array)
- `removed` (array)
- `removed_patterns` (array)
- `revision` (string)

### `start_prompt_discovery` (~327 tokens)

Start a Discover study to find evidence-grounded, untracked prompt opportunities for a website. Invoke after explicit user intent to start research and review the sources, country, language, requested prompt count and custom instructions with the user. This launches asynchronous external research and model calls; the prompt count is a target, not a guaranteed yield. Sources: website_analysis (website), social (market discussions), search_console (connected Search Console), keyword_gaps (plan-gated keyword opportunities), competitive_landscape (plan-gated category questions and comparisons researched from the website's tracked competitors; requires at least one tracked competitor), brand_guidelines (requires custom instructions). Returns the run ID and version when startup succeeds. Prompts are not automatically added to tracking. Poll the discovery history/progress tool with the returned run ID; do not start another study to check status. Requires prompt-management permission and source entitlements. Candidate results can be reviewed in the application's Discover page.

Input parameters:

- `country` (string): Country name or ISO code; defaults to United States.
- `custom_instructions` (string): Required when brand_guidelines (Custom instructions) is selected. Focus discovery on the customer's requested topics.
- `language` (string): Supported locale, for example en-US. Defaults to en-US.
- `name` (string, required)
- `prompt_count_range` (object): Supported min/max targets: 25/50 (default), 50/75, 75/100, 100/150, or 150/200.
- `sources` (array, required)
- `website_id` (string, required)

Output parameters:

- `run_id` (string)
- `version` (string)

### `start_response_streaming` (~359 tokens)

Run tracked prompts against external AI providers to collect new responses for a website. Sends prompt text to the selected providers, stores their responses in AthenaHQ, and consumes response credits. Starts immediately; use only for a user-requested run. Returns a workflow_id; poll get_response_streaming_status over MCP or GET /api/v1/response-streaming/status over the API for progress.

Input parameters:

- `only_locations` (boolean)
- `prompt_ids` (array): Specific tracked prompt UUIDs to run, from 1 to 1,000. Overrides schedule prompt selectors when supplied. Omit to use schedule_id selectors, or every active prompt when schedule_id is also omitted. P…
- `prompt_variations` (integer)
- `schedule_id` (string): Schedule UUID to attribute this run to and take prompt selectors from. A nonempty prompt_ids selection overrides those selectors. Omit to attribute the run to Default and run every active prompt unle…
- `selected_models` (object): Map of model id to enabled flag, e.g. { "chatgpt": true, "ai_overview": true, "ai_mode": false }. Model ids: chatgpt, ai_overview (Google AI Overviews; google_ai_overview is also accepted), perplexit…
- `use_locations` (boolean)
- `use_personas` (boolean)
- `website_id` (string, required)

Output parameters:

- `status` (string)
- `workflow_id` (string)

### `track_content_urls` (~418 tokens)

Register existing pages or third-party URLs as tracked Content Hub items so Athena attributes citations and mentions to them. Creates external content rows from bare URLs with no generation and no credit cost. Tracking starts immediately: the normalized URL becomes the citation/metric join key, so pages cited in the website's monitored AI responses accrue metrics with no publish step (use it for guest posts, partner placements, or any page Athena did not generate). Idempotent per URL: a URL already present on the website (any content type) is not duplicated; the response lists it under skipped with the existing content_id and type. Check that type before chaining destructive calls (a skip can resolve to first-party generated content that shares the URL). Rows are created without page text, which citation tracking does not need; the body can be filled from the app later. Duplicate URLs within one call (including tracking-param variants of the same page) collapse to one row, first occurrence wins. Optional sheet_id files rows under a Content Hub tab; view-type tabs resolve to the main pool (null), echoed per row. Optional per-URL fields set the customer's own Content Hub columns on the created row, addressed by column name as shown on the destination tab (text, number, date, checkbox, link, and multi-select columns; unknown multi-select options are created). An unknown column name or a value that does not fit the column type rejects the whole call and nothing is tracked; skipped URLs keep their existing values. If the user names a destination tab, resolve its id with get_content_hub_sheets before tracking. Omitting sheet_id uses the shared pool, not the user's currently open tab. After the call, report created_count and skipped_count separately, name the returned destination_name, and share content_hub_url so the user can open each item. Skipped rows keep their existing tab: use their returned destination and never describe them as newly added or moved.

Input parameters:

- `sheet_id`
- `urls` (array, required)
- `website_id` (string, required)

Output parameters:

- `created` (array)
- `created_count` (number)
- `skipped` (array)
- `skipped_count` (number)
- `success` (boolean)

### `update_brand_fact` (~145 tokens)

Update one brand fact's text, source URL, or confidence in the Knowledge Base. Only provided fields change; pass source_url: "" to clear the source. Changing the text creates a new fact (new id) and archives the current one; the new fact keeps the current review status and the response carries it. Source URL and confidence edits update the fact in place. Duplicates across other facts are not rejected here (Knowledge Base dedup owns those). Does not change review status.

Input parameters:

- `confidence` (string)
- `fact_id` (string, required)
- `source_url` (string)
- `text` (string)
- `website_id` (string, required)

Output parameters:

- `before` (object)
- `fact` (object)

### `update_identifiers` (~207 tokens)

Add or remove identifiers on the website's brand, or on one competitor, under the same rules as the Competitors page. Call get_identifiers first. The name and domain cannot be removed. An identifier that is already listed, or that another tracked brand or competitor on this website already uses, is refused, and nothing is saved. New AI responses use the change right away. Past responses are reanalyzed only when someone runs the backfill on the Competitors page, which costs credits; this tool never starts it. changes_awaiting_backfill counts the edits waiting for it, not responses.

Input parameters:

- `add` (array): Identifiers to add, exactly as they should match (trimmed).
- `competitor_id` (string): The competitor to read or edit, from get_competitors. Omit it for the website's own brand.
- `remove` (array): Identifiers to remove, exactly as get_identifiers lists them.
- `website_id` (string, required)

Output parameters:

- `added` (array)
- `case_sensitive` (boolean)
- `changes_awaiting_backfill` (integer): How many edits on this website, from anyone, wait for the backfill on the Competitors page. A count of edits, not of responses.
- `default_identifiers` (array)
- `entity` (object)
- `identifiers` (array)
- `removed` (array)

### `update_location` (~53 tokens)

Update a location for a website

Input parameters:

- `country` (string)
- `location` (string)
- `location_id` (string, required)
- `prompt_ids` (array)
- `website_id` (string, required)

Output parameters:

- `before` (object)
- `country` (string|null)
- `id` (string)
- `location` (string)

### `update_outreach_contact` (~268 tokens)

Edit a cited page's Outreach contact: author name, email, LinkedIn, or the draft's subject and body. Creates the contact when the page has none. Supply at least one field; only the fields supplied change, and null clears a field. A changed email is labeled as entered manually. Each change is recorded in the contact's activity history. Obtain user confirmation of the new values before calling.

Input parameters:

- `author_name`: Author name. Null clears it; omit to keep it.
- `email`: Email to pitch. Null clears it; omit to keep it.
- `linkedin`: Author LinkedIn URL. Null clears it; omit to keep it.
- `message`: Draft body. Null clears it; omit to keep it.
- `subject`: Draft subject. Null clears it; omit to keep it.
- `url` (string, required): Cited page URL, e.g. "example.com/blog/best-tools". A contact already saved under this exact URL (for example one the Outreach page saved for a query variant its URL rules list separately) is used fi…
- `website_id` (string, required)

Output parameters:

- `contact` (object)
- `created` (boolean): True when this call created the page's contact.

### `update_pillar` (~131 tokens)

Update a Knowledge Base pillar's name, description, or status. At least one of name, description, or status must be provided; only provided fields change, and description: "" clears the stored description. Renaming fails with a conflict when another pillar already uses the name. Status accepts published or archived: archiving hides the pillar from get_pillars and stops its facts feeding content generation, while keeping the facts stored.

Input parameters:

- `description` (string)
- `name` (string)
- `pillar_id` (string, required)
- `status` (string)
- `website_id` (string, required)

Output parameters:

- `before` (object)
- `pillar` (object)

### `update_prompt` (~88 tokens)

Update a prompt's metadata (text, type, topic, geography)

Input parameters:

- `countries` (array)
- `location_ids` (array)
- `primary_country` (string|null)
- `prompt` (string)
- `prompt_id` (string, required)
- `topic_id`
- `type`
- `volume` (string|null)
- `website_id` (string, required)

Output parameters:

- `before` (object)
- `countries` (array)
- `id` (string)
- `locations` (array)
- `text` (string)
- `topic_id` (string|null)
- `type` (string|null)
- `volume` (string|null)

### `update_topic` (~44 tokens)

Update a topic's name or description

Input parameters:

- `description`
- `name` (string)
- `topic_id` (string, required)
- `website_id` (string, required)

Output parameters:

- `before` (object)
- `description` (string|null)
- `id` (string)
- `name` (string)

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp#diagnostics

## Score history

- 2026-11-05: 66
- 2026-11-04: 66
- 2026-11-03: 65
- 2026-11-02: 65
- 2026-11-01: 64
- 2026-10-31: 64
- 2026-10-30: 64
- 2026-10-29: 63
- 2026-10-28: 63
- 2026-10-27: 62
- 2026-10-26: 62
- 2026-10-25: 61
- 2026-10-24: 61
- 2026-10-23: 61
- 2026-10-22: 60
- 2026-10-21: 60
- 2026-10-20: 60
- 2026-10-19: 59
- 2026-10-18: 59
- 2026-10-17: 58
- 2026-10-16: 58

## Common questions

### What is the AthenaHQ MCP server?

AthenaHQ is an MCP server listed in the public MCP registry as ai.athenahq/mcp. Track how AI assistants mention, cite, and rank your brand and competitors in AI search. This page covers its hosted endpoint (https://api.athenahq.ai/api/mcp).

### Is the AthenaHQ MCP server safe to use?

AthenaHQ scores 66 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the AthenaHQ MCP server expose?

AthenaHQ exposes 113 tools: open_ai_access, check_public_ai_access, get_prompt_schedules, get_ai_search_value, get_prompts, and 108 more. Their descriptions and schemas cost roughly 19,324 tokens of context every time the server is loaded.

### Does the AthenaHQ MCP server require authentication?

No. We connected to AthenaHQ without credentials and it answered, so anything it exposes is reachable by anyone who knows the address.

### Is the AthenaHQ MCP server still maintained?

AthenaHQ is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- Remote endpoint: https://api.athenahq.ai/api/mcp
- Website: https://docs.athenahq.ai/api-reference/mcp
- Changelog RSS feed: https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp.json
- HTML version of this page: https://verifymcp.io/servers/ai-athenahq-mcp/api-mcp
