Skip to Content
MCPTool guide

Hosted tool guide

The hosted tools reference is generated from the application’s capability module and answers which tools exist. This page answers how to call them. Every parameter below is taken from the tool’s registered input schema, so the types, bounds, defaults, and required-ness are the ones the server actually enforces.

Four tools here — guide_search, guide_get, canvas_validate, and canvas_apply_batch — are the load-bearing ones for safe canvas work and had no documentation before this page.

How to read the parameter tables

  • Required means the schema has no default and no .optional(). A missing required parameter fails input validation before the handler runs, and the error names the exact field.
  • Every string bound is a character count. Every numeric bound is inclusive.
  • Tools that write take an idempotencyKey of 8–200 characters. Reuse it only when retrying the identical payload; a changed intent needs a new key.
  • A tool call that fails scope checks returns insufficient_scope with HTTP 403 and a WWW-Authenticate challenge naming what to reconnect with. It never partially applies.

Three tools can incur provider cost: run_canvas_workflow, generate_image_in_canvas, and generate_video. Get explicit approval in the current turn before calling one, and never retry one automatically after a failure.


Search the canonical Gavana Canvas Agent Guide. This is the first call an agent should make in a session, and the call to make again whenever an operation is unfamiliar.

The guide is served from the application, not from documentation, so it cannot drift from the behaviour it describes. It is versioned — guide version 1.0.0 at the time of writing — and every result carries that version.

Read-only. Requires no scope at all — it works on a token with the narrowest possible grant. No provider cost.

Parameters

ParameterTypeRequiredNotes
querystring, max 240 charsNo, defaults to ""Free text. An empty query returns every topic, which is a cheap way to see the whole corpus.
limitinteger, 1–10No, defaults to 10Maximum results. The tool’s input schema enforces the range, so a value outside 1–10 is rejected as invalid input rather than clamped.

What it returns

{ "guideVersion": "1.0.0", "indexUri": "gavana://guides/canvas/v1/index", "query": "delete a node safely", "results": [ { "id": "existing-canvases", "title": "Editing Existing Canvases Safely", "description": "Preserve user structure, concurrent edits, and unrelated content while making scoped changes.", "uri": "gavana://guides/canvas/v1/existing-canvases", "score": 21 } ], "availableGuideIds": ["getting-started", "notes-text-sections", "..."] }

availableGuideIds is always the complete list of topic IDs, regardless of how the search scored. If a search returns nothing useful, pick an ID from that list and call guide_get directly.

How matching works

The query is lowercased and split on non-alphanumeric characters. Tokens of one character are discarded. Each surviving token scores against each topic:

Match locationPoints
Topic ID12
Title8
Keywords5
Description3
Body text1

Topics scoring zero are dropped, results sort by score then by ID, and the list is capped at limit and at 10 overall. This is deterministic lexical scoring — there is no embedding model behind it, so exact vocabulary matters. Searching overlap finds the layout topic; searching things bumping into each other does not.

The ten topics

IDCovers
getting-startedThe required inspect → guide → validate → edit → review sequence, and the non-negotiable safety rules
notes-text-sectionsWhen to use a sticky, a text node, or a Section; the Section JSON shape
sections-layoutPlacement, spacing, bounding-box maths for additions, the “add is not reorganise” rule
connectionsDirection, the four connection modes, batch-local client: references
prompt-listsPrompt List node shape, listItems, per-row referenceBindings
generated-assetsPreparing media nodes, paid execution boundaries, what “durable” actually means
existing-canvasesThe preservation contract, 409 handling, idempotency key reuse
paid-action-safetyThe intent boundary and the retry boundary
validation-recoveryReading findings, correcting invalid batches, evidence-based review
examples-common-mistakesCopyable good patterns and eleven named anti-patterns

Worked example

{ "name": "guide_search", "arguments": { "query": "section header overlap layout", "limit": 3 } }

Returns sections-layout and notes-text-sections at the top. Follow with guide_get on the winner.

When it fails

SymptomCauseFix
Input validation error naming queryQuery longer than 240 charactersShorten it. Long natural-language questions score no better than three good keywords.
Empty results arrayNo token matched anythingRetry with vocabulary from the topic table above, or read availableGuideIds and call guide_get.

guide_get

Read one full guide topic as Markdown.

Read-only. Requires no scope. No provider cost.

Parameters

ParameterTypeRequiredNotes
guideIdstring, 1–600 charsYesA topic ID (existing-canvases), the literal string index, or a full gavana://guides/canvas/v1/... URI.

What it returns

{ "id": "paid-action-safety", "title": "Paid Action Safety", "description": "Separate preparation from execution and prevent accidental or repeated provider charges.", "uri": "gavana://guides/canvas/v1/paid-action-safety", "mimeType": "text/markdown", "guideVersion": "1.0.0", "markdown": "# Paid Action Safety\n\nGuide version: 1.0.0\n\n## Intent boundary\n..." }

Passing index returns the guide index — a Markdown list of every topic with its description and URI — with id set to index.

Resources versus tools

A client that supports MCP resources can list and read the same content under gavana://guides/canvas/v1/, including the index at gavana://guides/canvas/v1/index. The two paths return identical Markdown and the same guide version, so use whichever your client supports. Tool-only clients lose nothing by using guide_search and guide_get.

Worked example

{ "name": "guide_get", "arguments": { "guideId": "index" } }

Then follow a URI straight from the index:

{ "name": "guide_get", "arguments": { "guideId": "gavana://guides/canvas/v1/connections" } }

When it fails

SymptomCauseFix
Error code unknown_canvas_guideThe ID or URI does not existThe error message lists every valid guide ID. Pick one from it — do not retry with a variation.
Input validation error naming guideIdEmpty string, or longer than 600 charactersSend a real topic ID.

canvas_validate

Lint a canvas, or dry-run a proposed batch of operations against the real server-side engine without applying it. This is the single most useful tool on the hosted surface and the one most often skipped.

Read-only. Requires canvas:read. No provider cost.

Validation never mutates the canvas and never consumes an idempotency key. You can call it as many times as you like.

Parameters

ParameterTypeRequiredNotes
canvasIdstring, 1–600 charsYesA canvas: handle. A plain canvas id works for a canvas you own.
baseRevisionstring, 1–200 charsNoThe revision from canvas_get. Only meaningful together with operations. If the canvas has moved on, validation returns 409 instead of validating a stale proposal.
operationsarray of objects, max 200NoProposed canvas_apply_batch operations. Presence of this array is what switches the tool into dry-run mode.

Two modes

Audit mode — omit operations. The server reads the canvas and lints the current graph.

Dry-run mode — pass operations. The server runs the canonical operation engine with validateOnly set, producing the graph that would exist, then lints that. Nothing is persisted and no idempotency key is consumed.

What it returns

Audit mode:

{ "guideVersion": "1.0.0", "scope": "current", "canvas": { "handle": "canvas:abc123:my-canvas", "revision": "rev_00291", "nodeCount": 34, "connectionCount": 21 }, "summary": { "errors": 0, "warnings": 2, "info": 1, "truncated": false, "passed": true, "reviewRequired": true }, "findings": [ { "code": "node_overlap", "severity": "warning", "message": "node:a1b2 overlaps node:c3d4.", "nodeHandles": ["node:a1b2", "node:c3d4"], "guideUri": "gavana://guides/canvas/v1/sections-layout" } ] }

Dry-run mode returns the same validation shape plus three extra keys: currentCanvas (the graph as it stands today), proposal (what the operations would produce), and destructiveImpact.

Reading the summary

summary.passed is true when there are zero errors. It is not a green light on its own.

summary.reviewRequired is true when there are errors, or warnings, or findings were truncated. Treat reviewRequired: true as “a human or the agent must look at this before writing”, and treat a warning you intend to keep as something to explain rather than silently ignore.

summary.truncated means findings hit a per-code cap of 50 and the list is incomplete; truncatedCodes names which codes were cut. Overlap detection also gives up and marks itself truncated on very large or very spread-out canvases — it buckets nodes into a 2,048-unit grid, refuses any node spanning more than 64 cells, and stops after 100,000 pairwise comparisons.

Every finding code

CodeSeverityMeans
invalid_node_geometryerrorPosition or size is non-finite, non-positive, or out of range. Coordinates must be within ±10,000,000; width and height must be positive and no larger than 10,000.
broken_connectionerrorA connection points at a node that does not exist.
unclear_connectionerrorA node connects to itself, a first-frame/last-frame edge does not run image → video, or a video target has more than one first-frame or last-frame edge.
unclear_connectionwarningA Section is used as a workflow endpoint, a list edge has no List at either end, or a reference edge starts somewhere other than an image.
unclear_connectioninfoTwo media nodes are connected with no mode. Confirm that a plain transformation flow is what you meant.
duplicate_connectionwarningTwo or more visible connections share the same source, target, and mode.
node_overlapwarningTwo ordinary nodes overlap by more than 8 units on both axes. Sections and deliberate batch overlays are exempt.
malformed_sectionerrorA node has metadata.isSection set but is not a text node of at least 200 × 160.
fake_section_headerwarningA wide, short, or large-font text node with no connections is imitating a Section header. Use a real Section.
unconnected_generated_outputwarningA generated image or video has no incoming connection and no output parent, so its lineage is unreadable.
orphan_media_placeholderwarningAn empty media node with no stored result and no relationship to a prompt, source, List, or stage.
broken_generated_lineageerrorA lineage field — batchRootId, listOutputId, firstFrameNodeId, referenceNodeIds, a listItems reference binding, and others — points at a node that is not on the canvas.
proposed_destructive_changewarningDry-run only. The batch deletes a node or connection. The message names the node and how many attached connections go with it.

Every finding carries a guideUri pointing at the guide topic that explains the rule, so an agent can resolve a finding without asking.

destructiveImpact

Present only in dry-run mode. It is the deletion summary you should show a human before applying anything:

{ "deletedNodeHandles": ["node:a1b2"], "deletedConnectionHandles": ["connection:x9y8"], "mediaNodeHandles": ["node:a1b2"], "generatedNodeHandles": ["node:a1b2"], "findings": [] }

mediaNodeHandles flags deletions of image or video nodes. generatedNodeHandles flags deletions of nodes that were produced by a generation run, an AI job, an Action, or a variation — in other words, work that cost something to make. A non-empty generatedNodeHandles deserves an explicit confirmation, not a summary line.

Worked example

Audit an existing canvas before proposing anything:

{ "name": "canvas_validate", "arguments": { "canvasId": "canvas:abc123:brand-refresh" } }

Dry-run a proposed deletion, pinned to the revision you read:

{ "name": "canvas_validate", "arguments": { "canvasId": "canvas:abc123:brand-refresh", "baseRevision": "rev_00291", "operations": [{ "type": "node.delete", "nodeId": "node:a1b2" }] } }

The full sequence is on Validate a batch before applying.

When it fails

SymptomCauseFix
409The canvas changed after the baseRevision you passedCall canvas_get again, rebase your operations onto the newer graph, and re-validate. Someone else edited while you were thinking.
403 insufficient_scopeToken lacks canvas:readReconnect. The challenge header names the scope.
404Wrong canvas handleUse a handle from canvas_list; do not assemble one.
Input validation error naming operationsMore than 200 operationsSplit into smaller batches. 200 is the hard cap on both validate and apply.
summary.truncated is trueToo many findings of one code, or a canvas too large for overlap analysisFix the reported instances and re-run; the next pass surfaces the ones that were cut.

canvas_apply_batch

Apply related node and connection operations atomically against one exact canvas revision. This is the only way the hosted server writes to a canvas graph.

Not read-only. Annotated destructive. Requires canvas:read and canvas:write. No provider cost — a batch never starts generation.

Atomic means all or nothing. If one operation is rejected, the canvas is untouched — there is no partial graph to clean up.

Parameters

ParameterTypeRequiredNotes
canvasIdstring, 1–600 charsYesA canvas: handle, or a plain id for a canvas you own.
baseRevisionstring, 1–240 charsNoThe revision from canvas_get. Omitting it makes the server read the latest revision immediately before writing — convenient, and strictly less safe. See below.
idempotencyKeystring, 8–200 charsYesCaller-stable retry key.
operationsarray of objects, 1–200YesThe batch. Shapes below.

Omitting baseRevision is not the same as being safe. It means “apply this to whatever the canvas looks like right now”, which defeats conflict detection. Pass the revision you actually read and inspected. Omit it only when you just created the canvas and nothing else can have touched it.

Operation shapes

The tool’s own schema accepts operations as free-form objects and defers to the canonical Canvas API engine, which enforces these eight shapes. Full field-level schemas are on the Canvases API resource.

typeRequired fieldsOptional
canvas.update—title (max 160), backgroundMode (dots | lines | blank), showImageInfo, viewport
node.createnodeclientId
node.updatenodeId, patch—
node.movenodeId, position—
node.resizenodeId, width, height—
node.deletenodeId—
connection.createeither connection, or both from and toclientId, mode
connection.deleteconnectionId—

A node is one of four types — image, video, text, sticky — with title (max 160), position, width and height (each 40–10,000), and metadata. A connection carries an optional mode of list, reference, first-frame, or last-frame; omit mode for a plain dependency flow.

Node and connection references accept node:<id>, a bare id, or client:<clientId>.

Batch-local client: references

Within one batch you can connect nodes that do not exist yet. Give a node.create a clientId, then reference it as client:<clientId> from a later operation in the same batch:

{ "canvasId": "canvas:abc123:brand-refresh", "baseRevision": "rev_00291", "idempotencyKey": "brief-and-generator-2026-08-04-01", "operations": [ { "type": "node.create", "clientId": "brief", "node": { "type": "text", "title": "Campaign brief", "position": { "x": 2400, "y": 200 }, "width": 480, "height": 320, "metadata": { "content": "Warm, editorial, no hard shadows." } } }, { "type": "node.create", "clientId": "generator", "node": { "type": "image", "title": "Hero variations", "position": { "x": 2960, "y": 200 }, "width": 512, "height": 512 } }, { "type": "connection.create", "clientId": "brief-to-generator", "from": "client:brief", "to": "client:generator" } ] }

This is why a batch is worth building even for two nodes: creating them separately leaves a window where the graph is connected to nothing.

What it returns

The apply result — including the new revision and the created handles — plus a validation block. The server runs the graph validator on the post-write canvas automatically and returns it in the same response, so you do not need a second canvas_validate call just to see the outcome.

Read validation.summary.reviewRequired on every write. A batch can be structurally valid and still leave a warning worth reporting.

Hard rules the engine enforces

  • Media content is server-owned. You cannot write image or video bytes, storage keys, or arbitrary media URLs into metadata.content. 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.
  • A Section is a text node with metadata.isSection set to true, at least 200 × 160. Anything else marked as a Section is a validation error.
  • Geometry is bounded. Width and height 40–10,000. Positions must be finite.
  • 200 operations maximum, 1 minimum.

Idempotency and conflicts

One stable key per intended payload. Retrying the identical batch with the same key is safe. If your intent changes — you corrected a position, added an operation, rebased after a conflict onto a different graph — use a new key. Reusing a key for a different payload is the one way to get a confusing result.

On 409, the canvas moved after you read it. Do not retry blindly:

  1. Call canvas_get again.
  2. Look at what changed. Someone else’s work is now in the graph.
  3. Rebase your intended addition around it, preserving their change.
  4. Apply again with a new key if the payload changed.

Worked example

The complete read → validate → apply → verify sequence, including how to handle a 409 mid-flight, is on Validate a batch before applying.

When it fails

SymptomCauseFix
409Revision conflictRe-read, rebase, preserve the concurrent change, retry. Never resolve it by dropping baseRevision.
403 insufficient_scopeToken lacks canvas:writeReconnect with write permission.
Operation rejected, nothing appliedA malformed operationThe batch is atomic — the canvas is unchanged. Fix the named operation. Do not re-send the batch minus the failing operation unless that is genuinely your intent.
Rejected for metadata.contentTried to put media content on an image or video nodeUse save_image_to_canvas or generate_image_in_canvas.
malformed_section in the returned validationSection is not a text node, or is smaller than 200 × 160Resize it and re-apply.
Node created but disconnectedThe connection operation was in a different batchPut creates and their connections in one batch.

canvas_list

List the canvases you own or can access, with exact handles, roles, revisions, and graph counts. The correct first call when the user has not named a canvas.

Read-only. Requires canvas:read. No provider cost.

ParameterTypeRequiredNotes
limitinteger, 1–25No, defaults to 10Maximum canvases to return.
{ "name": "canvas_list", "arguments": { "limit": 25 } }

When it fails. A 403 means the token lacks canvas:read — reconnect. An empty list on an account that has canvases means the token is delegating a different account than you expect; check which account you approved during OAuth.


canvas_get

Read the complete graph and current revision of one canvas. Call this before reasoning about or changing any existing canvas — the revision it returns is what makes a later write safe.

Read-only. Requires canvas:read. No provider cost.

ParameterTypeRequiredNotes
canvasIdstring, 1–600 charsYesA canvas: handle, or a plain id for a canvas you own.

Keep the returned revision — it is the baseRevision for canvas_apply_batch and for a canvas_validate dry-run.

When it fails. 404 means the handle is wrong; get it from canvas_list rather than reconstructing it. 403 means the token cannot read that canvas, which on a shared canvas may mean your role changed.


get_canvas_image

Read one image node and return an inline preview the model can actually look at, plus a temporary full-resolution link.

Read-only. Requires canvas:read. No provider cost.

ParameterTypeRequiredNotes
canvasIdstring, 1–600 charsYesA canvas: handle.
nodeIdstring, 1–600 charsYesA node: handle, or a plain node id.

Call canvas_get first when the user has not identified which node they mean. Guessing a node id here wastes a round trip at best.

What it returns

A structured block with the node handle, asset id, title, media type, width, height, a scoped previewUrl, and how many seconds that preview stays valid — plus the image itself, inlined so the model can inspect it, and a resource link.

The inline copy is re-encoded as WebP, capped at 2,048 pixels on the longest edge at quality 88. If that still exceeds 5 MB it is retried at 1,536 pixels and quality 72. The preview URL is validated to be a Gavana-origin scoped asset URL with exactly one token query parameter and nothing else, so a compromised upstream cannot redirect the client somewhere arbitrary.

That token parameter makes the preview URL a credential. It expires — previewExpiresInSeconds tells you when — but until then anyone holding the URL can fetch the image. Do not paste one into a shared document, a ticket, or a log. When you want to show a person the image, give them an open_canvas review link instead.

When it fails.

SymptomCauseFix
400 “not an image”The node is a text, sticky, or video nodeRead the canvas and pick an image node.
409 “does not have a stored result”The image node is an empty placeholder — generation has not finished 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 GIFNothing to do client-side; report it.

open_canvas

Return a verified browser link to a canvas. It checks access first, so the link you hand a human is one that will actually open.

Read-only. Requires canvas:read. No provider cost.

ParameterTypeRequiredNotes
canvasIdstring, 1–600 charsYesA canvas: handle.

Returns canvasId, title, and url. This is how an agent should end any turn that touched a canvas: with a link the person can click.

When it fails. 404 for a bad handle. A 502 means the service returned a canvas without an id or owner, which is a server-side problem — report the X-Request-ID rather than retrying.


save_image_to_canvas

Download one public HTTPS image, verify it, store it in Gavana, and add it as a durable image node. This is how an image created elsewhere — in ChatGPT, or at any public URL — becomes real canvas content with a node: handle you can pass to other tools.

Not read-only. Requires canvas:read, canvas:write, asset:read, and image:generate. No provider cost.

This tool needs image:generate even though it generates nothing. That scope is the one that governs writing image bytes into Gavana storage, so a token scoped only to canvas:write cannot save an image. If this call returns insufficient_scope and you were expecting write access to be enough, that is why.

Parameters

ParameterTypeRequiredNotes
imageobjectOne of image or imageUrlA client-supplied image file. Fields: download_url (URL, max 4,096), file_id (1–1,000), mime_type (optional), file_name (optional). Prefer this when your client has a file.
imageUrlURL string, max 4,096One of image or imageUrlMust start with https://.
destinationstring, 1–600 charsNo, defaults to agent-canvasagent-canvas for the persistent Agent Canvas, or an exact canvas handle.
titlestring, 1–160 charsNo, defaults to Image from ChatGPTNode title. Set something meaningful.
idempotencyKeystring, 8–200 charsYes
xnumber, −100,000 to 100,000NoExplicit position. Omit to let Gavana place it.
ynumber, −100,000 to 100,000No

Supplying neither image nor imageUrl fails validation with “Provide an image file or imageUrl.”

Worked example

{ "name": "save_image_to_canvas", "arguments": { "imageUrl": "https://example.com/hero-draft.png", "destination": "agent-canvas", "title": "Hero draft — warm editorial", "idempotencyKey": "hero-draft-2026-08-04-01" } }

Keep the returned node: handle. It is what generate_video wants as a firstFrame, and what create_canvas_workflow wants as a sourceNodeId default. The full flow is on Save a generated image.

When it fails. A non-HTTPS URL fails validation immediately. A URL that 404s or serves something that is not a raster image fails at fetch or sniff time — fix the URL rather than retrying. insufficient_scope almost always means the missing scope is image:generate.


create_canvas_workflow

Create a private, reusable Recipe and a workflow card on a canvas. This writes the workflow graph and never starts generation — that separation is deliberate, and it is what lets an agent build something on request without spending anything.

Not read-only. Requires canvas:read and canvas:write. No provider cost.

Parameters

The schema is strict — an unrecognised key is rejected rather than ignored.

ParameterTypeRequiredNotes
destinationstring, 1–600 charsNo, defaults to agent-canvas
namestring, 1–160 charsYes
descriptionstring, max 1,200No, defaults to ""
categoryenumNo, defaults to Product VisualizationOne of Brand & Visual Design, Product Visualization, Marketing & Ads, Content Package.
tagsarray of strings, each 1–80, max 12No, defaults to []
inputsarray of input objects, 1–16Yes
outputsarray of output objects, 1–8Yes
idempotencyKeystring, 8–200 charsYes
x, ynumber, −100,000 to 100,000NoCard position.

Each input object:

FieldTypeRequiredNotes
keystring matching A-Z a-z 0-9 _ -, 1–80YesStable key referenced by outputs.
labelstring, 1–80Yes
descriptionstring, max 200No, defaults to ""
typeimage | text | stickyYes
sourceNodeIdnode referenceNoAn existing node on the destination canvas. This is how you pin a fixed image default.
valuestring, 1–8,000NoStarting text for text or sticky inputs only. Images must use sourceNodeId.
useAsDefaultbooleanNo, defaults to falseKeep the node or text as a reusable default so later runs may omit this input.

Each output object:

FieldTypeRequiredNotes
keystring matching A-Z a-z 0-9 _ -, 1–80Yes
labelstring, 1–80Yes
descriptionstring, max 200No, defaults to ""
typeimage | textYesNote: no sticky on outputs.
promptstring, 1–8,000YesThe generation instruction.
inputKeysarray of input keys, 1–16YesWhich declared inputs feed this output.
model, size, qualitystringsNoPer-output overrides.

The pattern that makes reuse work

Save the fixed images first, then reference them:

  1. save_image_to_canvas for each image that stays the same every run. Keep the node: handles.
  2. create_canvas_workflow with those handles as sourceNodeId and useAsDefault: true.
  3. Later runs pass only the inputs that change.

Get this wrong and every run has to re-supply the product shot.

Returns the workflow — including its workflowNodeId and a browser url — and the canvas. Keep workflowNodeId; it is the only thing run_canvas_workflow accepts.

When it fails. A strict-schema rejection names the unexpected key. An image-typed input carrying value instead of sourceNodeId is the most common mistake. An output whose inputKeys names a key that no input declares is a modelling error worth catching before you build the card.


run_canvas_workflow

Run a workflow card, passing only the inputs that should change.

This can incur provider cost. Call it only when the current user message explicitly asks to run or generate. Never retry it automatically after a failure, a timeout, or an ambiguous response.

Not read-only. Requires canvas:read, canvas:write, asset:read, image:generate, and job:manage. Strict schema.

ParameterTypeRequiredNotes
destinationstring, 1–600 charsNo, defaults to agent-canvasMust be the canvas the workflow card lives on.
workflowNodeIdnode referenceYesThe exact workflowNodeId from create_canvas_workflow.
inputsobject, max 16 entries, values 1–8,000 charsNo, defaults to {}Only the inputs to replace. Keys may be stable input keys, exact portNodeId values, or input labels. Image values must be node: or asset: handles. Stored defaults may be omitted.
idempotencyKeystring, 8–200 charsYes
model, size, qualitystringsNoRun-level overrides.
waitSecondsinteger, 1–50No, defaults to 45How long to wait inline before handing back a resumable handle.

Asynchronous by design

The tool waits up to waitSeconds for the run to finish. If it does, you get the completed run with image outputs — each with a scoped preview. If it does not, you get the queued run back with its status, the destination, and the workflowNodeId.

A timeout is not a failure. Poll get_canvas_workflow_run with the returned run: handle. Do not call run_canvas_workflow again — that starts a second paid run.

Worked example

{ "name": "run_canvas_workflow", "arguments": { "destination": "canvas:abc123:product-shots", "workflowNodeId": "node:wf7k2m", "inputs": { "background": "matte terracotta, soft window light" }, "idempotencyKey": "terracotta-run-2026-08-04-01", "waitSeconds": 45 } }

The full sequence is on Run a canvas workflow.

When it fails.

SymptomCauseFix
400 “not a reusable workflow card on this canvas”workflowNodeId is a plain node, or lives on a different canvas than destinationPoint destination at the canvas holding the card.
409 “missing its Recipe identity”The card lost its Recipe provenanceRecreate the workflow. Do not retry.
Returns while still queuedNormal — the run exceeded waitSecondsPoll get_canvas_workflow_run. Never re-run.
Terminal provider failureThe provider rejected or failed the jobReport it and stop. Ask for fresh intent before any new attempt.

get_canvas_workflow_run

Check or resume one workflow run. Call it repeatedly while the run is queued or running.

Not annotated read-only — it participates in run lifecycle rather than being a pure read. Requires canvas:read and job:manage. No provider cost — polling never charges. Strict schema.

ParameterTypeRequiredNotes
runIdstring matching run: followed by 1–220 of A-Z a-z 0-9 _ -YesExactly the handle run_canvas_workflow returned.

A succeeded run with image outputs comes back with each output resolved to its canvas node, including a scoped preview the model can inspect.

When it fails. 400 “not a reusable workflow run” means the handle belongs to a different kind of run — check you did not pass an image job handle. A malformed handle fails the regex before any request is made.


generate_image_in_canvas

Create an image-generation target on a canvas, queue the connected provider, and wait briefly for a durable result.

This can incur provider cost. Explicit current-turn approval only. No automatic retries.

Not read-only. Requires canvas:read, canvas:write, asset:read, image:generate, and job:manage.

ParameterTypeRequiredNotes
promptstring, 1–8,000 charsYes
destinationstring, 1–600 charsNo, defaults to agent-canvas
idempotencyKeystring, 8–200 charsYes
modelstring, 1–600 charsNoA connected model handle or id. Omit to use the configured default.
sizestring, 1–80 charsNo
qualitystring, 1–80 charsNo
countinteger, 1–4No, defaults to 1Number of images. Each one costs.
titlestring, 1–160 charsNo, defaults to Generated image
waitSecondsinteger, 1–50No, defaults to 45

count is the parameter to be careful with. Four images is four times the cost, and the approval you got was probably for one.

Gavana prepares the destination and the target nodes before queueing, so the canvas shows where the result will land even while it is still generating. On timeout you get the queued job plus the destination and target node ids — poll rather than re-calling.

When it fails. A conflict on target preparation (“Automatic image targets are incomplete”) means a previous partial attempt reused this idempotency key — use a new key. A terminal provider failure is reported and stops there.


find_video_models

Find connected video models and their capabilities. Always call this before generate_video, because a guessed model handle reaches the provider layer rather than failing validation.

Read-only and free, but requires the video:generate scope. Looking up a model mutates nothing; discovering video models is still part of the generation path, so a token without video:generate cannot call it.

ParameterTypeRequiredNotes
querystring, 1–240 charsYesThe model or provider name the user asked for, for example Seedance 2.
capabilityenumNo, defaults to video.generateOne of video.generate, video.generate.fromImage, video.generate.fromFrames, video.generate.fromReferences.
limitinteger, 1–25No, defaults to 10

Match capability to the inputs you actually intend to pass. If a first frame is required, ask for video.generate.fromImage — a model that only supports text-to-video will accept the call and ignore your frame.

{ "name": "find_video_models", "arguments": { "query": "Seedance", "capability": "video.generate.fromImage", "limit": 5 } }

Take a model: handle from the result verbatim.

When it fails. An empty result means no connected model matches — the user has not connected that provider. Say so; do not substitute a different model. 403 means the token lacks video:generate.


generate_video

Start a video generation with an exact connected model.

This can incur provider cost, typically the highest on the platform. Explicit current-turn approval only. No automatic retries.

Not read-only. Requires canvas:read, asset:read, video:generate, and job:manage. Note that canvas:write is not required — the video job writes its own output rather than the caller editing the graph.

ParameterTypeRequiredNotes
modelstring, 1–650 charsYesAn exact model: handle from find_video_models. Not shape-validated — a wrong value fails later and less clearly.
promptstring, 1–8,000 charsYes
destinationstring, 1–600 charsNo, defaults to agent-canvas
idempotencyKeystring, 8–200 charsYes
aspectRatiostring, 1–40 charsNo
durationSecondsinteger, 1–120NoLonger usually costs more.
resolutionstring, 1–40 charsNo
generateAudiobooleanNo
firstFrameimage referenceNoA node: handle, an asset: handle, or a public HTTPS image URL.
lastFrameimage referenceNoRequires firstFrame. Supplying lastFrame alone fails validation.
referencesarray of image references, max 9NoDuplicates are rejected.
waitSecondsinteger, 1–50No, defaults to 45

Starting from an image you have in the conversation

Call save_image_to_canvas first, then pass the returned node handle as firstFrame and the same canvas as destination. A video cannot start from an image that only exists in the chat.

{ "name": "generate_video", "arguments": { "model": "model:seedance-2-pro", "prompt": "Slow push in, warm afternoon light, no camera shake.", "destination": "canvas:abc123:product-shots", "firstFrame": "node:img8q4", "durationSeconds": 6, "idempotencyKey": "hero-video-2026-08-04-01", "waitSeconds": 45 } }

On timeout you get a resumable job: handle. Poll get_video_job; never re-call generate_video.

When it fails.

SymptomCauseFix
Validation error on firstFramelastFrame supplied without firstFrameSupply both or neither.
Validation error on referencesDuplicate entriesDeduplicate.
Rejected referenceNot a node: handle, asset: handle, or HTTPS URLSave the image first and use its node handle.
Provider rejects the modelThe handle was guessed or is for a different capabilityCall find_video_models with the right capability.
Terminal failureProvider failed the jobReport it and stop.

get_video_job

Check or resume one video job.

Not annotated read-only. Requires job:manage only. No provider cost.

ParameterTypeRequiredNotes
jobIdstring matching job: followed by a UUIDYesExactly the handle generate_video returned. The UUID shape is enforced.

A succeeded job returns its protected Gavana output link, served through a Gavana-origin URL rather than a raw provider URL.

When it fails. 400 “not a video generation” means the handle belongs to an image job. A malformed handle fails the regex locally. If a job never leaves queued, report the state — do not start a second video.


Not on the hosted server

If you need node-level surgery (node_create, node_move, connection_delete), deterministic credit-free image action_* tools, Recipe Library search and forking, asset listing, canvas rendering, or provider discovery, those exist only on the local stdio server. See the local tools reference and Other clients.

Last updated on