Let AI agents test Telegram bots and Mini Apps as a real user: MCP server driving the official Telegram Web client in a real browser
Server has 22 tools with consistent naming (tg_* prefix) and descriptions present for all. However, parameter descriptions are minimal or missing for many tools. Input schemas are visible and properly typed, but lack depth in constraint documentation. Error handling is structured (AdapterError payloads) but recovery guidance is sparse. Output schemas are not formally documented. Tool composition is sound (each does one thing), but some tools combine related operations (e.g., tg_click_button accepts multiple selection modes). Descriptions average ~80 chars, below the 194-char baseline for A+ tools. No tool annotations (readOnlyHint/destructiveHint) despite clear risk classifications in metadata.
Clear the open chat's history (test isolation between scenarios).
Click an inline-keyboard button by text substring, or by 0-based row/col. Targets message_id or the last message that has buttons.
Click a reply-keyboard button (the keyboard shown near the input).
Forward a message by id via the forward picker. Empty to_chat forwards to the current chat (typical bot-test loop).
Open a visible browser window for one-time Telegram login (QR or phone). The session persists in the profile afterwards.
Headless login step 2: submit the confirmation code. May return password_needed for 2FA accounts (then call tg_login_password).
Parameter descriptions are minimal. Most params have 1-2 sentence descriptions lacking format/range constraints. E.g., 'timeout_s' lacks min/max bounds; 'kind' in tg_send_file lacks enum constraint documentation in description.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite clear risk classifications in metadata. tg_clear_chat is DESTRUCTIVE, tg_send_* are WRITE, but no MCP annotations present.
Output schemas not formally documented. Tools return JSON strings, but response structure (fields, types, pagination) is not declared in tool metadata. LLMs must infer structure from descriptions.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2026-07-28+ | v2 |
Headless login step 3: submit the two-factor password (2FA only).
Headless login step 1: submit the phone number. The code arrives on the account's other logged-in devices (or SMS); pass it to tg_login_code.
Click an element inside the Mini App by its snapshot ref (e.g. 'e3').
Close the open Mini App popup.
Open a Mini App via a web-app button on the last message (or by text).
Screenshot the open Mini App.
List interactive elements inside the open Mini App as [ref] lines usable with tg_miniapp_click / tg_miniapp_type.
Type text into a Mini App input by its snapshot ref.
Open a chat by @username or t.me link. Returns the last messages.
Read the last messages of the open chat as structured JSON (id, direction, text, time, button grid, media kind).
Screenshot the chat, a single message (scope='message' + message_id), or the whole window (scope='window').
Attach and send a file to the open chat. kind: auto (by extension) | photo | document.
Send a text message or /command to the currently open chat. reply_to: message id to reply to (0 = plain message).
Record and send a voice message using a fake microphone fed from a WAV file (PCM). Relaunches the browser on first use per file.
Report adapter mode, login state and profile location.
Block until the bot sends something new (the core test primitive). Returns the new incoming messages.
tg_click_button combines multiple selection modes (text, row/col, message_id) with unclear precedence. Description does not specify which parameter takes priority if multiple are provided.
Error recovery guidance is generic. AdapterError payloads return error type and message, but lack actionable next steps. E.g., 'chat_not_found' should suggest 'Try tg_open_chat with a different query.'