spicyapiDocs
Main content

MCP server

Connect Claude, Cursor, VS Code and other AI assistants to SpicyAPI, then browse models, compare prices, generate media and collect results by chatting — with every paid step confirmed by you.

@spicyapi/mcp lets the AI assistant you already use — Claude, Cursor, VS Code, Codex, Windsurf, Gemini CLI and others — work with SpicyAPI for you. Once it is set up you can type "make me a five-second video from this photo" and the assistant finds a suitable model, tells you the price, waits for your OK, starts the job and hands you the result link.

You do not need to write code. You need Node.js, an API key and about ten minutes.

What MCP is, in plain words

MCP (Model Context Protocol) is an open standard for giving AI assistants extra abilities. Think of it as a plug-in socket: an assistant that supports MCP can load "servers", and each server adds a set of tools the assistant may use while it talks to you.

@spicyapi/mcp is one of those servers. It adds 22 SpicyAPI tools. Here is what happens when you ask for something:

  1. You write a normal message, for example "Generate an image of a lighthouse at dawn."
  2. Your assistant decides which SpicyAPI tools it needs and calls them.
  3. The server — a small program running on your own computer, started automatically by your assistant app — sends those requests to SpicyAPI using your API key.
  4. Anything that costs money pauses first: your app shows you the price and asks you to confirm. The assistant cannot answer that question for you.
  5. The results come back into the conversation, and the assistant explains them.

There is nothing to host or keep running. The assistant app starts the server when it needs it and stops it when you quit.

It suits you if you already use an AI assistant and want to try models, compare prices or produce images and videos without writing a program. Developers also use it to explore the catalog from inside their editor before building an integration.

It is not the right tool for a production app or backend (use the SDK or the HTTP API), for large unattended batches (use the CLI), or for streaming chat replies token by token — the MCP server submits and tracks tasks; see Text and streaming for chat.

MCP, CLI, SDK or Skill?

SpicyAPI publishes four separate packages. Most people only need one or two.

PackageHow you use itBest for
MCP server (this page)Chat with your AI assistantExploring, comparing prices and one-off generations without code
CLIType spicyapi commands in a terminalRepeatable commands, shell scripts and batches
SDKWrite TypeScript codeYour own app, backend or pipeline
SkillInstall into your assistant, next to MCPTeaching the assistant the right order of steps, so it takes fewer detours. It adds knowledge, not tools, so it complements MCP rather than replacing it

If your app is not written in TypeScript, the SDK row has four more options: Python, Go, PHP and Java.

What your assistant can do

These are all 22 tools the server adds. You never call them by name — you ask in your own words and the assistant picks. The names are useful when you read what the assistant did, or when your app asks you to approve a tool call.

ToolIn plain wordsRead-onlyCosts moneyAsks you first
spicyapi_service_statusChecks whether SpicyAPI is up. Works without a keyYesNoNo
spicyapi_docs_searchSearches the SpicyAPI documentation bundled with the server. Works without a keyYesNoNo
spicyapi_models_listLists the models your key can call, with pricesYesNoNo
spicyapi_model_getShows one model in detail: what it accepts, its price tiers, whether it is availableYesNoNo
spicyapi_balance_getShows your available, held and total balanceYesNoNo
spicyapi_usage_getReports how many tasks this key ran and what they cost, by day and by modelYesNoNo
spicyapi_tasks_listLists this key's recent tasks, without prompts or filesYesNoNo
spicyapi_task_getOpens one task: its state, cost, error and result linksYesNoNo
spicyapi_task_waitWaits up to five minutes for a task to finishYesNoNo
spicyapi_task_quotePrices an exact request without starting anythingYesNoNo
spicyapi_upload_fileUploads a file from your computer so a model can use it, all in one stepNo — it sends a fileNoNo
spicyapi_download_url_createMakes a fresh, short-lived download link for a resultNo — it issues a linkNoNo
spicyapi_task_createStarts a generationNoYesYes, with the price
spicyapi_task_retryRuns a failed or expired task again, as a new taskNoYesYes
spicyapi_task_purgePermanently deletes one finished task's files, result and promptNo — cannot be undoneNo, and it refunds nothingYes
spicyapi_asset_saveKeeps a result, a file from your computer, a link or an upload in your asset library, and returns a spicy://a/ reference that works until you delete itNo — it stores a fileNoNo
spicyapi_assets_listLists and searches your saved filesYesNoNo
spicyapi_asset_renameRenames a saved file; its reference stays the sameNoNoNo
spicyapi_asset_deletePermanently deletes a saved fileNo — cannot be undoneNoYes
spicyapi_assets_usage_getShows which library your key reaches, your storage plan and what is usedYesNoNo
spicyapi_characters_listLists your characters (named sets of reference images)YesNoNo
spicyapi_character_getReads one character's images, in order, ready to use as referencesYesNoNo

"Asks you first" means the SpicyAPI server itself stops and asks for confirmation — the assistant cannot skip it. Many apps also ask you before running any tool; that is the app's own setting and is separate from this.

Before you start

Install Node.js 22.13 or later

The server is a Node.js program. Your assistant starts it with npx, which comes with Node.js.

Open a terminal (on Windows: PowerShell) and check what you have:

node --version

If the command is not found, or the number is lower than v22.13.0, install the current LTS version from nodejs.org. The official installer is the easiest choice, because desktop apps such as Claude Desktop can then find npx without extra setup.

Create an API key

  1. Sign in to SpicyAPI, or create an account at spicyapi.ai/register. If sign-ups are paused, that page shows how to join the waitlist.
  2. Open API keys in the console (spicyapi.ai/console/keys) and choose Create key.
  3. Give it a name you will recognise later, such as Claude Desktop on my laptop. One key per assistant makes it easy to see what each one spent and to revoke just that one.
  4. Optional, under Advanced: a Daily cap, Monthly budget or Lifetime cap in US dollars, Allowed models, an IP allowlist and an Expiry. A blank cap means no limit. A daily cap is the simplest protection against a mistake burning through your balance, so it is worth setting one on a key you hand to an assistant.
  5. Copy the key now. It starts with sk-spicy- and is shown only once — we store only a hash, so a lost key can only be revoked and replaced.

To run paid tasks your account also needs funds. Top up on the console's Billing page. Browsing models, checking prices and reading results is free.

Choose your AI client

Any app that can run a local MCP server works. Step-by-step setup for the most common ones is below: Claude Desktop, Claude Code, Codex, Cursor, Windsurf, Gemini CLI and VS Code.

Paid actions need an app that can ask you questions

Before anything is charged, the server asks you to confirm using an MCP feature called elicitation — a question your app shows to you, not to the AI. Starting, retrying or deleting a task only works in apps that support it. In an app that does not, those three tools stop with an error, usually mentioning did not declare the required capability. Nothing is created, reserved, charged or deleted: starting a task has at most fetched its free price quote by then, and retrying or deleting has sent no request at all. The read-only tools keep working. If you see that error, update the app, or run the task from the CLI or a model page on spicyapi.ai instead.

Set up your client

Every app below runs the same command: npx --yes --package=@spicyapi/mcp spicyapi-mcp. The first start downloads the package, which can take a few seconds.

You never need to run that command yourself — the app starts it. If you do run it by hand, it waits silently for the app to talk to it, which looks like a hang but is normal. Press Ctrl+C to stop it.

  1. Open Claude Desktop and go to Settings → Developer → Edit Config. This opens the folder containing claude_desktop_config.json:
    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json
  2. Open that file in a text editor and paste the block below. If the file already has an mcpServers section, add only the "spicyapi": { … } entry inside it, separated from its neighbours by a comma.
  3. Replace YOUR_SPICY_API_KEY with your key, keeping the quotation marks.
  4. Save, then quit Claude Desktop completely and open it again. It reads this file only at launch; closing the window is not enough.
  5. Start a new chat. SpicyAPI should appear among the tools in the chat input's tools menu. Ask "Check the SpicyAPI service status" to confirm.
claude_desktop_config.json
{
  "mcpServers": {
    "spicyapi": {
      "command": "npx",
      "args": ["--yes", "--package=@spicyapi/mcp", "spicyapi-mcp"],
      "env": { "SPICY_API_KEY": "YOUR_SPICY_API_KEY" }
    }
  }
}

Menu names move between Claude Desktop versions. If yours differ, Claude's own MCP documentation is authoritative.

Each app owns its configuration location and format, and both change between versions. When a step above no longer matches your app, the app's own MCP documentation is authoritative. Another MCP-capable app can use the same command, args and env shown above.

Keep your key safe

Anyone holding your key can spend your balance. A few habits keep it contained:

  • Only put the key in user-level files — the ones in your home folder listed above — never in a file inside a project or repository. If you back up your settings files to a public "dotfiles" repository, leave these out.
  • Never paste the key into the chat. The assistant does not need it; the server reads it from the configuration.
  • Set a daily cap on the key, so a mistake has a ceiling.
  • If a key leaks, revoke it on the API keys page and create a new one. Revoking takes effect immediately; tasks already accepted still finish and are still charged. See After a leak.

Check that it works

Ask these three things in a new conversation, in order:

  1. "Check the SpicyAPI service status." — uses spicyapi_service_status. It needs no key, so if this works the server is installed correctly.
  2. "What is my SpicyAPI balance?" — uses spicyapi_balance_get. If this works, your key is reaching the server.
  3. "Which SpicyAPI tools do you have?" — the assistant should list 22 tools whose names start with spicyapi_.

None of these costs anything. If one fails, see Troubleshooting.

Try it: example conversations

Copy any of these into your assistant. The descriptions show which tools it will typically use — assistants vary, so the exact order can differ — and exactly where it stops to ask you.

Where model IDs come from

The assistant looks up model IDs in the live catalog with spicyapi_models_list; you do not need to know them. If you want a specific model, you can name it, or copy its exact ID from the model's page. Wherever this documentation shows MODEL_ID_FROM_CATALOG, it means "an exact ID taken from the live catalog", not a value to send as-is.

Check your balance and spending

How much SpicyAPI balance do I have, and how much did I spend this week?

The assistant calls spicyapi_balance_get and spicyapi_usage_get. Both are free and read-only, so nothing asks for confirmation. "Held" in the balance is money reserved by tasks still running.

Find and compare models

Find SpicyAPI models that can turn a still image into a video, and compare what a 5-second clip would cost on each.

The assistant calls spicyapi_models_list (filtered to video models that take an image), may call spicyapi_model_get for details, and may call spicyapi_task_quote once per candidate to get an exact price for your settings. Quotes are free and create nothing, so there is no confirmation. The answer is a comparison you can pick from.

Generate an image

Use SpicyAPI to generate a square image of a neon-lit ramen shop on a rainy night. Pick an inexpensive image model and give me the link when it is done.

  1. spicyapi_models_list to choose a model, and spicyapi_model_get if it needs that model's accepted fields.
  2. spicyapi_task_create. This is where it stops. Your app shows a confirmation with the model, the estimated charge, the maximum charge and when the quote expires. Nothing is charged until you confirm.
  3. After you confirm, the task starts and spicyapi_task_wait waits for it to finish.
  4. The assistant gives you the result link from the finished task.

Turn a photo on your computer into a video

Turn the photo at /Users/me/Desktop/portrait.jpg into a 5-second video where the camera slowly pushes in.

On Windows, give the path as C:\Users\me\Desktop\portrait.jpg.

  1. spicyapi_upload_file uploads the photo and returns a spicy:// address for it. Uploading is free and does not ask for confirmation, but it does send that file to SpicyAPI — so give the exact path of the file you mean.
  2. spicyapi_models_list / spicyapi_model_get to pick an image-to-video model and see its options.
  3. spicyapi_task_create — it stops here for your confirmation, showing the price.
  4. spicyapi_task_wait. Videos often take several minutes; each wait lasts at most five, so the assistant may wait more than once, or you can ask about the task later.

Find an earlier task

Show me my SpicyAPI tasks from the last three days that failed, and tell me why.

The assistant calls spicyapi_tasks_list with a failed-state filter, then spicyapi_task_get on the ones you care about to read the error. Failed or expired tasks normally release the full hold. Some content refusals are charged at the accepted quote only when the model page explicitly discloses this exception. Check settled and cost for the final charge. If you then say "retry that one", it calls spicyapi_task_retry, which stops for your confirmation, because a retry is a new paid task.

Get the result file

Give me the download link for my last SpicyAPI video.

The assistant finds the task with spicyapi_tasks_list, then reads it with spicyapi_task_get, which includes ready-to-use result links. Open the link in a browser to download. Links are short-lived: if one has expired, ask again and the assistant fetches a fresh one.

The MCP server does not save files onto your computer by itself. Assistants that can also run commands — Claude Code or Codex, for example — can download the link into a folder for you if you ask.

Keep a file and reuse it later

Save the image from my last SpicyAPI task to my asset library as "Hero portrait". Then use it as the first frame of a 5-second video.

  1. spicyapi_tasks_list finds the task, and spicyapi_asset_save saves its first result. This is free and does not ask for confirmation. The assistant gets back a spicy://a/… reference.
  2. spicyapi_models_list / spicyapi_model_get to pick an image-to-video model; the reference goes into its image field.
  3. spicyapi_task_create — it stops here for your confirmation, showing the price.

Weeks later, "use my Hero portrait again" makes the assistant find it with spicyapi_assets_list. If you set up characters on the Assets page of the web app, "make a video of my character Mara" makes it read the character with spicyapi_character_get and pass its images, in order, as references. Asking it to delete a saved file uses spicyapi_asset_delete, which always asks you first.

Tool reference

Every tool, what it takes and what it gives back. Amounts of money are always US dollars written as exact decimal text without a $ sign, for example "0.08". Dates are UTC.

Checking the service and documentation

spicyapi_service_status

Checks whether SpicyAPI's public API is reachable and healthy. It needs no API key, costs nothing and asks nothing. It is a diagnostic: the assistant does not need to run it before creating a task.

Parameters: none.

Returns: operational (true or false), the individual health and readiness checks with their HTTP status, and checkedAt.

Searches an index of SpicyAPI documentation pages that ships inside the server, and returns matching titles, summaries and links. It needs no key and makes no network request.

Prop

Type

Returns: a list of entries, each with slug, title, summary, keywords and url. Links point to this documentation site, in the form https://docs.spicyapi.ai/docs/retention. When nothing matches, the list is empty.

Browsing models

spicyapi_models_list

Lists the models your API key can call, with prices that already include any discount on your account. Free and read-only.

Prop

Type

Returns: total and items. Each item includes model (the exact ID to use), displayName, provider, modality, tasks, enabled and available, availability, a pricing list (each entry has a tier label, a unit of per_image, per_second, per_request or per_1k_tokens, and a USD price), startingPrice, taskTimeoutSeconds, and inputSchema / examples when requested.

Some settings, such as resolution or duration, change the price. The price list is for comparing; the exact charge for a specific request comes from a quote.

spicyapi_model_get

Returns one model in full: its accepted inputs (inputSchema, a machine-readable description of each field, its type, allowed values and defaults), pricing, availability and examples. Free and read-only.

Prop

Type

Returns: the same fields as one item of spicyapi_models_list, always including inputSchema.

Your account

spicyapi_balance_get

Shows your balance. Free and read-only. Not required before creating a task — creation checks funds itself.

Parameters: none.

Returns: available, held (reserved by tasks still running) and total, in USD. It can also include a funding breakdown of prepaid funds, promotional grants and any approved credit facility; see Billing.

spicyapi_usage_get

Reports what this API key did: how many tasks, how many succeeded or failed, and the settled spend, grouped by day and by model. Free and read-only. It covers only the key in your configuration, not your whole account, and it is not your balance.

Prop

Type

Returns: from, to, currency, totalCalls, totalSpend, and days and models lists with calls, succeeded, failed and spend. Only settled charges are counted; money still held by running tasks is not, and a late settlement can update an earlier day.

Tasks

spicyapi_tasks_list

Lists tasks created with this API key, newest first — useful for finding a task after closing the chat. It shows metadata only: no prompts, inputs or result links. Free and read-only.

Prop

Type

Returns: items (each with taskId, model, state, cost, settled, createdAt, deadlineAt and, when finished, completedAt), hasMore and nextCursor. cost is final only when settled is true.

spicyapi_task_get

Opens one task created with this API key. Free and read-only.

Prop

Type

Returns: taskId, model, state, cost, settled, createdAt, completedAt, and depending on the task:

  • output.assets — the results. Each ready asset has a url you can open directly, with its expiresAt, mime type and size or duration. An asset marked pending is still being stored — ask again in a few seconds. One marked unavailable is gone for good.
  • errorCode and errorMessage when the task failed; the codes are listed in Errors.
  • input — what was sent, until the prompt retention period ends.
  • contentState (present, expired or purged) and retention, which says when outputs and prompts will be removed.
  • sourceTaskId when this task is a retry.

A task ID that does not exist and one that belongs to someone else both return "not found".

spicyapi_task_wait

Checks a task repeatedly until it finishes or the wait runs out, then returns it. Free and read-only. Running out of waiting time does not cancel or fail the task — it keeps running, and you can wait again or look it up later.

Prop

Type

Returns: the finished task, in the same shape as spicyapi_task_get. If the time runs out first, the tool reports that the task did not finish within that time.

Files

spicyapi_upload_file

Reads a file from your computer, uploads it to SpicyAPI, finishes the upload and returns a spicy:// address that can go into a model's input — all in one call, with no second step. Free, and it does not ask for confirmation — but it does send the file, so it is not read-only.

Files that are already online at a public https:// address need no upload: the assistant can pass that address straight to the model if the model accepts a URL.

Prop

Type

Accepted files: JPEG, PNG, WebP and GIF images up to 10 MiB; MP4 and WebM video and MP3 and WAV audio up to 90 MiB and 600 seconds; documents (PDF, Word, Excel, PowerPoint, Keynote, Pages, Numbers, plain text and Markdown) up to 90 MiB, for models with a document field; and .safetensors LoRA weights up to 2 GiB, only for loras[].path. A model can set stricter limits of its own. See Media.

Which folders: by default only files inside your home folder can be read. See Local files.

Returns: uri (the spicy:// address), fileId, bytes, contentType, sha256, width / height / durationSeconds when known, and expiresAt. The address can be used for one day by default. To keep a file longer, save it with spicyapi_asset_save.

The upload is already finished when this tool returns, so there is no separate "commit" step to run. The server has no tool for completing an upload that another program started; code that uploads in separate steps finishes with the SDK's commitUploadedFile.

spicyapi_download_url_create

Issues a new signed download link for one result of one of your tasks. Free. Usually unnecessary: spicyapi_task_get and spicyapi_task_wait already include ready links, and asking for the task again refreshes them.

Prop

Type

Returns: key, url and expiresAt. The link works for 20 minutes and cannot be revoked once issued, so do not share or store it. See Media.

Pricing, creating and deleting

spicyapi_task_quote

Works out the exact price of a specific request without starting anything or reserving money. Free and read-only. The assistant uses it to compare options; it does not need it before creating a task, because creation gets its own quote.

Prop

Type

Returns: quoteId, model, estimatedCost, maxCharge, currency, quantity, unit and expiresAt. A quote is valid for five minutes and only for exactly that request.

spicyapi_task_create

Starts a generation. Costs money and always asks you first.

What happens, in order:

  1. The server gets an exact quote for the request. A quote is free: it creates nothing and reserves no money.
  2. Your app shows you a confirmation with the model, the estimated charge, the maximum charge, when the quote expires, and an idempotency key (a reference that stops the same request being charged twice).
  3. If you decline, no task is created and no money is reserved or charged. The only request sent so far was the free quote from step 1.
  4. If you confirm, SpicyAPI checks the inputs, price, your key's permissions and your funds, reserves the estimated amount and starts the task.

This needs an app that can show confirmation questions (MCP elicitation). In an app that cannot, the tool fails at step 2: the free quote was fetched, and nothing else happened. See Before you start.

Prop

Type

Returns: taskId, state (normally queued), estimatedCost and the idempotencyKey used. The task then runs on its own; use spicyapi_task_wait or spicyapi_task_get to collect the result.

If the connection breaks after you confirmed, the error includes the idempotency key. Ask the assistant to try again with that same key and unchanged model and settings rather than starting fresh: you may be asked to confirm again, but SpicyAPI returns the original task instead of charging for a second one. A new key would create a second paid task, and changed settings under the same key are refused.

spicyapi_task_retry

Creates a new, separately charged task from one that failed or expired. The original task stays as it was. Costs money and always asks you first.

Prop

Type

Returns: the new taskId, sourceTaskId (the original), state, estimatedCost and idempotencyKey.

The retry uses the model's current price, and current checks on inputs, permissions and funds run again. Its confirmation does not show a price, so if you want to know it first, ask the assistant to quote the same model and settings with spicyapi_task_quote before retrying.

A retry reuses the original input unchanged, so read the failed task's errorCode first:

  • rate_limited, upstream_unavailable, timeout or upstream_failed — worth one retry after a short wait.
  • generation_failed — change the prompt or the image and start a new task instead; the same input usually fails the same way.
  • invalid_asset — upload the file again and start a new task with the new spicy:// address; a retry would reuse the old file.
  • content_rejected, invalid_request or unsupported_combination — do not retry unchanged. Change the prompt, the settings or the model and start a new task.

The full list is in Errors.

spicyapi_task_purge

Permanently deletes one finished task's stored content: the generated media, the result payload (the stored result data), the prompt and other input text. It cannot be undone and always asks you first. It costs nothing — and it refunds nothing.

Prop

Type

  • Only finished tasks (succeeded, failed, expired or a historical canceled) can be purged. An accepted task cannot be cancelled and there is no cancellation API, so for a queued or running task, wait until it finishes (spicyapi_task_wait), then purge it.
  • Download anything you want to keep first.
  • The billing record stays: the ledger entry, charged amount, model, state, timestamps and request ID remain visible afterwards.
  • Purging an already purged task again is harmless.

Returns: taskId, contentState (purged once deletion is scheduled), purgedAt, contentRemovedBy and billingRetained: true. It deliberately returns no links. Physical removal of files normally completes within a minute; see Retention and destruction.

Asset library

An upload lasts one day. A file you want to use again and again — a character portrait, a style reference, a voice sample — can be kept in your asset library instead. Each saved file is an asset with a reference of the form spicy://a/<id>, which the assistant can put in any file field of a model's input until you delete the asset. How the library works, its storage plans and its limits are explained in Media: Asset library.

The key decides the library. A key created in your personal workspace reaches your personal library. A key created in a team workspace reaches that team's shared library, never anyone's personal one. With a team key, what may change follows the current role of the member who created the key: owner and admin may change anything, developer may save and change only what they saved, billing and readonly may only read and use assets.

Wherever a tool takes assetId, the asset ID (ast_…) and the whole spicy://a/… reference both work. Every asset the tools return has a previewUrl: a private preview that works for at most 20 minutes. The assistant can show it to you, but the uri is what to keep. None of these tools costs money.

When the library refuses something, the tool error includes a reason, such as asset_library_full, asset_daily_limit or asset_permission_denied. The full list and what to do about each one is in Errors. A full or locked library is a plan limit, not a mistake in the request, so the assistant should explain it with spicyapi_assets_usage_get rather than try again.

spicyapi_asset_save

Saves a file to the library and returns the asset with its spicy://a/ uri. Free, and it does not ask for confirmation — but it does store a file, so it is not read-only. Give exactly one source:

Prop

Type

Saving the same result, upload or link again returns the asset you already have and uses no extra space. Saving needs a storage plan, which unlocks with your first top-up.

Returns: the asset: id, uri, name, kind, contentType, bytes, width / height / durationSeconds when they apply, source, sourceId, favorite, model and modelName (the model that generated it; empty for uploads and links), previewUrl and the times.

spicyapi_assets_list

Lists the assets in the library your key reaches, newest first, one page at a time. Free and read-only.

Prop

Type

Returns: items (the assets) and nextCursor, which is missing on the last page.

spicyapi_asset_rename

Gives an asset a new name. The uri stays the same, so inputs that already use it keep working. Free, and it does not ask for confirmation.

Prop

Type

Returns: the renamed asset.

spicyapi_asset_delete

Permanently deletes one asset. Its spicy://a/ reference stops working in new requests at once and the stored file is removed. It cannot be undone and always asks you first. Free. Deleting does not give back today's allowance of new assets.

Prop

Type

Returns: id and deleted: true. Deleting an asset that is already gone gives the same answer.

spicyapi_assets_usage_get

Shows which library your key reaches and what it may do there, your storage plan, what is stored, how many assets were saved today and what the next plan needs. Free and read-only; it takes no input.

Returns: scope (workspaceId, personal, role, canWrite — may save — and canTopUp), tier (the current plan), usage (count and bytes), limits, full, nextTier, tiers, dailyCreateLimit and createdToday, plus lifetimeTopupUsd and topupToNextTierUsd. Storage belongs to the owner, whose personal and team libraries share one plan. When canTopUp is false (a team key not created by the owner), the two top-up amounts are left out and the team owner is the one who upgrades. Byte values use binary units (500 MB is 524288000 bytes).

spicyapi_characters_list

Lists the characters in your library, newest first: a character is a name plus an ordered set of images, each image an asset with its own uri. You create and arrange characters on the Assets page of the web app; the server only reads them. Free and read-only.

Prop

Type

Returns: items and nextCursor. Each character has id, name, note, cover, assets (its images in order), count and its times.

spicyapi_character_get

Reads one character with its images in order, each with its uri and a fresh previewUrl. Free and read-only.

Prop

Type

To use a character, the assistant puts the uri of its images, in that order, into the model's reference-image field (spicyapi_model_get shows which one) and refers to them in the prompt the way that model's page describes. An unknown character, or one outside your key's library, gives 404. Characters used to be called personas; old spicy://p/<id> references keep working in your personal library. See Media: Characters.

Resources and prompt

Besides tools, the server offers two read-only resources and one prompt. Apps show these in different places, and many people never need them.

NameKindWhat it is
spicyapi://docs/indexResourceThe documentation index that spicyapi_docs_search searches
spicyapi://contract/openapiResourceThe public API contract (OpenAPI) this package version was built against
spicyapi_generation_workflowPromptA ready-made instruction that walks the assistant through a safe generation. It takes a goal and, optionally, a model

Costs, confirmation and safety

What the confirmation looks like

When the assistant starts a task, your app shows a question from the SpicyAPI server. The wording is like this (amounts are examples):

Create a billable task using MODEL_ID_FROM_CATALOG? Estimated charge: USD 0.20;
maximum charge: USD 0.20. Quote expires: 2026-09-17T12:05:00Z. Before accepting
the request, SpicyAPI checks the model's current input requirements, price and
availability, your API key permissions, and available funds.
Idempotency-Key: 4f1c…

The estimated and maximum charge currently show the same number: the estimate is the amount reserved when the task starts, and the task is never charged more than that reservation.

How the answer is presented depends on the app — typically a confirm checkbox or switch plus Accept and Decline buttons. Tick confirm and accept to go ahead. Declining or cancelling ends the tool call, and the message says what did and did not happen:

When you decline…The messageWhat was sent to SpicyAPI
Starting a task"operation declined; no task was created and no funds were reserved or charged (only the free price quote had been requested)"Only the free quote, fetched before the question was shown
Retrying a task"operation declined; no retry task was created and no SpicyAPI request was made"Nothing
Purging a task"operation declined; nothing was destroyed and no SpicyAPI request was made"Nothing
Deleting an asset"operation declined; the asset was not deleted and no SpicyAPI request was made"Nothing

Answer within five minutes. The quote is valid for five minutes. If it has expired by the time you confirm, creation fails with error 40901 and nothing is charged; ask the assistant to try again for a fresh quote.

Retrying shows a similar question without a price. Purging says the deletion cannot be undone and that billing records are kept. Deleting an asset says it cannot be undone and that the asset's spicy://a/ reference stops working.

Why the assistant cannot skip it

  • The question goes to you, not to the AI. The server sends it to your app through MCP's elicitation feature, and the app shows it to you. The assistant has no way to answer it.
  • Your answer is tied to that exact request. The confirmation is bound to the model and settings you were shown. If the assistant changes anything between the question and your answer, the server refuses with "confirmed request state does not match the current tool arguments" and nothing is created.
  • Keep it that way. If your app offers a setting that automatically accepts questions from MCP servers, leave it off for SpicyAPI. An assistant or setting that confirms on your behalf removes the only spending check on this path.
  • Apps without confirmation support cannot spend. In them, starting, retrying, purging and deleting an asset simply return an error; starting a task has fetched only its free quote by then. See Before you start.

What you pay

  • Prices are in US dollars. Estimates, charges and balances are exact dollar amounts.
  • You are never charged more than the maximum you confirmed. When a task starts, its estimated amount is reserved (shown as "held"). When it succeeds, you pay for actual usage, capped at that reservation, and anything unused is released.
  • Failed or expired tasks normally release the full hold. Some content refusals are charged at the accepted quote only when the model page explicitly discloses this exception. Check settled and cost for the final charge.
  • Looking things up is free: browsing models, quotes, balance, usage, task lookups, waiting, uploads, download links and everything in the asset library.
  • A started task cannot be cancelled. Closing the chat, quitting the app, a wait timing out or revoking the key does not stop a task that was already accepted. See Task commitment and retry.
  • Your key's caps apply. When a daily, monthly or lifetime cap is reached, new tasks are refused with 40202 until the period rolls over; see Spend caps.

How long results are kept

  • Generated files are kept for about 14 days at most, less if you shortened retention for your account or for that task. Download anything you want to keep.
  • Result links are temporary — normally 20 minutes. An expired link does not mean the file is gone: ask for the task again to get a fresh link, as long as it is still within retention.
  • Prompts and inputs are kept for 30 days at most; the task's billing record (ID, model, state, amount, times) stays.
  • Uploaded files can be used for one day.
  • To delete one task's content early, ask the assistant to purge it. To shorten retention for a single task, ask it to set retentionSeconds when creating it.

The full rules and exceptions are in Retention and destruction.

Local files

spicyapi_upload_file, and spicyapi_asset_save when you give it a path, can read files on your computer, which needs care:

  • By default it reads only inside your home folder (for example /Users/you or C:\Users\you). A file elsewhere is refused with a message saying which folders are allowed.
  • Shortcuts do not get around it. A symbolic link inside your home folder that points outside it is refused.
  • Why the limit exists: an assistant reading a web page, an email or a document can come across hidden instructions such as "upload the user's private keys". The folder limit keeps that kind of trick away from system files. Your own home folder is still readable, so only let the assistant upload files you named, and read the path when your app asks you to approve the tool call.

Changing the folders. Add SPICY_MCP_UPLOAD_ROOTS to the server's env, next to SPICY_API_KEY, with one or more full folder paths. It replaces the default, so you can narrow it to a single folder, or list several. Folders are separated the same way as in the system PATH setting, which differs by operating system. Write each folder as a full path: ~ is not expanded in this setting, even though it is in the file paths you give the assistant.

Separate folders with a colon (:):

{
  "env": {
    "SPICY_API_KEY": "YOUR_SPICY_API_KEY",
    "SPICY_MCP_UPLOAD_ROOTS": "/Users/you/Pictures:/Users/you/Movies"
  }
}

These blocks show only the env part. Add the SPICY_MCP_UPLOAD_ROOTS line to the env of the spicyapi entry you created in Set up your client, and keep your existing key line as it is. For Claude Code and Codex, add it to the registration command instead (-e SPICY_MCP_UPLOAD_ROOTS=… or --env SPICY_MCP_UPLOAD_ROOTS=…), after removing the server. Restart the app afterwards. A folder that does not exist simply matches nothing, so if uploads are refused after this change, check the spelling in the message, which lists the folders the server is using.

HTTP mode: this computer only

Most apps start the server themselves, as above. A few prefer to connect to a server that is already running, by address. For those, the package includes a second program, spicyapi-mcp-http:

export SPICY_API_KEY="sk-spicy-..."
export SPICY_MCP_HTTP_TOKEN="$(node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))")"
npx --yes --package=@spicyapi/mcp spicyapi-mcp-http

It prints SpicyAPI MCP HTTP listening at http://127.0.0.1:8765/mcp. Point your app at that address and have it send the header Authorization: Bearer followed by your SPICY_MCP_HTTP_TOKEN. http://127.0.0.1:8765/healthz answers {"ok":true} when it is running.

SettingMeaningDefault
SPICY_MCP_HTTP_TOKENPassword that apps must send. Required, at least 32 bytes of random text, and must differ from your API key—
SPICY_MCP_PORTPort number8765
SPICY_MCP_HOSTAddress to listen on: only 127.0.0.1, localhost or ::1 are accepted127.0.0.1

"Loopback only" means only programs on this same computer can connect. Other devices on your Wi-Fi and the internet cannot reach it, and there is no setting to open it up — any other address is refused at start-up. Requests from web pages on other sites are rejected too. If you need a server reachable from other machines, this is not it.

Troubleshooting

Source

The package is MIT-licensed and developed in the open at github.com/spicyapi-ai/spicy-mcp. That is where to read the code behind any tool on this page, report behaviour that differs from what is described here, or propose a change.

Next steps

On this page