What each error from the Spendesk MCP server means and what to do about it: missing permissions, roles, companies, stale versions, large queries and rate limits.
What the Spendesk MCP server answers when something goes wrong, and what to do. Most of the time your assistant reads these errors and explains them itself; this page is for when it cannot, and for developers building their own MCP client.
Errors come back at three levels:
| Level | What it looks like | Typical cause |
|---|---|---|
| HTTP | A status code on the request to /v1/mcp, before any tool runs | No valid token, wrong kind of credentials, too many requests |
| Protocol (JSON-RPC) | An error object with a code, instead of a result | A tool the connection cannot use, a malformed call |
| Tool | A normal result with isError: true and a sentence explaining the problem | A missing company, a role, an object that does not exist, a business rule |
A missing permission looks like a missing tool
The server only lists the tools your connection's permissions allow, and a call to any other tool gets the same answer as a tool that does not exist:
{ "jsonrpc": "2.0", "id": 7, "error": { "code": -32601, "message": "Tool 'cancel_purchase_order' not found" } }The server does not tell apart "this tool does not exist" from "this tool exists but not for you", and it does not ask for more permissions on the fly. So when the assistant says a tool is not available:
- Check the tool's permission in the MCP tool reference.
- Reconnect and tick that permission — write permissions are unticked by default.
- Check your role: on a connection for one company, the same answer comes back when you are not a Controller or Account Owner of that company.
In ChatGPT Business and Enterprise workspaces, a tool can also be missing because the published app has an old copy of the tool list — see Set up Claude, ChatGPT or Dust.
HTTP errors
| Status | Meaning | What to do |
|---|---|---|
401 | No token, or an expired one. The response has a WWW-Authenticate header pointing to the server's metadata. | The assistant refreshes the token on its own. If it keeps failing — for instance after 30 days without use — reconnect. |
403 invalid authentication method | The request did not use an OAuth 2.0 user token — a public API key, for instance. The MCP server only accepts tokens from the OAuth 2.0 authorization code flow. | Connect through OAuth, as described in Connect an AI assistant. |
403 invalid MCP client | The OAuth client is not an MCP client (for example an integration partner's client). | Use the client created for your assistant in Settings → Integrations → MCP. |
400 | The body is not a valid JSON-RPC message. | A client bug: check what it sends. |
429 | More than 100 simultaneous requests for a company, or 200 for an organisation, on top of the API rate limits. | Wait a moment and retry, with fewer calls in parallel. |
Protocol errors
| Code | Message | Meaning |
|---|---|---|
-32601 | Tool '<name>' not found | The tool does not exist, or the connection lacks its permission, or (one-company connection) your role is not allowed — see above. |
-32602 | Invalid tool call parameters | The tools/call request itself is malformed (no tool name, for example). |
Tool errors
A tool error is a normal result with isError: true. The text is written for the assistant, which usually corrects itself — picks a company, re-reads an object, narrows a query — and tries again.
Company and role
| Message | Meaning | What to do |
|---|---|---|
| This tool requires a companyId when using an organisation-level token… | An organisation-level connection must say which company each call is for. | Tell the assistant which company; it can list them with list_companies. |
| The provided companyId "…" does not match your token's company… | A one-company connection was asked about another company. | Connect at organisation level, or ask about the connected company. |
| Company "…" does not belong to your organisation, is inactive, or you are not a member of it. | The company is not one you can reach through this connection. | Check the company ID with list_companies. |
| Insufficient role for this tool in the target company | You are not a Controller or Account Owner of that company (organisation-level connection). | Ask for the role in that company, or work on another one. |
| Company is suspended · User membership is pending | Your access to the company is not active. | Resolve it in Spendesk. |
Inputs, objects and conflicts
| Message | Meaning | What to do |
|---|---|---|
| Invalid tool arguments: … | An input does not match the tool's schema (a wrong type, an unknown field, a value out of range). | The assistant fixes the call; the detail names the input. |
| No … found for id … | The object does not exist in that company. It is an answer, not a failure: retrying will not help. | Check the ID and the company. |
| … cannot be cancelled / closed / updated …: | A business rule refused the action — a purchase order that is not open, a payable in the wrong state. | Read the reason; re-read the object before deciding anything. |
| … because the provided version is no longer current | The object changed since the assistant read it (payables use a version to prevent overwriting someone else's change). | Re-read the object, check what changed, then decide again. |
| Unable to … | The action or read failed on Spendesk's side. | Retry a little later. For an action, first check whether it happened — creating a purchase order or a supplier twice creates two. |
Large queries
List tools return one page at a time: 100 items by default, up to 1,000 with pageSize. MCP responses do not include total counts — use hasNextPage (or the next cursor) to know whether there is more.
fetchAll asks the server to page through everything for you, up to maxItems (5,000 at most, which is also the default):
- When the limit is reached, the result is truncated:
meta.pagination.truncatedistrue. - To continue, call the tool again without
fetchAll, frommeta.pagination.resumePagewithpageSizeset tometa.pagination.pageSize— or, for cursor-based tools, frommeta.pagination.resumeCursor. Leaving outpageSizesilently skips records whenmaxItemswas below 100. - Better still, narrow the query: a shorter period, one supplier, one cost center.
For totals and rankings, the analysis tools (spendesk_analyze_spend, spendesk_analyze_settlements, spendesk_analyze_requests) always cover all the data; the assistant uses them instead of adding up pages. When a broad query fails because it is too large, the assistant splits it into smaller ones and combines them only once all have succeeded.
Coming changes
- A write permission will include the matching read. Today a connection with, say, Manage chart of accounts but not View chart of accounts sees the tools that change accounts but not the one that lists them. A planned change makes each write permission also grant its read tools — on the MCP server only; the REST API is unchanged.
- Accounting exports will get a read permission. Downloading an export and listing journal templates will move from Manage accounting exports to a new read permission; existing connections keep both tools.
These pages will be updated when the changes ship — see the changelog.
See also Assistant actions and safety, Error Handling for the REST API, and Rate Limiting.