FOR DEVELOPERS & AI AGENTS
SEO Bandwagon exposes a remote MCP (Model Context Protocol) server and a small public REST API. Connect Claude or any MCP client to query your Google Search Console data and tracked keyword rankings programmatically.
https://seobandwagon.com/api/mcpAuthorization: Bearer sbw_<48 hex characters>Example (Claude Code):
claude mcp add --transport http seobandwagon https://seobandwagon.com/api/mcp \ --header "Authorization: Bearer sbw_<your key>"
API keys are issued per SEO Bandwagon account and shown once at creation. There is no self-serve key page yet — contact us to request one. All tools return data scoped to your account; unauthenticated requests receive 401.
| TOOL | DESCRIPTION |
|---|---|
gsc_connection_status | Check the authenticated user's Google connection. Returns per-capability grant state (gsc.read, gsc.write, ga4.read, ads.read), the granted scopes, and whether the user needs to reconnect Google (the Connect button at seobandwagon.com/dashboard/search-console) to pick up newly added capabilities — sign-in itself grants identity only. |
gsc_list_sites | List the Google Search Console properties the authenticated user has access to. |
gsc_search_analytics | Query Google Search Console search analytics for a property. Returns rows of clicks, impressions, CTR, position, and sum_position grouped by the requested dimensions, plus aggregation_type, pagination meta (has_more/next_offset, one API request per call, max 25,000 rows), and data-loss warnings — read the warnings before summing anything: query grouping under-counts, and byPage impressions must never be compared to byProperty. Use gsc_list_sites first for valid siteUrl values (e.g. 'sc-domain:example.com'). |
gsc_verify_data_availability | Google's recommended preflight before any GSC reporting: which dates in the lookback window have data, which are still provisional (fresh, will change), and the latest date whose numbers are final. Build reports only up to latest_final_date; treat provisional_dates as an upsert window. |
gsc_accurate_totals | Ground-truth totals for a window: clicks, impressions, CTR, impression-weighted position, and sum_position from a pull with NO lossy dimensions. Use this as the denominator any time you sum query-grained rows — the sums will not match, and the gap is real data loss, not an error. Optional lossless breakdown dimensions: country, device, date. |
gsc_coverage_report | Measure what a query/page-grained analysis is blind to: pulls the detail rows and the matching accurate totals, and reports coverage_pct — the share of true impressions the chosen grain can see. State this number alongside any per-query conclusions. Coverage varies by window; measure it for the exact window you analyze. |
gsc_compare_periods | Compare two date windows: aggregate deltas for clicks/impressions/CTR/weighted position, and per-key rows when dimensions are given. Rows have status 'both' (real deltas), 'new' (only in period 2), or 'lost' (only in period 1) — new/lost rows carry null metrics for the missing side and null changes; never read them as zeros. Percentage deltas vs a zero base are null. |
gsc_top_queries | Top queries ranked by a chosen metric (clicks, impressions, ctr, position) over the full retrievable row set, then cut to limit — has_more means the ranked list was cut by your limit (raise limit or narrow the window; there is no startRow here). Optional per-query daily click trend for the top 20. Query-grained and therefore lossy: check warnings and gsc_coverage_report. |
gsc_top_pages | Top pages ranked by a chosen metric over the full retrievable row set (byPage impression units — never compare to byProperty totals). Optional queryBreakdown: top 10 queries for each of the top 10 pages. Page rows are lossless; the per-page query lists are lossy and cut to 10 by Google. |
gsc_query_page_pairs | Query→page attribution rows (the only way to get it) with byPage aggregation. The single most expensive request the GSC API offers — load scales with window length; keep windows short and avoid repeat pulls. Lossy at this grain: check warnings and gsc_coverage_report with entityType query_page. |
gsc_search_appearance | Rich-result (search appearance) performance: enumerates the property's appearance types, then optionally breaks each down by your dimensions via Google's documented two-step. Everything here is byPage-forced — do not compare these numbers to byProperty results. |
gsc_inspect_url | Inspect one URL's Google index status: verdict, coverage state, robots.txt/indexing state, last crawl, canonical pair, mobile usability, and detected rich results. Unknown enum values pass through verbatim — 'UNKNOWN' means the API omitted the field, never a fabricated verdict. |
gsc_bulk_inspect | Inspect up to 10 URLs in one call (per-URL results plus a success/failed summary). For larger sets, call repeatedly — the cap keeps one call inside the serverless time budget; URL Inspection also has a daily quota, so inspect samples, not whole sitemaps. |
gsc_list_sitemaps | List submitted sitemaps for a property with pending/index-file flags, last download time, file errors/warnings, and per-content-type submitted/indexed counts as reported by the Sitemaps API. |
gsc_sitemap_indexation_summary | Submitted vs indexed URL counts across sitemaps, as reported by the Sitemaps API — NOT the Index Coverage report (the public API does not expose it). Counts are only as fresh as each sitemap's last_downloaded; never-fetched sitemaps, stale fetches, and index-file double counting are all called out in warnings. |
gsc_submit_sitemap | Submit (or resubmit) a sitemap to Google Search Console. Requires the Search Console manage grant (gsc.write), which the Connect flow does not currently request (write access is parked pending Google verification) — only connections made while it was offered can use this tool. Throws with the reason on failure; success is only reported when Google accepted the submission. |
gsc_delete_sitemap | Remove a sitemap from Google Search Console (does not delete the file from your server, only the submission). Requires gsc.write, which the Connect flow does not currently request (parked pending Google verification). Throws with the reason on failure. |
gsc_analyze_opportunities | Scan for SEO opportunities: low-CTR queries worth better titles/snippets, striking-distance keywords (positions 4-10), and indexation-coverage gaps. Returns prioritized opportunities, quick wins, and an impact estimate — with warnings whenever an underlying pull was truncated or grain-lossy, so counts are labeled floors when they are floors. |
gsc_content_gaps | Cluster queries where the site ranks poorly but gets impressions — candidate topics for new or expanded content, with per-cluster impressions and weighted position. Query×page grained (lossy; warnings included). |
gsc_cannibalization_check | Find queries where multiple pages of the site compete: per-query page lists with click/impression splits and a consolidation recommendation. Query×page grained (lossy; warnings included). |
rank_tracker_keywords | List the authenticated user's tracked keywords from the SEO Bandwagon rank tracker, with last known Google position, search volume, and GSC metrics. Optionally filter by domain. |
rank_tracker_history | Get historical Google position checks (serp_history) for a domain the authenticated user tracks, optionally filtered to one keyword. Note: positions are only recorded when a rank check runs. |
clients_list | List clients (leads) visible to the authenticated user. Admins see the full roster; other users see only the client record linked to their account. Returns id, name, contact email, status, and notes — use the id with the client_audits_* tools. |
clients_create | Create a client (lead) record. Admin-only. Provide a name; contact email, GSC site URL, notes, and status (e.g. 'lead', 'active') are optional. Returns the created client including its id. |
client_audits_add | Attach an audit report (markdown) to a client. Admin-only. Provide clientId (from clients_list/clients_create), the audited domain, a title, a kind tag (e.g. local-seo, gbp-listings, geo, summary), and the full markdown body. Clients see exactly ONE report: their newest kind='client-report' (or, if they have none, their top report). Every other report is working history, visible to admins only. A client-report must use the H2 sections Executive Summary → The Opportunity in Search → How We Capture It → Technical Fixes, in that order, or it is rejected; attach a new one to supersede the old. Optionally pass pdfBase64 (plus pdfFilename) to attach a branded PDF, offered as a download beside the HTML. Pass displayOrder to pin a report in the admin list (lowest first, 1 for the audit); omit it to leave the report in newest-first order. |
client_audits_list | List audit reports attached to a client (id, domain, title, kind, created date; bodies omitted unless includeContent is true). Admins can read any client; other users only their own. |
client_audits_delete | Permanently delete ONE audit report attached to a client — the uploads made by client_audits_add, nothing else. Admin-only. Requires both clientId and auditId, and the audit must belong to that client, so a report can only be removed through the client that owns it. Use it to clear a superseded report after uploading its replacement (client_audits_add appends rather than replaces, so the old row otherwise stays on the share page). Deletes the client_audits row and its stored PDF; it never touches the client record or any other table, and it cannot be undone. |
client_share_link | Get the share URL for a client's gated audit page (seobandwagon.com/audit/<slug>, e.g. /audit/moli-windows). The page shows a teaser and requires Google sign-in; the first account to sign in claims the client record (sets its linked user + contact email). Admin-only. Generates the slug (and a legacy token) on first call; pass rotate=true to rotate the legacy token — the slug URL is unaffected. |
ga4_list_properties | List the GA4 accounts and properties this Google account can access, with numeric property ids. Property ids ('123456789') are what every other ga4_* tool takes — never the G-XXXXXXX measurement id. |
ga4_property_details | One property's settings (timezone, currency), its data streams (with G-XXXXXXX measurement ids and site URLs), and its configured key events — the metric behind keyEvents in reports. |
ga4_run_report | Run a GA4 Data API report: any dimensions/metrics (discover them with ga4_metadata), optional FilterExpression filters and orderBys, limit/offset paging. Responses ALWAYS disclose data-quality caveats as warnings — sampling (with the sampled %), '(other)'-row collapse, privacy thresholding, truncation — plus API-computed totals and property quota state. Read the warnings before trusting differences between numbers. |
ga4_realtime_report | Active users right now, by screen/page and other realtime dimensions. Totals come from the API aggregation — summing dimension rows double-counts users appearing in multiple rows. |
ga4_landing_pages | Landing-page performance bundle: sessions, users, new users, bounce rate, engagement rate, session duration, and key events per landingPage — the GA4 counterpart of gsc_top_pages, with loss-disclosure warnings. |
ga4_organic_search_performance | Google-organic landing-page performance: sessions/users/keyEvents per landingPage filtered to sessionSource=google AND sessionMedium=organic — the GA4 slice whose traffic scope corresponds to Search Console, and the input to GSC↔GA4 cross-verification. |
ga4_metadata | Discover the dimensions and metrics (including custom definitions) a property supports, or — with checkDimensions/checkMetrics — pre-flight a combination for compatibility before running an expensive report. |
gsc_ga4_page_join | Cross-verify Search Console against GA4 per page: GSC clicks/impressions/position joined to GA4 google-organic sessions/users/keyEvents on normalized landing-page paths, with unjoinable rows in gsc_only/ga4_only buckets (never silently dropped), BOTH sources' loss warnings labeled by source, and scope_notes explaining why the two never match exactly (clicks≠sessions, timezone boundaries, anonymized queries vs untagged visitors). Use it to validate that sampled/thresholded GA4 numbers are consistent with GSC ground truth. |
The captures API stores and retrieves on-page SEO analyses from the SEO Bandwagon Chrome extension. Requires an API key (captures scope) or a signed-in session; 401 otherwise.
POST /api/v1/captures — ingest a full SEO analysis payload. Same-URL captures are deduped within one hour (409).GET /api/v1/captures?url=… — fetch up to 50 captures for a URL, matching across protocol, www, and trailing-slash variants.Agents can discover these services automatically:
/.well-known/api-catalog — API catalog (RFC 9727 linkset)/.well-known/mcp/server-card.json — MCP server card/.well-known/agent-skills/index.json — Agent skills index/api/health — Health endpoint/auth.md — Agent authentication guide/.well-known/oauth-protected-resource — Protected resource metadata (RFC 9728)/llms.txt — llms.txt