Liquid MCP server

The exchange runs a Model Context Protocol (MCP) server. Add it to an agent, and the agent can look up models and prices, preview a purchase, read your balance and buy answers.

To add it, run liquid mcp claude or follow Connect. Tools that buy charge your balance and need a spend key.

Use the server while you build. In an application, call the REST API.

Connect

The server is at https://router.inference.ai.exchange/mcp. It uses the Streamable HTTP transport and keeps no session.

There are two ways to sign in:

Sign in with your browser

Only an owner or admin of the workspace can approve a key. The page shows where the browser goes next. Approve only if you started the request from that app.

The key that the client gets:

The box is unticked for a client that asks for mcp:read, and ticked for mcp:spend. You decide either way.

The Liquid CLI

The Liquid CLI adds the server in one step. Use claude, codex, cursor or opencode. A liquid claude or liquid opencode session has it already.

liquid mcp claude

Claude Code

claude mcp add --transport http liquid https://router.inference.ai.exchange/mcp
claude mcp login liquid

You can also run /mcp in a session, select liquid, and choose Authenticate.

Codex CLI

codex mcp add liquid --url https://router.inference.ai.exchange/mcp
codex mcp login liquid

Run the login on the machine where Codex runs, because Codex receives the code on http://127.0.0.1.

Cursor

Add this to ~/.cursor/mcp.json, then sign in from the MCP settings.

{
  "mcpServers": {
    "liquid": { "url": "https://router.inference.ai.exchange/mcp" }
  }
}

OpenCode

Add this to ~/.config/opencode/opencode.json. OpenCode starts the sign-in when the server answers 401, or when you run opencode mcp auth liquid.

{
  "mcp": {
    "liquid": {
      "type": "remote",
      "url": "https://router.inference.ai.exchange/mcp",
      "enabled": true
    }
  }
}

Claude Desktop and Claude on the web

The exchange is not in the connector directory, so add a custom connector.

  1. Open Customize → Connectors, and choose Add custom connector. On a Team or Enterprise plan, an owner first adds it in Organization settings → Connectors, and each member then chooses Connect.
  2. Set the name to Liquid Inference and the server URL to https://router.inference.ai.exchange/mcp. Leave the OAuth client ID and secret empty.
  3. Choose Add, then Connect, and approve the request in your browser.

Use a key

A key with the spend scope can buy answers. A key that can only view the market can use the other tools. See API keys. Export the key once:

export LIQUID_API_KEY=sk-liquid-...

Claude Code

claude mcp add --transport http liquid https://router.inference.ai.exchange/mcp \
  --header "Authorization: Bearer $LIQUID_API_KEY"

Codex CLI

Add this to ~/.codex/config.toml.

[mcp_servers.liquid]
url = "https://router.inference.ai.exchange/mcp"
bearer_token_env_var = "LIQUID_API_KEY"

Cursor and OpenCode

Use the config from above and add the key:

Tools

Each tool calls the REST endpoint of the same name in the API reference, with the same key rules, rate limits and billing.

Tools that read

These tools need any key, unless the table says read.

Tool What it does Key
list_models Lists the models that the exchange serves now. any
get_model Gets one model card: context window, features, prices. any
compare_models Compares two to five models. Takes models. any
get_book Lists the resting offers. any
get_markets Gets the providers and offers for each model. any
get_routers Lists router models, such as liquid.auto. any
get_fills Lists the newest settled jobs of a model. It never names a buyer. any
get_volume Gets the tokens and jobs per model, router and preset. any
get_throughput Gets the measured speed of each provider and model. any
get_lifetime Gets the jobs settled and tokens processed in all. any
count_tokens Estimates input tokens. Takes prompt, system. any
dry_run Previews a purchase and buys nothing. See Preview a purchase. any
get_video Gets the status of a video job. See Video. any
get_balance Gets the workspace balance. read
get_limits Gets what the key can spend: grade, balance, spend limit and the part used. read
get_job Gets the receipt of one job. read
list_receipts Lists the jobs of the workspace, newest first. read

list_models and get_book take kind, max_price_usd, limit and offset (see Find a model). get_volume and get_throughput take days (1 to 90). list_receipts takes limit, cursor, and model and outcome as comma-separated lists.

Tools that buy

These tools charge the balance. They need a spend key.

Tool What it buys Arguments
send_message One answer. See Buy an answer. See that section.
generate_image One to ten images. model, prompt; optionally n, size, quality, output_format, references
generate_speech Spoken audio. model, input, voice; optionally response_format (mp3, opus, aac, flac, wav or pcm), speed, references
create_video A video job. It returns the job ID. model, prompt; optionally seconds (at most 20), size, callback_url, references
transcribe A transcript of an audio file. model, audio_base64; optionally language, prompt, response_format, max_usd_per_second
decide Answers to typed questions. state, questions; optionally model, orderings
embed Vectors for one text or up to 2,048 texts. model, input; optionally dimensions, encoding_format

Every tool that buys also takes cap_usd and the purchasing controls.

Preview a purchase

Call dry_run before send_message. It shows the estimated charge and the winning offer. It places no job and holds no funds.

Argument Meaning
model The model to preview.
input_tokens Default 4,000.
max_output_tokens Default 1,000.
cap_usd, task, tools Optional. task is general or coding.

kind previews a job that is not chat. Send the size of the job with it:

kind Size
image_generation n (default 1), optionally size.
audio_speech characters, optionally voice (default alloy).
video_generation Optionally seconds and size.
audio_transcription seconds of audio.
embedding Optionally inputs (default 1) and dimensions. input_tokens sizes each text.
decision questions, optionally orderings (default 4). input_tokens sizes the situation.

Find a model

Kind Unit of max_price_usd
text A million output tokens
embedding, decision A million input tokens
Other kinds One image, character or second

Buy an answer

send_message charges the balance by the tokens used. cap_usd is the most that the job can cost. An offer with a higher worst case does not compete.

The reply has the answer, the usage and the exchange block with the job ID and charge.

send_message takes model and a prompt, messages or both. Optional arguments:

Group Arguments
Input system, image_urls (https or data:image URLs), attachments
Sampling temperature, top_p, top_k, min_p, repetition_penalty, frequency_penalty, presence_penalty, seed, logit_bias, stop
Output logprobs, top_logprobs, reasoning_effort, response_format (text, json_object or a JSON schema object), max_tokens
Tools tools, tool_choice
Cost and retry cap_usd, idempotency_key

When the model calls a tool, the reply has tool_calls. The server does not run them. To continue, send the assistant turn with its tool_calls, then a tool turn with the result.

To retry a call that timed out without a second purchase, send the same idempotency_key. Every tool that buys takes it. The job runs to its end even when the client leaves, so a retry without a key can buy twice.

Other buying tools

decide

decide calls POST /v1/systemone. See the Decisions API.

embed

embed calls POST /v1/embeddings and charges per input token. Vectors are floats, so keep the list short.

transcribe

transcribe charges for each second of audio.

Images and speech

generate_image and generate_speech return the media and the exchange block.

Media and references

create_video, generate_image and generate_speech take references. generate_image and create_video also take reference_image_urls.

Argument Meaning
image_url create_video only. An https or data:image address. The video starts from this frame.
reference_image_urls Images that the output should keep.
references The full form: a list of {type: "image", url}, {type: "audio", data, format}, {type: "video", url} and {type: "file", file_data, filename}.
callback_url create_video only. An https address that the exchange calls when the job ends.

Video

get_video takes video_id and optionally wait_seconds (up to 300), include_file and chunk. A completed job also returns:

For a larger file, open download_url. If there is no link, send chunk (0, 1, and so on). Each chunk is 1 MB as base64, and the reply states chunk_count. A file can be at most 64 MB this way. Send include_file as false to get the status and the link only.

Purchasing controls

The tools that buy, and dry_run, take the x-liquid-* header controls as arguments. A value that cannot be read is a tool error, and nothing is charged.

Argument Header Value
retention x-liquid-retention none keeps only offers whose provider does not retain the content. allowed is the default.
ttft_ms x-liquid-ttft-ms The most time to the first token, in milliseconds.
tag x-liquid-tag A label for the spend. At most 63 letters, digits, dots, dashes and underscores.
rules x-liquid-rules An object with other rules of the exchange block, such as exchange.privacy.regions. It cannot set exchange.candidates.models.allow or exchange.rank.strategy.

Reference

Resources and prompts

A resource read needs the same key as its tool. liquid://models, book, markets, routers, balance and lifetime hold the data of the tools with those names. liquid://models/{model}, liquid://book/{model}, liquid://markets/{model} and liquid://fills/{model} hold the data for one model. liquid://jobs/{job_id} holds one receipt.

completion/complete gives model IDs for model and models, and recent job IDs for job_id.

Three prompts write a request and buy nothing: find_cheapest (task, optionally max_usd), audit_spend (optionally days) and compare_models (models).

Widgets

A client that supports MCP Apps shows a widget under some results. The tool names it in _meta.ui.resourceUri. A widget has no button that buys.

Each widget is ui://liquid/<name>: models, model, book, receipts, job, markets, fills, account (get_balance, get_limits), image, speech, video (create_video, get_video) and dry-run. The name follows the tool, such as book for get_book.

The widgets are resources with the media type text/html;profile=mcp-app. The server offers the io.modelcontextprotocol/ui extension.

Results and progress

A result holds the data as text and as structuredContent. A list is the object { "items": [...] }. A failed tool has no structuredContent.

get_video with wait_seconds checks the job until it completes, fails or the time ends. For a notifications/progress message at each check, the client must send _meta.progressToken and accept text/event-stream. A refusal for the grade of the key then arrives as a tool error, not a 403.

The server does not use elicitation. When a purchase is refused with a proposed_retry, the result says to ask the person.

Tool errors

A failed tool returns a result with isError set. It holds the HTTP status and the error body of the endpoint. See Errors.

How the sign-in works

This section is for people who build a client.

  1. A request to /mcp without a key returns 401 with a WWW-Authenticate header. It names the resource metadata (RFC 9728) at /.well-known/oauth-protected-resource/mcp.
  2. That metadata names the authorization server (RFC 8414, /.well-known/oauth-authorization-server).
  3. The client identifies itself in one of two ways.
    • Metadata document. The client_id is the https address of a JSON document, and the server metadata sets client_id_metadata_document_supported to true.
      • The address must have a path, no query or fragment, no port, and a public host name.
      • The document must name its own address as client_id, list redirect_uris, and use token_endpoint_auth_method none. It must be at most 8 KB with a JSON content type.
      • The exchange reads it at sign-in. It follows no redirect and refuses a host in its own network.
    • Registration. The client registers at the registration_endpoint (RFC 7591). All clients are public: token_endpoint_auth_method is none.
      • Each redirect_uri must use https, http on localhost, 127.0.0.1 or [::1], or an app scheme.
      • An app scheme is a reverse-DNS name (it has a .) or one of claude, cursor, goose, vscode, vscode-insiders, windsurf and zed.
  4. The client opens the authorization_endpoint with response_type=code, code_challenge_method=S256 and a state. PKCE is required. A resource (RFC 8707) must be the address of the MCP server or the router origin, or the exchange returns invalid_target.
  5. The scope is mcp:read, mcp:spend, or both. mcp:spend includes reading. Any other scope gets invalid_scope. With no scope, the client asks for mcp:read. The token response names the scope that the person granted, which can be less.
  6. Each redirect to the client, success or error, carries iss (RFC 9207). The client must compare it with the issuer that it recorded and refuse a code on a mismatch.
  7. The client sends the code to the token_endpoint with the code_verifier. The response has the key as access_token, with token_type Bearer and expires_in in seconds. There are no refresh tokens.

The /mcp route refuses a browser request with an Origin that is not the exchange or a loopback address.

A code works one time and ends after 5 minutes. If a client sends a code twice, the exchange revokes the key that the first request got. A wrong code_verifier uses up the code.

Asking for more access

A 401 carries scope="mcp:read" in WWW-Authenticate. If a key cannot do what a tool needs, the server answers 403 with error="insufficient_scope" and the needed scope, such as scope="mcp:spend". The JSON body still has the tool error.