Agent Server
revision-sensitive RuneLite UI, packet, or in-game outcomes; treat those as live-client verification pending unless the page records direct evidence.
Agent Server operates as a disabled-by-default n3 plugin. It exposes a localhost-only HTTP API for agent and client development on a Java 11 HttpServer bound to 127.0.0.1. The default RANDOM_TCP mode chooses and persists separate ports in the 20000-60000 range; FIXED_TCP uses the configured ports. The default ON_DEMAND bind mode opens listeners while Break Handler reports an active automation plugin, an observable workflow runs or suspends, or a user-opened connection window remains active. Requests extend the window. After the configured idle interval with no active owner, both listeners close and invalidate sessions, leases, and in-flight operations. ALWAYS provides explicit compatibility. Authentication defaults to GENERATED, which creates a session-only 256-bit bearer token before binding; CONFIGURED requires the secret RuneLite config value to be nonblank, while DISABLED acts as an explicit insecure opt-out.
Security and mutation protocol
Except for GET /api/v1/health, all routes, direct MCP requests, and WebSocket handshakes require Authorization: Bearer <token> when you enable authentication. /ready requires authentication. You can reveal, copy, and rotate generated tokens from the panel. Rotation invalidates sessions, leases, and stream connections. WebSocket query tokens support clients that cannot set headers, but client tooling may record URLs, so prefer bearer headers.
Raw write clients must create a session with POST /api/v1/sessions, explicitly acquire the lease with POST /api/v1/lease/acquire, renew through POST /api/v1/lease/renew, release through POST /api/v1/lease/release, and supply sessionId on every operational write. The server accepts sessionId flexibly from HTTP headers (X-N3-Session-Id, Session-Id, SessionID, X-Session-Id) or request body properties (sessionId, SessionID, session_id). An Idempotency-Key can be supplied via header (Idempotency-Key, X-Idempotency-Key) or body (idempotencyKey, IdempotencyKey, idempotency_key), and defaults to a random UUID if omitted. The lease defaults to 30 seconds and requires renewal every 10 seconds. Session creation skips acquiring it. Use GET /api/v1/lease/status and GET /api/v1/operations/{id} for sanitized status. The stdio bridge performs this protocol automatically and accepts N3_AGENT_SERVER_TOKEN.
Agent Server Architecture & Request Execution Flow
Runtime Model
- Config group:
n3agentserver. - Default endpoint: persisted-random loopback TCP, shown in the Agent Server panel. Fixed mode defaults to
127.0.0.1:17631(HTTP) and127.0.0.1:17632(dashboard stream). - Direct MCP endpoint:
POST /mcpusing Streamable HTTP without SSE.GET /mcpreturns 405. - The sidebar panel shows bind address, port, running state, request count, last error, and plugin-operation availability.
- Read endpoints snapshot live client state on the RuneLite client thread.
GET /api/v1/debug/contextandn3_get_debug_contextreturn one bounded, atomic player/modal/inventory/scene/navigation/trace/error snapshot. Use focused reads when one domain is sufficient.- Gameplay write endpoints route through
Api.actions.*. Idempotent operation records retain theirInteractionResultand skip treating dispatch alone as confirmed success. Plugins needing account settings must declare and enforce their own requirements. - Clients must avoid tight retry loops. Treat
PACEDand failure responses as pacing signals and retry with randomized or backoff behavior. - Plugin operations cover all loaded RuneLite plugins.
PacketUtilsPluginlists as readable but ignores disable commands because it owns shared suite runtime state. /mcpallows missingOriginfor non-browser clients and restricts browser origins to localhost.
JSON Envelopes
Workflow telemetry sits available from authenticated GET /api/v1/workflow/status and direct MCP tool n3_get_workflow_status. The response contains immutable snapshots and bounded transition histories for active and retained-terminal registered workflows.
Read success:
{ "ok": true, "status": "ok", "data": {} }
Write success or failure:
{
"ok": true,
"status": "SUCCESS",
"message": "Queued dialog continue",
"result": { "status": "SUCCESS" }
}
Errors:
{
"ok": false,
"status": "PACED",
"message": "Action pacing is active"
}
Endpoints
OpenAPI JSON. The generated contract checks against the operation catalog and requires every documented operation to exist in the router. Import it into Swagger Editor, ReDoc, or an OpenAPI client generator; use the effective URL shown in the Agent Server panel. The checked-in document uses fixed-mode port 17631 as an illustrative default.
For example, after assigning the panel URL to $agentUrl and copying the generated token:
$agentUrl = "http://127.0.0.1:<effective-port>"
$token = "<generated-token>"
curl.exe "$agentUrl/api/v1/state" -H "Authorization: Bearer $token"
curl.exe -X POST "$agentUrl/api/v1/sessions" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -d '{"clientName":"raw-example"}'
# Response returns {"ok": true, "data": {"sessionId": "<session-id>", ...}}
curl.exe -X POST "$agentUrl/api/v1/lease/acquire" `
-H "Authorization: Bearer $token" `
-H "Content-Type: application/json" `
-H "X-N3-Session-Id: <session-id>"
curl.exe -X POST "$agentUrl/api/v1/walk" `
-H "Authorization: Bearer $token" `
-H "Content-Type: application/json" `
-H "X-N3-Session-Id: <session-id>" `
-H "Idempotency-Key: <uuid>" `
-d '{"x":3222,"y":3222,"plane":0}'
Read endpoints:
GET /api/v1/healthprovides unauthenticated liveness;GET /api/v1/readyprovides authenticated readiness.GET /api/v1/stateGET /api/v1/diagnosticsGET /api/v1/stream/statusGET /api/v1/navigation/statusGET /api/v1/workflow/statusfor active and retained-terminal workflow telemetry.GET /api/v1/login/modesGET /api/v1/login/statusGET /api/v1/widgets/listGET /api/v1/widgets/search?text=...&action=...&limit=...GET /api/v1/widgets/describe?widgetId=...&index=...&action=...returns sanitized listener presence, parent/runtime-index metadata, the selected named-action dispatch mode, and (whenactionexists) the resolved visible action owner without exposing listener arguments or live widget objects.GET /api/v1/inventoryGET /api/v1/playersGET /api/v1/npcsGET /api/v1/objects(player-nearest objects first, then the requested limit)GET /api/v1/ground-itemsGET /api/v1/skillsGET /api/v1/developer/metricsfor a structured developer snapshot including world, player position, skills, inventory, bank state, session/account context, and optional screenshot capture.GET /api/v1/bank/statusfor bank-open status.GET /api/v1/bankfor the bank item snapshot.GET /api/v1/pluginsGET /api/v1/plugins/statusGET /api/v1/plugins/config?className=...GET /api/v1/plugins/configsGET /api/v1/plugins/logs?className=...&limit=...GET /api/v1/menu-entriesGET /api/v1/last-interactionsGET /api/v1/varbit?id=...GET /api/v1/varplayer?id=...GET /api/v1/varbit-changesGET /api/v1/suite/capabilitiesfor the current coverage catalog across REST, direct MCP, SDK docs, typed read/write domains, and read-only SDK helpers.GET /api/v1/sdk/read?method=...for simple allowlisted read-only SDK helper calls. UsePOST /api/v1/sdk/readwhen the helper needs structured arguments.GET /api/v1/worldGET /api/v1/world-mapGET /api/v1/cameraGET /api/v1/line-of-sight?fromX=...&fromY=...&fromPlane=...&toX=...&toY=...&toPlane=...GET /api/v1/item-metadata?itemId=...GET /api/v1/prices?itemId=...GET /api/v1/socialGET /api/v1/progress?quest=...GET /api/v1/recent-eventsGET /api/v1/questhelperGET /api/v1/productionGET /api/v1/minigamesGET /api/v1/loadout/state
Write endpoints:
Tab-dependent writes never prepend an implicit /api/v1/tab/open call. Inventory actions and equip require Inventory visible; unequip requires Equipment; prayer state changes require Prayer; spell writes require Magic; attack-style and auto-retaliate changes require Combat. If the prerequisite is closed, the endpoint returns WIDGET_HIDDEN targeting tab/<TAB_NAME> and dispatches exactly once. Call /api/v1/tab/open or n3_tab_open, observe the selected tab, and then submit the dependent request.
POST /api/v1/widgets/clickwithwidgetId, optional dynamic-childindexfrom widget list/search results, optionalaction/actions, or rawop. Supplyindexwhen multiple live widgets share a packed ID. Prefer named actions; rawopprovides a live-debug escape hatch for actionless widgets, not the default automation style.POST /api/v1/inventory/interactwithname,id, orindex, plus optionalaction/actions.POST /api/v1/dropwithname,id, orindex.POST /api/v1/npcs/interactwithname,id, orindex, plus optionalaction/actions.POST /api/v1/players/interactwith exactname, plus optionalaction/actions.POST /api/v1/objects/interactwithnameorid, plus optionalaction/actions.POST /api/v1/ground-items/pickupwithnameorid, plus optionalaction/actions.POST /api/v1/walkwithx,y, optionalplane, optionalreachedDistance, and optionalcancelOnNewTarget(defaulttrue). Send{"cancel":true}to cancel the active walker path. The endpoint starts or reuses a walker path and stays non-blocking; pollGET /api/v1/statefor progress.POST /api/v1/navigation/previewwithx,y, and optionalplaneto inspect a path without starting movement.POST /api/v1/login/profile/apply,POST /api/v1/login/start, andPOST /api/v1/login/clearmanage memory-only dashboard login profiles. Status responses omit secrets, and login attempts cap out until the profile clears or reapplies.POST /api/v1/bank/open.POST /api/v1/bank/close.POST /api/v1/bank/transactwith anoperationsarray and optionalcloseflag.POST /api/v1/deposit.POST /api/v1/withdrawwithnameorid,amount, and optionalnoted.POST /api/v1/dialogue/continue.POST /api/v1/dialogue/selectwithindexortext.POST /api/v1/dialogue/amountwith positive integeramount.POST /api/v1/dialogue/textwith non-blanktextfor a visible chatbox text input.POST /api/v1/developer/heartbeatwith optionalwebhookUrl,secret, andincludeScreenshotto publish a developer metrics heartbeat payload.POST /api/v1/plugins/enablewithclassName.POST /api/v1/plugins/disablewithclassName.POST /api/v1/plugins/config/setwithclassName,key, andvalue.POST /api/v1/plugins/config/unsetwithclassNameandkey.POST /api/v1/use-item/itemwithsourceId/targetIdorsourceName/targetName.POST /api/v1/use-item/npcwithsourceIdandnpcName.POST /api/v1/use-item/objectwithsourceIdorsourceName, plusobjectName.POST /api/v1/use-item/ground-itemwithsourceIdandgroundItemId.POST /api/v1/sdk/readwithmethodand any helper-specific arguments. Accepts only explicit read-only SDK helper ids; rejects mutating helpers and gameplay actions.POST /api/v1/ge/open,/api/v1/ge/close,/api/v1/ge/collect, and/api/v1/ge/cancel.POST /api/v1/shop/buywithnameorid, plus optionalquantityof1,5,10, or50.POST /api/v1/trade/accept,/api/v1/trade/decline, and/api/v1/trade/offer.POST /api/v1/equipment/equipand/api/v1/equipment/unequip.POST /api/v1/prayer/set,/api/v1/prayer/set-only,/api/v1/prayer/disable-all,/api/v1/prayer/quick-toggle,/api/v1/prayer/quick-open, and/api/v1/prayer/quick-set.POST /api/v1/magic/cast,/api/v1/magic/select, and/api/v1/magic/deselect.POST /api/v1/combat/toggle-spec,/api/v1/combat/set-attack-style, and/api/v1/combat/auto-retaliate.POST /api/v1/tab/open.POST /api/v1/production/choose,/api/v1/production/quantity, and/api/v1/production/amount.POST /api/v1/transport/travelwith a supported transporttypeand destination enum name.POST /api/v1/deposit-box/deposit-all,/api/v1/deposit-box/deposit-equipment,/api/v1/deposit-box/deposit, and/api/v1/deposit-box/close.POST /api/v1/bank-inventory/deposit.POST /api/v1/bank-worn-equipment/deposit-all.POST /api/v1/drop-pattern.
For dynamic widgets, POST /api/v1/widgets/click and n3_click_widget accept visible text plus an optional named action instead of a packed ID. Exact addressing still accepts an optional index alongside widgetId. The exact Grand Exchange Close tuple (widgetId=30474242, index=11, action=Close) uses the shared revision-cached native menu-action route. menu-action-dispatch.md documents resolution and cache behavior.
NPC and object reads accept optional name, radius, interactableOnly, and
limit filters. Direct MCP and the stdio bridge default these reads to 15
tiles, interactable targets, and 10 results. The stdio-only
n3_batch_inspect tool combines up to five common read surfaces in one call.
Tab selection, bank opening, deposit/withdraw inventory changes, dialogue
continue/select, prayer set, and quick-prayer toggle attach bounded observation
data and can promote DISPATCHED to CONFIRMED only after the declared
postcondition is observed. A fresh observation.trace records native transport
evidence; it never substitutes for an unobserved domain postcondition.
Direct MCP Endpoint
/mcp implements MCP Streamable HTTP in non-SSE mode for local agents connecting directly to the RuneLite plugin:
initialize,ping,tools/list, andtools/callreturn JSON-RPC responses withContent-Type: application/json.notifications/initializedand accepted JSON-RPC notifications return HTTP 202 with no body.GET /mcpreturns HTTP 405 because Agent Server omits an SSE stream.- Protocol failures return JSON-RPC errors. Gameplay and business-logic failures return MCP tool results with
isError: trueand structured Agent Server orInteractionResultdetails.
Plugin Operations
Plugin config endpoints restrict to the target plugin config group. set and unset accept only keys belonging to the plugin descriptor or already stored under that plugin group, preventing callers from writing arbitrary cross-plugin config groups.
Plugin logs use a live-buffer only. Agent Server captures recent SLF4J/Logback events while running and filters by the target plugin class/package; it ignores historical RuneLite log files on disk.
MCP Bridge
tools/agent-mcp provides a local MCP stdio bridge for agents supporting tool calls. The MCP process operates outside the RuneLite plugin and respects Agent Server routing. It calls the same localhost HTTP endpoints above and returns the Agent Server JSON envelope as both MCP text content and structured content. It relies on REST APIs for compatibility and separates itself from the direct /mcp endpoint.
Setup:
cd tools\agent-mcp
npm install
npm run build
Example MCP client registration:
{
"mcpServers": {
"n3-agent": {
"command": "node",
"args": ["<repo-root>/tools/agent-mcp/dist/index.js"],
"env": {
"N3_AGENT_SERVER_URL": "http://127.0.0.1:<effective-port>",
"N3_AGENT_SERVER_TOKEN": "<configured-or-generated-token>"
}
}
}
}
The bridge intentionally exposes only REST-backed runtime tools plus its local n3_batch_inspect composition tool. SDK documentation/search tools (search, get_class, get_method, list_packages, list_classes, get_examples, n3_describe_api, n3_search_api_docs, and n3_read_api_doc) live on direct /mcp, bypassing the bridge. Runtime read tools include debug context and the state/stream/navigation/login/developer/widget/scene/plugin/menu/varbit tools plus n3_get_suite_capabilities, n3_read_sdk, n3_get_world, n3_get_world_map, n3_get_camera, n3_get_line_of_sight, n3_get_item_metadata, n3_get_prices, n3_get_social, n3_get_progress, n3_get_recent_events, n3_get_questhelper, n3_get_production, n3_get_minigames, and n3_get_loadout_state. Command tools mirror the matching endpoint, including navigation preview, memory-only login profile apply/start/clear, developer heartbeat, n3_walk, n3_click_widget, n3_interact_inventory, n3_interact_player, dialogue/plugin/config commands, n3_use_item_on_*, GE, shop, trade, equipment, prayer, magic, combat, tab, production, transport, deposit-box, bank-inventory, bank-worn-equipment, and inventory drop-pattern commands.
The MCP bridge creates its session at startup, acquires before its first write, renews every 10 seconds while owning the lease, generates UUID idempotency keys, and releases on clean shutdown. It omits retrying gameplay commands.
Navigation State
GET /api/v1/state includes a navigation object for polling active walks:
activeGoal: requested target point, when one tracks.reachedDistance: accepted radius for awalkNear/Agent Server walk request.pathSize: current tracked path size.state: activeWalkerStatusname orIDLE.distanceToDestination: player distance to the tracked target, or-1when unavailable.playerPosition: current local-player world point when available.activeRequestId,walkerStatus, andwalkerFailureReason: the active Shortest Path request and structured Walker outcome. Idle snapshots reportwalkerStatusasIDLE; the serializer omits nullable active-path fields.requestedTargetandnormalizedTarget: the caller's target and the route planner's executable target.currentStepIndex,totalStepCount,currentStepType,currentStepName,currentStepStart, andcurrentStepEnd: the active route stage and its bounds.execution: queued state, current land destination, last progress position, last decision, stall count, movement attempts, and recovery attempts.recentTelemetry: up to 20 recent Walker decision events in chronological order. After Walker clears its active path, read the terminalstatus,failureReason, request ID, target, position, and decision from this list.
Terminal history does not change operation-ledger convergence. A navigation operation may remain DISPATCHED while recentTelemetry records the Walker domain outcome; callers must inspect navigation state and the retained terminal event instead of treating dispatch as arrival.