Telegram channel tools for AI agents — read public channels, search, analyze engagement. No MTProto.
shadow-tg has 7 well-named, read-only tools with complete input schemas and reasonable descriptions. All tools follow verb_noun naming (get_posts, search_posts, resolve_channel, inspect_channel, search_channels, get_discussion, get_post_media). Descriptions are 50 - 200 chars, explaining WHAT and WHEN. Input schemas include types and defaults. However, output schemas are documented only in docstrings, not in structured form. Error handling is minimal, most failures return generic 404/429 responses without recovery guidance. No tool annotations (readOnlyHint, idempotentHint) despite all being read-only. Parameter descriptions are adequate but lack format constraints (e.g., 'channel' accepts @name, t.me/name, or URL but doesn't specify the format formally). No batch variants or composition helpers.
Fetch comments on a post via the discussion widget. Loads t.me/{channel}/{post_id}?embed=1&discussion=1 and parses the comment thread (first page server-rendered, older pages via API).
Extract media URLs (photos, videos, documents) from a post. Parses t.me/s/{channel}/{post_id} and returns CDN links for all attached media.
Fetch recent posts from a Telegram channel via t.me/s/{channel}. Args: channel: Channel username (e.g. 'delfilv', '@durov', or full URL like 'https://t.me/durov') limit: Max posts to return (default 30, max ~100 per page) before: Pagination cursor (post ID from next_before in previous response) Returns: {requested, canonical, channel, title, posts: [{id, text, hashtags, date, views, views_raw, link, has_photo, has_video, has_document, has_poll, is_forward_restricted, is_forwarded}], count, has_more, next_before} `requested` is what you asked for; `canonical`/`channel` come from data-post (alias channels may differ, e.g. @delfilv → @jaunumi).
Analyze channel quality: subscribers, engagement, recency, inflation signals. Fetches one t.me/s page and computes heuristic flags (size, views, engagement ratio, staleness). Not Telegram truth — estimates only.
Resolve @username or t.me/ link to channel info. Tries t.me/s first (fast, static). Alias usernames may differ.
Output schemas documented only in docstrings, not in structured MCP response format. LLMs cannot parse docstring examples reliably.
Error responses lack recovery guidance. 404 and 429 errors return bare status codes without suggesting next steps (e.g., 'Channel not found. Try search_channels() to find similar channels.').
No tool annotations despite all tools being read-only. Adding readOnlyHint=true would help clients optimize caching and retry logic.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | <=2025-11-25 | v2 |
Search public Telegram channels via DuckDuckGo. Searches 'site:t.me/s/ {query}' and parses organic results into channel metadata.
Scan recent posts in a channel for a keyword or #hashtag. Not a full-channel search index: fetches up to ~100 posts (3 pages) via get_posts and filters client-side (case-insensitive substring). Args: channel: Channel username query: Search keyword or #hashtag (case-insensitive) limit: Max matching posts to return (default 30) Returns: {channel, query, posts: [...], count, total_matched, total_scanned}
Parameter 'channel' accepts multiple formats (@name, t.me/name, URL) but description lacks formal format specification. LLMs may pass invalid formats.
No batch tools. Agents calling get_posts in a loop for multiple channels waste tokens and latency. A get_posts_batch(channels: [str]) variant would improve efficiency.