# Suparanku MCP Server

suparanku v1.1.0 · MCP protocol 2025-11-25 · transport: Streamable HTTP (stateless).

> This reference is generated from the live tool registry — it never drifts from the server.

## Endpoint

```
https://app.suparanku.com/api/mcp/v1
```

Pin the versioned URL above. `https://app.suparanku.com/api/mcp` (unversioned) is an alias to the
current stable major and may advance to a new major in the future.

## Versioning

The tool catalog is semver-versioned (current v1.1.0). Additive
changes (new tool, new optional parameter, new output field) ship as MINOR within
this endpoint — re-read `tools/list` to pick them up. Breaking changes ship as a
new `/api/mcp/vN` endpoint; the previous version keeps working until an announced
sunset date, and any tool being retired is marked **Deprecated (sunset …)** below
before removal. See the Changelog at the end of this document.

## Connect

Any MCP-compatible client/agent. Two ways to authenticate:

- **Personal Access Token (PAT)** — create one in the Suparanku app under
  Settings → MCP & API tokens, then pass it as a Bearer token. For clients that
  only speak stdio, bridge with: `npx mcp-remote https://app.suparanku.com/api/mcp/v1 --header "Authorization: Bearer <TOKEN>"` (pin mcp-remote >= 0.1.16).
- **OAuth 2.1** — interactive hosted clients discover the authorization server
  via `/.well-known/oauth-protected-resource` and run Authorization Code + PKCE.

## How it works

Suparanku measures how AI assistants (ChatGPT, Claude, Gemini, etc.) talk about a brand
across five axes — visibility, position, sentiment, competitors, and sources — and turns
that into prioritized recommendations and content briefs for the Japanese market.

WORKFLOW (call suparanku_how_it_works for the full end-to-end algorithm):
1. Call suparanku_list_companies FIRST to get a company_id. Every other tool needs one.
2. Pass company_id (and optionally brand_id, an own brand) to each tool.
3. Use suparanku_explain_term / suparanku_get_glossary to understand the metrics.
4. suparanku_get_metrics is the unified analytics tool — pick group_by and either a
   date_range (trend) or a scan_ref from suparanku_list_scans (one past scan, all cuts).
   Sentiment and competitor share are returned there, not as separate tools.

TENANCY & PERMISSIONS:
- A token can span multiple companies (call suparanku_list_companies to see which),
  but only those it is scoped to: your active memberships intersected with the token scope.
  It can never reach a company outside that set (no cross-tenant access).
- READ tools work whenever the company has MCP access (read or full).
- WRITE tools require the company to be mcp_access="full", your role to be member or higher,
  and a read+write token. DELETE tools additionally require an allow-destructive token and
  confirm:true, and some (delete_prompt, delete_topic) are irreversible / break comparability.
- A company owner/admin can revoke a specific credential's access to THEIR company at any
  time. If a company that previously worked starts returning NOT_FOUND, your access to it was
  revoked — other companies on the same token are unaffected. Re-run suparanku_list_companies.

OUTPUT: results are paginated and size-capped; tables come back as CSV. Errors are returned
as tool errors with guidance on how to fix the call — read them and self-correct.

PAGING & LOOPS:
- List/source reads return { total, offset, limit, has_more }. To read a whole list, advance
  offset += limit while has_more is true.
- Marking up sources: call suparanku_list_source_categories once for the valid categories, then
  loop suparanku_get_sources(only_unmarked:true) → suparanku_set_source_category_bulk until
  unmarked_count reaches 0.
- Triaging possible competitors: add/dismiss REMOVE a candidate and re-rank the list, so a plain
  offset += limit walk skips candidates. Page through with READ-ONLY calls first to collect the
  full set (by canonicalKey), THEN add/dismiss.
- Fixing the site (site audit): run_site_fast_audit → poll get_latest_site_audit_run → 
  get_site_schema(only_problems:true) for the pages that need work → per page, page through
  list_technical_recommendations (summary cards; advance offset += limit while has_more) +
  get_page_outbound_links to triage links. A null-status link is NOT auto-broken: an external
  "no_response" is often a bot-block — resolve it with set_link_verdict (ok/bad), don't treat it as
  broken. For each rec, call get_recommendation for the full fix brief + artifacts, apply, deploy, re-run.
- Reports: suparanku_generate_report → poll suparanku_get_report until status "done" →
  suparanku_get_report_download_url (the URL expires in ~15 minutes — re-mint, never store it).
- Rate limit is per-company weighted cost-units per minute (Starter 60). Long write loops can hit
  TOO_MANY_REQUESTS — expect it, back off, and retry; do not hammer at full speed.

## Tools — read (43)

### `suparanku_help`

Read this first. Explains what Suparanku is, how to use this MCP (workflow + tenancy + read vs write), and lists every available tool. Optionally pass `topic` to filter the tool list.

- kind: read-only, idempotent
- input: topic
- since: v1.0.0

### `suparanku_how_it_works`

Read this to understand the WHOLE Suparanku workflow end-to-end (the Context → Analytics → Growth → Action loop, steps 0–9), with the tools for each step. Complements suparanku_help (which just lists the tools).

- kind: read-only, idempotent
- input: (no input)
- since: v1.0.0

### `suparanku_explain_term`

Explain a Suparanku / AI-visibility (GEO) domain term so you can interpret the data correctly — e.g. "visibility", "position", "sentiment", "sample", "content brief", "source", "markup version". Pass the term in `term`.

- kind: read-only, idempotent
- input: term
- since: v1.0.0

### `suparanku_get_glossary`

Return the full Suparanku / AI-visibility (GEO) glossary so you understand every metric and concept before working with the data. No input.

- kind: read-only, idempotent
- input: (no input)
- since: v1.0.0

### `suparanku_list_source_categories`

List every source (cited-domain) category Suparanku uses — id, label, meaning, and whether you can assign it — so you can mark up "unknown" (needs-markup) domains. Call this before suparanku_set_source_category(_bulk). No input.

- kind: read-only, idempotent
- input: (no input)
- since: v1.1.0

### `suparanku_list_companies`

List the companies this token can access, with each company_id, name, plan tier, your role, and its MCP access level (none/read/full). ALWAYS call this FIRST — every other tool needs a company_id from here.

- kind: read-only, idempotent
- input: (no input)
- since: v1.0.0

### `suparanku_list_brands`

List a company’s own tracked brands (id, name, language, domain). Use a brand id as brand_id in other tools.

- kind: read-only, idempotent
- input: company_id
- since: v1.0.0

### `suparanku_list_topics`

List a brand’s topics (theme groupings of prompts) with prompt counts.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.0.0

### `suparanku_list_competitors`

List the competitors already MARKED/tracked for a brand. For not-yet-marked suggestions use suparanku_list_possible_competitors.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.0.0

### `suparanku_list_possible_competitors`

The FULL potential-competitor inbox — every discovery source merged and deduped against already-tracked and dismissed competitors: live AI answers (source ai_answers), market research (research_player / research_proposal / research_watchlist) and earlier audit candidates (wave_candidate). `confirmed:true` = a research candidate corroborated by current live AI answers (highest trust, sorted first); `seenInAnswers:true` also includes mentions-derived earlier audit candidates, while false rows remain research hypotheses. Rows with ai_answers carry `canonicalKey`/`promptIds` (pass canonicalKey to suparanku_get_possible_competitor_evidence for the exact prompts/answers); every row carries `dismissAliases` — to act, mark it with suparanku_add_competitor or dismiss it with suparanku_dismiss_possible_competitor (canonicalKey + displayName + dismissAliases as its aliases). Paginated: `total` is the full inbox count, follow `has_more`. NOTE: add/dismiss REMOVE a row from this list and re-rank it, so a plain `offset += limit` walk skips rows — page through with READ-ONLY calls first to collect the full set, THEN act.

- kind: read-only, idempotent
- input: company_id, brand_id, limit, offset
- since: v1.0.0

### `suparanku_get_possible_competitor_evidence`

For ONE possible competitor (pass its `canonical_key` from suparanku_list_possible_competitors): the actual prompts/AI answers where it was spotted — prompt text, which LLM, the matched phrase and sentiment. Use it to decide whether to mark it as a competitor (suparanku_add_competitor) or dismiss it. Returns up to `limit` most-recent mentions from the last 90 days (no offset paging).

- kind: read-only, idempotent
- input: company_id, brand_id, canonical_key, scope, prompt_id, limit
- since: v1.0.0

### `suparanku_get_competitor_mentions`

For ONE tracked competitor (pass its `competitor_brand_id` from suparanku_list_competitors): the prompts/AI answers in the LATEST scan where it appeared — prompt text, which LLM, the matched snippet, sentiment and position. `answers_count` = number of answers it appeared in; `prompts_count` = number of distinct prompts. Use it to verify the competitor’s aliases are catching the right answers. Paginated: page with `limit`/`offset`, follow `has_more`.

- kind: read-only, idempotent
- input: company_id, brand_id, competitor_brand_id, topic_id, include_branded, limit, offset
- since: v1.0.0

### `suparanku_get_competitor_topic_gaps`

Where competitors beat you, per topic: your share of AI answers vs EVERY tracked competitor’s share over the window (share = answers mentioning the brand / total answers sampled for the topic). Rows sort by the deficit (best competitor − you, descending); `gap_pp` is that deficit in percentage points and `beaten:true` flags a deficit of 30pp or more. The branded topic is excluded (not a competitive comparison), as are topics where nobody appears. `total_runs` = answers sampled for the topic; `low_data:true` (fewer than 30 runs) means the shares are directional, not statistical — still shown, never hidden. Matches the dashboard’s “Where they beat you” view.

- kind: read-only, idempotent
- input: company_id, brand_id, date_range
- since: v1.8.0

### `suparanku_get_competitor_source_gap`

For ONE tracked competitor (pass its `competitor_brand_id` from suparanku_list_competitors): the cited domains whose pages verifiably mention that competitor while NO cited page on the domain mentions your brand — i.e. the publications to target next. Up to 30 domains ordered by citation volume, each with its source category. `unverified_count` = cited URLs in the window that could not yet be checked for this competitor (excluded from the list, not evidence either way). Branded prompts (text naming a tracked brand) are excluded — the gap measures open-market answers only.

- kind: read-only, idempotent
- input: company_id, brand_id, competitor_brand_id, date_range
- since: v1.8.0

### `suparanku_list_scans`

List a brand’s scan events (most recent first): id, started_at, trigger, status, markup_version (comparability marker). Use a scan id as scan_ref in suparanku_get_metrics to read that point-in-time.

- kind: read-only, idempotent
- input: company_id, brand_id, limit
- since: v1.0.0

### `suparanku_get_metrics`

The unified analytics tool: visibility, position, sentiment, sources and competitor share. Choose group_by (overall/topic/provider/competitor/prompt) and EITHER a date_range (trend) OR a scan_ref from suparanku_list_scans (one past scan, all cuts). sentiment & competitor share are returned here — there are no separate tools for them.

- kind: read-only, idempotent
- input: company_id, brand_id, group_by, date_range, scan_ref
- since: v1.0.0

### `suparanku_get_sources`

The websites AI answers cite for a brand (latest scan). level="domain" (default) returns a PAGE of domains with mention counts + effective category + a needs-markup marker; level="url" returns up to 50 URLs for a specific domain (pass `domain`). Counts in the domain response: `total` = number of domains AFTER filters (use it for paging — compare against `offset`); `total_sources` = total citation volume (Σ counts), NOT a domain count; `unmarked_count` + `category_counts` are over the FULL set (unaffected by filters), for planning and completion. Filters (domain level): `only_unmarked:true` returns only domains still needing a category — loop with it until `unmarked_count` reaches 0 to mark everything; `category` returns only domains of one effective category (see `category_counts` for the distribution). Page with `limit`/`offset` and follow `has_more`.

- kind: read-only, idempotent
- input: company_id, brand_id, level, topic_id, domain, only_unmarked, include_branded, category, limit, offset
- since: v1.0.0

### `suparanku_list_prompts`

List a brand’s tracked prompts (id, text, topic, per-provider stats). Use a prompt id with the prompt-scan tools. Paginated: `total` is the full count, page with `limit`/`offset` and follow `has_more` (rows are heavy, so large brands need paging).

- kind: read-only, idempotent
- input: company_id, brand_id, topic_id, limit, offset
- since: v1.0.0

### `suparanku_get_prompt_scan_meta`

For one prompt: which AI providers were sampled, how many samples, and per-prompt aggregates — WITHOUT the full answer texts. Then call suparanku_get_verbatim_answer for a specific provider+sample.

- kind: read-only, idempotent
- input: company_id, prompt_id, scan_ref
- since: v1.0.0

### `suparanku_get_verbatim_answer`

The full verbatim AI answer for a prompt — heavy, so fetch only the provider+sample you need (read suparanku_get_prompt_scan_meta first). Includes the brand’s position, citations and sentiment.

- kind: read-only, idempotent
- input: company_id, prompt_id, provider_id, sample_index, scan_ref
- since: v1.0.0

### `suparanku_list_recommendations`

ALL of the brand’s current recommendations in one call as a FLAT, paginated list of summary cards (each item carries `category` = context | technical | content, plus status, impact/effort and — for content — brief_status). This is NOT the full detail: for one item’s steps/evidence/brief use suparanku_get_recommendation. `counts` gives the per-category active totals (matches the dashboard badges). Optionally filter by `status` and/or `category`. Paginate with limit/offset until has_more is false.

- kind: read-only, idempotent
- input: company_id, brand_id, locale, status, category, limit, offset
- since: v1.1.0

### `suparanku_list_context_recommendations`

List CONTEXT recommendations (improve the data Suparanku tracks) as paginated summary cards (id, status, impact/effort) — NOT the full detail. Prioritised with impact/effort. Includes manual VISUAL verifications from the site audit (signal_key `context.site.*`, marked `manual:true`) — e.g. the og:image review, whose card carries `imageUrl`: SHOW that image to the user in the chat, ask whether it looks right (crop, blur, readable text, branding), and only then mark it via suparanku_set_recommendation_status (done records the verified-OK verdict). These never affect the SRPS score. Paginate with limit/offset until has_more is false; for one item’s detail use suparanku_get_recommendation.

- kind: read-only, idempotent
- input: company_id, brand_id, status, limit, offset
- since: v1.0.0

### `suparanku_list_technical_recommendations`

List TECHNICAL recommendations (site/markup changes for AI crawlers, from the site audit) as paginated summary cards (id, status, impact/effort, scope, affected_count + a small URL sample) — NOT the inline fix brief. Prioritised with impact/effort. Optionally narrow with audit_scope: "site" or "page:<url>". Paginate with limit/offset until has_more is false; for one item’s full fix brief (plain-language explanation + ready-to-paste artifacts + machineReadable.fix/verify) call suparanku_get_recommendation. AUTONOMOUS FIX LOOP: run_site_fast_audit → poll get_latest_site_audit_run until done → get_site_schema(only_problems:true) to find the pages that need work → for each, page through this list + get_page_outbound_links to triage links (resolve a no_response with set_link_verdict, fix a broken one on the site) → for each rec, suparanku_get_recommendation for the full brief, apply its artifacts per its steps → deploy → run_site_fast_audit again; fixed checks auto-resolve.

- kind: read-only, idempotent
- input: company_id, brand_id, status, limit, offset, locale, audit_scope
- since: v1.0.0

### `suparanku_list_content_recommendations`

List CONTENT recommendations (what to write to close visibility gaps) as paginated summary cards (id, status, impact/effort, brief_status) — NOT the full brief. Each item carries brief_status (none/generating/ready/failed) so you know whether a brief already exists. Paginate with limit/offset until has_more is false; for one item’s full brief use suparanku_get_recommendation / suparanku_get_content_brief.

- kind: read-only, idempotent
- input: company_id, brand_id, status, limit, offset
- since: v1.0.0

### `suparanku_get_recommendation`

Full detail of one recommendation (description, steps, evidence, status, published URLs). For a TECHNICAL recommendation the `brief` field carries the complete deterministic fix inline: a plain-language explanation (problem, why it matters, desired state, how to fix) plus a concrete developer brief — ordered steps, ready-to-paste artifacts, acceptance criteria, an optional risk note, and machineReadable.fix/verify. `brief.copyText` is the same fix as one self-contained, copy-ready ENGLISH brief (matches the in-app Copy brief button), with the affected pages listed at the end. Apply the artifacts, then re-run the audit to auto-resolve it. Content-deep checks instead return brief.status="needs_generation" (use suparanku_generate_content_brief).

- kind: read-only, idempotent
- input: company_id, brand_id, recommendation_id, locale
- since: v1.0.0

### `suparanku_get_content_brief`

Return the content brief for a content recommendation. Response is { brief_status, brief?, hint }: ready→the brief; none→no brief yet + how to generate one; generating→poll later; failed→reason. Never an opaque error.

- kind: read-only, idempotent
- input: company_id, brand_id, recommendation_id
- since: v1.0.0

### `suparanku_get_brief_rewrite`

Return the rewrite-brief content for a recommendation (rewrites of existing URLs), distinct from the main content brief.

- kind: read-only, idempotent
- input: company_id, brand_id, recommendation_id
- since: v1.0.0

### `suparanku_get_company_usage`

This company’s MCP-relevant quotas and remaining budget: manual refreshes and content briefs (used / quota / reset date), scope limits (max brands/prompts/topics/competitors), and mcp_access. No prices.

- kind: read-only, idempotent
- input: company_id
- since: v1.0.0

### `suparanku_get_report`

Latest PDF report metadata (id, status, locale, data window, is_stale) + the last 10 completed reports (history). Does NOT trigger generation (use suparanku_generate_report) and does NOT return the file — pass a report id to suparanku_get_report_download_url for a time-limited download link.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.0.0

### `suparanku_get_report_download_url`

Mint a fresh, time-limited download URL (valid ~15 minutes) for a COMPLETED PDF report. Pass a report id from suparanku_get_report (latest.id or a history row id). The URL expires — do not store it; re-call this tool whenever you need to download again. Only reports with status "done" have a file.

- kind: read-only, idempotent
- input: company_id, brand_id, report_id
- since: v1.8.0

### `suparanku_get_scan_status`

Poll the status of a manual scan started with suparanku_run_manual_scan (queued/running/completed, per provider).

- kind: read-only, idempotent
- input: company_id, brand_id, prompt_ids
- since: v1.0.0

### `suparanku_get_site_audit`

The brand’s domain-level site audit for its primary domain: the SRPS / SRPS+ scores, the grouped domain checks (accessibility, AI-agent access, entity/LLMO, base metrics, social card) with their verdicts, page/locale counts, and the manual-check state. For one page’s detail use suparanku_get_page_audit; for the page-by-page tree use suparanku_get_site_schema.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.2.0

### `suparanku_get_site_schema`

The brand’s crawled pages with per-page status: URL, locale, section, HTTP status, verdict, SRPS (fast) / SRPS+ (deep) scores, Lighthouse perf_score, AI-cited count, issue counts, flags, and the redirect / client_redirect markers (a "200" that redirects client-side is a fake-200 shell — `clientRedirect:true`; a server-side 3xx to a different page is a `redirect` node). Pass `only_problems:true` to return only pages that need attention. Use a page URL with suparanku_get_page_audit (per-page detail) or suparanku_get_page_outbound_links / suparanku_get_page_inbound_links (its link graph). Paginated: page with limit/offset and follow has_more (large sites have many pages).

- kind: read-only, idempotent
- input: company_id, brand_id, only_problems, limit, offset
- since: v1.2.0

### `suparanku_get_page_audit`

The full audit for ONE page (pass its `url`): fast + deep check categories with verdicts, the SRPS / SRPS+ scores, the on-page links block (status + role), canonical/noindex flags and AI citations. For the link graph with status classification + the no-response verdict use suparanku_get_page_outbound_links / suparanku_get_page_inbound_links. List pages first with suparanku_get_site_schema.

- kind: read-only, idempotent
- input: company_id, brand_id, url
- since: v1.2.0

### `suparanku_get_latest_site_audit_run`

Status of the most recent FAST-family site-audit run (full crawl or fast page re-audit) for the brand: status (queued/running/done/partial/failed/blocked) and pages_done/pages_total progress. Poll this after suparanku_run_site_fast_audit until status is done/partial, THEN read suparanku_list_technical_recommendations. The parallel homepage deep run every full audit kicks is not reported here — deep results appear in suparanku_get_page_audit.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.4.0

### `suparanku_get_page_inbound_links`

Internal links pointing TO this page (the inbound side of the link graph): which crawled pages link here, with the anchor text, the link group, and the source page’s HTTP status. Answers "how was this page found / what links here" and explains an orphan or a 404 in the tree. Paginated. Pass a page URL from suparanku_get_site_schema.

- kind: read-only, idempotent
- input: company_id, brand_id, url, limit, offset
- since: v1.5.0

### `suparanku_get_page_outbound_links`

The on-page (outbound) links for ONE page, each classified for triage: status_class (ok / redirect / broken / no_response / not_checked / app_scheme), the no-response manual verdict (pending / ok / bad) and the `effective` status after that verdict. A null status is NEVER a confirmed break — an EXTERNAL no_response is often a bot-block (x.com, instagram, Cloudflare), an INTERNAL null is "not_checked" (target outside the audited set). Triage off `effective` (what SRPS / link health reflect), not raw `status_class`. Filter with all | errors (effective broken) | no_response (all unreachable externals) | external. Paginated. Pass a page URL from suparanku_get_site_schema; resolve a no-response link with suparanku_set_link_verdict.

- kind: read-only, idempotent
- input: company_id, brand_id, url, filter, limit, offset
- since: v1.5.0

### `suparanku_get_unverified_links`

Every EXTERNAL outbound link across the WHOLE site whose probe was a no-response (status null) or a bot-block (401/403/429) — neither is a confirmed dead link, so each needs a verdict (big hosts like openai.com behind Cloudflare reject the crawler while the URL opens fine in a browser). Deduped by href, with the site-wide verdict (pending / ok / bad), the probe status, and how many pages it appears on. The one-stop triage queue: list here, then resolve each with suparanku_set_link_verdict (ok = works, bad = really dead). Pass only_pending:true for just the actionable set. Paginated.

- kind: read-only, idempotent
- input: company_id, brand_id, only_pending, limit, offset
- since: v1.5.0

### `suparanku_get_indexing_status`

Google index status per own-site page (Search Console URL Inspection): verdict, coverage reason. Filter published (published from a recommendation) | cited (AI-cited) | all. Empty with connected:false when Search Console is not connected.

- kind: read-only, idempotent
- input: company_id, brand_id, filter, limit, offset
- since: v1.7.0

### `suparanku_get_search_performance`

Per-page Google Search clicks/impressions/position for the selected window (7d|28d|90d) with previous-window values, from the customer’s Search Console. Empty with connected:false when not connected.

- kind: read-only, idempotent
- input: company_id, brand_id, period, limit, offset
- since: v1.7.0

### `suparanku_get_real_demand`

Real-demand calibration: candidate demand clusters synthesized from real Google queries that no Market Map cluster covers (a human accepts/dismisses them in the UI). Grounds coverage decisions in actual search demand.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.7.0

### `suparanku_get_ai_traffic`

Real visits from AI assistants (ChatGPT, Perplexity, Gemini, …) per own-site page, from the customer’s GA4 — classified by our referrer registry. FLOOR, not ceiling: many AI-assistant visits arrive without a referrer. Empty with connected:false when GA4 is not connected.

- kind: read-only, idempotent
- input: company_id, brand_id, period, limit, offset
- since: v1.7.0

### `suparanku_get_citation_traffic_insights`

The citation×traffic join per page: cited_with_traffic (working — reinforce), cited_no_traffic (citation without clicks), ai_visits_not_cited (engines send visitors to pages never seen cited — hidden demand). Requires GA4; lists are empty when not connected.

- kind: read-only, idempotent
- input: company_id, brand_id
- since: v1.7.0


## Tools — write (34)

### `suparanku_create_brand`

Create a NEW brand inside an existing company (subject to the company’s max_brands limit — see suparanku_get_company_usage). Does NOT create a new company. Requires admin role. Provide aliases (the only match strings), a domain, and a short business description.

- kind: write
- input: company_id, brand_name, aliases, domain, description, industry, target_audience, primary_language
- since: v1.0.0

### `suparanku_update_brand_profile`

Update a brand’s profile fields (name, description, industry, target_audience, domain, primary_language). Changing primary_language is a METHODOLOGY EVENT: it re-keys matching and bumps the markup version, so metrics before/after are not directly comparable.

- kind: write, idempotent
- input: company_id, brand_id, name, description, industry, target_audience, domain, primary_language
- since: v1.0.0

### `suparanku_update_brand_domains`

Set a brand’s primary domain + secondary domains (these define the "owned" source category).

- kind: write, idempotent
- input: company_id, brand_id, primary, secondary
- since: v1.0.0

### `suparanku_update_brand_aliases`

Replace a brand’s aliases (the match strings). Methodology event — re-keys matching + bumps markup version.

- kind: write, idempotent
- input: company_id, brand_id, aliases
- since: v1.0.0

### `suparanku_create_topic`

Create a topic (theme grouping for prompts) on the active brand.

- kind: write
- input: company_id, brand_id, name, description, color
- since: v1.0.0

### `suparanku_create_topics_bulk`

Create several topics on the active brand in ONE call — use this instead of looping suparanku_create_topic. De-dupes names within the request and SKIPS names that already exist (rather than failing the whole batch). Returns { created, skipped } so you can see which names were new.

- kind: write
- input: company_id, brand_id, items
- since: v1.3.0

### `suparanku_set_topic_color`

Set or clear a topic’s swatch color. Prefer a hex value (e.g. "#4F46E5"); pass null to clear and let the UI auto-pick.

- kind: write, idempotent
- input: company_id, topic_id, color
- since: v1.0.0

### `suparanku_rename_topic`

Rename a topic.

- kind: write, idempotent
- input: company_id, topic_id, name
- since: v1.0.0

### `suparanku_set_topic_metadata`

Set or clear a topic’s description.

- kind: write, idempotent
- input: company_id, topic_id, description
- since: v1.0.0

### `suparanku_delete_topic` (destructive)

Delete a topic. METHODOLOGY EVENT + irreversible markup change: it orphans the topic’s prompts and bumps the markup version, breaking timeline comparability across the change. Requires confirm:true and an allow-destructive token.

- kind: write, destructive, idempotent
- input: company_id, topic_id, confirm
- since: v1.0.0

### `suparanku_create_prompt`

Add a tracked prompt to the active brand (optionally assigned to a topic).

- kind: write
- input: company_id, brand_id, text, topic_id
- since: v1.0.0

### `suparanku_create_prompts_bulk`

Add several tracked prompts to the active brand in ONE call (each optionally assigned to a topic via topic_id) — use this instead of looping suparanku_create_prompt. Does NOT start a scan: run suparanku_run_manual_scan afterwards (spends manual-refresh quota) or wait for the next scheduled scan. Returns the created prompt ids.

- kind: write
- input: company_id, brand_id, items
- since: v1.3.0

### `suparanku_update_prompt`

Update a prompt’s text, topic assignment, or active flag.

- kind: write, idempotent
- input: company_id, prompt_id, text, topic_id, active
- since: v1.0.0

### `suparanku_delete_prompt` (destructive)

Delete a prompt. IRREVERSIBLE HARD DELETE: it permanently removes the prompt AND its captured AI answers / scan history (the metrics derived from it disappear). Prefer setting active:false to stop scanning while keeping history. Requires confirm:true and an allow-destructive token.

- kind: write, destructive, idempotent
- input: company_id, prompt_id, confirm
- since: v1.0.0

### `suparanku_add_competitor`

Mark/track a competitor for the active brand. Provide its name + aliases (match strings). A competitor can have several official sites — pass them in `sites` (first = primary, the only one profiled). `domain` remains accepted for one site.

- kind: write
- input: company_id, brand_id, name, aliases, domain, sites
- since: v1.0.0

### `suparanku_update_competitor`

Update a tracked competitor’s name, aliases, or sites. Pass the full desired site list in `sites` (first = primary, the only one profiled); omit or empty to clear. `domain` remains accepted for a single site.

- kind: write, idempotent
- input: company_id, competitor_brand_id, name, aliases, domain, sites
- since: v1.0.0

### `suparanku_delete_competitor` (destructive)

Stop tracking a competitor. This is a SOFT delete (reversible). Requires confirm:true and an allow-destructive token.

- kind: write, destructive, idempotent
- input: company_id, competitor_brand_id, confirm
- since: v1.0.0

### `suparanku_add_competitor_alias`

Add one alias (match string) to a tracked competitor.

- kind: write, idempotent
- input: company_id, competitor_brand_id, alias
- since: v1.0.0

### `suparanku_dismiss_possible_competitor`

Dismiss an AI-suggested (possible) competitor so it stops being suggested. Pass the canonical_key + display_name from suparanku_list_possible_competitors.

- kind: write, idempotent
- input: company_id, brand_id, canonical_key, display_name, aliases, reason
- since: v1.0.0

### `suparanku_undismiss_competitor`

Reverse a dismissal so the brand is suggested as a possible competitor again.

- kind: write, idempotent
- input: company_id, dismissed_id
- since: v1.0.0

### `suparanku_set_source_category`

Override the category of a cited domain (e.g. owned / competitor / media / review). Call suparanku_list_source_categories for the valid `source_type` values and what each means.

- kind: write, idempotent
- input: company_id, brand_id, domain, source_type
- since: v1.0.0

### `suparanku_set_source_category_bulk`

Override categories for several domains at once (the mark-up-everything loop). Call suparanku_list_source_categories for the valid `source_type` values and what each means.

- kind: write, idempotent
- input: company_id, brand_id, items
- since: v1.0.0

### `suparanku_clear_source_override`

Remove a manual category override for a domain (revert to the auto classification).

- kind: write, idempotent
- input: company_id, brand_id, domain
- since: v1.0.0

### `suparanku_track_source`

Pin a specific URL (e.g. a piece you published) so future scans report whether AI cites it.

- kind: write
- input: company_id, brand_id, url, label
- since: v1.0.0

### `suparanku_untrack_source`

Remove a pinned tracked-source URL.

- kind: write, idempotent
- input: company_id, brand_id, tracked_source_id
- since: v1.0.0

### `suparanku_generate_content_brief`

Generate a content brief for a CONTENT recommendation (spends 1 of the company’s monthly content-brief quota — see suparanku_get_company_usage). Then read it with suparanku_get_content_brief.

- kind: write
- input: company_id, brand_id, recommendation_id
- since: v1.0.0

### `suparanku_generate_brief_rewrite`

Generate a rewrite section of an existing content brief, for a placement key like "r0" (spends content-brief quota).

- kind: write
- input: company_id, brand_id, recommendation_id, placement_key
- since: v1.0.0

### `suparanku_set_recommendation_status`

Move a recommendation through its lifecycle: in_progress / done / dismissed / reopen. For a manual site-audit VERIFY rec (evidence.manual=true — Google/Bing indexing, the og:image visual review), done/reopen also records/clears the underlying manual-check verdict, keeping the Site Audit page and the rec in sync. For the og:image review, first SHOW the image (the rec’s imageUrl) to the user in the chat and get their confirmation that it looks right — only the human can judge the visual; never mark it done unseen.

- kind: write, idempotent
- input: company_id, brand_id, recommendation_id, action
- since: v1.0.0

### `suparanku_mark_recommendation_published`

Mark a content recommendation as done and (optionally) attach the published URL(s) so future scans track them.

- kind: write, idempotent
- input: company_id, brand_id, recommendation_id, urls
- since: v1.0.0

### `suparanku_run_manual_scan`

Trigger a manual re-scan of specific prompts (spends 1 of the monthly manual-refresh quota — see suparanku_get_company_usage). Returns enqueued info; poll progress with suparanku_get_scan_status using the same prompt ids.

- kind: write
- input: company_id, brand_id, prompt_ids
- since: v1.0.0

### `suparanku_generate_report`

Request a PDF visibility report for the brand’s current scan data. Idempotent per data snapshot: if a report for the SAME current data + locale already exists it is returned immediately (already_generated:true) without re-generating. Otherwise generation is enqueued (async) — poll suparanku_get_report until status is "done", then fetch the file with suparanku_get_report_download_url. No quota cost. `locale` sets the report language (defaults to the requesting user’s language).

- kind: write, idempotent
- input: company_id, brand_id, locale
- since: v1.8.0

### `suparanku_run_site_fast_audit`

Trigger a FAST audit of the brand’s whole primary-domain site (no quota cost — soft-throttled). Async — poll suparanku_get_latest_site_audit_run until status is done/partial, then read results via suparanku_get_site_audit / suparanku_get_site_schema and the fixes via suparanku_list_technical_recommendations. AUTONOMOUS FIX LOOP: run this → poll → list technical recs → apply each rec’s inline brief.artifacts → deploy → run this again; fixed checks auto-resolve. For a deeper rendered-page audit of specific pages use suparanku_run_page_deep_audit.

- kind: write
- input: company_id, brand_id
- since: v1.2.0

### `suparanku_run_page_deep_audit`

Trigger a DEEP (rendered-page) audit of specific page URLs. Spends 1 of the monthly deep-page-audit quota PER url (see suparanku_get_company_usage) — the call is rejected if the remaining quota is smaller than the number of urls. Async: results appear in suparanku_get_page_audit once it finishes.

- kind: write
- input: company_id, brand_id, urls
- since: v1.2.0

### `suparanku_set_link_verdict`

Triage a single EXTERNAL "no response" outbound link (one whose status came back null — see effective:"no_response" in suparanku_get_page_outbound_links). Mark it "ok" (verified false-positive, e.g. x.com bot-blocks the probe → excluded from broken), "bad" (a confirmed dead link → folds into link_health and lowers SRPS), or null to reset to pending. The verdict is a property of the URL, so it applies to EVERY page that links to that href and re-scores them all in the moment. Only verdict effective:"no_response" links. Re-pull suparanku_get_page_outbound_links / suparanku_get_page_audit afterwards to see the recomputed SRPS.

- kind: write, idempotent
- input: company_id, brand_id, href, verdict
- since: v1.5.0


## Glossary

- **visibility**: How often a brand appears in AI assistants’ answers for the tracked prompts, expressed as a percentage (brand mentions ÷ total answers sampled). Higher is better.
- **position**: Where the brand appears within an AI answer when it is mentioned (1 = first). Lower (earlier) is better. Reported as an average over the answers where the brand was mentioned.
- **sentiment**: The tone of how an AI answer talks about the brand, scored from -2 (very negative) to +2 (very positive). Averaged over the answers where the brand was mentioned.
- **sample**: One captured AI answer to a tracked prompt for a given assistant. Several samples per prompt are averaged so the reported numbers are stable rather than reflecting a single run’s randomness.
- **scan**: A measurement event: the tracked prompts are asked across the selected AI assistants and the answers are analysed. Scans run on a schedule and can also be triggered manually; each scan becomes a comparable point on the timeline.
- **prompt**: A question or query that real users might ask an AI assistant, tracked so you can see how the brand shows up in the answers.
- **topic**: A grouping of related prompts (e.g. a product category or use-case) so metrics can be broken down by theme.
- **competitor**: Another brand tracked for comparison. Suparanku reports how often competitors appear in AI answers alongside (or instead of) your brand.
- **possible competitor**: A brand that AI answers surfaced organically and that has not yet been confirmed/marked as a competitor. Review the suggestions and mark the real ones to track them.
- **source**: A website/domain or URL that an AI answer cited. Sources are categorised (e.g. your own site, a competitor’s, media, review/aggregator, etc.) so you can see what AI relies on.
- **content brief**: An actionable specification for a piece of content that addresses a visibility gap — what to write, in what format, against which criteria, and where to publish it. Generated on demand from a content recommendation.
- **recommendation**: A prioritised, concrete action to improve AI visibility. Three kinds: context (improve the data Suparanku tracks), technical (site/markup changes for AI crawlers), and content (what to write).
- **markup version**: A counter that increases whenever you change what is measured (aliases, competitors, prompts, topics, brand language). Metrics from before and after a change are flagged as not directly comparable on the timeline.
- **GEO**: Generative Engine Optimization — improving how a brand is represented in the answers of AI assistants (the AI-era analogue of SEO). Sometimes called LLMO (LLM Optimization).

## Changelog

### v1.8.0 — 2026-07-17

- New write tool suparanku_generate_report: request a PDF visibility report for the brand’s current scan data — idempotent per data snapshot (an existing report for the same data is returned instead of re-generated; otherwise generation is enqueued, poll suparanku_get_report). New read tool suparanku_get_report_download_url: mint a fresh ~15-minute download URL for a completed report. suparanku_get_report’s description was corrected — it returns metadata + history only, never a download URL.
- New read tool suparanku_get_competitor_topic_gaps: per-topic share-of-voice vs every tracked competitor, with the deficit in percentage points and a beaten flag (≥30pp) — the dashboard’s “Where they beat you” view. Topics where every prompt names the own brand are excluded.
- New read tool suparanku_get_competitor_source_gap: for one tracked competitor, the cited domains verifiably mentioning it while never mentioning you — publication targets, with citation counts and an unverified footnote count.
- suparanku_list_possible_competitors UPGRADED to the FULL potential-competitor inbox (single source of truth): live AI-answers suggestions merged with market-research players/proposal/watchlist and earlier audit candidates, deduped against tracked/dismissed, with sources[] provenance and a confirmed-by-live-answers flag. AI-answers fields (canonicalKey, mentionCount, promptIds, …) keep their previous names; research-only rows carry a canonicalKey fallback and no answer metrics.

### v1.7.0 — 2026-07-12

- Five new read tools over the Google integrations (Search Console + GA4): suparanku_get_indexing_status (per-page Google index verdict + coverage reason), suparanku_get_search_performance (per-page clicks/impressions/position with previous-window values), suparanku_get_real_demand (candidate demand clusters synthesized from real queries the Market Map does not cover), suparanku_get_ai_traffic (per-page visits from AI assistants via the customer’s GA4 — an explicit floor, not a ceiling) and suparanku_get_citation_traffic_insights (the citation×traffic join: cited-with-traffic / cited-no-traffic / AI-visits-not-cited). All five return an empty result with connected:false when the integration is not connected — never an error.

### v1.6.0 — 2026-06-29

- The technical-recommendation `brief` (suparanku_get_recommendation) is now a plain-language explanation (problem, why it matters, desired state, how to fix) plus a concrete developer brief (ordered steps, ready-to-paste artifacts, acceptance criteria, an optional risk note, machineReadable.fix/verify). Internal-only fields are no longer returned anywhere on the MCP surface.
- All recommendation list tools (suparanku_list_recommendations, suparanku_list_context_recommendations / _technical_ / _content_) are now paginated summary lists: they accept limit/offset and return { recommendations, total, offset, limit, has_more } so an agent can page through the whole set without the response getting truncated. Each item is a slim card (id, status, impact/effort, and for a technical issue aggregate scope + affected_count + a small URL sample) — NOT the full payload.
- suparanku_list_technical_recommendations no longer inlines the fix brief (it did since 1.4.0). The full fix brief and the complete evidence.affected[] list now come from suparanku_get_recommendation.
- suparanku_list_recommendations changed shape from a grouped object { context, technical, content } to a flat paginated array with `category` on each item; per-category active totals stay available as `counts`.

### v1.5.0 — 2026-06-28

- New read tools suparanku_get_page_inbound_links and suparanku_get_page_outbound_links: the link graph to/from one page. Outbound links carry status_class (ok / redirect / broken / no_response / not_checked / app_scheme), the no-response manual verdict, and the effective status after that verdict, plus an all | errors | no_response | external filter.
- New write tool suparanku_set_link_verdict: resolve an external no-response link as ok (verified false-positive) or bad (confirmed dead). The verdict is site-wide (applies to every page linking to that href) and re-scores SRPS in the moment.
- New read tool suparanku_get_unverified_links: the site-wide queue of external links that came back no-response or bot-blocked (401/403/429), deduped with their verdict + page count — list them, then resolve each with suparanku_set_link_verdict. External bot-block statuses are now treated like a no-response (verdictable), not auto-counted as broken.
- suparanku_get_site_schema now accepts only_problems:true (return only pages with issues / a non-2xx status / a client-side fake-200 redirect) and documents the perf_score, redirect and client_redirect fields it already returns.

### v1.4.0 — 2026-06-24

- New read tool suparanku_get_latest_site_audit_run: poll the latest site-audit run’s status + page progress (drives the autonomous fix loop after suparanku_run_site_fast_audit).
- suparanku_list_technical_recommendations and suparanku_get_recommendation now return an inline deterministic 7-part fix brief for technical findings (ready-to-paste artifacts + machineReadable fix/verify) and accept an optional locale; content-deep checks return brief.status="needs_generation".

### v1.3.0 — 2026-06-24

- New write tool suparanku_create_topics_bulk: create up to 150 topics on the active brand in one call (de-dupes within the request and skips names that already exist; returns created + skipped).
- New write tool suparanku_create_prompts_bulk: add up to 150 tracked prompts in one call (each optionally assigned to a topic via topic_id) — replaces looping suparanku_create_prompt. Does not start a scan.

### v1.2.0 — 2026-06-23

- New read tools suparanku_get_site_audit, suparanku_get_site_schema, suparanku_get_page_audit: the domain-level site audit (SRPS / SRPS+ + grouped checks), the crawled page tree, and one page’s full audit detail.
- New write tools suparanku_run_site_fast_audit (fast full-site audit, no quota) and suparanku_run_page_deep_audit (deep rendered-page audit of specific URLs, spends the monthly deep-page-audit quota per url).
- suparanku_list_technical_recommendations now accepts an optional audit_scope filter ("site" for domain-level findings or "page:<url>" for one page).

### v1.1.0 — 2026-06-21

- New read tool suparanku_list_source_categories: the full source-category reference (id, label, meaning, settable flag) so agents can mark up unknown domains.
- suparanku_set_source_category(_bulk) now accept the full settable category set (added ecommerce, aggregator, industry_assoc, academic, job) — matching the dashboard.
- New read tool suparanku_list_recommendations: ALL current recommendations (context + technical + content) in one call, grouped by kind.
- Removed the weekly_visibility_report and competitor_gap_analysis workflow prompts (low value; the tools cover the same flows directly).

### v1.0.0 — 2026-06-20

- Initial stable MCP surface — read + write tools ship together.
- List/source reads accept limit/offset and return total + has_more; get_sources adds only_unmarked + category filters and unmarked_count/category_counts.
- New reads get_possible_competitor_evidence + get_competitor_mentions: the prompts/AI answers where a possible or tracked competitor was mentioned.
