An automated engagement bot using the FastMCP framework and Python async architecture was designed to respond to FastMCP-related tweets on X/Twitter. The bot utilized ChromaDB for semantic search and OpenRouter’s Claude Haiku for generating replies, operating within X’s free tier constraints (17 writes/day, 1 search/15 minutes). However, it encountered critical issues with rate limit handling and tone appropriateness.
Issue
The engagement bot faced three main challenges:
- Rate Limit Misclassification: When encountering X’s HTTP 429 rate limit response, the bot recorded it as a successful empty search, leading to unnecessary delays before retrying (85 minutes instead of immediate retries).
- Tone Mismatch: Generated replies adopted a conversational, support-bot tone with greetings and filler phrases (e.g., “Hey there!”, “Hope this helps!”), which was inappropriate for a developer-focused X account. It also used third-person references (“they”) instead of first-person authority (“we”).
- Protocol Bypass: The bot bypassed FastMCP’s sampling protocol by directly calling OpenAI, which created architectural inconsistencies and missed protocol benefits like model preference management.
Culprit
Rate Limit Handling
The function _search_fastmcp_tweets() returned empty arrays ([]) for both successful empty searches and rate limits, making it impossible to distinguish between the two scenarios. The state management unconditionally recorded search times regardless of whether the API request succeeded or was rate-limited.
Tone Mismatch
The LLM prompt included generic conversational instructions without developer-specific constraints, leading to inappropriate tone and language choices. For example:
- Greetings and filler phrases were included in replies.
- Third-person references were used instead of first-person authority.
Protocol Bypass
The server-side code instantiated OpenAI clients directly instead of using FastMCP’s ctx.sample() method, bypassing the protocol’s benefits and creating architectural inconsistencies.
Solution
Rate Limit Distinction
- Modified the return type of
_search_fastmcp_tweets()to useNonefor rate limits and[]for empty results, enabling the system to distinguish between the two scenarios. - Added conditional state recording to ensure search times were only recorded for successful searches.
- Implemented immediate retry logic for rate limits, reducing delays from 85 minutes to 60 seconds.
Developer Tone Enforcement
- Updated the LLM prompt to include strict rules enforcing a developer-focused tone:
- Eliminated greetings, sign-offs, and filler phrases.
- Mandated the use of first-person references (“we”) to align with the bot’s identity as FastMCP.
- Required direct and concise corrections without padding.
FastMCP Protocol Integration
- Client-Side: Implemented a sampling handler in
main.pyto convert messages to OpenAI format and call the API through FastMCP’s protocol. - Server-Side: Updated the
_generate_reply()function to use FastMCP’sctx.sample()method, ensuring all LLM calls flowed through the protocol. - Configuration: Added support for configurable models via environment variables, enabling easy switching without code changes.
Key Improvements
- Rate Limit Handling: Immediate retries for rate limits, improving efficiency.
- Tone Consistency: Replies now reflect a developer-focused, authoritative tone (e.g., “We fixed this in v0.4.2 – check the changelog” instead of “Hope this helps!”).
- Protocol Compliance: All LLM calls are processed through FastMCP’s protocol, ensuring consistency and flexibility.
- Model Configurability: Easy switching between models using environment variables.
Result: The engagement bot now reliably handles rate limits, produces appropriate developer-focused replies, and adheres to FastMCP’s protocol, improving both functionality and consistency.