# Tools

Every tool the AIclicks MCP server exposes.

The AIclicks MCP server exposes one tool per public `/api/v1/*` endpoint and forwards your API key on every call. Most tools are read-only; a few **write** tools (`add_prompt`, `add_competitor`, `create_domain`) mutate your account — see [Write / manage](#write-manage).

Tools are auto-discovered by the client — there's no manual registration. Once connected, your assistant lists them via the standard MCP `tools/list` call. The reference below mirrors what your assistant sees.

<Callout kind="info" collapsed="false">
  Almost every tool needs a `domain_id`. Call `list_domains` first to get the IDs your API key can access, then pass one into the other tools.
</Callout>

## Account

### `validate_key`

Confirm the API key works. Returns the team it's bound to, the allowed-domains scope, and the per-minute rate limit. No parameters.

### `list_domains`

List every tracked domain your API key can access. 

**Team key:** returns a flat array of `{id, name, website, …}`. 

**Master key:** returns an array of teams, each `{team_id, team_name, domains: […]}` — use `team_name` to attribute a domain to its team. If an item has a `domains` array you got the grouped (master) shape; otherwise items are domains directly. Start every session with this call.

## Catalog

### `list_prompts`

Paginated list of tracked prompts under a domain. Useful for "show me the queries we monitor for example.com."

**Params**: `domain_id`, `page` (default 1), `size` (default 25, max 100), `topic_id` (optional filter).

### `list_tags`

Tags defined for a domain, each with its UUID and name. Resolve tag names to the `tag_ids` `add_prompt` expects — only existing tags can be attached (no create-tag tool).

**Params**: `domain_id`.

### `list_topics`

Topics defined for a domain, each with its UUID and name. Resolve topic names to the `topic_ids` `add_prompt` expects — only existing topics can be attached (no create-topic tool).

**Params**: `domain_id`.

### `list_fanout_queries`

The discovery-stage expanded query set — fan-out queries the LLMs actually asked when probing a prompt. Helps debug "why did my prompt return this answer?"

**Params**: `domain_id`, `days` (default 30, 1–365), `model` (default `all`).

### `get_prompt_statistics`

Per-prompt performance over time — which tracked prompts win or lose the brand visibility. Returns the top N prompts (by total mentions), each with its `estimated_search_volume` and a daily `series` of `mentions`, `responses`, `citations`, and `avg_position`. Answers "which prompts gained or dropped the most?"

**Params**: `domain_id`, `days` (default 30), `limit` (default 25, top N by mentions, max 100).

## Time-series

All time-series tools share the same shape: `{ data: { items: [{date, value}] }, generated_at }`. Days are snapped to `7d`, `30d`, or `90d` buckets server-side.

### `get_visibility_time_series`

Daily visibility share for the domain — the percentage of monitored prompts where the brand was mentioned.

**Params**: `domain_id`, `days` (default 30).

### `get_mentions_time_series`

Raw mention count per day across all monitored prompts.

**Params**: `domain_id`, `days` (default 30).

### `get_citability_time_series`

Citation-eligibility ratio per day — what fraction of brand mentions came with a citation back to your domain.

**Params**: `domain_id`, `days` (default 30).

### `get_citations_time_series`

Raw citation count per day — outbound links pointing to your domain across AI search results.

**Params**: `domain_id`, `days` (default 30).

## Citations & rankings

### `get_citations`

URL-level citation view: every page the domain appears in across AI search results over the window, with citation frequency, aggregate mention count, prompt count, `prompt_ids` (the prompts that drove each URL — resolve to text/volume via `list_prompts`), models that cited it, and first/last seen dates. Sorted by frequency desc.

**Params**: `domain_id`, `days` (default 30).

### `get_brand_rankings`

Current share-of-voice ranking for the domain vs. its tracked competitors. One flat list with `is_brand: true` on your row and `false` on each competitor.

**Params**: `domain_id`, `days` (default 30).

### `get_competitor_time_series`

The trend version of `get_brand_rankings`: daily visibility / share-of-voice / position per tracked competitor (plus the brand). Each entry — brand first, then competitors — has a `series` of daily `{visibility, sov, mentions, avg_position, sentiment}` plus window averages. Answers "how is competitor X trending vs us?"

**Params**: `domain_id`, `days` (default 30), `model` (default `all`).

### `get_competitor_discovery`

Brands that appear in AI answers to your tracked prompts but **aren't in your tracked competitor set yet** — ranked by `prompts_mentioned` (out of `total_prompts`). The "who should I be tracking?" tool, complementing `get_brand_rankings` (already-tracked only).

**Params**: `domain_id`, `days` (default 30).

### `list_competitors`

The competitors currently tracked for the domain, with optional filters. Complements `get_brand_rankings` (metrics) with the plain tracked-set list.

**Params**: `domain_id`, `is_dedicated` (optional), `active` (optional).

## ChatGPT ads

Advertising surfaced inside ChatGPT answers for the domain's prompts.

### `get_chatgpt_ads_kpis`

Headline ChatGPT-ads metrics — prompts with ads, brand appearances, unique advertisers, total ad cards seen — each with a delta vs the previous equal-length window.

**Params**: `domain_id`, `days` (default 30).

### `get_chatgpt_ads_leaderboard`

Brands advertising on ChatGPT for the domain's prompts, ranked by prompt coverage.

**Params**: `domain_id`, `days` (default 30).

### `get_chatgpt_ads_timeline`

Daily ChatGPT-ads activity for the domain over the window — the ads trend.

**Params**: `domain_id`, `days` (default 30).

### `get_chatgpt_ads_prompts`

Tracked prompts that triggered ChatGPT ads, paginated.

**Params**: `domain_id`, `days` (default 30), `page` (default 1), `per_page` (default 50, max 500).

### `get_chatgpt_ads_cards`

Individual ChatGPT ad cards (creatives/advertisers) seen for the domain's prompts, paginated.

**Params**: `domain_id`, `days` (default 30), `page` (default 1), `per_page` (default 50, max 500).

### `get_model_leaderboard`

Per-channel performance: visibility and average position broken out by AI channel (ChatGPT, Claude, Perplexity, Gemini…). Sorted by visibility desc.

**Params**: `domain_id`, `days` (default 30).

## Sentiment

How AI answers feel about the brand and what drives it. Every sentiment tool takes an optional `model` filter — pass a **generic channel name** (`ChatGPT`, `Perplexity`, `Gemini`, `AI Overviews`, `Claude`…) or leave it `all`.

### `get_sentiment_overview`

Positive vs. negative split for how LLMs talk about the brand, plus total mentions across the window. Best for "how do AI answers feel about us right now?"

**Params**: `domain_id`, `days` (default 30), `model` (default `all`).

### `get_sentiment_time_series`

Daily positive-sentiment percentage — the share of each day's themes that are positive. Shows whether sentiment is trending warmer or colder.

**Params**: `domain_id`, `days` (default 30), `model` (default `all`).

### `list_sentiment_themes`

The named themes AI answers raise, each tagged `positive` or `negative` with an occurrence count. Sorted by occurrences desc — the \*names may be non-English; classifyon the `sentiment` field.

**Params**: `domain_id`, `days` (default 30), `model` (default `all`).

### `get_sentiment_theme_sources`

The URLs cited when those themes were raised, rolled up by citation frequency — which pages shape
how LLMs describe the brand. \`modehannel names.

**Params**: `domain_id`, `days` (d`all`).

## GA4 / LLM traffic

Real site traffic referred by AI assistants, read from the brand's connected Google Analytics 4 property and filtered to LLM/AI sources. This is the _did-AI-visibility-turn-into-visitors_ side, distinct from the visibility/citation tools (which measure appearance inside AI answers). Every tool takes an optional `llm_source` filter (`chatgpt`, `perplexity`, `claude`, `gemini`, `copilot`…); omit for all sources. All return empty/zeroed views (not an error) when the domain has no GA4 connection.

### `get_ga4_summary`

Totals of AI-referred traffic — sessions, users, pageviews — plus the previous period for deltas.

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_by_llm`

AI-referred sessions/users/pageviews broken out per LLM source, plus the previous period — which assistants actually send visitors.

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_timeline`

Daily AI-referred sessions over the window, each day split by LLM source. The traffic time-series.

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_top_pages`

Pages ranked by AI-referred sessions (`page_path` + `sessions`, desc) — which content wins AI visitors.

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_top_locations`

AI-referred traffic by country (`location` + `sessions`, desc).

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_top_browsers`

AI-referred traffic by browser (`browser` + `sessions`, top 10 desc).

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_devices`

AI-referred traffic by device category — mobile / desktop / tablet (`device` + `sessions`).

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

### `get_ga4_key_events`

GA4 key events / conversions attributed to AI-referred traffic — `total`, per-LLM breakdown, top events — plus the previous period's total. The did-AI-traffic-convert view.

**Params**: `domain_id`, `days` (default 30), `llm_source` (optional).

## Write / manage

These tools **change your account**. Each requires the caller to be a member of the target team on a **Pro+ plan** (403 otherwise). Your assistant should confirm intent before calling them.

### `add_prompt`

Add a tracked prompt to a domain, optionally with topics and tags. Consumes one prompt credit. Errors on a duplicate prompt (409) or when the team is out of credits (400).

**Params**: `domain_id`, `text`, `topic_ids` (optional), `tag_ids` (optional — omit to auto-assign default tags, pass `[]` to attach none).

### `add_competitor`

Start tracking a competitor for a domain. Defaults to the **tracked (dedicated)** list — actively analyzed and counts against the plan's dedicated-competitor limit; the assistant should flag this before adding. Errors if it already exists (409) or the dedicated-competitor limit is reached (400).

**Params**: `domain_id`, `competitor_domain`, `competitor_name`, `is_dedicated` (default **true**; set false for a passive/discovery entry), `competitor_variations` (optional).

### `create_domain`

Create a new brand (domain) with prompts, so analysis starts immediately. Subject to the team's domain limit. Before creating, the assistant should ask whether you want to supply your own prompts or have them generated — and if generated, draft a set, list it, and confirm with you before the call. You must pass a `prompts` list or set `generate_prompts=true` (server-side, not shown for review) — a brand with nothing to analyze stays stuck in the "analyzing" state. New rows can take up to \~30 min to appear in the dashboard (client-side cache).

**Params**: `team_id`, `name`, `website`, `country` (optional), `prompts` (list of `{text, topics?, tags?}`), `generate_prompts` (default false).

## Error contract

Every tool returns the same envelope as the underlying REST endpoint. On failure the assistant sees a structured error — most commonly:

| HTTP | Meaning                      | What the assistant sees                 |
| ---- | ---------------------------- | --------------------------------------- |
| 401  | Bad / missing API key        | `Missing or malformed aiclicks API key` |
| 403  | Key can't access this domain | `domain_id not in caller scope`         |
| 429  | Rate limit (60 req/min/key)  | Backend error surfaced with retry-after |
| 500  | Backend error                | Generic `Internal server error`         |

See [Troubleshooting](/mcp-troubleshooting) for fixes.
