Skip to main content
Glama

update_room_config

Update room configuration in the lobby by providing any subset of settings. Resets both players' ready flags to ensure agreement on new config. Fails if game is already in progress.

Instructions

Host-only: tweak room config while still in the lobby.

Only fields passed (non-None) are updated. Any change resets both seats' ready flags — if readiness was previously agreed upon, the config shift might change the deal. Fails outside the pre-game states (COUNTING_DOWN, IN_GAME, FINISHED).

── Locking ── Input validation + scenario load happen OUTSIDE state_lock (pure I/O). The actual config mutation + readiness reset happen atomically under state_lock.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
connection_idYes
scenarioNo
team_assignmentNo
host_teamNo
fog_of_warNo
max_turnsNo
turn_time_limit_sNo

Implementation Reference

  • The actual implementation of the update_room_config tool. It is an async MCP tool registered via @mcp.tool() decorator. Validates input (scenario, team_assignment, host_team, fog_of_war, max_turns, turn_time_limit_s) outside the state lock, then atomically mutates the RoomConfig under state_lock. Also resets both seats' ready flags and recomputes room status.
    @mcp.tool()
    async def update_room_config(
        connection_id: str,
        scenario: str | None = None,
        team_assignment: str | None = None,
        host_team: str | None = None,
        fog_of_war: str | None = None,
        max_turns: int | None = None,
        turn_time_limit_s: int | None = None,
    ) -> dict:
        """Host-only: tweak room config while still in the lobby.
    
        Only fields passed (non-None) are updated. Any change resets
        both seats' ready flags — if readiness was previously agreed
        upon, the config shift might change the deal. Fails outside
        the pre-game states (COUNTING_DOWN, IN_GAME, FINISHED).
    
        ── Locking ──
        Input validation + scenario load happen OUTSIDE state_lock
        (pure I/O). The actual config mutation + readiness reset
        happen atomically under state_lock.
        """
        # ── Input validation (no locks) ──
        scenario_state = None
        if scenario is not None:
            try:
                scenario_state = load_scenario(scenario)
            except Exception as e:
                return _error(ErrorCode.BAD_INPUT, f"scenario load failed: {e}")
        if team_assignment is not None and team_assignment not in ("fixed", "random"):
            return _error(
                ErrorCode.BAD_INPUT, "team_assignment must be 'fixed' or 'random'"
            )
        if host_team is not None and host_team not in ("blue", "red"):
            return _error(ErrorCode.BAD_INPUT, "host_team must be 'blue' or 'red'")
        if fog_of_war is not None and fog_of_war not in (
            "none",
            "classic",
            "line_of_sight",
        ):
            return _error(
                ErrorCode.BAD_INPUT,
                "fog_of_war must be 'none' | 'classic' | 'line_of_sight'",
            )
        if max_turns is not None and (max_turns < 1 or max_turns > 200):
            return _error(
                ErrorCode.BAD_INPUT, "max_turns must be between 1 and 200"
            )
        if turn_time_limit_s is not None and (
            turn_time_limit_s < 10 or turn_time_limit_s > 3600
        ):
            return _error(
                ErrorCode.BAD_INPUT,
                "turn_time_limit_s must be between 10 and 3600",
            )
    
        with app.state_lock():
            conn = app._connections.get(connection_id)  # noqa: SLF001
            if conn is None or conn.state != ConnectionState.IN_ROOM:
                return _error(
                    ErrorCode.TOOL_NOT_AVAILABLE_IN_STATE,
                    "update_room_config requires state=in_room",
                )
            info = app.conn_to_room.get(connection_id)
            if info is None:
                return _error(ErrorCode.NOT_IN_ROOM, "connection not seated")
            room_id, slot = info
            room = app.rooms.get(room_id)
            if room is None:
                return _error(ErrorCode.ROOM_NOT_FOUND, f"room {room_id} vanished")
            if slot != Slot.A:
                return _error(
                    ErrorCode.BAD_INPUT,
                    "only the host (slot A) can update room config",
                )
            if room.status not in (
                RoomStatus.WAITING_FOR_PLAYERS,
                RoomStatus.WAITING_READY,
            ):
                return _error(
                    ErrorCode.TOOL_NOT_AVAILABLE_IN_STATE,
                    f"room is in {room.status.value}; config locked",
                )
    
            if scenario is not None:
                room.config.scenario = scenario
                # Switching scenario implicitly resets max_turns to the new
                # scenario's declared cap unless the host overrides it in
                # the same call.
                if max_turns is None and scenario_state is not None:
                    room.config.max_turns = scenario_state.max_turns
            if team_assignment is not None:
                room.config.team_assignment = team_assignment  # type: ignore[assignment]
            if host_team is not None:
                room.config.host_team = host_team  # type: ignore[assignment]
            if fog_of_war is not None:
                room.config.fog_of_war = fog_of_war  # type: ignore[assignment]
            if max_turns is not None:
                room.config.max_turns = max_turns
            if turn_time_limit_s is not None:
                room.config.turn_time_limit_s = turn_time_limit_s
    
            # Config change resets readiness so both sides explicitly
            # re-agree on the new terms.
            for seat in room.seats.values():
                seat.ready = False
            room.recompute_status()
            log.info(
                "update_room_config: room=%s scenario=%s fog=%s teams=%s host_team=%s",
                room_id,
                room.config.scenario,
                room.config.fog_of_war,
                room.config.team_assignment,
                room.config.host_team,
            )
        return _ok({})
  • The RoomConfig dataclass defines the shape of data that update_room_config writes to: scenario, max_turns, team_assignment, host_team, fog_of_war, turn_time_limit_s.
    @dataclass
    class RoomConfig:
        """Per-room configuration. Mutable pre-game so the host can tweak it.
    
        Frozen semantics would be nicer for safety, but the UX is that the
        host can flip scenario / fog / team mode in the lobby before both
        players press ready. `update_room_config` is the single write path
        (host-only, refuses once COUNTING_DOWN/IN_GAME/FINISHED).
    
        - team_assignment="fixed":  host gets host_team; joiner gets the other.
        - team_assignment="random": coin-flipped at game-start time.
        - fog_of_war / max_turns / turn_time_limit_s drive the engine and
          filter behavior during the match.
        """
    
        scenario: str
        max_turns: int = 20
        team_assignment: TeamAssignment = "fixed"
        host_team: HostTeam = "blue"
        fog_of_war: FogMode = "none"  # easier onboarding; bump to "classic" per-room
        # Default is deliberately huge so neither the client-side agent
        # loop nor the server-side forfeit interferes with reasoning-model
        # debugging. Hosts can dial it down to blitz-game values from the
        # room Actions panel; 1800s (30 min) is a reasonable upper ceiling
        # for a single turn where a weak model with many units needs the
        # full observe-act-observe cycle plus ample reasoning tokens.
        turn_time_limit_s: int = 1800
  • register_lobby_tools() is called from app.py to register all lobby tools (including update_room_config) onto the FastMCP instance. The tool is registered via the @mcp.tool() decorator at line 538.
    def register_lobby_tools(mcp: FastMCP, app: App) -> None:
  • App initialization: imports and calls register_lobby_tools(mcp, app) to attach all lobby tools including update_room_config to the MCP server.
    from silicon_pantheon.server.lobby_tools import register_lobby_tools
    
    register_lobby_tools(mcp, app)
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses key behaviors: only non-None fields updated, ready flags reset on any change, atomic mutation under state_lock, and failure conditions outside pre-game states. No annotations, so description carries full burden and does well.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Structured with clear sections and about 6 sentences. Could be slightly tighter, but overall well-organized and not overly verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite good usage and transparency, missing parameter explanations and no output schema make it incomplete for an agent to correctly invoke the tool, especially with 7 parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has zero descriptions (0% coverage) and description does not explain individual parameters like scenario, team_assignment, etc. It only states that only passed (non-None) fields are updated, leaving parameter meaning unclear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'tweak room config while still in the lobby' with specific verb 'tweak' and resource 'room config', distinguishing it from siblings like create_room, join_room, preview_room, and set_ready.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Specifies 'Host-only' and 'while still in the lobby', and notes it fails outside pre-game states (COUNTING_DOWN, IN_GAME, FINISHED). However, it does not explicitly state when not to use or suggest alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/haoyifan/Silicon-Pantheon'

If you have feedback or need assistance with the MCP directory API, please join our Discord server