Skip to Content
MCPTroubleshooting

Troubleshooting

Find your symptom. Each entry says what the cause actually is and what to do about it.

If a paid tool timed out, failed, or gave an ambiguous answer, do not call it again. run_canvas_workflow, generate_image_in_canvas, and generate_video each start real provider work. Jump to Paid work looks stuck before doing anything else.

Start here: three checks that isolate the problem

Run them in order. Each one rules out a layer.

Is the transport up?

Ask the agent to call guide_search with any query.

That tool requires no scope at all. If it succeeds, transport and authentication are fine and your problem is permissions or usage. If it fails, nothing else will work — the problem is connection or auth.

Is the token delegating the right account?

Call canvas_list.

If it returns canvases, your token works and is attached to the account you expect. An empty list on an account that definitely has canvases means you approved a different Gavana account during OAuth than the one you were thinking of.

How many tools are registered?

Check your client’s MCP panel.

CountMeans
29Hosted endpoint
57Local stdio server
Fewer than 57 on a local serverGAVANA_MCP_TOOLSETS, GAVANA_MCP_TOOLS, GAVANA_MCP_EXCLUDE_TOOLS, or GAVANA_MCP_READ_ONLY is set
0, or the server shows as failedConnection problem — see below

Connection problems

The server will not connect at all

CheckDetail
The URLhttps://app.gavana.ai/mcp. No trailing slash, no path after it.
The transportStreamable HTTP. If your client asks for a type, it is HTTP or “remote”, never stdio.
Whether a browser openedThe hosted endpoints authenticate through browser OAuth. If no browser opened, the client did not start the flow — check for a blocked pop-up.
Workspace policySome ChatGPT and Claude workspaces require an administrator to allow custom connectors first.

405 method_not_allowed on a GET

Expected, not a fault. The hosted endpoints are stateless JSON-RPC over POST. A GET returns 405 with an Allow: POST, OPTIONS header. If your client only ever gets 405, it is probing rather than speaking MCP — confirm it is registered as a streamable-HTTP MCP server rather than a plain web hook.

403 access_denied mentioning Origin

Your browser-based client is sending an Origin header Gavana does not accept. The hosted endpoints allow https://chatgpt.com, https://claude.ai, and the Gavana origin itself, plus anything the deployment explicitly permits.

Non-browser clients send no Origin header and are unaffected — so if you are seeing this from a terminal client, something in between is adding the header.

The local stdio server will not start

SymptomCauseFix
npx cannot resolve @gavana.ai/mcpThe package is published publicly at 0.2.0, so this means npm is being proxied through a private registry that does not mirror itPoint npm at the public registry for this scope, or use a hosted endpoint. With application repository access, bun run canvas:mcp runs it from source.
Node version errorNode.js 20 or newer is requiredUpgrade Node.
Starts, then every call fails authNo credential reached the processSet GAVANA_BASE_URL and GAVANA_AGENT_TOKEN, or run gavana auth login to write ~/.config/gavana/agent.json.
Wrong package nameIt is @gavana.ai/mcp, with the .aiA name without .ai does not resolve.

Missing or unexpected tools

A tool the docs mention is not in my client’s list

You seeCause
29 tools, and node_create is absentnode_*, connection_*, action_*, recipe_search, recipe_fork, asset_list, canvas_render, and provider_list exist only on the local stdio server.
Fewer tools than expected locallyGAVANA_MCP_TOOLSETS, GAVANA_MCP_TOOLS, GAVANA_MCP_EXCLUDE_TOOLS, or GAVANA_MCP_READ_ONLY is set in the server’s environment.

find_video_models returns 403 insufficient_scope

The hosted tools reference lists it as read-only, which is accurate — looking up a model mutates nothing. It still requires the video:generate scope, because discovering video models is part of the generation path. A token without that scope is refused before the handler runs.

The tool list changed after I edited the URL

Some clients keep the original OAuth grant when you edit a server’s URL in place. Remove the server and add it again rather than editing:

claude mcp remove gavana && claude mcp add --transport http gavana https://app.gavana.ai/mcp

Authentication and scope errors

401 invalid_token

The token is missing, malformed, expired, or revoked.

  • Hosted: reconnect the client and complete OAuth again.
  • Local: Agent Access tokens default to Never expiry. If this token was created with a custom 1–90 day expiry, create a replacement and update the client’s environment.
  • Check you are not passing a token in a URL or a custom header. Gavana accepts bearer tokens in the Authorization header only.

403 insufficient_scope

The token is valid but lacks a scope the tool needs. The error message names the missing scopes, and the WWW-Authenticate header repeats them.

The scope check happens before the handler runs, so nothing partial occurred and no paid work started.

Common cases:

ToolMissing scope, usually
save_image_to_canvasimage:generate — that scope governs writing image bytes into Gavana, not just generating them. canvas:write alone is not enough.
run_canvas_workflow, generate_image_in_canvas, generate_videojob:manage — without it you can start work but cannot poll, wait for, or cancel it.
find_video_modelsvideo:generate

Token creation rejects my scope selection

Scope dependencies are enforced at creation, not silently added:

  • canvas:write requires canvas:read
  • element:write requires element:read
  • image:generate requires canvas:read, canvas:write, and asset:read
  • video:generate requires canvas:read and asset:read

The error names exactly which are missing. The token creation form selects dependants for you.

It works, but touches the wrong account

You approved a different Gavana account during OAuth. Disconnect and reconnect, watching which account you sign in as. For a local token, the token itself is bound to the account that created it — create one from the right account.


Canvas errors

409 on canvas_apply_batch or a canvas_validate dry-run

The canvas changed after you read the revision you passed. Someone else’s work is now in the graph.

Re-read

canvas_get for the current revision and graph.

Look at what changed

If they added a Section where yours was going, your coordinates now collide. If they deleted the node you meant to delete, that operation will fail.

Rebase, preserving their change

Move your nodes. Never move theirs.

Decide on the key

Byte-identical payload after rebasing? Reuse the key. Anything changed? New key.

Do not resolve a 409 by omitting baseRevision. That removes conflict detection, not the conflict — the write then silently lands on top of whatever is there.

Two 409s in a row means someone is actively working in that canvas. Say so and stop rather than racing them.

404 on a canvas or node

The handle is wrong. Get canvas handles from canvas_list and node handles from canvas_get. Do not reconstruct a handle from parts, and do not truncate one to fit.

The batch was rejected and nothing happened

Correct behaviour. canvas_apply_batch is atomic — one invalid operation means no partial graph. The error names the failing operation.

Fix that operation. Do not resend the batch minus the failure unless dropping it is genuinely your intent.

malformed_section in the validation output

A Section is a text node with metadata.isSection: true, at least 200 × 160. Any other node type, or a smaller one, is an error.

Rejected for writing metadata.content

Media is server-owned. You cannot write image or video bytes, storage keys, or arbitrary media URLs into node metadata. A non-empty metadata.content is rejected when the node is, or is becoming, an image or video.

Use save_image_to_canvas or a generation tool.

canvas_validate says summary.truncated

Findings hit the 50-per-code cap, or overlap analysis gave up. Overlap detection buckets nodes into a 2,048-unit grid, refuses any node spanning more than 64 cells, and stops after 100,000 comparisons.

Fix the findings you can see and run it again — the next pass surfaces what was cut. Meanwhile, say your report is incomplete.

summary.passed is true but something is still wrong

passed only means zero errors. reviewRequired is the field to read: it is true when there are errors, or warnings, or truncation.


This is the section where the wrong move costs money.

A paid tool returned while still queued

This is normal and it is not a failure. The tool waited waitSeconds — 45 by default, 50 maximum — and handed you a resumable handle because the work was not finished.

Do not call the paid tool again. The original run is still going. A second call starts a second paid run.

Poll instead:

Started withPoll withHandle shape
run_canvas_workflowget_canvas_workflow_runrun:
generate_videoget_video_jobjob: followed by a UUID

Polling is free. Call it again while the status is queued or running.

Raising waitSeconds does not make generation faster. It only changes how long the tool blocks before giving you the handle.

A paid run failed terminally

Report it and stop. Ask for fresh intent before any new attempt.

Do not automatically retry a terminal failure, a timeout, a disconnect, or an ambiguous provider response with a new key. The idempotency key protects against a duplicate request; it does not make a second deliberate attempt free.

400 “not a video generation” or “not a reusable workflow run”

You passed the wrong kind of handle. get_video_job takes a job: handle from generate_video; get_canvas_workflow_run takes a run: handle from run_canvas_workflow. They are not interchangeable.

A run succeeded but I cannot find the image

A run reporting success is not the same as durable canvas content. Read the canvas:

{ "name": "canvas_get", "arguments": { "canvasId": "canvas:abc123:product-shots" } }

Check the output node exists, is of type image, and carries server-owned media rather than being an empty placeholder. A video job in particular may return a protected download link without materialising a native video node — report what the server actually returned rather than assuming durability.

The agent started generating without being asked

The server’s instructions tell the model to require explicit current-turn intent, but instructions are not enforcement. The hosted endpoint registers the paid tools and the token holds the scopes that can run them.

If this happened, treat it as a contract break: tell the agent to stop, and require explicit current-turn approval before any further paid call. For unattended local work, set GAVANA_MCP_READ_ONLY=true or issue a token without generation scopes.


Image errors

SymptomCauseFix
400 “not an image” from get_canvas_imageThe node is text, sticky, or videoRead the canvas and pick an image node.
409 “does not have a stored result”Empty placeholder — generation unfinished or never startedCheck the run or job. Do not start a new generation to work around it.
413Source over 50 MB, or the re-encoded preview still over 5 MBUse the full-resolution link instead of the inline preview.
415Stored bytes are not PNG, JPEG, WebP, or GIFReport it; there is no client-side fix.
save_image_to_canvas rejects the URLNot HTTPS, or over 4,096 charactersUse an HTTPS URL. Plain http:// is refused.

Getting help

When you report a problem, include:

  • The X-Request-ID from the failing response. It identifies the exact request in Gavana’s logs.
  • The tool name and the HTTP status or error code.
  • Which server you are on — hosted /mcp, or local stdio.
  • The canvas handle, if the problem is canvas-specific.

Send the X-Request-ID and nothing else that is sensitive. Never include an Agent Access token, an OAuth token, a screenshot showing one, or canvas content you would not publish. The request ID is enough to find the failure without any of that.

Last updated on