Connect agents and bots
Agents and bots reach your PC through the Idlerate relay. You never point them at your home IP.
Using an assistant bot or another MCP client? Jump to Assistant bots and other MCP clients.
- MCP URL:
https://relay.idlerate.dev/mcp - Auth:
Authorization: Bearer idr_v1_xxxxxxxx_xxxxxxxx(key from the dashboard)
Create a key
- Sign in at relay.idlerate.dev.
- Pair at least one machine (see Machines).
- Open Connect a new agent (or create a key on the Agents section).
- Pick the machine, a label, and the scopes you want. Copy the key — it is shown once.
Default scopes cover listing models, running jobs, reading results, cancelling jobs, and managing keys. You can clear keys:manage before creating the key if the agent should not mint new keys. See Keys.
Never paste a real key into chat, a ticket, or a public gist. If one leaks, revoke it on the dashboard.
MCP setup
Cursor
Put this in ~/.cursor/mcp.json (or your project .cursor/mcp.json):
{
"mcpServers": {
"idlerate": {
"url": "https://relay.idlerate.dev/mcp",
"headers": { "Authorization": "Bearer idr_v1_xxxxxxxx_xxxxxxxx" }
}
}
}
Replace idr_v1_xxxxxxxx_xxxxxxxx with your key. Restart Cursor or reload MCP servers.
Claude Code
In the project .mcp.json (or your Claude Code MCP config):
{
"mcpServers": {
"idlerate": {
"type": "http",
"url": "https://relay.idlerate.dev/mcp",
"headers": { "Authorization": "Bearer idr_v1_xxxxxxxx_xxxxxxxx" }
}
}
}
ChatGPT (custom connectors)
Add a custom connector / MCP server:
- URL:
https://relay.idlerate.dev/mcp - Header:
Authorization: Bearer idr_v1_xxxxxxxx_xxxxxxxx
Exact UI labels vary between ChatGPT apps; any custom connector that supports streamable HTTP MCP with a bearer header works the same way.
GitHub Copilot (VS Code agent mode)
In .vscode/mcp.json for the workspace (or your user MCP config):
{
"servers": {
"idlerate": {
"type": "http",
"url": "https://relay.idlerate.dev/mcp",
"headers": { "Authorization": "Bearer idr_v1_xxxxxxxx_xxxxxxxx" }
}
}
}
GitHub Copilot agent mode in Visual Studio and JetBrains uses the same URL and bearer header when those products support remote MCP with custom headers.
Assistant bots and other MCP clients
Assistant bots and MCP clients that let you add your own connector can use Idlerate too. Pick the option that matches what the connector form asks for.
Before you start, create a key under Connect a new agent (see Create a key). One key works with every machine on your account. Clear keys:manage if the assistant only needs to run models.
Keep the key out of chat and out of files you share or commit. Put it in the client’s secret or credential storage when it has one. If a key ends up in a chat or a repo, revoke it on the dashboard and make a new one.
Option 1: Remote URL and header
Use this when the client takes a server URL and lets you add a custom header.
- URL:
https://relay.idlerate.dev/mcp - Header name:
Authorization - Header value:
Bearer idr_v1_xxxxxxxx_xxxxxxxx
Store the header value as a secret if the client offers that. Transport is streamable HTTP.
Option 2: Local command with mcp-remote
Use this when the client only takes a command to run, or can’t store a secret in a header. The open-source mcp-remote bridge runs locally, talks to the relay over HTTPS, and reads the key from an environment variable. You need Node.js 18 or later on the computer that runs the command.
- Save your key as an environment variable named
IDLERATE_MCP_KEY, using the client’s secret or environment settings. -
Add a local (stdio) connector with this command:
bash -c 'exec npx -y mcp-remote https://relay.idlerate.dev/mcp --header "Authorization:Bearer ${IDLERATE_MCP_KEY}"'Keep the single quotes, so the variable is read when the command starts rather than written into the config.
If the client uses a JSON config with command, args, and env, the same setup looks like this:
{
"mcpServers": {
"idlerate": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://relay.idlerate.dev/mcp",
"--header",
"Authorization:Bearer ${IDLERATE_MCP_KEY}"
],
"env": { "IDLERATE_MCP_KEY": "idr_v1_xxxxxxxx_xxxxxxxx" }
}
}
}
mcp-remote fills in ${IDLERATE_MCP_KEY} itself. Leave out the space after Authorization:; some clients split arguments on spaces.
Test it
After the connector is added, it should show five tools: list_models, run_model, get_status, get_result, and cancel. Then paste:
Use the Idlerate connector. Call list_models and show me each machine with its status and models. Then call run_model with a small model from that list and the prompt "Reply with one word: ready". Wait with get_status (wait_ms 25000) until it finishes, then show me the get_result output. Do not print the API key.
You should see your machines and a one-word answer, usually within a few seconds when the PC is awake. If the tools don’t appear, check the key and the header format. If run_model stays queued, the PC is asleep, paused, or offline. See Troubleshooting.
Agent prompt (paste this)
Use the Idlerate MCP server (https://relay.idlerate.dev/mcp) that is already set up in your connectors. Call list_models. Each machine is a separate card in machines. Call run_model, and pass machine (the device id or the exact name) when the job has to run on one of them. Poll get_status until the job finishes, then get_result. Do not print the API key.
HTTP API (curl)
Any client that can POST JSON to /mcp works. There is no second API. Session flow:
initialize— keep themcp-session-idresponse header.tools/callforlist_models, thenrun_model, and so on.
curl -s -X POST https://relay.idlerate.dev/mcp \
-H "authorization: Bearer idr_v1_xxxxxxxx_xxxxxxxx" \
-H "content-type: application/json" \
-H "accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"example","version":"0"}}}'
Use the returned mcp-session-id on the next calls:
curl -s -X POST https://relay.idlerate.dev/mcp \
-H "authorization: Bearer idr_v1_xxxxxxxx_xxxxxxxx" \
-H "content-type: application/json" \
-H "accept: application/json, text/event-stream" \
-H "mcp-session-id: SESSION_FROM_INITIALIZE" \
-H "mcp-protocol-version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_models","arguments":{}}}'
Tool names and arguments are in Tools reference.
Bots and automations
Slack and Discord bots, cron scripts, and n8n-style workflows can use the same /mcp endpoint over plain HTTP. Call it from your bot’s backend, never from a browser or a client app.
- Create a key with only
models:list,models:run, andjobs:read. Clearkeys:manage. - Store it as a server-side environment variable, for example
IDLERATE_API_KEY. Don’t hard-code it or commit it. - Responses may come back as JSON or as a short
text/event-stream. The example handles both.
Minimal Node.js 18+ example (no dependencies):
// idlerate.mjs — run with: IDLERATE_API_KEY=... node idlerate.mjs
const RELAY_URL = "https://relay.idlerate.dev/mcp";
const KEY = process.env.IDLERATE_API_KEY; // server-side only
let session = null, id = 0;
async function rpc(method, params) {
const headers = {
authorization: `Bearer ${KEY}`,
"content-type": "application/json",
accept: "application/json, text/event-stream",
};
if (session) {
headers["mcp-session-id"] = session;
headers["mcp-protocol-version"] = "2025-06-18";
}
const res = await fetch(RELAY_URL, {
method: "POST", headers,
body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method, params }),
});
session = res.headers.get("mcp-session-id") ?? session;
const text = await res.text();
const json = text.trim().startsWith("{")
? text
: text.split("\n").filter(l => l.startsWith("data:")).map(l => l.slice(5)).pop();
const msg = JSON.parse(json);
if (msg.error) throw new Error(msg.error.message);
return msg.result;
}
async function call(name, args) {
const r = await rpc("tools/call", { name, arguments: args });
if (r.isError) throw new Error(r.structuredContent?.error ?? `${name} failed`);
return r.structuredContent;
}
await rpc("initialize", {
protocolVersion: "2025-06-18", capabilities: {},
clientInfo: { name: "my-bot", version: "1" },
});
const { job_id } = await call("run_model", {
model: "qwen2.5:7b",
prompt: "Summarize this support thread in two sentences: ...",
});
let st;
do { st = await call("get_status", { job_id, wait_ms: 25000 }); }
while (!["succeeded", "failed", "cancelled"].includes(st.status));
if (st.status !== "succeeded") throw new Error(st.error ?? st.status);
let out = "", offset = 0, page;
do {
page = await call("get_result", { job_id, offset });
out += page.output; offset = page.next_offset;
} while (!page.done);
console.log(out);
In a Slack or Discord bot, run this in your event handler after you acknowledge the event, then post out back to the channel. In n8n-style tools, use an HTTP Request node per step with the same headers and bodies. Keep the key in the tool’s credential store.
If the PC is asleep or paused, get_status keeps returning queued. Set your own overall timeout and reply “GPU offline, try later” instead of waiting forever.
Next
- Tools reference — what each tool accepts and returns
- Troubleshooting — connection and job errors