diff --git a/agent/claude_wrapper.py b/agent/claude_wrapper.py index 2518c36c..33aa1198 100644 --- a/agent/claude_wrapper.py +++ b/agent/claude_wrapper.py @@ -54,6 +54,27 @@ async def ask_claude(message: str, session_id: str) -> ClaudeResult: if not Path(CLAUDE_CWD).is_dir(): raise ClaudeError(f"CLAUDE_CWD does not exist: {CLAUDE_CWD}") + # Whitelist only our MCP tools so Claude Code can call them without + # human approval. Names follow the convention mcp____. + # We deliberately omit built-in tools (Bash, Write, Edit, Read, etc.) + # — the assistant doesn't need them for live-state Q&A and they'd be a + # security/permissions footgun on an unattended service. + allowed_tools = ",".join( + [ + "mcp__overlord__get_live_players", + "mcp__overlord__get_recent_rares", + "mcp__overlord__query_telemetry_db", + "mcp__overlord__get_player_state", + "mcp__overlord__get_inventory", + "mcp__overlord__get_inventory_search", + "mcp__overlord__get_combat_stats", + "mcp__overlord__get_equipment_cantrips", + "mcp__overlord__get_quest_status", + "mcp__overlord__get_server_health", + "mcp__overlord__suitbuilder_search", + ] + ) + args = [ CLAUDE_BIN, "-p", @@ -61,6 +82,11 @@ async def ask_claude(message: str, session_id: str) -> ClaudeResult: session_id, "--output-format", "json", + "--allowed-tools", + allowed_tools, + # Auto-approve any tool that's in --allowed-tools. + "--permission-mode", + "bypassPermissions", ] logger.info(