""" MCP tools for Unpredictable Lord game. This module contains all MCP tool functions that are exposed to external LLM clients via the Gradio MCP server. """ import logging import uuid from unpredictable_lord.game_state import ( ADVICE_DESCRIPTIONS, PERSONALITY_DESCRIPTIONS, create_session, execute_turn_logic, get_available_advice, get_session, ) logger = logging.getLogger(__name__) def init_game(personality: str = "cautious") -> dict: """ Initialize a new game session and return the session information. This MCP tool creates a new game session with the specified lord personality. Use the returned session_id for all subsequent game operations. Args: personality: The lord's personality type. Options: "cautious" (risk-averse), "idealist" (emotional idealist), "populist" (popularity-focused). Defaults to "cautious". Returns: dict: Session information including session_id and initial game state. """ session_id = str(uuid.uuid4()) # Validate personality if personality not in PERSONALITY_DESCRIPTIONS: personality = "cautious" # Create game session using game_state module state = create_session(session_id, personality) logger.info( f"New game session created: {session_id} with personality: {personality}" ) return { "session_id": session_id, "message": f"New game started! You are now the advisor to a {personality} lord.", "personality_description": PERSONALITY_DESCRIPTIONS[personality], "available_advice": ADVICE_DESCRIPTIONS, "game_state": state.to_dict(), } def get_game_state(session_id: str) -> dict: """ Get the current game state for a session. This MCP tool retrieves the current state of a game session, including all parameters, turn number, and game status. Args: session_id: The session ID returned from init_game. Returns: dict: Current game state or error message if session not found. """ state = get_session(session_id) if state is None: return { "error": "Session not found", "message": f"No game session found with ID: {session_id}. Please call init_game first.", } return { "session_id": session_id, "game_state": state.to_dict(), "status_summary": state.get_status_summary(), } def list_available_advice() -> dict: """ Get all available advice options that can be given to the lord. This MCP tool returns a list of all possible advice types that can be used with execute_turn(). The Lord AI should interpret the user's free-form suggestion and map it to one of these options. Returns: dict: Dictionary containing all available advice options with their names, descriptions, and expected effects. """ return { "advice_options": get_available_advice(), "usage": "Interpret the user's advice and select the most appropriate option from the list above.", } def execute_turn(session_id: str, advice: str) -> dict: """ Execute a turn with the given advice. This MCP tool is called by the Lord AI after interpreting the user's suggestion. The lord will decide whether to follow the advice based on personality and trust. Args: session_id: The session ID returned from init_game. advice: The advice type to execute. Must be one of: - "increase_tax": Raise taxes (Treasury ↑, Satisfaction ↓) - "decrease_tax": Lower taxes (Treasury ↓, Satisfaction ↑) - "expand_territory": Military expansion (Territory ↑, Treasury ↓, risky) - "improve_diplomacy": Diplomatic efforts (Royal Trust ↑, Treasury ↓) - "public_festival": Hold festival (Satisfaction ↑, Treasury ↓) - "build_infrastructure": Build infrastructure (Population ↑, Treasury ↓) - "do_nothing": Maintain current state Returns: dict: Result containing: - adopted: Whether the lord followed the advice - action_taken: The actual action the lord took - parameter_changes: Changes to game parameters - game_over: Whether the game has ended - new_state: Updated game state """ state = get_session(session_id) if state is None: return { "error": "Session not found", "message": f"No game session found with ID: {session_id}. Please call init_game first.", } result = execute_turn_logic(state, advice) logger.info( f"Turn executed for session {session_id}: advice={advice}, " f"adopted={result.get('adopted')}, action={result.get('action_taken')}" ) return result