Reading a failure that arrives as a success
Every MCP result travels inside a successful HTTP response. The transport succeeded; whether the tool did is written in the body. Agents are good at reading bodies and bad at doubting them, which is how "done" ends up meaning "the request was delivered". This guide lists the failures you will actually see with TaskLite from Claude Code, and what to say to the agent for each.
Where the error lives
An MCP tool result has an isError flag and content. A failed call returns isError: true with a message, inside a JSON-RPC response, inside an HTTP 200. Claude Code shows the message, but the model decides what to do with it. Most of the time it retries correctly. The cases below are the ones where it does not.
Refusal 1: column type mismatch
create_column refuses an obvious mismatch between a column's name and its type: "Install Date" as text, "Phone" as number, "Price" as text. The refusal names the suggested type. What goes wrong: the agent sometimes reports "the server rejected the column" and stops, or creates a differently named text column to get around it, which defeats the point (a date stored as text never powers a calendar or a reminder).
Refusal 2: wrong host
The app API lives on api.tasklite.net. Calling app.tasklite.net/apps/<slug>/api/... returns a 404 with a JSON body that says exactly this. What goes wrong: the agent builds the URL from the admin link it saw earlier, gets the 404, and either invents an endpoint or declares the API broken.
The silent one: stale column ids
Cells are keyed by column id. An agent that creates columns and then writes items without calling get_board_schema may use ids it guessed or remembered from another board. Depending on the values, the write succeeds with the wrong cells filled, or with cells ignored. No refusal, no error, wrong data. This is the failure that looks most like success.
Authentication failures
| Message | Meaning | Fix |
|---|---|---|
| Authentication required (401 on /mcp) | No credential reached the server | Reconnect the connector; for keys, check the header |
| Failed to authenticate API key | The key is revoked, expired or mistyped | Create a new key in the app, update the client |
| Unsupported protocol version | Client and server negotiated different MCP versions | Harmless; the client retries with a supported version within a second |
| Not allowed by CORS | A browser called the API directly | Move the call to your server |
Making the agent doubt success
Three habits that catch most of the above. Ask for a read-back after writes: "list the items you created and show me the cells." Ask for the spec before the client code. And end a build with a real query: "query the board and count the rows"; if the count is wrong, the agent finds out before you do.
When it is actually the server
A 500 from /mcp or a tool result with "Internal error" is ours. It is rare and it is logged; write to [email protected] with the tool name and the time, and the message you saw. Status codes and the full tool reference are in the developer manual.
Frequently asked questions
- Why not return HTTP errors for tool failures?
- Because MCP defines tool errors inside the protocol so the model can read and act on them. Transport errors are for the transport. It is the right design; it just requires agents to read.
- Does the hosted connector behave differently from the local package?
- Same tools, same refusals. The hosted one adds OAuth and the protocol-version negotiation; the local one uses your API key directly.
- Can I see the raw tool responses in Claude Code?
- Yes, expand the tool call in the transcript. The
isErrorflag and the message are there verbatim.