Skip to main content
Glama
hbd

MCP Chat

by hbd

wait_for_message

Wait for incoming chat messages using long-polling. This tool blocks execution until a message arrives or timeout occurs, enabling real-time conversation flow in chat rooms.

Instructions

Wait for a message in the chat room (long-polling).

This tool blocks until a message is received or the timeout is reached. Use this after sending a message to wait for a response, or call it first to wait for an incoming message.

Conversation flow:

  • If you sent the last message: wait_for_message to get response

  • If you're waiting for first contact: wait_for_message before sending

  • After receiving a message: send_message to respond, then wait_for_message again

Args: room_id: The ID of the chat room to listen in client_id: Your client identifier (from enter_queue or join_room) timeout: Timeout in seconds (default: 60, max: 300)

Returns: On message: {"message": "text", "sender": "name", "timestamp": "...", "message_id": "..."} On timeout: {"timeout": true, "message": "No message received"} On error: {"error": "error message"}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
room_idYes
client_idYes
timeoutNo

Implementation Reference

  • The primary handler function for the 'wait_for_message' MCP tool. It uses long-polling with asyncio.Queue to wait for incoming messages in a chat room, handles timeouts, validation, and cleanup. Registered via @mcp.tool() decorator, with schema inferred from type hints and docstring.
    async def wait_for_message(
        room_id: str, client_id: str, timeout: int = 60
    ) -> Dict[str, Any]:
        """Wait for a message in the chat room (long-polling).
    
        This tool blocks until a message is received or the timeout is reached.
        Use this after sending a message to wait for a response, or call it first
        to wait for an incoming message.
    
        Conversation flow:
        - If you sent the last message: wait_for_message to get response
        - If you're waiting for first contact: wait_for_message before sending
        - After receiving a message: send_message to respond, then wait_for_message again
    
        Args:
            room_id: The ID of the chat room to listen in
            client_id: Your client identifier (from enter_queue or join_room)
            timeout: Timeout in seconds (default: 60, max: 300)
    
        Returns:
            On message: {"message": "text", "sender": "name", "timestamp": "...", "message_id": "..."}
            On timeout: {"timeout": true, "message": "No message received"}
            On error: {"error": "error message"}
        """
        # Use the provided client_id
        connection_id = client_id
    
        # Validate timeout
        timeout = min(timeout, 300)  # Max 5 minutes
        timeout = max(timeout, 1)  # Min 1 second
    
        # Get user
        user = connections.get(connection_id)
        if not user:
            logger.error(f"User not found for client_id: {client_id}")
            logger.debug(f"Active connections: {list(connections.keys())}")
            return {"error": f"User not found. Invalid client_id: {client_id}"}
    
        # Get and validate room
        room = await room_manager.get_room(room_id)
        if not room:
            return {"error": "Room not found"}
    
        if not room.active:
            return {"error": "Chat has ended"}
    
        # Verify user is in the room
        if not room.has_user(user.user_id):
            return {"error": "You are not in this room"}
    
        # Create a message queue for this user if not exists
        if room_id not in message_queues:
            message_queues[room_id] = {}
    
        # Create queue with reasonable size limit
        message_queue: asyncio.Queue[Dict[str, Any]] = asyncio.Queue(maxsize=100)
        message_queues[room_id][user.user_id] = message_queue
    
        logger.info(
            f"User {user.name} waiting for messages in room {room_id} (timeout: {timeout}s)"
        )
    
        try:
            # Wait for a message with timeout
            message_data = await asyncio.wait_for(
                message_queue.get(), timeout=float(timeout)
            )
    
            logger.info(
                f"Message received for {user.name}: {message_data.get('content', '')[:50]}..."
            )
    
            return {
                "message": message_data["content"],
                "sender": message_data["sender_name"],
                "timestamp": message_data["timestamp"],
                "message_id": message_data["message_id"],
            }
    
        except asyncio.TimeoutError:
            logger.info(f"Timeout waiting for message for {user.name}")
            return {"timeout": True, "message": "No message received within timeout period"}
    
        except asyncio.CancelledError:
            # Client cancelled the request - this is normal behavior
            logger.info(f"Wait cancelled for {user.name}")
            # Re-raise to let the framework handle it properly
            raise
    
        except Exception as e:
            logger.error(f"Error in wait_for_message: {e}")
            return {"error": f"Unexpected error: {str(e)}"}
    
        finally:
            # Clean up queue registration
            if room_id in message_queues and user.user_id in message_queues[room_id]:
                del message_queues[room_id][user.user_id]
                # Clean up empty room entries
                if not message_queues[room_id]:
                    del message_queues[room_id]
                logger.info(f"Cleaned up message queue for {user.name}")
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes the blocking/long-polling behavior, timeout handling, and different return scenarios (message, timeout, error). However, it doesn't mention potential side effects like resource consumption during blocking or whether multiple concurrent waits are allowed.

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

Conciseness5/5

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

The description is well-structured and appropriately sized. It starts with the core purpose, provides usage guidelines, outlines conversation flow, details parameters, and specifies return values. Every section earns its place with no redundant information.

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

Completeness5/5

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

Given the tool's complexity (blocking behavior with timeout) and lack of annotations/output schema, the description provides complete context. It covers purpose, usage patterns, parameter semantics, and detailed return value specifications for all possible outcomes (message, timeout, error).

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

Parameters5/5

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

With 0% schema description coverage, the description fully compensates by explaining all three parameters: room_id ('The ID of the chat room to listen in'), client_id ('Your client identifier'), and timeout ('Timeout in seconds' with default and max values). This adds crucial meaning beyond the bare schema.

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?

The description clearly states the tool's purpose with specific verbs ('wait for a message', 'blocks until') and resource ('in the chat room'), distinguishing it from siblings like send_message (which sends) or join_room (which joins). It explicitly mentions long-polling behavior, which is a key differentiator.

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

Usage Guidelines5/5

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

The description provides explicit guidance on when to use this tool versus alternatives, including specific conversation flow scenarios: 'Use this after sending a message to wait for a response, or call it first to wait for an incoming message.' It also outlines a clear sequence with sibling tools in the conversation flow section.

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/hbd/mcp-chat'

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