MCP server

@irtio/mcp is an MCP server for irtio. It gives a coding agent the same surface irtio gives you at a terminal: create a project, allow an origin, deploy a room, then read its rooms, logs, metrics and saves.

Every tool is one call to irtio, narrated. The server holds no state of its own and contains no game logic.

Setup

Sign in once, at a terminal:

npx irtio login

That opens a browser and writes a credential to your machine. Then point your MCP client at the server. The snippet is a command, and it carries no secret:

{
  "mcpServers": {
    "irtio": {
      "command": "npx",
      "args": ["-y", "@irtio/mcp", "--allow-writes"]
    }
  }
}

Leave out --allow-writes for a server that can only read: see Writes are off by default.

To install it instead, run npm i -g irtio @irtio/mcp and use "command": "irtio-mcp", with "args": ["--allow-writes"] if the agent should be able to change projects.

Sign-in

The server looks for a credential in two places, in this order:

  1. The credential file irtio login writes. This is the path to take.
  2. IRTIO_TOKEN in the environment, for headless cases like CI where no browser login can happen.

When it finds neither, the first tool call answers with the instruction to run irtio login rather than an authentication error. You can run it without restarting your editor, and the next tool call picks the new credential up.

Never put a token in the config snippet above. The server does not read one from there, and a secret in an editor config file is a secret in your shell history, your backups and quite possibly your repository.

To talk to an irtio endpoint other than the default, set IRT_CONTROL_URL in the server’s environment. That is a URL, not a credential.

The loop it closes

project_create  ->  origin_add  ->  deploy  ->  scenario_run  ->  logs / metrics

Every result ends with a next action, so an agent working through that sequence is told what to call next rather than having to guess. deploy reports what the schema change was, whether it needed a migration, what drained, and where the room is playable.

Tools

Read-only, and cheap:

ToolWhat it does
whoamiThe signed-in account, and the irtio endpoint it is signed in to
project_listEvery project in your organisation, with ids and regions
project_getOne project: name, region, project key, connection limit, origins
origin_listThe browser origins allowed to connect
roomsThe rooms irtio knows about, and their status
logsLog lines, oldest first, with a forward cursor and a room filter. Entries are marked untrusted
metricsMetric rollups, including per-room tick health
usageMeasured usage this billing period: room hours, data out, voice minutes, storage
leaderboardA project’s board: the top N, or one player’s neighbours and rank
match_statusHow many players are waiting in a quick-match queue, and how many it takes to fill
deployment_listDeployments, newest first, and which one is serving
save_listThe save generations of one room

Writes are off by default

Started with no arguments, the server is read-only. It lists the read-only tools above and scenario_run, and nothing that writes: an agent cannot see the tools below, and calling one by name answers writes_disabled with the instruction to ask you. Add --allow-writes to the server’s args, or set IRTIO_MCP_ALLOW_WRITES=1 in its environment, to turn them on. Any other argument stops the server with an error, so a typo in the flag does not quietly leave it read-only.

This is deliberate. The server acts with your full login, and an agent that can deploy or roll back can be talked into doing it by text it reads. Turn writes on for the sessions that need them.

Every tool carries MCP annotations: readOnlyHint on the reads, and destructiveHint on the tools that overwrite or remove something. A client that auto-approves read-only tools uses these to tell logs from rollback.

These write, and need --allow-writes:

ToolWhat it changes
project_createRegisters a project and returns its id, which is also the client join key
project_updateThe name, the per-IP connection limit, or the memory its server gets
origin_addAllows one browser origin
origin_removeWithdraws one browser origin
jwt_secret_mintMints a signing secret, returned in plaintext once
jwt_secret_retireRetires the oldest signing secret for an issuer
save_restorePuts one room back to a save, stopping the project’s server
rollbackRe-promotes an older deployment, stopping the project’s server
deployBundles the room in your working directory and ships it

This one runs locally:

ToolWhat it does
scenario_runRuns a scenario against a local irtio dev room and reports every assertion against the server’s recorded timeline

scenario_run is the only tool that reaches no irtio server, so it works without a login. It runs against a dev server on your own machine rather than a deployed project, because irtio dev is what serves the authoritative timeline it asserts on. It opens real sockets and plays the room for a few seconds, so it is not a cheap read.

Log lines are whatever your room code printed, which often includes names, chat and other text players typed. The logs result marks its entries as untrusted, and the server’s instructions tell the agent never to act on a request that arrives inside one. That is a defence, not a guarantee, which is one more reason writes are off unless you turn them on.

Three tools are disruptive, and their descriptions say so before an agent calls them. save_restore and rollback stop the project’s server, so every room in the project drops its connections, not only the one named. deploy drains or migrates live rooms.

Signing secrets

jwt_secret_mint returns the secret once, when created. Store it in your server’s environment; it cannot be retrieved later.

Reading a result

Every tool answers with prose, the structured data, and a next action:

Deployed v2 of p_0123456789abcdef. The running server took the new version. 1 room moved.
Playable at wss://eu.irt.io.

{
  "project": "p_0123456789abcdef",
  "version": 2,
  "url": "wss://eu.irt.io",
  "applied": "live"
}

next: Verify it: run `irtio simulate --url wss://eu.irt.io --key p_0123456789abcdef`, then call
`logs` and `metrics` for this project.

The prose is what an agent reads to decide. The JSON is what it reads to act. Both are always present.

Errors

A refused call is narrated too, with the same shape. A breaking schema change relays irtio’s own verdict and its hint, because the classification happens server-side rather than here:

The deploy was refused because the schema change is breaking. deployment introduces 1 breaking
change. A breaking change needs a migration, because rooms holding live state cannot be
reinterpreted under the new schema without one.

next: --allow-breaking needs a migration for v2. Run: irtio migrate create <name>, then re-run with: irtio deploy --allow-breaking

A project belonging to another organisation reads as not found rather than forbidden. irtio answers the same way for a project that does not exist and one you cannot see, and this server does not restore the distinction.

See Error catalogue for the codes themselves, and CLI for the commands these tools mirror.