Skip to main content

Agent Server

Verification boundary

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) and 127.0.0.1:17632 (dashboard stream).
  • Direct MCP endpoint: POST /mcp using Streamable HTTP without SSE. GET /mcp returns 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/context and n3_get_debug_context return 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 their InteractionResult and 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 PACED and failure responses as pacing signals and retry with randomized or backoff behavior.
  • Plugin operations cover all loaded RuneLite plugins. PacketUtilsPlugin lists as readable but ignores disable commands because it owns shared suite runtime state.
  • /mcp allows missing Origin for 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/health provides unauthenticated liveness; GET /api/v1/ready provides authenticated readiness.
  • GET /api/v1/state
  • GET /api/v1/diagnostics
  • GET /api/v1/stream/status
  • GET /api/v1/navigation/status
  • GET /api/v1/workflow/status for active and retained-terminal workflow telemetry.
  • GET /api/v1/login/modes
  • GET /api/v1/login/status
  • GET /api/v1/widgets/list
  • GET /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 (when action exists) the resolved visible action owner without exposing listener arguments or live widget objects.
  • GET /api/v1/inventory
  • GET /api/v1/players
  • GET /api/v1/npcs
  • GET /api/v1/objects (player-nearest objects first, then the requested limit)
  • GET /api/v1/ground-items
  • GET /api/v1/skills
  • GET /api/v1/developer/metrics for a structured developer snapshot including world, player position, skills, inventory, bank state, session/account context, and optional screenshot capture.
  • GET /api/v1/bank/status for bank-open status.
  • GET /api/v1/bank for the bank item snapshot.
  • GET /api/v1/plugins
  • GET /api/v1/plugins/status
  • GET /api/v1/plugins/config?className=...
  • GET /api/v1/plugins/configs
  • GET /api/v1/plugins/logs?className=...&limit=...
  • GET /api/v1/menu-entries
  • GET /api/v1/last-interactions
  • GET /api/v1/varbit?id=...
  • GET /api/v1/varplayer?id=...
  • GET /api/v1/varbit-changes
  • GET /api/v1/suite/capabilities for 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. Use POST /api/v1/sdk/read when the helper needs structured arguments.
  • GET /api/v1/world
  • GET /api/v1/world-map
  • GET /api/v1/camera
  • GET /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/social
  • GET /api/v1/progress?quest=...
  • GET /api/v1/recent-events
  • GET /api/v1/questhelper
  • GET /api/v1/production
  • GET /api/v1/minigames
  • GET /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/click with widgetId, optional dynamic-child index from widget list/search results, optional action/actions, or raw op. Supply index when multiple live widgets share a packed ID. Prefer named actions; raw op provides a live-debug escape hatch for actionless widgets, not the default automation style.
  • POST /api/v1/inventory/interact with name, id, or index, plus optional action/actions.
  • POST /api/v1/drop with name, id, or index.
  • POST /api/v1/npcs/interact with name, id, or index, plus optional action/actions.
  • POST /api/v1/players/interact with exact name, plus optional action/actions.
  • POST /api/v1/objects/interact with name or id, plus optional action/actions.
  • POST /api/v1/ground-items/pickup with name or id, plus optional action/actions.
  • POST /api/v1/walk with x, y, optional plane, optional reachedDistance, and optional cancelOnNewTarget (default true). Send {"cancel":true} to cancel the active walker path. The endpoint starts or reuses a walker path and stays non-blocking; poll GET /api/v1/state for progress.
  • POST /api/v1/navigation/preview with x, y, and optional plane to inspect a path without starting movement.
  • POST /api/v1/login/profile/apply, POST /api/v1/login/start, and POST /api/v1/login/clear manage 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/transact with an operations array and optional close flag.
  • POST /api/v1/deposit.
  • POST /api/v1/withdraw with name or id, amount, and optional noted.
  • POST /api/v1/dialogue/continue.
  • POST /api/v1/dialogue/select with index or text.
  • POST /api/v1/dialogue/amount with positive integer amount.
  • POST /api/v1/dialogue/text with non-blank text for a visible chatbox text input.
  • POST /api/v1/developer/heartbeat with optional webhookUrl, secret, and includeScreenshot to publish a developer metrics heartbeat payload.
  • POST /api/v1/plugins/enable with className.
  • POST /api/v1/plugins/disable with className.
  • POST /api/v1/plugins/config/set with className, key, and value.
  • POST /api/v1/plugins/config/unset with className and key.
  • POST /api/v1/use-item/item with sourceId/targetId or sourceName/targetName.
  • POST /api/v1/use-item/npc with sourceId and npcName.
  • POST /api/v1/use-item/object with sourceId or sourceName, plus objectName.
  • POST /api/v1/use-item/ground-item with sourceId and groundItemId.
  • POST /api/v1/sdk/read with method and 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/buy with name or id, plus optional quantity of 1, 5, 10, or 50.
  • POST /api/v1/trade/accept, /api/v1/trade/decline, and /api/v1/trade/offer.
  • POST /api/v1/equipment/equip and /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/travel with a supported transport type and 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, and tools/call return JSON-RPC responses with Content-Type: application/json.
  • notifications/initialized and accepted JSON-RPC notifications return HTTP 202 with no body.
  • GET /mcp returns 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: true and structured Agent Server or InteractionResult details.

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.

GET /api/v1/state includes a navigation object for polling active walks:

  • activeGoal: requested target point, when one tracks.
  • reachedDistance: accepted radius for a walkNear/Agent Server walk request.
  • pathSize: current tracked path size.
  • state: active WalkerStatus name or IDLE.
  • distanceToDestination: player distance to the tracked target, or -1 when unavailable.
  • playerPosition: current local-player world point when available.
  • activeRequestId, walkerStatus, and walkerFailureReason: the active Shortest Path request and structured Walker outcome. Idle snapshots report walkerStatus as IDLE; the serializer omits nullable active-path fields.
  • requestedTarget and normalizedTarget: the caller's target and the route planner's executable target.
  • currentStepIndex, totalStepCount, currentStepType, currentStepName, currentStepStart, and currentStepEnd: 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 terminal status, 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.