MCP is not open yet. These pages are ready for when it opens. You can make an agent key now; it starts working when MCP opens. Until then the address below does not answer.
Adaver MCP tool reference
This page describes the three tools an agent sees at https://api.adaver.nuvai.dev/mcp. The text comes from the server code (crates/adaver-server/src/mcp/). If the code and this page ever differ, the code wins: the agent reads the tool descriptions from the server itself.
Overview
| Tool | What it does | Permission (scope) the key needs | Cost |
|---|---|---|---|
list_presets | Lists the five presets and what each is for | none | free |
get_balance | Shows how many images the account has left | balance | free |
vectorize_image | Turns a PNG, JPEG or WebP image into an SVG | vectorize | 1 image |
A tool the key has no permission for is not shown to the agent. If the agent calls it anyway, the answer is "unknown tool", the same as for a tool that does not exist.
The server keeps no session. Every request stands alone. Each answer is one JSON message (no event stream).
list_presets
"Lists the five vectorization presets and what each is for. Free, changes nothing."
Input: nothing.
Output (structuredContent, and the same JSON as text):
{
"presets": [
{ "name": "auto", "use_for": "...", "default": false },
{ "name": "high_quality", "use_for": "...", "default": true }
]
}| Preset | Use for |
|---|---|
auto | Looks at the image and picks the settings for you. Good when you do not know the image type. |
high_quality | Detailed result with smooth curves and strokes. The default. Best for most images. |
fast | Fewer layers and a quicker answer. Good for drafts and simple images. |
anime_optimized | Smooth-gradient artwork such as anime and illustrations. Smaller files, with some colour banding. |
gradient_aware | Logos and art with gradients. Draws real SVG gradients instead of many flat patches. |
get_balance
"Shows how many images the account has left and whether the free image is still unused. Free, changes nothing you can see."
Input: nothing. Needs: scope balance.
Output:
| Field | Meaning |
|---|---|
metered | false while billing is off: calls are free and unlimited, and the other fields are left out |
available | Images the account can use now (bought + this period's allowance + the free image) |
balance | Bought images |
allowance | This period's subscription images. They end at the period's end. |
reserved | Images held by calls that are still running |
free_available | The one free image is still unused |
free_needs_verification | The free image needs a verified email first |
out_of_images | Nothing is left |
get_balance shows the account. It does not show how much of a key's daily limit is used. A key that is at its limit learns it from the daily_cap_reached error (with used, limit and resets_at).
vectorize_image
"Turns a PNG, JPEG or WebP image into a clean SVG. THIS CHARGES 1 IMAGE to the account (the account's one free image counts); if the call fails, the image is given back."
Needs: scope vectorize.
Input
Send exactly one of image_url and image_base64. Unknown fields are refused.
| Field | Type | Meaning |
|---|---|---|
image_url | string | A public https link to a PNG, JPEG or WebP image. Up to 25 MB and 25 megapixels. |
image_base64 | string | The image as base64 text (a data: prefix is fine). Only for small images: the whole request may be at most 4 MiB, so about 3 MB of image. |
preset | string | One of the five presets. Left out: high_quality. For a photo, fast or auto usually works better. |
options | object | Optional fine tuning: single values (numbers, booleans, text). Allowed keys: max_colors, merge_threshold, color_precision, filter_speckle, corner_threshold, line_fit, smoothing, contour_smoothing, shapes, clean_regions, gradients, stacking, mode, bw_threshold, denoise. Most calls do not need it. |
idempotency_key | UUID | A fresh random UUID (version 4) the agent makes up for this one job. See Safe retries. |
confirm_token | UUID | Only for a key in confirm mode. See Confirm mode. |
How the image is downloaded from image_url: https only, at most 3 redirects (each one checked again), and private or internal addresses are refused. The type is read from the bytes, never from the file name.
Output
On success (structuredContent, and the same JSON as one text block):
| Field | Meaning |
|---|---|
width, height | Size of the picture |
bytes | Size of the SVG in bytes |
elements | Number of shapes in the SVG |
palette | The colours used, as #rrggbb |
preset | The preset that was used |
warnings | Short notes about the result (often empty) |
request_id | The id of this call |
charged | true when this call spent 1 image. false for a free replay. |
replayed | true for a free repeat of a job that was already charged. Left out when false. |
svg | The SVG itself, when it is small enough (see below) |
link | { "url": ..., "expires_in_secs": ... } for a bigger SVG, instead of svg |
Inline SVG or link
| SVG size | What the agent gets |
|---|---|
| Up to 100 KB | svg: the SVG text, inline |
| Bigger | link.url: a secret address, valid for 15 minutes (expires_in_secs says how long). It also comes as a resource_link block. |
About the link:
- No key is needed to open it. Anyone who has the address can read the SVG until it ends. Do not share it.
- It answers
image/svg+xmlwithno-store,nosniffand asandboxcontent security policy, so a browser never runs code from it. - After it ends, or for a wrong address, the answer is
404. - One account keeps at most 10 live links. A new one removes the oldest.
These are the server's default limits. The operator can change them (inline 1 KB to 1 MB, link 60 s to 1 hour).
Charging
- One call that finishes spends 1 image. The account's one free image counts.
- If the call fails after the image was held, the image is given back. If the client goes away or the call takes too long, the image is given back too.
- Nothing is charged for a refusal: bad input, limits,
daily_cap_reached,content_refused,confirmation_required,insufficient_imagesand the other errors below.
Content check
Every image is checked automatically for content we do not trace (Azure AI Content Safety), the same check as on the website. A refused image is the tool error content_refused and charges nothing. A key that sends several refused images in an hour is paused for the rest of the hour (too_many_refusals, see Limits). If the check cannot be made at that moment, the image is traced anyway.
- Every new call for the same picture is a new trace and spends 1 more image. Call again only when the user wants a new trace.
Safe retries
The idempotency_key makes a retry safe after a network error or a timeout.
| Situation | Result |
|---|---|
Same idempotency_key, same picture and settings, job finished | Free replay: the same SVG again, charged: false, replayed: true. Up to 2 free replays, within 1 hour. |
| Same key, job still running | in_progress. Wait. Do not send a new key meanwhile, that charges again. |
| Same key, replays used up | already_done. To trace again on purpose, use a new key (1 more image). |
| Same key, other picture or other settings | key_reused. Make a new key. |
No idempotency_key sent | Every call is a new job and charges 1 image, even for the same picture. A retry cannot be told apart from a new request, so send a key if you may need to retry. |
Always make a fresh random UUID. Never copy an example UUID.
Confirm mode
A key can be set to confirm mode. Then no call charges until the user agrees.
1st call (no confirm_token) -> error "confirmation_required" with confirm_token, price, expires_in_secs
nothing is charged
agent asks the user: "Spend 1 image?"
user says yes -> same call again + confirm_token -> charged once
user says no -> do not call again- The token works only for the same key, the same picture and the same settings.
- It lives 10 minutes by default (
expires_in_secssays how long). - If the first call had an
idempotency_key, the token is that same value. Sending both is fine. A differentidempotency_keynext to the token is refused. - Sending the token again after the charge is a free replay, never a second charge.
- A client that supports MCP questions (elicitation, protocol version 2026-07-28 or newer) gets a yes/no box instead. "No" answers
confirmation_declined.
The account page has no switch for confirm mode yet, so keys made there have it off.
What confirm mode can and cannot do. The question goes through your AI client, and Adaver cannot see who answered it: the agent itself receives the confirm_token, so an agent that ignores the rule (a bug, or instructions hidden in a page it read) can send the token without asking you. Confirm mode is a seat belt for well-behaved clients, not a lock. The hard limit is the key's daily cap: the server enforces it whatever the agent does. Set the cap to what you are willing to spend in a day.
Limits
| Limit | Value | Error |
|---|---|---|
| Daily limit per key | "Images per day" on the key, 1 to 200 (default 20). A day is the UTC day by default. | daily_cap_reached (429) |
vectorize_image calls per key | 30 per 10 minutes | rate_limited (429) |
| Images our content check refused, per key | 5 per hour. After that the key is paused until the hour ends. Only this key is paused. | too_many_refusals (429) |
| Traces running at once per account | 2 | too_many_jobs (429) |
| Requests running at once per account | 6 | too_many_requests (429) |
| Request body | 4 MiB | payload_too_large (413) |
| Image | 25 MB, 25 megapixels | payload_too_large, image_too_large |
| Whole call | about 4 minutes | timeout (504). The tracing step gets only the time that is left, so a slow trace usually ends as the tool error timeout with the image given back. |
A free replay still works when the key is at its daily limit.
Errors
There are two kinds of errors.
1. Tool errors. The HTTP answer is 200 and the tool result has isError: true. It has one text block that holds a JSON object:
{
"code": "daily_cap_reached",
"message": "This key has used its daily limit of 20 images. ...",
"retry_after_secs": 3600,
"request_id": "..."
}It always has code, message and request_id. Some have more: field (which input is wrong), limit, actual, retry_after_secs, free_needs_verification, confirm_token.
2. HTTP errors. The request is refused before any tool runs. The body is JSON with code, message and request_id. The x-request-id header has the same id.
HTTP errors
| Status | code | Meaning |
|---|---|---|
| 401 | unauthenticated | No key, a wrong key, a revoked or expired key, or a key that is not an agent key. The answer has a WWW-Authenticate header. |
| 403 | account_restricted | The account is in a cooldown or suspended |
| 408 | request_timeout | The request body took too long to arrive |
| 413 | payload_too_large | The request is bigger than 4 MiB. Send large images by URL. |
| 429 | too_many_requests | This account already has 6 requests running (all its keys count together). Wait for one to finish. |
| 503 | busy | The server is busy. Wait retry_after_secs. |
| 503 | mcp_disabled | The MCP door is switched off for now |
| 504 | timeout | The request took too long and was stopped. If the call was charged, a retry with the same idempotency_key replays it for free; otherwise nothing was charged. |
Tool errors of vectorize_image
code | Meaning | What to do |
|---|---|---|
bad_request | An input is wrong (see field): both or no image, bad base64, unknown preset or option | Fix the input |
confirmation_required | Confirm mode: price quote, nothing charged | Ask the user, then call again with confirm_token |
confirmation_declined | The user said no | Do not call again for this picture unless the user asks |
confirm_token_unknown | The token is not valid for this key | Call again without confirm_token for a new quote |
confirm_token_expired | The token is too old | Call again without it, and ask the user again |
confirm_token_mismatch | The token was for another picture or other settings | Send the same picture, preset and options, or get a new quote |
key_reused | The idempotency_key was used for another job | Use a new idempotency_key |
in_progress | The same job is still running | Wait; retry only with the same idempotency_key |
already_done | The job was charged and its free replays are used up | A new idempotency_key traces again (1 more image) |
daily_cap_reached | The key used its daily limit (limit, used, resets_at) | Wait until resets_at, or raise the limit on the account page |
content_refused | Our automatic content check refused the image. Nothing was charged. | Do not retry the same image. Check what the agent sends. |
too_many_refusals | The key sent several images the content check refused in the last hour, so it is paused. Nothing was charged (limit, retry_after_secs). | Wait retry_after_secs. Do not retry before then, and check the images. |
insufficient_images | No images left, or the free image needs a verified email | Buy images or verify the email |
account_in_debt | A refund came after the images were used | Buy images to settle it, or contact support |
rate_limited | Too many vectorize_image calls for this key | Wait retry_after_secs |
too_many_jobs | The account already has conversions running | Wait for one to finish |
busy | The server is busy | Wait retry_after_secs |
fetch_failed | The image could not be downloaded from image_url | Use a public https link to the image file |
payload_too_large | The image is larger than 25 MB | Use a smaller image |
unsupported_image | Not a PNG, JPEG or WebP | Convert the image |
damaged_image | The image could not be read | Check the file |
image_too_large | More than 25 megapixels | Use a smaller image |
too_thin, nothing_to_trace | The image has nothing the engine can trace | Use another image |
too_complex | The SVG would have too many shapes or bytes. Nothing was charged. | A smaller or simpler image, or options such as {"max_colors": 8} or a higher filter_speckle |
engine_unavailable, bad_gateway | The tracing service is not available or answered badly | Try again in a moment |
timeout | The call took too long | Retry with the same idempotency_key |
internal | Something went wrong on our side | Retry; send us the request_id if it stays |
get_balance can answer internal. list_presets has no tool errors.
Server metadata
GET https://api.adaver.nuvai.dev/.well-known/oauth-protected-resource (and .../oauth-protected-resource/mcp) returns a small public JSON document that names the resource (.../mcp) and links to the documentation. The 401 answer points at it. Agent keys do not need it today; OAuth sign-in will.

