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 want | Run |
|---|---|
| Claude Code to play | claude mcp add gommo -- "C:\RF Online\GoMMO_RF.exe" -headless -mcp |
| Your own program over HTTP | GoMMO_RF.exe -headless -serve |
| To watch while it plays | leave 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.
| Tool | What it does |
|---|---|
observe | Everything at once: position, health, map, the nearest entities with their distances, bag, equipment, skills, chat channels, standing orders, and the event cursor. |
events | What 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_best | The 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_lua | Runs Lua in the client's script sandbox and returns what it returns. No file or network access. |
start_orders, stop_orders, orders_status | Standing 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:
| Parameter | Default | |
|---|---|---|
x, y | where the character stands | centre of the area |
radius | 300 | how far from the centre it hunts |
drink_below | 0.5 | health fraction at which it drinks |
potion | any item named like a potion | part of the name of the item to drink |
rest_below | 0.35 | health fraction at which it stops and rests |
loot | true | pick up drops after each kill |
avoid_players | false | walk back to the centre when a player comes into the area |
minutes | 0 | stop after this long; 0 runs until stopped |
It raises these notices in events:
| Notice | When |
|---|---|
died | the character died; it has respawned |
player_near | a player entered the area (once per player) |
area_empty | no monster in the area for 30 seconds |
out_of_potions | it needed to drink and had nothing |
done | minutes ran out |
reconsult | every 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 /observe | the observe snapshot |
GET /tools | every tool with its JSON Schema |
GET /events?since=N&wait_seconds=S | the events tool |
GET /stream?since=N | the 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 /orders | orders 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.