MCP server
rent.dev is an MCP server as well as a REST API. An agent that speaks MCP gets the same account, sandboxes and payments as 32 tools, and a second endpoint with no login for prices, the provider catalog, docs and signup.
https://mcp.rent.dev/ mcpTwo endpoints
| Endpoint | Credentials | Tools |
|---|---|---|
https://mcp.rent.dev/mcp | An API key or an OAuth access token. | 32: the provider catalog, funds, sandboxes, GPU pods and the account. |
https://mcp.rent.dev/mcp/public | None. | rent_quote, rent_list_providers, rent_search_docs, rent_signup, rent_supply_guide |
rent_list_providers answers with the catalog as compact summaries: each provider's capabilities, whether an agent can drive it, and the cheapest hourly price among its matching offerings. The whole catalog, with each row's region, source and date, is on the catalog page. A listed provider may be unpriced: its terms may permit display but not comparison, no price row may match the filters, or its rows may carry no hourly figure.
Both are stateless Streamable HTTP. Every request is a POST, there is no session to open or keep, and any other method answers 405.
Connect a client
{
"mcpServers": {
"rent": {
"url": "https://mcp.rent.dev/mcp",
"headers": {
"Authorization": "Bearer rent_sk_…"
}
}
}
}No key yet? Call rent_signup on the public endpoint. It answers the key once, with this endpoint's URL and the header to send. Pass idempotency_key, a random value you keep, to be able to repeat the call without making a second account.
curl -s https://mcp.rent.dev/ mcp/ public \
-H "Content-Type: application/ json" \
-H "Accept: application/ json, text/ event-stream" \
-H "MCP-Protocol-Version: 2025-11-25" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/ list","params":{}}'The answer comes back as JSON or as an event stream with one message.
Authentication
/mcp takes the credentials the REST API takes: Authorization: Bearer rent_sk_…, X-API-Key, or an OAuth access token issued for the resource https://mcp.rent.dev/mcp. Without one it answers 401, with a WWW-Authenticate challenge that points at the protected-resource metadata (RFC 9728).
Each tool checks its scope before it runs. An API key has every scope but supply, so the partner supply tools need an OAuth token that carries it; an API key gets a forbidden result from them. An OAuth token that lacks a scope gets a 403 insufficient_scope challenge naming the scope to ask for.
A request that carries a browser Origin must come from this server's origin, from the site's, or from localhost when the endpoint itself is local. Any other origin answers 403.
Protocol versions
The server speaks MCP 2026-07-28: server/discover, and the client's version, capabilities and name in each request's _meta. A client on an earlier revision negotiates with initialize; these are accepted: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07.
A tools/list answer may be kept for 5 minutes (ttlMs). The list does not change within a deploy.
A typical session
rent_quote: what a task costs.rent_get_balance, andrent_topupwhen it is short.rent_create_sandbox.rent_exec, orrent_start_processfor work that outlasts one call.rent_terminate_sandbox.
Tools on /mcp
| Tool | What it does | Scope | Hints |
|---|---|---|---|
| rent_list_providers | List providers | none | read-only, idempotent |
| rent_quote | Quote sandbox prices | none | read-only, idempotent |
| rent_get_balance | Get the balance | billing | read-only, idempotent |
| rent_topup | Top up the balance | billing | open world |
| rent_create_sandbox | Create a sandbox | sandbox | open world |
| rent_get_sandbox | Get a sandbox | sandbox | read-only, idempotent |
| rent_list_sandboxes | List sandboxes | sandbox | read-only, idempotent |
| rent_exec | Run a command | sandbox | destructive, open world |
| rent_start_process | Start a background process | sandbox | destructive, open world |
| rent_get_process_output | Read process output | sandbox | read-only, idempotent, open world |
| rent_run_code | Run code in a kernel | sandbox | destructive, open world |
| rent_read_file | Read a file | sandbox | read-only, idempotent, open world |
| rent_write_file | Write a file | sandbox | destructive, idempotent, open world |
| rent_get_port_url | Get a port URL | sandbox | read-only, idempotent |
| rent_extend_sandbox | Extend a sandbox | sandbox | idempotent, open world |
| rent_pause_sandbox | Pause a sandbox | sandbox | idempotent, open world |
| rent_resume_sandbox | Resume a sandbox | sandbox | idempotent, open world |
| rent_terminate_sandbox | Terminate a sandbox | sandbox | destructive, idempotent, open world |
| rent_create_gpu_pod | Create a GPU pod | gpu | open world |
| rent_list_gpu_pods | List GPU pods | gpu | read-only, idempotent, open world |
| rent_terminate_gpu_pod | Terminate a GPU pod | gpu | destructive, idempotent, open world |
| rent_set_byok_credential | Store a vendor key | keys | open world |
| rent_get_usage | Get usage | billing | read-only, idempotent, open world |
| rent_get_operation | Get an operation | none | read-only, idempotent |
| rent_supply_guide | Read the provider guide | none | read-only, idempotent |
| rent_supply_enroll | Enrol nodes | supply | none |
| rent_supply_nodes | List your nodes | supply | read-only, idempotent |
| rent_supply_node | Get a node | supply | read-only, idempotent |
| rent_supply_update_node | Change a node | supply | idempotent |
| rent_supply_probe_node | Probe a node now | supply | open world |
| rent_supply_revoke_node | Revoke a node | supply | destructive, idempotent, open world |
| rent_supply_earnings | Get your earnings | supply | read-only, idempotent |
rent_list_providers
Lists rent.dev's provider catalog as compact summaries: each provider's capabilities (offerings, pricing types, interfaces, auth and product capabilities), display-only summary_verdict, agentic flag, the provenance of its cheapest matched offering and that offering's price row. Read-only and anonymous on /mcp/public. A listed provider may be unpriced: its terms may permit display but not comparison (clause names that denial and its prices are withheld), no price row may match the filters, or its rows may carry no hourly figure (a GPU row then gives unpriced_reason: monthly_rate, no_time_unit or unknown_gpu_count; a per-unit row has usd and unit but no hourly figure). include_offerings carries every matching offering, not just the cheapest. use asserts a rights use on providers and figures (default display). limit caps providers only. Every offer carries covers, gpu.count, region_id and comparison_group: the group names the purchasable unit (GPU model, count, market, pricing type, canonical region and commitment), so two offers are price-comparable exactly when their groups match. region accepts the vendor's label or the canonical id; gpu_count, covers and figure narrow the grain.
rent_quote
Dollars per completed task for rent.dev's own sandboxes beside every published-rate vendor, by workload profile, plus hourly GPU rows. Defaults: all three profiles, 2 vCPU, 4096 MiB. A quote is a price list, not a reservation; it holds nothing.
rent_get_balance
Your prepaid balance in micro-USD (1 USD = 1,000,000): total, held by running sandboxes, and available, and whether the account is frozen.
rent_topup
method "card": answers a pay link for a person (valid 24 hours; Stripe Checkout, no API key needed). On clients that take URL elicitation the link is shown to the person first, then the tool answers it. method "x402": charges USDC over MCP with x402. The first call answers isError with the PaymentRequired object (amount = credits + 5.5%; sign within its maxTimeoutSeconds, 120 s); retry the same call with the PaymentPayload in _meta["x402/payment"]. The paid call settles, credits, and answers the SettleResponse in _meta["x402/payment-response"]. The balance shows card payments once Stripe confirms them; check with rent_get_balance.
rent_create_sandbox
Starts a Linux sandbox (a Firecracker microVM) and holds its cost from your balance; it is charged by the second while it runs. Waits up to wait_s for placement and answers the sandbox; past that it answers an operation id (op_…) to poll with rent_get_operation, whose response is the sandbox. The sandbox id (lse_…) lives until rent_terminate_sandbox or the timeout (default 300 s). A short balance answers 402 insufficient_balance with a card pay link (valid 24 hours) and an x402 top-up URL. Arguments not listed here go to the REST route as they are, which refuses them by name.
rent_get_sandbox
One sandbox by id: state (requested, placing, running, paused, settling, terminated, failed), template, size, timeout_at, port-URL domain, and what it has been charged and holds.
rent_list_sandboxes
Your sandboxes, newest first. By default every state but terminated and failed; state picks one. next_cursor is opaque and only for the next call of this tool.
rent_exec
Runs a shell command (/bin/bash -l -c) in a running sandbox and answers when it exits: stdout, stderr, exit_code (null when killed by the timeout), timed_out. timeout_s defaults to 50, so the answer comes back inside common client tool timeouts. For work that runs longer (servers, builds, training), start it with rent_start_process and read its output with rent_get_process_output. Arguments not listed here go to the REST route as they are, which refuses them by name.
rent_start_process
Starts a command in the background and answers at once with its process id. The process id is valid while the sandbox runs; read its output with rent_get_process_output. The process ends with the sandbox. Arguments not listed here go to the REST route as they are, which refuses them by name.
rent_get_process_output
Output of a background process after a cursor, whether it still runs, and its exit code. Omit cursor to read from the start; pass the answer's cursor back unchanged to read only newer output. Cursors and process ids are valid while the sandbox runs.
rent_run_code
Runs code on the Jupyter kernel of a code-interpreter-v1 sandbox and answers its rich results (text, images as base64, …), stdout, stderr and error. State persists between calls in one context_id; a context lives as long as the sandbox. timeout_s defaults to 50. Arguments not listed here go to the REST route as they are, which refuses them by name.
rent_read_file
Reads a file from a running sandbox. Without encoding the content comes back as UTF-8 text when it is valid UTF-8, else as base64.
rent_write_file
Writes a file in a running sandbox, creating parent directories and replacing what is there. content is UTF-8 text, or base64 with encoding base64.
rent_get_port_url
The public HTTPS URL of a port in the sandbox (https://{port}-{sandbox}.{domain}). It serves while the sandbox runs and something listens on the port.
rent_extend_sandbox
Sets a running sandbox to stop timeout_s seconds from now (at most 86400), holding the added cost first on the key that started it; a short balance answers 402 with top-up links. An API key with a spend limit cannot extend a sandbox another key started (403 forbidden).
rent_pause_sandbox
Pauses a running sandbox, keeping its memory and files; the id stays valid and rent_resume_sandbox continues it.
rent_resume_sandbox
Resumes a paused sandbox with a new timeout (default 300 s), holding its cost first on the key that started it; a short balance answers 402 with top-up links. An API key with a spend limit cannot resume a sandbox another key started (403 forbidden).
rent_terminate_sandbox
Ends a sandbox now, deleting its memory and files, and settles its charge. Terminating an ended sandbox answers it unchanged. The id keeps answering rent_get_sandbox.
rent_create_gpu_pod
Starts a GPU pod on RunPod with your own RunPod key (store it with rent_set_byok_credential, vendor runpod). RunPod bills your key by the hour until rent_terminate_gpu_pod; no rent.dev balance is used. The pod id (lse_…) lives until it is terminated. Arguments not listed are refused by name.
rent_list_gpu_pods
Your GPU pods, newest first, every state. next_cursor is opaque and only for the next call of this tool.
rent_terminate_gpu_pod
Ends a GPU pod on RunPod, deleting its container disk, and stops RunPod's billing. Terminating an ended pod answers it unchanged.
rent_set_byok_credential
Stores your own vendor key (BYOK) for e2b and vercel sandboxes or runpod GPU pods, after one read-only call to the vendor checks it. The secret is an argument of this call; it is stored sealed and never returned. fields: e2b {api_key}, vercel {token, team_id, project_id}, runpod {api_key}. The credential id (cred_…) stays valid until you delete it (DELETE /v1/byok/credentials/{id}). An API key with a spend limit cannot store one (403 forbidden): use an uncapped key or a signed-in person.
rent_get_usage
Usage over a period (default the last 30 days): what rent.dev billed for its own sandboxes, beside showback of BYOK usage your vendors bill you for.
rent_get_operation
A long-running operation by id (op_… or operations/op_…), as tools answer them for work that outlasts a call (sandbox placement, x402 settlement). Poll about every 2 s until done; then exactly one of response (the finished resource) or error (a Problem). The id stays readable after it is done.
rent_supply_guide
The guide for providers who run rent.dev nodes, as Markdown: the two ways to run a node, every step with its exact command, each node state and what to do next, every check with its fix, every problem, rates and the holdback. Read it before rent_supply_enroll. Needs no scope, and the public endpoint serves it too.
rent_supply_enroll
Makes claim tokens for new nodes, one per node, each valid for 10 minutes and shown only in this answer. lines holds the exact shell line for each token: run it on the machine and the node kit sets the machine up, claims the node, links it and reports each step. The token reaches the kit on stdin, never as a process argument. On a host the claim comes after the install, and a first install can outlast the token: when the line ends with claim_invalid, call this tool again and run the same line with the new token. That run is quick, because the host is already set up. A refusal carries retryable, owner_action_required and next; run next.command after next.after_s seconds.
rent_supply_nodes
Your nodes, newest claim first, each with its state, checks and next step. next_cursor is only for the next call of this tool.
rent_supply_node
One of your nodes: state, wire, region, ask, capacity, templates, checks with their fixes, suspension reasons, placement and setup timings. next names the one command to run and when; poll this until next.action is none.
rent_supply_update_node
Changes a node's ask, capacity, region or payout. A new ask applies to leases placed from now on; running leases keep their rates. More slots or a new region sends the node back to probing. Changing payout needs signed_nonce: a nonce from GET /v1/accounts/nonce, signed with your account's agent key over the message rent.dev payout v1\n<node_id>\n<nonce>\n<public_key> (four lines joined by newlines, no newline at the end). A refusal carries retryable, owner_action_required and next; run next.command after next.after_s seconds.
rent_supply_probe_node
Makes the node's next probe due now, and takes a suspended node back to probing. The probe starts within about a minute. Read the outcome with rent_supply_node. A probe already running is refused with probe_in_progress. A refusal carries retryable, owner_action_required and next; run next.command after next.after_s seconds.
rent_supply_revoke_node
Takes a node out for good: it gets no new leases and its link is removed. A revoked node cannot come back; enrol the machine again for a new node. Revoking a revoked node answers it unchanged. A refusal carries retryable, owner_action_required and next; run next.command after next.after_s seconds.
rent_supply_earnings
What your nodes have earned: pending, releasable, frozen and paid-out totals in micro-USD, and one page of entries, newest first. A lease shows once it settles, never while it runs. An entry becomes releasable after the holdback, which is longer when the customer paid by card. next_cursor is only for the next call of this tool.
Tools on /mcp/public
| Tool | What it does | Scope | Hints |
|---|---|---|---|
| rent_quote | Quote sandbox prices | none | read-only, idempotent |
| rent_list_providers | List providers | none | read-only, idempotent |
| rent_search_docs | Search the rent.dev docs | none | read-only, idempotent |
| rent_signup | Sign up | none | none |
| rent_supply_guide | Read the provider guide | none | read-only, idempotent |
rent_search_docs
Keyword search over the sections of rent.dev's full docs (llms-full.txt): each hit is one section, best first, with its heading path and Markdown. The docs are re-read every five minutes.
rent_signup
Creates a rent.dev account and answers its API key, shown this once (store it; it stays valid until revoked), with the authenticated MCP URL and the Authorization header to connect with, and a three-line REST quickstart. To be able to retry, pass idempotency_key, a random value you keep (a UUID will do): if the answer is lost, call again with the same value within 24 hours and you get the same account with a new API key that replaces the first, not a second account. That holds while the account is untouched (its key never used, nothing bound to it, no money in); after that the repeat is refused with idempotency_key_reused and answers no key. Without idempotency_key every call creates a new account. The account starts with a zero balance: a call that needs credit answers 402 with a card pay link and an x402 top-up, or use rent_topup on the authenticated server.
Results and errors
A tool answers its value as structuredContent, and as the same JSON in a text block. A refusal is an isError result whose content is the Problem the REST API would have answered, with its code. The codes are listed on the errors page.
Paying from inside a tool call
When a call needs more credit, the Problem is a 402 with topup.checkout_url and topup.x402_url. A 2026-07-28 client that takes URL elicitation is handed the pay link as an input request instead, and the call runs again once the person has answered.
rent_topup with method: "card" answers a pay link for a person, valid 24 hours. With method: "x402" it charges USDC over MCP:
- The first call answers
isErrorwith the x402 PaymentRequired object as its structured content. - Sign it within 120 seconds and call again with the same arguments and the PaymentPayload in
_meta["x402/payment"]. - The paid call settles, credits the balance and answers the settlement in
_meta["x402/payment-response"].
A payment that is broadcast but not yet confirmed answers an operation instead. Poll it with rent_get_operation.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "rent_topup",
"arguments": {
"method": "x402",
"amount_usd": "5.00"
},
"_meta": {
"x402/payment": "<PaymentPayload>"
}
}
}