MCP server.
Connect Claude Code, Claude Desktop, Cursor, or anything else that speaks the Model Context Protocol, directly to your GPU.ai account. Thirty-five tools in three tiers: 23 free and read-only, seven writes that take a single confirmation, and five money tools gated behind a price you have to see and confirm.
With it connected, the agent can look up GPU types and live prices, provision instances, deploy application templates, start fine-tuning jobs, run chat completions, manage SSH keys and webhook endpoints, watch what is running, and terminate it when the work is done, without you leaving the editor and without pasting anything into a dashboard.
It is a local stdio server: your client spawns it as a subprocess and talks JSON-RPC to it over stdin/stdout. Nothing is hosted, nothing is proxied, and your API key never leaves your machine: the server calls https://api.gpu.ai/v1 directly, exactly as the CLI and the SDKs do.
§ 20.1Install¶
The server is published to npm as @gpuai/mcp and runs on Node 22 or newer:
npx -y @gpuai/mcp@latestYou do not normally run that by hand; your MCP client runs it for you, using the configuration in the next section. There is nothing to install globally and no separate npm install step: npx fetches the package on first launch and caches it.
§ 20.2Client setup¶
The API key is passed only through the environment block of your client's MCP configuration. It is never a command-line flag: arguments show up in ps output and shell history, and a credential does not belong in either.
§20.2.1Claude Code¶
Create .mcp.json in your project root, or edit the existing one:
{
"mcpServers": {
"gpuai": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@gpuai/mcp@latest"],
"env": {
"GPUAI_API_KEY": "${GPUAI_API_KEY}"
}
}
}
}Claude Code expands ${GPUAI_API_KEY} from your shell environment when it spawns the server, so the key stays out of the file and out of version control. Export it once in your shell profile:
export GPUAI_API_KEY=gpuai_live_...Claude Code can also write this entry for you with claude mcp add. Restart the session afterwards, then ask the agent to check gpu_auth_status: if the key is wired correctly it comes back with your spend envelope.
§20.2.2Claude Desktop¶
Claude Desktop launches servers with a minimal environment and does not expand shell variables or inherit your shell profile, so the value is written literally:
{
"mcpServers": {
"gpuai": {
"command": "npx",
"args": ["-y", "@gpuai/mcp@latest"],
"env": {
"GPUAI_API_KEY": "gpuai_live_..."
}
}
}
}The file lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. Restart the app after editing it.
Any other MCP client works the same way: a command, its arguments, and an environment block carrying GPUAI_API_KEY. Cursor's mcp.json uses the same mcpServers shape as Claude Code.
§ 20.3Authentication¶
GPUAI_API_KEY | Required. The API key the server authenticates with. |
GPUAI_API_BASE | Optional. Base URL override for a custom, self-hosted or staging endpoint. Defaults to https://api.gpu.ai/v1. |
Mint a key in the dashboard. It is the same key the gpu CLI uses, so one export covers both tools.
The server fails fast, and offline. At startup it checks only that the key is present and that a base-URL override is a valid absolute http(s) URL. It makes no network call at boot, so a flaky connection can never look like a bad key, and a bad key surfaces as a clear “check GPUAI_API_KEY” message on the first tool call rather than as a mysterious startup failure.
The key is never echoed. It is not returned by any tool, not written into any error message, and not included in a confirmation prompt. Every error string the server produces passes through a redaction step first, so even an API response that echoed a credential back would be scrubbed before you saw it.
§20.3.1Use a dedicated key¶
Mint a separate API key for agent use rather than reusing the one in your CI or your laptop's shell profile. Two concrete benefits: independent revocability (if anything looks wrong you revoke that one key and the agent stops, while your pipeline and your own CLI keep working) and clean attribution, so “what did the agent spend” is answerable.
If the agent only needs to look things up, mint a read_only key. All 23 free tools work with one, and the twelve guarded tools (seven writes, five money tools) structurally cannot be called with it. The API rejects the write before the request reaches provisioning. One free tool needs no credential at all: gpu_health_get is an unauthenticated liveness probe, which is what makes it useful for telling an outage apart from a bad key.
There is also no “who am I” endpoint on the public API, and this server does not invent one. gpu_auth_status proves your key works and shows your spend envelope; it does not report an account identity.
§ 20.4Base URL¶
GPUAI_API_BASE overrides the API base URL for custom, self-hosted or staging endpoints. Leave it unset and every call goes to production:
"env": {
"GPUAI_API_KEY": "${GPUAI_API_KEY}",
"GPUAI_API_BASE": "https://api.internal.example.com/v1"
}- Unset always means production. There is no hidden non-production default. A tool that silently pointed at the wrong environment would look like it was working while touching the wrong account and the wrong invoice.
- The guardrail does not relax on a non-production base URL. Quote, confirm, execute applies identically wherever you point it. There is no “it's only staging” path through the confirmation.
§ 20.5The confirmation contract¶
Every tool sits in exactly one of three tiers, and membership decides what the server does before the tool is allowed to run: reads are free, writes confirm once, money tools quote a price and require explicit confirmation. None of that is advisory: the confirmation lives in each tier's own wrapper, so a tool cannot be added to a guarded tier without it.
| Free, read-only23 tools | Nothing happens first. No confirmation, no charge, no mutation. These work with a read_only key and never count against the inference budget. |
| Writes, single confirmation7 tools | One confirmation. The server describes exactly what will change and returns a single-use token; nothing happens until you confirm. There is no price line, because nothing is billed. |
| Money tools5 tools | A price. Four of the five quote and confirm every call; chat completions confirm a session budget once and then run inside it. |
§20.5.1Money tools: quote, confirm, execute¶
Five of the thirty-five tools can create a charge or destroy something you are paying for. Four of them, create and deploy and fine-tune and terminate, go through the same two-call handshake, and it is the server that enforces it, not the tool description, and not the agent's judgment. A client that ignored every hint the server publishes still could not reach a charge without a confirmation. The fifth, gpu_chat_completion, is metered per call and uses the session-budget shape described below.
- The agent calls the tool. Nothing is provisioned. The server resolves your request against live pricing (including the region, and including
"auto"GPU selection, so what gets priced is a specific machine) and returns a price summary plus a single-use confirmation token. No write is made. - You see the price.
2x h100_sxm (on_demand) in us-west-2 at $4.98/hr, with the 24-hour estimate and a reminder that it keeps billing until terminated. If capacity is not currently available at that configuration, or the figure is derived rather than quoted, the summary says so instead of quietly implying a launch will succeed. - You say yes. The agent calls the tool again with the token and the same parameters. Only then does anything get created.
The token is single-use, short-lived, and bound to the parameters that were quoted. Confirming with anything changed (a different GPU count, a different tier, a different instance id) does not execute; it re-quotes at the new price and asks again. So an approval cannot be carried over onto a bigger machine than the one you priced.
- One confirmation covers one call. The next create asks again.
- A pre-authorization given before the price existed does not count. Telling the agent up front to skip the questions unlocks nothing: the token is minted by the quote, and there is no quote until the price has been looked up.
- Hardware is always explicit. GPU type, count (1–8) and tier are required fields with no defaults. An omission is a rejected call, not a silent decision. Auto-selection is available on template deploys, but only by passing the literal
"auto"(a choice, not a forgotten field). - A confirmed launch cannot cost more than the number you approved. When you set no price ceiling, the quoted price (an estimated one included) becomes the ceiling, so the API itself refuses to place above the number you approved. A request that cannot be priced at all is refused outright rather than quoted. The one exception is a custom
disk_gb: extra disk folds into the hourly rate, so no automatic ceiling is applied there. Setmax_price_per_houryourself to bound those launches. - Known-impossible launches are refused at quote time. Three specific conditions are checked before a confirmation is ever requested: an instance launch (create or template deploy) from an account with no SSH keys, an
ssh_key_idsentry that does not exist, and a fine-tuning base model that is not in the catalog. Fine-tuning runs no SSH pre-flight; its key attachment is org-scoped and checked at execution. Checks the platform can only run at execution (a fine-tuningtraining_fileid, a catalog model's fine-tune eligibility, per-key attach settings) still fail after confirmation, without billing, and the quote says which is which. When a pre-flight read itself fails, the quote proceeds rather than refusing: "could not check" is never treated as "checked and bad". - A failed call is never silently retried. A create that errored may have partially provisioned; the agent is told to report it and re-confirm rather than risk double billing.
- Fine-tuning is capped, not quoted. A training job has no fixed price (it bills for as long as it runs), so
gpu_fine_tuning_createrequiresmax_budget_usd. That cap is the number that bounds the job. Passing0means no cap, and should only ever be a decision you made out loud. - Every money quote shows what the session has already spent. Both kinds of quote, a provisioning price and a chat session budget, end with one line covering inference spend this session, provisioning spend this session, and your organization's month-to-date total read from the ledger. A confirmed launch books one hour of its quoted rate into that session total: the minimum just committed to, not an extrapolation. If the ledger read fails the line says so and the quote still stands, because the guardrail never depends on it.
Where a client supports MCP elicitation, the server asks you directly in that client's own UI. Support for this is uneven and many clients, including scripted and CLI-driven ones, do not advertise it, so the flow you will normally see is the two-call handshake with the agent relaying the quote. Both paths run through the same enforcement; elicitation is nicer UX on top of it, never a replacement for it.
§20.5.2Writes: one confirmation, no price¶
Seven tools change account state without billing anything: creating and deleting SSH keys and webhook endpoints, cancelling a fine-tuning job, renaming an instance, and lowering the spending limit. No charge is not no consequence, and an agent acting on injected instructions does not need a billable route to do damage. So writes get the same machinery as the money tools with the price line replaced by a consequence sentence: the first call changes nothing and returns a summary plus a single-use, parameter-bound token; the second call carrying that token executes. One confirmation covers one call, a pre-authorization given before the change was described does not count, and a failed call is reported rather than silently retried.
- Adding an SSH key is an access decision, not paperwork. The confirmation for
gpu_ssh_keys_createstates that an SSH key grants persistent access to provisioned instances: anyone holding the matching private key can log in to any instance it is attached to, for as long as it stays attached. - Creating a webhook endpoint is an egress decision. The confirmation for
gpu_webhooks_createstates that GPU.ai sends event data to that URL every time a subscribed event fires, so whoever controls the URL can read the account activity it describes. Event types are always explicit, never inferred. - The webhook signing secret is shown exactly once. It is returned by the create call and by nothing else: no later read includes it, and no endpoint can fetch it back. A lost secret means deleting the endpoint and creating a new one, which issues a new secret that anything verifying deliveries has to be updated with.
- Deleting an SSH key does not revoke access already granted. It stops the key being attached to new instances. Machines already provisioned with it keep it in their own
authorized_keys, which this call does not touch. - Renaming is rename-only.
gpu_instances_updatetakes a display name and rejects any other field rather than ignoring it, so “cannot resize, move or restart anything” is a parse failure rather than a promise in a description.
§20.5.3Inference: a session budget, not a prompt per call¶
gpu_chat_completion bills per call by token, and a typical call costs a fraction of a cent. Quoting and confirming every one of them would put a prompt in front of every message, which is the friction that gets a guardrail switched off entirely. It uses a different shape instead: approve once, run many, ask again at the wall.
- The first call in a session runs nothing. It returns a session budget quote, $1.00 by default, plus a single-use confirmation token. Propose a different figure with
session_budget_usd, which accepts $0.01 to $100: the number is chosen by the agent and merely displayed to you, and a large figure buried in quote text is exactly what click-through misses. A larger allowance is still reachable, one approved slice at a time. - Confirming approves the budget and runs that call.
- Calls inside the budget then run immediately: no quote, no token, no prompt.
- Two things re-open the question. A single call estimated above the $0.10 per-call ceiling is confirmed on its own even with plenty of headroom, and a budget spent to its limit sends the next call back to a fresh budget quote rather than running it.
The ceiling is checked before the budget gate, deliberately: were it the other way round, an oversized call arriving in a session with no budget yet would surface as “needs a budget”, you would approve an ordinary $1 session, and the oversized call would then execute having never been confirmed on its own.
- Estimate, then reconcile. Before a call runs its worst case is reserved against the budget: the prompt is sized at roughly four characters per token, the completion side is priced at the
max_tokensbound (default 1024) rather than a guess at what the model will emit, and both are priced from the model's own published rates (input_per_1m_tokens_cents/output_per_1m_tokens_cents, fetched per call rather than from a rate table baked into the package, which would go stale silently). After the call, the reservation is replaced by what was actually billed from the response's usage. - A failed call releases its estimate. A request that never billed gives its reservation back, so a run of transient errors cannot shrink your budget by money nobody was charged.
- The wall is evaluated on actual settled spend, not on estimates. A window whose real spend has reached the limit is closed even if in-flight estimates suggest headroom.
- The budget covers inference only. Provisioning and fine-tuning keep their own per-action price confirmation and are not charged against it; gating the same dollars twice would exhaust a chat budget on spend that was never inference. Read-only tools never count against it either.
- “Session” means one server process. The budget lives in the server's memory and does not survive a restart, because your approval did not.
- A model with no published per-token pricing is refused, not priced at zero. An unpriceable call is exactly the call that must not slip through. Models metered per image or per second of video are not chat models.
- Streaming is not available. A tool result is a complete value, and the usage block reconciliation depends on arrives at the end.
§20.5.4Spending limits are lower-only¶
gpu_spending_limit_get reads your organization's monthly cap, optional daily cap, spend against each, and what remains. It is free and read-only. gpu_spending_limit_update can only make the limit more restrictive:
- Decreases only. Anything that is not a strict decrease is refused before a confirmation exists, at quote time, so no token is ever minted for it. A raise is structurally unconfirmable rather than confirmable-but-discouraged, because raising a ceiling is the setup for spending under it.
- Clearing the daily cap counts as a raise and is refused too; it is not even expressible in the tool's schema.
- Setting a cap where none exists is allowed, as is putting a monthly limit on an organization that has none: both are strictly more restrictive, which is the only direction this tool moves in.
- Enforcement mode is preserved. The API has no partial update, so the tool re-sends your organization's current enforcement mode and auto-terminate setting with the decrease. A limit change can never silently flip an org into a mode that stops running instances.
- Even a decrease needs org-admin. That is an account-role gate, not a key scope: a 403 here means asking an admin, not rotating the key.
§ 20.6Tool reference¶
§20.6.1Free, read-only (23)¶
None of these mutate anything, none cost money, and all of them work with a read_only key.
gpu_auth_status | Verifies the configured key and reports the account's spend envelope: monthly limit, spend this month and today, what remains. Call it first. Never returns the key, and reports no identity. |
gpu_types_list | Available GPU types with memory and specifications. Resolves “something with lots of VRAM” into an exact type before anything is priced. |
gpu_pricing_list | Hourly prices and live availability per GPU type, region and tier (on_demand; spot is currently unavailable sitewide and returns no rows). Prices are per instance-hour and cover every GPU in the instance. |
gpu_instances_list | Your organization's instances. Terminated ones are excluded unless asked for. This is the “what is currently billing” tool. |
gpu_instances_get | One instance by id: status, hardware, region, hourly price, and SSH connection details once it is running. |
gpu_operations_get | Polls a long-running operation by id: the handle returned by create, deploy and terminate. |
gpu_ssh_keys_list | Your registered SSH keys, by name and fingerprint, so a launch can attach one. Never returns private key material. |
gpu_usage_get | Historical usage bucketed by hour, day, week or month, optionally grouped by instance or GPU type. Answers “what have I spent”. |
gpu_templates_list | The curated application templates that can be deployed onto an instance, with the hardware each one needs. |
gpu_models_list | Models available on the serverless inference API, optionally filtered by modality. Also the source of base models available for fine-tuning. |
gpu_fine_tuning_get | One fine-tuning job by id. This is the poll surface for fine-tuning: a job carries its own status and does not produce an operation id. |
gpu_fine_tuning_list | Your fine-tuning jobs, newest first. Finds a job id, and answers “is anything still running and therefore still billing”. |
gpu_fine_tuning_events_list | The progress events for one fine-tuning job: where a failed job explains itself, before anyone speculates about the cause. |
gpu_models_get | One serverless model by id: modality, context window, and per-token pricing (input_per_1m_tokens_cents / output_per_1m_tokens_cents). Not comparable to the per-hour instance prices. |
gpu_templates_get | One application template by id, including the hardware it requires, so a deploy quote's GPU type and count come from the template rather than a guess. |
gpu_environments_list | The launch environment catalog: certified frameworks and their versions, what each includes, and the raw VM image options. Exactly the values the environment field accepts. |
gpu_ssh_keys_get | One registered SSH key by id: name, fingerprint, public key. Confirms the key about to be attached is the one you hold the private half of. |
gpu_webhooks_list | Your webhook endpoints with their URLs and subscribed event types. The signing secret is never included in a listing. |
gpu_webhooks_get | One webhook endpoint by id. The signing secret is not returned here and cannot be retrieved by any read: it is shown once, at creation. |
gpu_spending_limit_get | Your organization's monthly cap and optional daily cap, the spend against each, and what remains. No limit configured is a normal result, not an error. |
gpu_deposits_list | Your stablecoin deposits, newest first, with the current minimum deposit. Answers “did my funding arrive”. Read-only: this server cannot create a deposit. |
gpu_deposits_get | One deposit by id: its status, the amount, and how much has been credited so far. |
gpu_health_get | Liveness probe for the API. Needs no authentication, so it tells a platform outage apart from a problem with your key. |
§20.6.2Writes, single confirmation (7)¶
Each one changes account state, costs nothing, and still takes an explicit confirmation: the first call describes the change and returns a single-use token, the second call executes it. No price is quoted, because nothing is billed.
gpu_ssh_keys_createRequiresname, public_key | Registers an SSH public key on the account. The confirmation states that this grants persistent access to provisioned instances. Only ever add a key the user handed you. |
gpu_ssh_keys_deleteRequiresssh_key_id | Removes a key so it can no longer be attached to new instances. Does not revoke access on instances already provisioned with it: their authorized_keys are untouched. |
gpu_webhooks_createRequiresurl, event_types | Registers a URL for event delivery. The confirmation states that GPU.ai sends event data to this URL. The signing secret is returned once, here, and never again. |
gpu_webhooks_deleteRequireswebhook_endpoint_id | Stops deliveries to an endpoint. Its signing secret goes with it: a replacement endpoint gets a new one, and anything verifying deliveries has to be updated. |
gpu_instances_updateRequiresinstance_id, name | Renames an instance. Display name only; any other field is a parse error rather than an ignored one. Billing, state and connection details are untouched. |
gpu_fine_tuning_cancelRequiresfine_tuning_job_id | Cancels a fine-tuning job, stopping it and its GPU. This is how a running job stops billing. At a zero balance it returns 402 and the job keeps running: see the caveat above. |
gpu_spending_limit_updateRequiresmonthly_limit_dollars | Lowers the monthly limit, and optionally sets or lowers the daily cap. Decreases only: a raise is refused before a confirmation exists. Requires org-admin. |
§20.6.3Money tools (5)¶
The first four quote a price and require an explicit confirmation for every call. gpu_chat_completion confirms a session budget once and then runs inside it, with a per-call ceiling on top.
gpu_instances_createRequiresgpu_type, gpu_count (1–8), tier | Provisions a GPU instance. Asynchronous: returns an operation id immediately. |
gpu_instances_deployRequirestemplate_id, gpu_type (or "auto"), gpu_count, tier | Deploys a curated template onto a newly provisioned instance. The same billable provisioning as a create, with a template attached. |
gpu_fine_tuning_createRequiresmodel, training_file, method, gpu_type, max_budget_usd | Submits a LoRA/QLoRA fine-tuning job against a curated base model. Bills per GPU-hour for as long as it runs. |
gpu_instances_terminateRequiresinstance_id | Terminates an instance and stops its billing. Destructive and irreversible: data not copied off is gone. The confirmation shows what will be destroyed and what it currently costs. |
gpu_chat_completionRequiresmodel, messages | Runs a chat completion against a served model, metered per token. Gated by a session budget ($1.00 by default, settable up to $100) and a $0.10 per-call ceiling rather than a confirmation per message. Not streamed. |
§ 20.7Provisioning is asynchronous¶
A confirmed create or deploy never blocks. It returns an operation id immediately, as the first line of the response, and the agent is instructed to report that id to you straight away. It is the only handle on a request that may already be spending money, and a call that dies mid-flight must not take the id with it.
- Poll
gpu_operations_getwith that id, on a backoff: 2s after the first call, increasing by 1s each time to a maximum of 10s. Terminal states aresucceeded,failedandcancelled; anything else means keep going. This is the same cadence the CLI uses. - On
failed, check for leftovers. A failed provision can still leave a running, billing instance. The tool descriptions tell the agent to list instances and terminate anything billable left behind, but it is worth knowing that is the expected recovery, not an exception. - Nothing stops on its own. Billing starts when the instance runs and continues until
gpu_instances_terminatesucceeds. Terminate, then verify: list instances afterwards and confirm.
Provisioning capacity can take around fifteen minutes on slow-boot hardware. allocating means capacity is still being acquired, starting means the machine exists and is booting, and running means it is ready.
§ 20.8Related¶
- The gpu CLI: the same capabilities from a terminal.
- TypeScript SDK and Python SDK: the typed clients underneath.
- Endpoint reference: every /v1 endpoint the tools wrap.