Old School Ops

Client Automation API

Letting an AI agent or your own program observe and play a character through the GoMMO client, over MCP or HTTP.

Every game · updated 2026-09-26

The GoMMO client can be driven by a program outside it: Claude Code, Claude Desktop, any other Model Context Protocol client, a Python loop, or curl. The program sees what the character sees and acts through the same actions a client script uses: walk, fight, loot, wear, drink, talk.

Nothing listens unless you start the client with -mcp or -serve.

Starting it

The client is GoMMO_RF.exe (Windows) or GoMMO_RF (Linux), in client-gommo/ of your server download. Copy it and its scripts/ folder into the folder holding your RF_Online.bin, so it can read monster and item names from your client.

You wantRun
Claude Code to playclaude mcp add gommo -- "C:\RF Online\GoMMO_RF.exe" -headless -mcp
Your own program over HTTPGoMMO_RF.exe -headless -serve
To watch while it playsleave out -headless: the window opens and the agent drives the character in it

-headless needs no graphics driver, which is what makes the Linux binary useful on a server.

The client logs in with the account in gommo.ini beside it, or makes a new one on its first run. -login and -password name another. -host and -port pick the server; without them it uses the server in launcher.ini beside it, then this game's default on 127.0.0.1.

Run from outside the RF folder, pass -rf "C:\RF Online" so names resolve. Without it, monsters and items appear as table numbers.

Claude Desktop

Add the client to claude_desktop_config.json:

{
  "mcpServers": {
    "gommo": {
      "command": "C:\\RF Online\\GoMMO_RF.exe",
      "args": ["-headless", "-mcp"]
    }
  }
}

What the agent can do

Ask the client for the list: MCP tools/list or GET /tools, both generated from the build you are running. GoMMO_RF.exe -verbs lists the script verbs the single-action tools come from.

ToolWhat it does
observeEverything at once: position, health, map, the nearest entities with their distances, bag, equipment, skills, chat channels, standing orders, and the event cursor.
eventsWhat happened after a cursor: combat, chat, deaths, respawns, level-ups, players arriving and leaving, map changes, standing-order notices. Pass back next as the next since. wait_seconds blocks until something happens.
walk_to, fight, loot_nearby, equip_bestThe common actions, each run to completion. fight walks to the target first.
attack, use_skill, use_item, pick_up, say, whisper, equip, step_toward, stop, ...One action each, the same as the script verb of that name.
run_luaRuns Lua in the client's script sandbox and returns what it returns. No file or network access.
start_orders, stop_orders, orders_statusStanding orders, below.

An action that returns without an error was sent. Whether it worked is in the next observe or in events: the server decides whether a swing hits or an item can be picked up.

Standing orders

A model takes seconds to answer and a fight moves faster than that. start_orders hands the fast loop to a script that runs in the client, and the agent is told only when it has something to decide.

The default script, default/standing, hunts an area. Its parameters:

ParameterDefault
x, ywhere the character standscentre of the area
radius300how far from the centre it hunts
drink_below0.5health fraction at which it drinks
potionany item named like a potionpart of the name of the item to drink
rest_below0.35health fraction at which it stops and rests
loottruepick up drops after each kill
avoid_playersfalsewalk back to the centre when a player comes into the area
minutes0stop after this long; 0 runs until stopped

It raises these notices in events:

NoticeWhen
diedthe character died; it has respawned
player_neara player entered the area (once per player)
area_emptyno monster in the area for 30 seconds
out_of_potionsit needed to drink and had nothing
doneminutes ran out
reconsultevery reconsult_seconds (default 60), with health and position

Pass script to run another script as orders, or source for inline Lua. Your script reads its parameters with params() and raises a notice with notify("reason", details). Starting new orders replaces running ones; stop_orders stops them and halts the character.

HTTP

-serve listens on 127.0.0.1:47800; -serve-addr picks another loopback address. It refuses any address that is not on this machine.

Each start writes a new token to automation.token beside the client. Every request carries it:

curl -H "Authorization: Bearer $(cat automation.token)" http://127.0.0.1:47800/observe
Request
GET /observethe observe snapshot
GET /toolsevery tool with its JSON Schema
GET /events?since=N&wait_seconds=Sthe events tool
GET /stream?since=Nthe same events as a Server-Sent Events stream; reconnect with Last-Event-ID
POST /act{"tool": "fight", "args": {"seconds": 20}} runs any tool
POST /lua{"source": "return vitals()"}
GET / POST / DELETE /ordersorders status, start, stop

A request with a wrong or missing token gets 401. A request whose Host is not localhost or 127.0.0.1 gets 403, so a web page cannot reach the API through a rebound DNS name.

For server operators

A client under -mcp or -serve declares itself as scripted when it logs in, the same as one running a script. ALLOW_SCRIPTED_CLIENTS in settings.cfg decides whether your server accepts it; see Refusing scripted clients. A modified client can leave the declaration out, so the setting is a stated policy, not a detection.

Something here wrong?

Out of date, incomplete, or assuming something it should not. Documentation errors are bugs, and this one arrives tagged and pointed at this page.

Loading…
Open the full search page