Skip to main content
Glama
leo4life2

Minecraft MCP Server

by leo4life2

readChat

Retrieve recent Minecraft server chat messages, including player chats, whispers, system alerts, action bar messages, and titles. Filter by type, username, or timeframe for focused insights.

Instructions

Read recent chat messages from the server. Returns player messages, system messages, whispers, action bar messages, and titles.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
countNoNumber of recent messages to return (default: 20, max: 100)
filterTypeNoFilter by message type: 'all', 'chat', 'whisper', 'system', 'actionbar', 'title' (default: 'all')
filterUsernameNoFilter messages by specific username (optional)
timeLimitNoOnly return messages from the last N seconds (optional)

Implementation Reference

  • The main handler function for the readChat MCP tool. It retrieves filtered recent chat messages from the bot's history, formats them, and outputs via bot.emit('alteraBotEndObservation').
    export const readChat = async (
        bot: Bot,
        params: ISkillParams,
        serviceParams: ISkillServiceParams,
    ): Promise<boolean> => {
        const skillName = 'readChat';
        const requiredParams: string[] = [];
        const isParamsValid = validateSkillParams(
            params,
            requiredParams,
            skillName,
        );
        if (!isParamsValid) {
            serviceParams.cancelExecution?.();
            bot.emit(
                'alteraBotEndObservation',
                `Mistake: You didn't provide all of the required parameters ${requiredParams.join(', ')} for the ${skillName} skill.`,
            );
            return false;
        }
    
        // Initialize chat history for this bot if not exists
        if (!chatHistories.has(bot)) {
            initializeChatHistory(bot);
        }
    
        const history = chatHistories.get(bot) || [];
    
        // Parse parameters with defaults
        const count = Math.min(params.count || 20, 100); // Cap at 100 messages
        const timeLimit = params.timeLimit as number | undefined;
        const filterType = (params.filterType || 'all') as string;
        const filterUsername = params.filterUsername as string | undefined;
    
        // Filter messages based on parameters
        let filteredMessages = [...history]; // Copy array to avoid mutation
    
        // Apply time filter if specified
        if (timeLimit && timeLimit > 0) {
            const cutoffTime = new Date(Date.now() - (timeLimit * 1000));
            filteredMessages = filteredMessages.filter(msg => msg.timestamp >= cutoffTime);
        }
    
        // Apply type filter
        if (filterType !== 'all') {
            filteredMessages = filteredMessages.filter(msg => msg.type === filterType);
        }
    
        // Apply username filter
        if (filterUsername) {
            filteredMessages = filteredMessages.filter(msg =>
                msg.username && msg.username.toLowerCase() === filterUsername.toLowerCase()
            );
        }
    
        // Get the most recent messages up to count
        const recentMessages = filteredMessages.slice(-count);
    
        // Format messages for output
        const formattedMessages = recentMessages.map(msg => {
            const timeStr = msg.timestamp.toLocaleTimeString();
            let formatted = `[${timeStr}]`;
    
            switch (msg.type) {
                case 'chat':
                    formatted += ` <${msg.username || 'Unknown'}>: ${msg.message}`;
                    break;
                case 'whisper':
                    formatted += ` [Whisper] <${msg.username || 'Unknown'}>: ${msg.message}`;
                    break;
                case 'system':
                    formatted += ` [System] ${msg.message}`;
                    break;
                case 'actionbar':
                    formatted += ` [Action Bar] ${msg.message}`;
                    break;
                case 'title':
                    formatted += ` [Title] ${msg.message}`;
                    break;
                default:
                    formatted += ` ${msg.message}`;
            }
    
            return formatted;
        });
    
        // Create summary
        const summary = [
            `=== Chat History ===`,
            `Showing ${recentMessages.length} messages`,
            filterType !== 'all' ? `Filtered by type: ${filterType}` : '',
            filterUsername ? `Filtered by user: ${filterUsername}` : '',
            timeLimit ? `From last ${timeLimit} seconds` : '',
            `==================`,
            ...formattedMessages
        ].filter(line => line !== '').join('\n');
    
        bot.emit('alteraBotEndObservation', summary);
    
        return true;
    };
  • Input schema definition for readChat tool, including parameters and description used for MCP tool listing.
    readChat: {
        description: "Read recent chat messages from the server. Returns player messages, system messages, whispers, action bar messages, and titles.",
        params: {
            count: {
                type: "number",
                description: "Number of recent messages to return (default: 20, max: 100)"
            },
            timeLimit: {
                type: "number",
                description: "Only return messages from the last N seconds (optional)"
            },
            filterType: {
                type: "string",
                description: "Filter by message type: 'all', 'chat', 'whisper', 'system', 'actionbar', 'title' (default: 'all')"
            },
            filterUsername: {
                type: "string",
                description: "Filter messages by specific username (optional)"
            }
        },
        required: []
    },
  • Helper function to initialize chat message collection by attaching Mineflayer event listeners to the bot.
    export function initializeChatHistory(bot: Bot): void {
        // Don't initialize twice
        if (chatHistories.has(bot)) {
            return;
        }
    
        const history: ChatMessage[] = [];
        chatHistories.set(bot, history);
    
        // Helper function to add message to history
        const addToHistory = (type: ChatMessage['type'], message: string, username?: string, rawMessage?: any) => {
            history.push({
                timestamp: new Date(),
                type,
                message: message.toString(),
                username,
                rawMessage
            });
    
            // Trim history if it gets too large
            if (history.length > MAX_HISTORY_SIZE) {
                history.splice(0, history.length - MAX_HISTORY_SIZE);
            }
        };
    
        // Listen to various chat events
        bot.on('chat', (username, message) => {
            addToHistory('chat', message, username);
        });
    
        bot.on('whisper', (username, message) => {
            addToHistory('whisper', message, username);
        });
    
        // System messages (server messages, join/leave, etc.)
        bot.on('message', (jsonMsg) => {
            // Skip if it's a regular chat message (already handled)
            const msgText = jsonMsg.toString();
    
            // Try to determine if it's a system message
            if (jsonMsg.json) {
                // Check if it's not a regular chat message
                const isChat = jsonMsg.json.translate === 'chat.type.text';
                const isWhisper = jsonMsg.json.translate === 'commands.message.display.incoming';
    
                if (!isChat && !isWhisper) {
                    addToHistory('system', msgText, undefined, jsonMsg);
                }
            }
        });
    
        // Action bar messages
        bot.on('actionBar', (jsonMsg) => {
            if (jsonMsg) {
                addToHistory('actionbar', jsonMsg.toString(), undefined, jsonMsg);
            }
        });
    
        // Title messages
        bot.on('title', (text) => {
            if (text) {
                addToHistory('title', text.toString());
            }
        });
    
        // Clean up on bot end
        bot.once('end', () => {
            chatHistories.delete(bot);
        });
    } 
  • Registers all skills (including readChat) as MCP tools in the ListToolsRequestHandler response.
    // Add all registered skills as tools
    const skillTools = skillRegistry.getAllSkills().map(skill => ({
        name: skill.name,
        description: skill.description,
        inputSchema: skill.inputSchema
    }));
    
    return { tools: [...tools, ...skillTools] };
  • Calls initializeChatHistory after bot spawn to enable readChat functionality.
    initializeChatHistory(bot);
Behavior2/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 mentions the types of messages returned (player, system, whispers, etc.), which adds some context, but fails to cover critical aspects like whether this is a read-only operation, potential rate limits, authentication needs, or how recent messages are defined. This leaves significant gaps for a tool that interacts with server data.

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?

The description is a single, efficient sentence that front-loads the core purpose and lists return types. It avoids unnecessary words, but could be slightly improved by structuring it into two sentences for better readability (e.g., separating purpose from return details).

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

Completeness3/5

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

Given the tool's moderate complexity (4 parameters, no output schema, no annotations), the description is minimally adequate. It covers what the tool does and return types, but lacks details on behavioral traits, usage context, and output format, leaving the agent with incomplete information for optimal use.

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

Parameters3/5

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

The schema description coverage is 100%, so the schema already fully documents all four parameters. The description adds no additional parameter semantics beyond what's in the schema, such as explaining interactions between parameters or default behaviors. This meets the baseline of 3 for high schema coverage.

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

Purpose4/5

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

The description clearly states the verb ('Read') and resource ('recent chat messages from the server'), making the purpose specific and understandable. However, it doesn't explicitly differentiate from siblings like 'sendChat' beyond the obvious read vs. send distinction, which is why it's a 4 rather than a 5.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives or any contextual prerequisites. It simply states what it does without indicating scenarios for its use, leaving the agent to infer usage from the tool name alone.

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

Related 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/leo4life2/minecraft-mcp-http'

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