feat: external brain tools — queue, tool_execute, brain_mode_set

CLI can now BE the brain:
- brain_mode_set: switch gateway to external mode
- queue_get: poll incoming player commands
- queue_complete: send response back to player
- tool_execute: call any gateway tool directly (rcon, display, npc, etc.)

28 MCP tools total. When in external mode, Opus in the CLI
processes player commands instead of Codex/Anthropic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code
2026-03-28 20:10:15 -04:00
parent 29a1c4d5bf
commit 8b740f3ec1
+91
View File
@@ -125,6 +125,97 @@ async def gateway_health() -> str:
return f"Error: {e}"
# --- Brain mode + command queue ---
@mcp.tool()
async def brain_mode_set(mode: str) -> str:
"""Switch gateway between internal (AI loop) and external (CLI brain) mode.
In external mode, player commands are queued for YOU to handle.
In internal mode, the gateway's own AI (Codex/Anthropic) handles them.
Args:
mode: "internal" or "external"
"""
try:
data = await _patch(f"/v2/brain-mode?mode={mode}")
return json.dumps(data, indent=2)
except Exception as e:
return f"Error: {e}"
@mcp.tool()
async def queue_get() -> str:
"""Get pending player commands waiting for you to handle.
Only works when brain_mode is 'external'. Returns commands with
player name, mode, message, world context, and player context.
Process each command by calling tools, then complete it with queue_complete.
"""
try:
data = await _get("/v2/queue")
return json.dumps(data, indent=2)
except Exception as e:
return f"Error: {e}"
@mcp.tool()
async def queue_complete(cmd_id: str, response_text: str) -> str:
"""Complete a queued command — sends the response back to the player.
Args:
cmd_id: Command ID from queue_get
response_text: The message to send to the player
"""
try:
data = await _post(f"/v2/queue/complete/{cmd_id}", {
"response_text": response_text,
"player_message": response_text,
})
return json.dumps(data, indent=2)
except Exception as e:
return f"Error: {e}"
@mcp.tool()
async def tool_execute(
tool: str,
params: str = "{}",
player: str = "",
server: str = "dev",
) -> str:
"""Execute a Mortdecai gateway tool directly. YOU are the brain.
Available tools: rcon_execute, rcon_query, display_send, display_interactive,
npc_spawn, npc_bulk_spawn, npc_despawn, npc_bulk_despawn, npc_list,
npc_command, npc_script_write, npc_script_read, eye_players, eye_world,
eye_events, memory_read, memory_write, history_read, logs_read,
sound_play, world_query, schem_list, schem_place, schem_download,
creative_name, perms_manage
Args:
tool: Tool name (e.g. "rcon_execute")
params: JSON string of tool parameters
player: Player context (for session lookup)
server: Server target — dev or prod
"""
try:
tool_params = json.loads(params) if isinstance(params, str) else params
except json.JSONDecodeError:
return f"Invalid JSON params: {params}"
try:
data = await _post("/v2/tools/execute", {
"tool": tool,
"params": tool_params,
"player": player,
"server": server,
})
return json.dumps(data, indent=2)
except Exception as e:
return f"Error: {e}"
# --- Player commands (through gateway) ---