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:
- You write a normal message, for example "Generate an image of a lighthouse at dawn."
- Your assistant decides which SpicyAPI tools it needs and calls them.
- 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.
- 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.
- 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.
| Package | How you use it | Best for |
|---|---|---|
| MCP server (this page) | Chat with your AI assistant | Exploring, comparing prices and one-off generations without code |
| CLI | Type spicyapi commands in a terminal | Repeatable commands, shell scripts and batches |
| SDK | Write TypeScript code | Your own app, backend or pipeline |
| Skill | Install into your assistant, next to MCP | Teaching 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.
| Tool | In plain words | Read-only | Costs money | Asks you first |
|---|---|---|---|---|
spicyapi_service_status | Checks whether SpicyAPI is up. Works without a key | Yes | No | No |
spicyapi_docs_search | Searches the SpicyAPI documentation bundled with the server. Works without a key | Yes | No | No |
spicyapi_models_list | Lists the models your key can call, with prices | Yes | No | No |
spicyapi_model_get | Shows one model in detail: what it accepts, its price tiers, whether it is available | Yes | No | No |
spicyapi_balance_get | Shows your available, held and total balance | Yes | No | No |
spicyapi_usage_get | Reports how many tasks this key ran and what they cost, by day and by model | Yes | No | No |
spicyapi_tasks_list | Lists this key's recent tasks, without prompts or files | Yes | No | No |
spicyapi_task_get | Opens one task: its state, cost, error and result links | Yes | No | No |
spicyapi_task_wait | Waits up to five minutes for a task to finish | Yes | No | No |
spicyapi_task_quote | Prices an exact request without starting anything | Yes | No | No |
spicyapi_upload_file | Uploads a file from your computer so a model can use it, all in one step | No — it sends a file | No | No |
spicyapi_download_url_create | Makes a fresh, short-lived download link for a result | No — it issues a link | No | No |
spicyapi_task_create | Starts a generation | No | Yes | Yes, with the price |
spicyapi_task_retry | Runs a failed or expired task again, as a new task | No | Yes | Yes |
spicyapi_task_purge | Permanently deletes one finished task's files, result and prompt | No — cannot be undone | No, and it refunds nothing | Yes |
spicyapi_asset_save | Keeps 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 it | No — it stores a file | No | No |
spicyapi_assets_list | Lists and searches your saved files | Yes | No | No |
spicyapi_asset_rename | Renames a saved file; its reference stays the same | No | No | No |
spicyapi_asset_delete | Permanently deletes a saved file | No — cannot be undone | No | Yes |
spicyapi_assets_usage_get | Shows which library your key reaches, your storage plan and what is used | Yes | No | No |
spicyapi_characters_list | Lists your characters (named sets of reference images) | Yes | No | No |
spicyapi_character_get | Reads one character's images, in order, ready to use as references | Yes | No | No |
"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 --versionIf 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
- 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.
- Open API keys in the console (spicyapi.ai/console/keys) and choose Create key.
- 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. - 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.
- 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.
- 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
- macOS:
- Open that file in a text editor and paste the block below. If the file already has an
mcpServerssection, add only the"spicyapi": { … }entry inside it, separated from its neighbours by a comma. - Replace
YOUR_SPICY_API_KEYwith your key, keeping the quotation marks. - Save, then quit Claude Desktop completely and open it again. It reads this file only at launch; closing the window is not enough.
- 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.
{
"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:
- "Check the SpicyAPI service status." — uses
spicyapi_service_status. It needs no key, so if this works the server is installed correctly. - "What is my SpicyAPI balance?" — uses
spicyapi_balance_get. If this works, your key is reaching the server. - "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.
spicyapi_models_listto choose a model, andspicyapi_model_getif it needs that model's accepted fields.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.- After you confirm, the task starts and
spicyapi_task_waitwaits for it to finish. - 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.
spicyapi_upload_fileuploads the photo and returns aspicy://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.spicyapi_models_list/spicyapi_model_getto pick an image-to-video model and see its options.spicyapi_task_create— it stops here for your confirmation, showing the price.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.
spicyapi_tasks_listfinds the task, andspicyapi_asset_savesaves its first result. This is free and does not ask for confirmation. The assistant gets back aspicy://a/…reference.spicyapi_models_list/spicyapi_model_getto pick an image-to-video model; the reference goes into its image field.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.
spicyapi_docs_search
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 aurlyou can open directly, with itsexpiresAt,mimetype and size or duration. An asset markedpendingis still being stored — ask again in a few seconds. One markedunavailableis gone for good.errorCodeanderrorMessagewhen the task failed; the codes are listed in Errors.input— what was sent, until the prompt retention period ends.contentState(present,expiredorpurged) andretention, which says when outputs and prompts will be removed.sourceTaskIdwhen 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:
- The server gets an exact quote for the request. A quote is free: it creates nothing and reserves no money.
- 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).
- 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.
- 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,timeoutorupstream_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 newspicy://address; a retry would reuse the old file.content_rejected,invalid_requestorunsupported_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,expiredor a historicalcanceled) can be purged. An accepted task cannot be cancelled and there is no cancellation API, so for aqueuedorrunningtask, 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.
| Name | Kind | What it is |
|---|---|---|
spicyapi://docs/index | Resource | The documentation index that spicyapi_docs_search searches |
spicyapi://contract/openapi | Resource | The public API contract (OpenAPI) this package version was built against |
spicyapi_generation_workflow | Prompt | A 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 message | What 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
settledandcostfor 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
40202until 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
retentionSecondswhen 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/youorC:\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-httpIt 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.
| Setting | Meaning | Default |
|---|---|---|
SPICY_MCP_HTTP_TOKEN | Password that apps must send. Required, at least 32 bytes of random text, and must differ from your API key | — |
SPICY_MCP_PORT | Port number | 8765 |
SPICY_MCP_HOST | Address to listen on: only 127.0.0.1, localhost or ::1 are accepted | 127.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
Models
How the live catalog describes each model, its inputs and its prices
Billing
Holds, settlement, spend caps and how failed tasks are released
Retention and destruction
How long results and prompts are kept, and how to delete them sooner
Skill
Teach your assistant the SpicyAPI workflow alongside the MCP tools
CLI
The same catalog, quotes and tasks from a terminal, for scripts and batches
Errors
Every error code, what it means and whether retrying helps

