GSC Wizard MCP Server
Your AI assistant can query Search Console analytics
Documentation
GSC Wizard MCP
This server implements the Model Context Protocol. Once connected, your AI assistant can query Search Console analytics, inspect URLs, manage topic clusters and content groups, use Google Inspection API, submit URLs to IndexNow, and more, all scoped to your own account.
All you need to connect: an MCP API key, free for every GSC Wizard account. Create one at tool.gscwizard.com/account/api-keys. Keys look like gscw_live_... and are shown only once at creation.
Why analysis runs server-side
Most SEO and analytics MCP servers hand the raw rows back to the model: thousands of query/page records streamed into the context window for the LLM to crunch. Language models are not built for arithmetic over large tables. They are slow at it, they burn tokens doing it, and they make mistakes (dropped rows, miscounted sums, hallucinated totals) that are hard to catch.
GSC Wizard does the opposite. Every analysis (CTR curves, decay detection, cannibalization, opportunity scoring, path breakdowns, ranking changes, full SEO reports) is computed in server-side Python and SQL, against the data warehouse, before anything reaches the model. The tool returns the finished result, not the raw input.
What that gets you
- Far fewer tokens. A single tool call returns a compact, finished answer instead of tens of thousands of rows the model has to read, hold in context, and pay for.
- Much faster. Aggregations run on the warehouse in milliseconds. The model spends its time reasoning about the result, not grinding through a spreadsheet one token at a time.
- Not prone to errors. The math is deterministic. Numbers come from real queries, so there is no risk of the model miscounting or inventing totals.
- Bigger datasets in scope. Because the heavy lifting never enters the context window, the server can analyze months of data and millions of rows that would never fit in a prompt.
The model still does what it is good at: interpreting the findings, spotting the story, and recommending what to do next. The crunching just happens where it belongs.
Endpoint
Streamable HTTP
https://mcp.gscwizard.com/mcp
Two ways to authenticate, both tied to your GSC Wizard account:
- API key (header): send
Authorization: Bearer gscw_live_.... Best for config-file clients (Claude Code, Cursor, VS Code, Windsurf). - OAuth 2.1 (sign-in): clients that support remote OAuth (ChatGPT, the Claude web/app Connectors UI, the native Claude Desktop connector) discover it automatically and walk you through a Google sign-in and consent screen. No key to copy or store.
In clients that render rich tool output (such as ChatGPT), summary tools like get_site_summary, query_top_queries, query_top_pages, get_ranking_changes, list_sites, and generate_seo_report display an interactive, theme-aware card/table view. Other clients receive the same data as JSON.
Connect a client
The server speaks Streamable HTTP, so any client that supports remote MCP servers can connect. The config-file clients below (Claude Code, Cursor, VS Code, Windsurf) authenticate with an API-key header: replace gscw_live_... with your key. Clients that support remote OAuth (ChatGPT, the Claude web/app Connectors UI, the native Claude Desktop connector) instead just need the URL and will sign you in: see the OAuth note in each section.
Claude Code
claude mcp add --transport http gsc-wizard \
https://mcp.gscwizard.com/mcp \
--header "Authorization: Bearer gscw_live_..."
Claude Desktop
Easiest (OAuth, no Node): Settings → Connectors → Add custom connector, enter https://mcp.gscwizard.com/mcp as the URL, and leave the OAuth fields blank. Claude registers itself automatically, opens a Google sign-in and consent screen, and connects. Nothing to copy or store.
Add custom connector: paste the URL, leave the OAuth fields blank.
Alternative (static API key): Claude Desktop's config file launches only local (stdio) servers, so pasting a "type": "http" entry is rejected as invalid. To use an API key instead of OAuth, bridge the remote server through mcp-remote (requires Node.js). Settings → Developer → Edit Config, then add:
{
"mcpServers": {
"gsc-wizard": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp.gscwizard.com/mcp",
"--header", "Authorization:${AUTH_HEADER}"
],
"env": { "AUTH_HEADER": "Bearer gscw_live_..." }
}
}
}
The key goes in env rather than inline because mcp-remote splits each --header value on spaces, so Authorization:${AUTH_HEADER} is written without a space. On Windows, if npx fails to launch, set "command": "cmd" and prepend "/c", "npx" to args. Quit and reopen Claude Desktop fully after saving.
Cursor
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json in a project:
{
"mcpServers": {
"gsc-wizard": {
"url": "https://mcp.gscwizard.com/mcp",
"headers": {
"Authorization": "Bearer gscw_live_..."
}
}
}
}
VS Code (GitHub Copilot agent mode)
Add to .vscode/mcp.json in your workspace (or run the MCP: Add Server command). VS Code uses servers, not mcpServers, and can prompt for the key so it stays out of source control:
{
"inputs": [
{ "id": "gscw-key", "type": "promptString", "description": "GSC Wizard MCP key", "password": true }
],
"servers": {
"gsc-wizard": {
"type": "http",
"url": "https://mcp.gscwizard.com/mcp",
"headers": {
"Authorization": "Bearer ${input:gscw-key}"
}
}
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json. Windsurf uses serverUrl for remote servers:
{
"mcpServers": {
"gsc-wizard": {
"serverUrl": "https://mcp.gscwizard.com/mcp",
"headers": {
"Authorization": "Bearer gscw_live_..."
}
}
}
}
ChatGPT
Requires a paid ChatGPT plan (Plus, Pro, Business, or Enterprise). Custom MCP servers live under Settings → Apps (developer mode, formerly "Connectors"). Enable Developer mode, add an app, and enter https://mcp.gscwizard.com/mcp as the Server URL. ChatGPT uses OAuth 2.1: it registers itself, then opens the GSC Wizard sign-in and consent screen. Leave the OAuth client ID/secret fields blank (the server supports dynamic client registration). There is no API-key field, which is expected: ChatGPT cannot present static bearer tokens, so it uses OAuth.
New App (Developer mode): Server URL + Authentication “OAuth”; client ID/secret left blank.
Programmatic access also works through the OpenAI Responses API, which accepts a remote MCP tool with a headers object, so there you can pass Authorization: Bearer gscw_live_... directly. Note that ChatGPT's built-in Deep Research connectors only call search and fetch tools; full tool access is via developer-mode apps and the Responses API.
Any other MCP client
Point it at the Streamable HTTP endpoint and send your key as a bearer token:
URL: https://mcp.gscwizard.com/mcp
Header: Authorization: Bearer gscw_live_...
Key names vary between clients (for example transport vs type, url vs serverUrl), but the URL and bearer header stay the same. Check your client's MCP docs if the keys above are not recognized.
Authentication and scopes
Each API key carries a scope, chosen when you create it:
- Read only: query data and run reports. Cannot add, edit, or delete anything.
- Read & write: everything read keys can do, plus mutations (add sites, submit IndexNow, manage clusters, and so on). Every mutation is audit-logged.
MCP access is free for every account, no subscription required. Revoke a key from the same API keys page; revocation takes effect immediately.
Rate limits
Tool calls are rate limited per account to protect your Search Console quota and keep the service responsive. Two windows apply at once, and a call must fit within both:
| Window | Limit |
|---|---|
| Per minute | 60 tool calls |
| Per hour | 1,000 tool calls |
The limit is shared across every key and session on your account, so opening more sessions does not raise it. Only tool invocations (tools/call) count: protocol handshakes such as initialize and tools/list are free, and a batched request that invokes several tools counts as one call per tool.
When you exceed a window the server returns HTTP 429 with a Retry-After header giving the seconds until the window resets, and a JSON-RPC error body: { "error": { "code": -32000, "message": "Rate limit exceeded (minute window). Retry after 42s." } }. Pause for Retry-After seconds and retry. Most clients surface this as a transient error you can simply re-run.
These limits are separate from Google's own quotas. URL Inspection tools (inspect_url, bulk_inspect_urls, check_tracked_url_now) also draw on the daily ~2,000-inspection-per-property quota you share with the GSC Wizard UI.
Tools
The server exposes 55 tools. You normally just ask your assistant in natural language ("show my top queries last month for example.com") and it picks the right tool and fills the arguments. The JSON under each tool below shows the argument shape, so you can see what each one accepts. Dates use YYYY-MM-DD and are optional on every tool that takes a date range: omit startDate/endDate and the server uses the most recent settled window automatically (never pass null or the string "null"). siteUrl is a value returned by list_sites (a URL prefix like https://example.com/ or a domain property like sc-domain:example.com).
Date ranges are optional. Every tool that takes a date range treats startDate and endDate as optional: omit them and the server analyzes the last 28 days Search Console has settled (its data lags ~2-3 days). Pass one end or both to narrow the window; the comparison tools (get_ranking_changes, find_decaying_content) default the baseline to the same-length period immediately before the current one. You never need to know today's date, and you should never sendnull or the string "null" for a date.
Where the numbers come from. The search-analytics tools (query_search_analytics, query_top_queries,query_top_pages, query_countries,query_devices, get_site_summary,get_query_performance, get_page_performance) and the analysis-report tools (get_ranking_changes,find_decaying_content, get_decay_overview,analyze_cannibalization,analyze_ctr_curve, find_page_poaching_opportunities,score_opportunities, breakdown_by_path,analyze_sampling_impact, get_sitemap_performance,get_cross_site_summary, get_tag_group_view) read from the GSC Wizard data warehouse when it has your property: that gives you longer history and no Search Console sampling. Otherwise they fall back to the live Search Console API automatically. Every response includes adataSource field set to clickhouse or api so you always know which one answered. Warehouse responses also include asettledThrough date and a freshness note: warehouse data settles ~2 days behind real-time, so for the most recent day or two the live API is the better source. Requests that need the searchAppearance dimension, the googleNews type, three or more distinct dimensions, or pagination always use the live API.
Reads 37
list_sites read
List Search Console properties connected to the account.
{}
No arguments. Start here to get the siteUrl values the other tools expect.
get_account_info read
Profile, connected Google accounts, and subscription state.
{}
No arguments.
generate_seo_report read
Runs the whole analysis suite for a property in one call and returns a complete, self-contained HTML report (overview, top queries/pages, countries & devices, CTR curve, opportunities, ranking changes, decay, cannibalization, sections, coverage, sitemaps). Much faster than calling each tool separately.
{
"siteUrl": "sc-domain:example.com",
"days": 28,
"format": "html"
}
days defaults to 28 (7-180). format: "html" (default, ready-to-open report) or "json" (raw data bundle). includeSitemap defaults to true.
query_search_analytics read
Ad-hoc searchAnalytics.query against a property. The most flexible read tool.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"dimensions": [
"query",
"page"
],
"rowLimit": 1000,
"filters": [
{
"dimension": "country",
"operator": "equals",
"expression": "usa"
}
]
}
startDate/endDate, dimensions, rowLimit (defaults to 1000, uncapped; the live-API path auto-paginates past 25000), searchType, startRow, and filters are all optional. Omit the dates for the last 28 settled days.
get_site_summary read
Last-N-days totals plus a prior-period comparison.
{
"siteUrl": "sc-domain:example.com",
"days": 28
}
days defaults to 28 (max 180).
inspect_url read
Run the URL Inspection API for one URL and persist the result to history.
{
"siteUrl": "sc-domain:example.com",
"inspectionUrl": "https://example.com/blog/post"
}
get_inspection_quota read
Remaining URL inspections available today for a property.
{
"siteUrl": "sc-domain:example.com"
}
list_saved_filters read
Saved filter presets, optionally restricted to one property.
siteUrl is optional; omit it to list every saved filter on the account.
list_topic_clusters read
Topic clusters defined for a property.
list_content_groups read
Content groups and their URL-matching rules for a property.
list_sitemaps read
Sitemaps submitted to Search Console for a property.
list_url_inspections read
Persisted URL inspection history (paginated).
{
"siteUrl": "sc-domain:example.com",
"urlContains": "/blog/",
"limit": 100
}
urlContains is optional; limit defaults to 100 (max 500).
query_top_queries read
Top search queries by clicks for a date range.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"limit": 100
}
limit defaults to 100, uncapped (pull the whole property if you want); searchType defaults to "web". startDate/endDate are optional: omit them for the last 28 settled days.
query_top_pages read
Top landing pages by clicks for a date range.
query_countries read
Per-country clicks/impressions breakdown.
limit defaults to 100, uncapped. startDate/endDate are optional: omit them for the last 28 settled days.
query_devices read
DESKTOP / MOBILE / TABLET split for a date range.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28"
}
startDate/endDate are optional: omit them for the last 28 settled days.
list_annotations read
Chart annotations (platform, account, or property scope).
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-01-01",
"endDate": "2026-05-28"
}
All fields optional; omit siteUrl for account-wide annotations.
list_algo_updates read
Confirmed Google ranking updates from the status feed.
{
"startDate": "2026-01-01",
"endDate": "2026-05-28"
}
Both dates optional; omit for the full history.
list_indexnow_submissions read
IndexNow submission history for a property.
{
"siteUrl": "sc-domain:example.com",
"limit": 100
}
limit defaults to 100 (max 500).
get_page_performance read
Daily clicks/impressions/CTR/position for a single URL.
{
"siteUrl": "sc-domain:example.com",
"pageUrl": "https://example.com/blog/post",
"startDate": "2026-05-01",
"endDate": "2026-05-28"
}
get_query_performance read
Daily metrics for a single query, optionally on one URL.
{
"siteUrl": "sc-domain:example.com",
"query": "seo tools",
"pageUrl": "https://example.com/blog/post",
"startDate": "2026-05-01",
"endDate": "2026-05-28"
}
pageUrl is optional; omit it to measure the query site-wide.
get_ranking_changes read
New, lost, improved, and declined queries (or pages) between two periods.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"comparisonStartDate": "2026-04-01",
"comparisonEndDate": "2026-04-28",
"dimension": "query",
"limit": 50
}
dimension is "query" or "page" (default query); limit defaults to 50, uncapped.
find_decaying_content read
Queries or pages losing clicks vs a baseline period, bucketed severe / moderate / mild.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"comparisonStartDate": "2026-02-01",
"comparisonEndDate": "2026-02-28",
"dimension": "page",
"minImpressions": 100
}
start/end is the recent period; comparison* is the earlier baseline. dimension defaults to "page".
get_decay_overview read
Per-query or per-page matrix of clicks/impressions/position broken down by month or week (the app's Query Decay / Content Decay heatmap).
{
"siteUrl": "sc-domain:example.com",
"dimension": "query",
"granularity": "month",
"metric": "clicks",
"months": 16,
"limit": 50
}
Defaults to the last 16 complete months. granularity "month" or "week"; metric clicks/impressions/position/ctr. Each row has a `values` array aligned to `periods`. Pass startDate/endDate to override the window.
analyze_cannibalization read
Queries where two or more pages compete, scored by impression-split entropy.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"minImpressions": 10
}
minImpressions defaults to 10; limit defaults to 100, uncapped.
analyze_ctr_curve read
Actual CTR by position bucket (1-20) vs industry benchmarks (AWR, First Page Sage, Sistrix, Backlinko).
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"minImpressions": 10,
"benchmarkSource": "all"
}
benchmarkSource: awr | firstPageSage | sistrix | backlinko | all (default all). CTR values are 0-1 ratios; a negative delta means the bucket underperforms that benchmark.
find_page_poaching_opportunities read
Queries ranking just outside the top, with estimated click upside if pushed to a target position.
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"minPosition": 4,
"maxPosition": 20,
"targetPosition": 3,
"fallbackBenchmark": "awr"
}
Click upside uses the property's OWN CTR curve at targetPosition; fallbackBenchmark (awr | firstPageSage | sistrix | backlinko, default awr) is used only where the site has no data. Response reports targetCtr and ctrSource ("own" or the benchmark key). Position band and target are tunable; limit defaults to 100, uncapped.
score_opportunities read
Impression-weighted opportunity score favoring high-impression queries near the top of page two.
Considers positions 3-30; limit defaults to 100, uncapped.
breakdown_by_path read
Aggregates page performance by host + first folder segment(s).
{
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"depth": 1
}
depth (1-4) controls how many path segments form each group; limit defaults to 100, uncapped.
analyze_sampling_impact read
Estimates the share of clicks/impressions GSC hides via anonymization (query and page dimensions).
Only the live-API path reveals true sampling; the warehouse is unsampled (see the response note).
get_sitemap_performance read
Fetches a sitemap, extracts its URLs, and joins each with GSC clicks/impressions/position.
{
"siteUrl": "sc-domain:example.com",
"sitemapUrl": "https://example.com/sitemap.xml",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"maxUrls": 500
}
The sitemap host must belong to the property. One level of sitemap-index expansion; maxUrls caps the join (defaults to 500, uncapped).
get_cross_site_summary read
Last-N-days clicks/impressions across all your properties (optionally one tag), with per-site totals.
{
"days": 28,
"tag": "client-a"
}
tag is optional; days defaults to 28 (max 180); maxSites is optional with no hard cap: omit it to include ALL matched properties, or pass a number to cap how many are processed.
list_tags read
Every tag on the account (global + property tags) with the number of properties carrying each.
{
"includeSites": false
}
includeSites defaults to false; set true to also list the property URLs under each tag.
get_tag_group_view read
Aggregated cross-site report for all properties carrying a tag (the /group/tag dashboard): totals + comparison, daily trend, per-site totals, and merged top queries/pages/countries/devices.
{
"tag": "client-a",
"days": 28,
"dimensions": [
"query",
"page",
"country",
"device"
],
"limit": 100
}
days defaults to 28 (max 180); searchType defaults to "web"; dimensions defaults to all four; limit defaults to 100 (max 1000); maxSites is optional with no hard cap: omit it to include ALL tagged properties, or pass a number to cap.
get_indexing_tracker read
Indexing Tracker config and a status summary (indexed / not-indexed / pending / errors / warnings).
Returns tracker: null when no tracker is configured for the property.
list_tracked_urls read
Paginated list of tracked URLs with their latest indexing status, filterable and searchable.
{
"siteUrl": "sc-domain:example.com",
"filter": "warnings",
"search": "/blog/",
"page": 1,
"pageSize": 50
}
filter: all | indexed | not_indexed | pending | errors | warnings. pageSize max 100.
get_indexing_tracker_report read
Indexing health report: score, coverage breakdown, crawl freshness, lost and newly-indexed pages.
{
"siteUrl": "sc-domain:example.com",
"days": 30
}
days defaults to 30 (max 90).
Mutations 18
Require a read & write key. All mutations are recorded in an append-only audit log.
add_site write
Register a GSC property in GSC Wizard. The property must already exist in your Search Console account.
{
"siteUrl": "sc-domain:example.com",
"tags": [
"client-a"
]
}
tags are optional.
create_gsc_property write
Create new URL-prefix properties in Google Search Console (e.g. folder-level properties) and register them in GSC Wizard. Auto-verified if the parent domain is owned. Use add_site instead for properties that already exist in GSC.
{
"parentSiteUrl": "sc-domain:example.com",
"propertyUrls": [
"https://example.com/blog/",
"https://example.com/docs/"
]
}
parentSiteUrl must be an existing registered property whose Google account owns the domain. register defaults to true; up to 50 URLs.
update_site write
Edit tags, branded keywords, or sitemap URLs on a registered property.
{
"siteUrl": "sc-domain:example.com",
"tags": [
"client-a",
"priority"
],
"brandedKeywords": [
"example",
"example brand"
],
"sitemapUrls": [
"https://example.com/sitemap.xml"
]
}
Pass only the fields you want to change.
manage_tags write
Create, assign, unassign, rename, or delete property tags across the account (the tag side of the /group/tag dashboard).
{
"action": "assign",
"tag": "client-a",
"siteUrls": [
"sc-domain:example.com",
"https://example.org/"
]
}
action: create | assign | unassign | rename | delete. siteUrls is required for assign/unassign; newName is required for rename. rename and delete apply across every property and the global tag list.
delete_site write
Unregister a property. Cascades to its clusters, groups, filters, inspections, and annotations.
{
"siteUrl": "sc-domain:example.com",
"confirm": true
}
confirm must be true; this is irreversible.
create_topic_cluster write
Create a topic cluster of keywords on a property.
{
"siteUrl": "sc-domain:example.com",
"name": "Pricing",
"keywords": [
"pricing",
"cost",
"plans"
]
}
delete_topic_cluster write
Delete a topic cluster by id.
{
"clusterId": "00000000-0000-0000-0000-000000000000"
}
create_content_group write
Create a content group partition. Rules match URLs by prefix / contains / regex / equals.
{
"siteUrl": "sc-domain:example.com",
"name": "Blog",
"rules": [
{
"type": "prefix",
"value": "https://example.com/blog/"
}
]
}
color and description are optional; up to 50 rules.
delete_content_group write
Delete a content group by id.
{
"groupId": "00000000-0000-0000-0000-000000000000"
}
create_saved_filter write
Save a reusable filter preset for a property.
{
"siteUrl": "sc-domain:example.com",
"name": "Non-branded, mobile",
"filters": {
"device": "MOBILE",
"excludeBranded": true
}
}
filters is a free-form object matching the dashboard filter shape.
delete_saved_filter write
Delete a saved filter by id.
{
"filterId": "00000000-0000-0000-0000-000000000000"
}
create_annotation write
Add a chart annotation on a date (e.g. a release or campaign marker).
{
"siteUrl": "sc-domain:example.com",
"eventDate": "2026-05-15",
"label": "Site redesign launched",
"description": "New template rolled out across the blog.",
"color": "#2563eb"
}
Omit siteUrl for an account-wide annotation; description, category, color optional.
delete_annotation write
Delete a chart annotation by id.
{
"annotationId": "00000000-0000-0000-0000-000000000000"
}
submit_indexnow_urls write
Submit up to 100 URLs to IndexNow for the property.
{
"siteUrl": "sc-domain:example.com",
"urls": [
"https://example.com/new-page",
"https://example.com/updated-page"
]
}
bulk_inspect_urls write
Inspect a list of URLs sequentially and persist each result.
{
"siteUrl": "sc-domain:example.com",
"urls": [
"https://example.com/a",
"https://example.com/b"
]
}
Counts against the daily 2,000-inspection/property quota (shared with the UI); stops and reports skipped URLs once the cap is hit. Pass up to 2,000 URLs.
add_tracked_urls write
Add URLs to the Indexing Tracker (creates the tracker if needed). Up to 1,800 URLs per property.
{
"siteUrl": "sc-domain:example.com",
"urls": [
"https://example.com/page-1",
"https://example.com/page-2"
]
}
URLs must belong to the property. New URLs start as "pending"; the hourly cron or check_tracked_url_now inspects them.
remove_tracked_urls write
Remove URLs from the Indexing Tracker.
{
"siteUrl": "sc-domain:example.com",
"urls": [
"https://example.com/page-1"
]
}
check_tracked_url_now write
Run an immediate URL Inspection for up to 10 tracked URLs and update their status and history.
Counts against the daily 2,000-inspection/property quota; returns a quota message when exhausted.
Calling a tool directly (curl)
Most users never need this; clients handle the JSON-RPC for you. But to test a tool by hand, POST a tools/call request to the endpoint (after the SDK has opened a session):
curl -X POST https://mcp.gscwizard.com/mcp \
-H "Authorization: Bearer gscw_live_..." \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "query_top_queries",
"arguments": {
"siteUrl": "sc-domain:example.com",
"startDate": "2026-05-01",
"endDate": "2026-05-28",
"limit": 10
}
}
}'
Troubleshooting
- 401 unauthorized: the
Authorization: Bearerheader is missing, malformed, or the key has been revoked or expired. - A mutation tool is missing or refused: your key is read-only. Create a new read & write key.
- 429 rate limit exceeded: tool calls are capped per account at 60 per minute and 1,000 per hour. The response includes a
Retry-Afterheader (seconds); pause and retry after it elapses. Protocol handshakes do not count toward the limit. - Health check:
GET https://mcp.gscwizard.com/healthreturns{ "ok": true }when the server is up.