# Storevisor API and MCP error codes

> Every refusal the Storevisor MCP server (https://storevisor.devino.ca/mcp) and API (https://storevisor.devino.ca/api/tools/<tool name>) can answer, what it means and what to do.

## Request refusals

Answered before any tool runs. The HTTP status is the one shown; the body is JSON.

### invalid_token

- Status: 401. On: MCP and API.
- Means: No credential was sent, or the one sent is not valid for this host. The WWW-Authenticate header carries the reason and the resource_metadata address an MCP client uses to sign in again.
- What to do: Send `Authorization: Bearer <key>` with a workspace key from the MCP & API page, or sign in again through your AI client.
- Answer: `{"error":"invalid_token","message":"<reason>"}`
  - `workspace key not recognised or revoked`: The key was revoked, or mistyped. Create a new one on the MCP & API page.
  - `not a token from this server`: The bearer is neither a workspace key nor a token this host issued.
  - `access token expired; refresh it`: Your AI client refreshes it on its own; if not, connect again.
  - `this token is for another server, not <host>/mcp`: A StoreScope Analytics token was sent to Storevisor, or the reverse. Each product host has its own connection.
  - `token carries no workspace; connect again`: Connect again and pick a workspace.
  - `you are no longer a member of this workspace`: Your membership was removed. Ask an owner for a new invite link.
  - `this connection was revoked; connect again`: The AI app was disconnected on the MCP & API page.
  - `access token could not be verified`: The token is damaged or was signed with an old key. Connect again.

### rate_limited

- Status: 429. On: MCP and API.
- Means: More than 60 calls a minute from one key or one AI connection (the answer carries retry_after_s and a Retry-After header), or more than 30 refused credentials a minute from one address (no Retry-After).
- What to do: Wait the number of seconds in Retry-After (or a minute), then repeat the call. Calls refill steadily: spread them out rather than sending them in bursts.
- Answer: `{"error":"rate_limited","retry_after_s":12}`

### payload_too_large

- Status: 413. On: MCP and API.
- Means: The request body is over 256 KB. The answer is the plain text "payload too large" (the server-wide body limit), or this JSON from the MCP endpoint's own check.
- What to do: Send less in one call (shorter text, fewer items).
- Answer: `payload too large`

### unknown_tool

- Status: 404. On: API.
- Means: The name after /api/tools/ is not a tool of either product.
- What to do: Use a name from the API reference. Names are lower case with underscores.
- Answer: `{"error":"unknown_tool"}`

### invalid_body

- Status: 400. On: API.
- Means: The request body is not JSON.
- What to do: Send the tool's arguments as one JSON object (or an empty body for a tool without arguments), with Content-Type: application/json.
- Answer: `{"error":"invalid_body","message":"body must be a JSON object of arguments"}`

### method_not_allowed

- Status: 405. On: MCP.
- Means: A GET to /mcp. The server is stateless: JSON-RPC over POST only, no event stream and no sessions.
- What to do: POST each JSON-RPC message.
- Answer: `{"error":"method_not_allowed","message":"POST JSON-RPC only (stateless, no SSE)."}`

### -32700

- Status: 400. On: MCP.
- Means: The JSON-RPC body is not JSON.
- What to do: Send one valid JSON-RPC message per POST.
- Answer: `{"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"Parse error: body is not JSON"}}`

### -32600

- Status: 400. On: MCP.
- Means: The body is a JSON-RPC batch (an array), or not a JSON-RPC object.
- What to do: Send one message per POST; batches are not supported.
- Answer: `{"jsonrpc":"2.0","id":null,"error":{"code":-32600,"message":"JSON-RPC batch requests are not supported; send one message per POST"}}`

### -32601

- Status: 200 (MCP), 400 (API). On: MCP and API.
- Means: A JSON-RPC method this server does not offer.
- What to do: Use initialize, tools/list and tools/call (and resources/prompts on StoreScope Analytics).
- Answer: `{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}`

### -32000

- Status: 503. On: MCP and API.
- Means: Every worker that runs tools is in use right now.
- What to do: Wait the Retry-After seconds (5) and repeat the call.
- Answer: `{"jsonrpc":"2.0","id":null,"error":{"code":-32000,"message":"StoreScope is busy right now; retry in a few seconds"}}`

### -32603

- Status: 502. On: MCP and API.
- Means: The tool ran out of time (15 minutes), or its worker stopped without answering. The error was logged.
- What to do: Repeat a read. Before repeating a write, check its result first (a release or listing read): a write that ran out of time may have reached the store.
- Answer: `{"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"the tool ran out of time"}}`
  - `the tool ran out of time`: The call took longer than 15 minutes.
  - `the request failed; try again`: The worker stopped without an answer.

## Tool refusals

A tool call that was refused. Over MCP it is a tool result with isError: true whose text (and structuredContent) is the JSON below; over the API it is that JSON with status 400.

### -32602

- Status: 400. On: MCP and API.
- Means: The arguments do not match the tool's input schema (a missing required field, a wrong type, a value out of range). Nothing ran.
- What to do: Fix the arguments named in the message; the API reference lists each tool's fields.
- Answer: `"MCP error -32602: Input validation error: Invalid arguments for tool <tool>: ..." (MCP: a tool result with isError; API: that text as the JSON body)`

### SCOPE_MISSING

- Status: 400. On: MCP and API.
- Means: The connection or key may not use this tool. In practice: a write tool called with read-only access (a read key, a connection approved without "make changes", a viewer, or a workspace whose owner turned AI changes off). Carries requiredScope.
- What to do: Use a read-and-write key, or connect again and tick the box that allows changes. A viewer, or a workspace with AI changes off, stays read-only whatever the key says.
- Answer: `{"code":"SCOPE_MISSING","message":"<tool> requires the \"listings:write\" scope; ...","requiredScope":"listings:write"}`

### WRONG_PRODUCT

- Status: 400. On: MCP and API.
- Means: The tool belongs to the other product: StoreScope Analytics tools run on its host, Storevisor tools on its own. Carries product.
- What to do: Call it on the other product's host. The same account and workspace work there; the AI connection or key is per host.
- Answer: `{"code":"WRONG_PRODUCT","message":"<tool> belongs to the ops product; ...","product":"ops"}`

### CONFIRMATION_REQUIRED

- Status: 400. On: MCP and API.
- Means: A write was called with apply: true, but the confirmToken is missing or does not match. Nothing reached the store, and no new token was issued. Carries reason.
- What to do: Call the tool again without apply to get a new preview and confirm_token, then repeat the SAME arguments (with any commit_args merged in) plus apply: true and that confirmToken within 10 minutes.
- Answer: `{"code":"CONFIRMATION_REQUIRED","message":"apply:true was refused (expired) — ...","reason":"expired"}`
  - `malformed`: No token, or not a token.
  - `bad_signature`: The token was altered, or was issued in another workspace.
  - `expired`: The token is older than 10 minutes.
  - `mismatch`: The arguments, the tool, the person or the AI connection differ from the preview's.
  - `reused`: The token was already used. Each token commits once.

### CONSENT_REVOKED

- Status: 400. On: MCP and API.
- Means: The approval behind an OAuth connection was revoked or narrowed. The cloud answers a revoked connection earlier, with 401 invalid_token ("this connection was revoked; connect again"), so this code is not expected from it.
- What to do: Connect again.
- Answer: `{"code":"CONSENT_REVOKED","message":"..."}`

### TOOL_EXECUTION_FAILED

- Status: 400. On: MCP and API.
- Means: The tool could not do what was asked. A refusal the tool wrote itself (a store that is not connected, a store's own refusal, an argument the store would not accept) is passed on word for word; anything else is a generic message with an audit_id, and the details are in our log.
- What to do: Read the message: it says what to change. With an audit_id, try again, and quote the number on the Support page if it stays.
- Answer: `{"code":"TOOL_EXECUTION_FAILED","message":"...","audit_id":123}`
  - `<tool> needs <a store connection>, and this workspace has none yet. Connect it on the Connections page, then call <tool> again. Nothing was read or changed.`: Connect that store (see Connect your stores).
  - `<tool> is not available on this server`: The tool is not offered in the cloud (uploads, the Resolution Center, App Privacy).
  - `unknown tool "<name>" — call tools/list for the tools this token can use`: The name is not a tool.
  - `<tool> failed; see server log (audit row <n>)`: An unexpected failure, logged under that number.

## Write outcomes

Not errors of the call: a write answered normally, with a status saying it did not happen.

### status: rejected

- Status: 200. On: MCP and API.
- Means: A write's preview was refused (invalid input for the store, a missing prerequisite, a value identical to the current one). The answer lists the reasons and carries commit: not_available and commit_reason. No token is issued; nothing reached the store.
- What to do: Fix what the reasons say and preview again.
- Answer: `{"status":"rejected","explanation":"...","commit":"not_available","commit_reason":"This preview was REJECTED and cannot be committed: ..."}`

### status: failed

- Status: 200. On: MCP and API.
- Means: A confirmed write reached the store and the store refused it. The explanation carries the store's answer, and the workspace's Activity page lists the call as failed.
- What to do: Read the explanation. Preview again before retrying: the store's state may have moved.
- Answer: `{"status":"failed","change_id":42,"explanation":"<the store's answer>", ...}`

Connection errors: https://storevisor.devino.ca/docs/connect.md
