Breaking: MCP wire names no longer use dots. Anthropic's Messages API (and MCP clients that forward tool definitions to it — Claude Desktop, Claude Code, Zed, etc.) reject tool names outside ^[a-zA-Z0-9_-]{1,64}$. Dotted names loaded the server but failed on first tool invocation with HTTP 400.
All 26 tools and 5 prompts renamed: namespace separator is now _ instead of .. Semantics unchanged.
| Before (≤0.11.0) | After (≥0.12.0) |
|---|---|
citations.check |
citations_check |
citations.predict |
citations_predict |
citations.trend |
citations_trend |
citations.provenance |
citations_provenance |
citations.evidence |
citations_evidence |
citations.freshness |
citations_freshness |
domain.am_i_cited |
domain_am_i_cited |
domain.cited_for |
domain_cited_for |
domain.cited_for_diff |
domain_cited_for_diff |
panel.track |
panel_track |
panel.run |
panel_run |
report.visibility |
report_visibility |
competitors.compare |
competitors_compare |
competitors.compete |
competitors_compete |
competitors.canonical_set |
competitors_canonical_set |
signals.ai_overview |
signals_ai_overview |
signals.answer_box |
signals_answer_box |
signals.wikipedia |
signals_wikipedia |
signals.gsc_gap |
signals_gsc_gap |
signals.bing_gap |
signals_bing_gap |
audit.sitemap |
audit_sitemap |
audit.sitemap_map |
audit_sitemap_map |
audit.crawler_access |
audit_crawler_access |
audit.schema |
audit_schema |
audit.llms_txt |
audit_llms_txt |
audit.structured_data |
audit_structured_data |
audit.citation_readiness (prompt) |
audit_citation_readiness |
audit.competitor_snapshot (prompt) |
audit_competitor_snapshot |
audit.crawler_checkup (prompt) |
audit_crawler_checkup |
audit.gap_analysis (prompt) |
audit_gap_analysis |
audit.sitemap_coverage (prompt) |
audit_sitemap_coverage |
Fixes #1.
Two adapter regressions blocking real queries:
- OpenAI adapter sent
systemas a top-level Responses-API parameter; the API renamed it toinstructions, so every call returned400 Unknown parameter: 'system'. Switched toinstructions. Affectscheck_citations(engine=auto when onlyOPENAI_API_KEYis set, or engine=openai explicitly),canonical_competitor_set, and any downstream tool that fans through OpenAI. check_citationsoutput schema requiredraw_answer: string | null, but thebrave_serpandbing_serpadapters (web_rank engines) legitimately omitraw_answerbecause SERP responses have no synthesized answer text. Calls succeeded upstream and citations landed in the local cache, but the tool returnedMCP error -32602: Invalid structured content ... raw_answer Required. Schema is nowstring | null | undefined, with the description updated to call out that web_rank engines don't produce a raw answer.
Four new tools, a seventh engine, plus MCP prompts and resources surfaces.
New tools:
citation_evidence(query, engine?, max_results?, context_chars?)- extract the cited snippet from each citation's location inraw_answer. Returns context window + nearest quoted span or containing sentence per citation. Tells you why an engine cited a URL, not just that it did.crawler_access_audit(url, bots?, fetch_with_ua?)- verify GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-Web, PerplexityBot, Perplexity-User, CCBot, Google-Extended, Applebot-Extended, Bytespider, and Meta-ExternalAgent can fetch a URL. Parses robots.txt and does a live GET under each bot's User-Agent. Surfaces both robots.txt blocks and UA-based gating.sitemap_citation_map(sitemap_url, domain?, since?, limit?)- cross-reference a sitemap with the citation cache. Inverse ofaudit_sitemap: reports which URLs have actually been cited, by which engines and queries, vs which are unmapped. Requires the cache to be primed first.canonical_competitor_set(query, engines?, top_n?, max_results?, exclude_domains?)- fan a query across engines and aggregate citations by registered domain. Returns top competitor domains ranked by cross-engine consensus, with per-engine breakdown.
New engine:
google_ai_modeadapter via SerpAPI'sgoogle_ai_modeendpoint (distinct fromai_overview). Wired intocheck_citationsand downstream tools.
MCP surfaces beyond tools (Stage 3 / AL-566):
- Prompts - 5 server-side prompt templates the client can offer end users:
audit_citation_readiness(url)- chains predict_citation + schema_auditcompetitor_snapshot(query, your_url?)- chains canonical_competitor_set + compete_for_queryai_crawler_checkup(url)- runs crawler_access_audit and writes a remediation listcitation_gap_analysis(domain, days?)- drives gsc_citation_gap and suggests next editorial movessitemap_coverage_review(sitemap_url)- runs sitemap_citation_map and recommends priorities
- Resources - cache views clients can read without firing tools:
citation://cache/summary- entry counts by type/engine, unique queries/URLs, oldest/newestcitation://panels- saved panels + per-panel snapshot countscitation://docs/llms-txt- llms.txt primer (markdown)citation://docs/ai-crawlers- AI crawlers cheatsheet (markdown)citation://domain/{domain}/cited-for- dynamic resource template: citations for{domain}from the local cache
Compatibility:
Enginetype now includesgoogle_ai_mode. All tools that previously took anengineenum accept it; the downstream tools (am_i_cited,run_panel) extend their enum to match.- New dep:
robots-parser@3.0.1forcrawler_access_audit.
- Switch OpenAI adapter default model to
gpt-4o-mini(wasgpt-4.1-mini). Removed theOPENAI_MODELenv override - the model is now hardcoded. Citations come from theweb_search_previewtool, not model reasoning, so the smaller model has no impact on citation quality.
Four new tools, a sixth search engine, and a per-host fetch gate.
New tools:
schema_audit(url)- deep schema.org validation. Walks every JSON-LD block, checks required fields per@type(Article needsheadline+author+datePublished, FAQPage needsmainEntity, HowTo needsstep, etc.), and reports malformed JSON-LD. Returns issues list and valid/invalid verdict.llms_txt_generator(sitemap_url, site_title, ...)- generate anllms.txt(https://llmstxt.org spec) from a sitemap. Groups URLs by top-level path; optionalfetch_titles=truepulls<title>for richer link text.answer_box_position(query, engine?, max_results?)- bin each cited URL's first mention inraw_answerinto early/middle/late thirds. Surfaces whether your URL is cited up-front or buried.citation_provenance(query, engines?, max_results?)- fan a query out across multiple engines and report per-URL cross-engine consensus. Returnsconsensus_urls(URLs cited by ALL engines) andengine_countper URL.
New engine:
braveadapter via Brave Web Search API (BRAVE_API_KEY; free tier 2000/month).engineenum oncheck_citationsextended.
Infrastructure:
- Per-host concurrency + rate-limit middleware in
lib/fetch.ts. Env:CITATION_MAX_CONCURRENT_PER_HOST(default 4),CITATION_MIN_INTERVAL_MS_PER_HOST(default 0). 429 responses logged. OPENAI_MODELenv var lets callers override the defaultgpt-4.1-minimodel on the OpenAI adapter (citations come from theweb_search_previewtool, so cheaper models cost less without losing citation quality).
Three new tools + observability + test coverage.
New tools:
compete_for_query(query, your_url, engine?, max_competitors?)- end-to-end competitive snapshot. Callscheck_citationsto find what an AI cites, then runscompare_domainson your URL vs the top cited competitors. Returns your score, average competitor score, and the gap.citation_freshness_score(query, engine?, max_results?)- scores how recent the pages cited for a query are. 0-100 recency_score with 365-day halflife, plus per-URL freshness bucket (fresh/current/stale/ancient/unknown). Surfaces queries where AI cites old content.cited_for_diff(domain, baseline_until, current_since?, engine?)- diff ofcited_forbetween two time windows. Returns queries gained and lost. Cache-only, no API spend.
Observability:
- New
CITATION_LOG_LEVELenv var (debug/info/warn/error, defaultinfo) controls stderr verbosity. - Centralized
lib/log.tsstderr logger; all tool logging routes through it. - Startup line now includes resolved log level and full tool list.
Coverage:
- Smoke tests extended to all v0.2.0 tools (track_queries, run_panel, citation_trend, compare_domains, wikipedia_mentions, audit_sitemap) and the three new v0.4.0 tools.
- Log-level resolution covered by tests.
Internal: server version constant in src/index.ts was stale at 0.1.0; now tracks package.json.
Page-level scoring rewrite. predict_citation now discriminates between thin pages and deep articles on the same domain.
New signals on predict_citation:
- Content depth:
word_count,reading_time_minutes,h1_count,h2_count,h2_question_count,table_of_contents_present,image_count - Structured data (split out):
has_article_schema,has_faq_schema,has_howto_schema,has_breadcrumb_schema - Link graph:
internal_link_count,external_link_count,authority_link_count(counts links to wikipedia, github, .gov, .edu, arxiv, MDN, etc.) - Metadata hygiene:
title_length,meta_description_length,has_open_graph,has_twitter_card - Freshness:
date_modified_iso,last_modified_days_ago(parsed from JSON-LDdateModified,article:modified_time, or<time datetime>)
scoreSignals rebalanced across six buckets: domain authority (25), structured data (20), content depth (20), link graph (12), freshness (8), metadata hygiene (10), transport (5).
suggestFixes adds actionable advice for thin content, missing FAQ schema when question H2s exist, stale freshness, missing authority links, missing TOC on long pages.
7 new tools for editorial workflows + bulk audits.
track_queries(name, queries[], domain?, action)- save / load / list named query panelsrun_panel(name, domain?, engine?)- run a panel through am_i_cited and snapshot to diskcitation_trend(panel, since?)- time-series report of citation rate + per-query gained/lost deltascompare_domains(urls[])- side-by-side predict_citation across 2-10 URLswikipedia_mentions(domain, limit?, lang?)- list Wikipedia articles referencing the domainaudit_sitemap(sitemap_url, limit?, concurrency?)- bulk predict_citation across every URL in a sitemapgsc_citation_gap(domain, queries[], start_date, end_date, ...)- join GSC performance with AI citation status to surface "ranks in Google but invisible in AI" queries
Adds google-auth-library dependency for service-account auth in gsc_citation_gap.
Initial release.
check_citations(query, engine?, max_results?)- URLs cited by Perplexity, Claude, ChatGPT, Gemini, or Bingam_i_cited(domain, queries[], engine?)- presence and rank for a domain across a query clusterai_overview(query, location?, hl?)- Google AI Overview presence and cited sources (SerpAPI)cited_for(domain, since?, engine?, limit?)- queries the domain was cited for, from local cachepredict_citation(url)- 0-100 citation likelihood from public signals (Wikipedia, schema.org, llms.txt, GitHub, Reddit, canonical, HTTPS)- Local JSON cache at
~/.config/citation-intelligence/cache.json - BYO API key passthrough; nothing stored remotely