Standalone MCP server that lets AI agents download and preview Telegram stickers from Telegram file_id and emoji metadata.
Telegram Sticker MCP
English | 简体中文
Standalone FastMCP server for downloading and previewing Telegram stickers from
AI agent workflows. It accepts a Telegram sticker file_id, calls Telegram
getFile, caches the original sticker by file_unique_id, and returns local
paths and metadata that an MCP-capable agent can inspect.
This works with any AI agent or bot connected through a channel that can pass
Telegram sticker file_id and emoji metadata to the model. Code-managed
agents can usually register the stdio MCP directly; Claude Desktop and other
remote-client setups can use streamable HTTP with optional OAuth.
What This Does
This project:
- Downloads Telegram stickers by
file_idthrough the Telegram Bot API. - Caches sticker files by Telegram
file_unique_id. - Generates preview PNGs and optional preview sheets for TGS/WEBM stickers.
- Exposes one MCP tool:
download_sticker(file_id, emoji, mode, refresh). - Supports stdio and streamable HTTP transports.
- Reads Telegram tokens only from environment variables.
This project does not:
- Receive Telegram updates or host a Telegram bot webhook/poller.
- Replace a chat bridge such as cc-connect.
- Bypass Telegram Bot API permissions.
- Guess sticker files without a valid
file_id. - Make MCP tools visible to an agent unless your MCP client is configured.
Requirements
- Python 3.11 or newer.
- Node.js and npm for the local
lottie-webdependency used by TGS previews. - Optional: Chrome, Chromium, or Edge for higher-quality TGS and WEBM previews.
- A Telegram bot token from
@BotFather. - A channel/bridge that passes Telegram sticker
file_idandemojito the agent.
Install
git clone https://github.com/yanyan1115/telegram-sticker-mcp.git
cd telegram-sticker-mcp
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
npm install
cp .env.example .env
Edit .env with your own Telegram bot token before running the server.
Telegram Bot Token
- Open Telegram and talk to
@BotFather. - Create a bot with
/newbot. - Copy the bot token into
.envasTELEGRAM_BOT_TOKEN. - If the token is ever exposed, use BotFather's
/revokeflow and update your environment.
HTTP host/origin allowlists do not replace token security. Keep real bot tokens, OAuth secrets, access tokens, refresh tokens, and MCP client configs containing secrets out of git.
Configuration
The server reads credentials and runtime settings from environment variables.
export TELEGRAM_BOT_TOKEN='<telegram-bot-token>'
export TELEGRAM_STICKER_CACHE_DIR="$HOME/.cache/telegram-sticker-mcp"
TELEGRAM_BOT_TOKEN is the primary token variable. For compatibility with
multi-agent setups, the server also checks inherited TELEGRAM_CODEX_TOKEN and
TELEGRAM_GEMINI_TOKEN values when TELEGRAM_BOT_TOKEN is unset.
Optional preview/runtime settings:
export CHROME='/usr/bin/google-chrome'
export TELEGRAM_STICKER_CACHE_DIR="$HOME/.cache/telegram-sticker-mcp"
Optional streamable HTTP settings:
export MCP_HOST='127.0.0.1'
export MCP_PORT='8890'
export MCP_ALLOWED_HOSTS='sticker-mcp.example.com,sticker-mcp.example.com:*'
export MCP_ALLOWED_ORIGINS='https://sticker-mcp.example.com'
Optional OAuth settings for a public Remote MCP HTTP endpoint:
export MCP_OAUTH_ENABLED='1'
export MCP_OAUTH_ISSUER_URL='https://sticker-mcp.example.com'
export MCP_OAUTH_RESOURCE_URL='https://sticker-mcp.example.com/mcp'
export MCP_OAUTH_CONNECT_SECRET='<manual-connector-secret>'
export MCP_OAUTH_STORE="$HOME/.cache/telegram-sticker-mcp/oauth_store.json"
OAuth protects the HTTP transport. Stdio transport remains local and environment-based.
Run
Stdio transport:
python telegram_sticker_mcp.py
Streamable HTTP transport:
python telegram_sticker_mcp.py --transport streamable-http
PowerShell stdio wrapper:
.\run_sticker_mcp.ps1
Bash HTTP wrapper:
./run_sticker_mcp_http.sh
The wrapper scripts are examples. Customize paths, process managers, reverse proxies, and TLS outside this repository for your own deployment.
MCP Client Examples
Replace paths with the absolute path to your clone. Keep real tokens in your
environment or .env, not directly in client config files.
Codex ~/.codex/config.toml:
[mcp_servers.telegram_sticker]
command = "python"
args = ["/path/to/telegram-sticker-mcp/telegram_sticker_mcp.py"]
Gemini settings.json:
{
"mcpServers": {
"telegram_sticker": {
"command": "python",
"args": ["/path/to/telegram-sticker-mcp/telegram_sticker_mcp.py"],
"includeTools": ["download_sticker"],
"trust": false
}
}
}
Claude Desktop stdio example:
{
"mcpServers": {
"telegram-sticker": {
"command": "python",
"args": ["/path/to/telegram-sticker-mcp/telegram_sticker_mcp.py"]
}
}
}
Remote MCP HTTP example:
export MCP_HOST='127.0.0.1'
export MCP_PORT='8890'
export MCP_OAUTH_ENABLED='1'
export MCP_OAUTH_ISSUER_URL='https://sticker-mcp.example.com'
export MCP_OAUTH_RESOURCE_URL='https://sticker-mcp.example.com/mcp'
export MCP_OAUTH_CONNECT_SECRET='<manual-connector-secret>'
python telegram_sticker_mcp.py --transport streamable-http
Point your remote MCP client at:
https://sticker-mcp.example.com/mcp
If your agent still says the tool is unavailable, restart the agent or start a new conversation after changing MCP config.
Quick Verification
Use this smoke test to verify the Telegram token and download path before
configuring an MCP client. Replace PASTE_FILE_ID_HERE with a sticker file_id
that your bot is allowed to access.
python - <<'PY'
import asyncio
import json
from telegram_sticker_mcp import download_sticker
async def main():
result = await download_sticker(
file_id="PASTE_FILE_ID_HERE",
emoji="🙂",
mode="preview",
refresh=True,
)
print(json.dumps(result, indent=2, ensure_ascii=False))
asyncio.run(main())
PY
On Windows PowerShell:
@'
import asyncio
import json
from telegram_sticker_mcp import download_sticker
async def main():
result = await download_sticker(
file_id="PASTE_FILE_ID_HERE",
emoji="🙂",
mode="preview",
refresh=True,
)
print(json.dumps(result, indent=2, ensure_ascii=False))
asyncio.run(main())
'@ | python -
MCP Tool
download_sticker(file_id, emoji, mode="preview", refresh=false)
Modes:
fast Download/cache the original file and return metadata; skip preview rendering.
preview Download/cache and generate or reuse the representative PNG preview.
full Do preview mode plus a multi-frame PNG preview sheet when possible.
When refresh=false, the local cache keeps a hashed file_id index. Repeated
calls with the same file_id can return cached artifacts without calling
Telegram getFile again. The index also stores public metadata such as
width, height, frame_rate, frames, and duration_ms when known.
Example success response:
{
"path": "/home/example/.cache/telegram-sticker-mcp/<file_unique_id>.webp",
"emoji": "🙂",
"file_unique_id": "<stable-id>",
"cached": false,
"mime_type": "image/webp",
"source_file_path": "stickers/file.webp",
"telegram_file_size": 131646,
"request_id": "9fd8d7f1e44d4c0bad9e84ff1cc0fa3b",
"note": "Static sticker cached as WEBP.",
"preview_path": null,
"preview_mime_type": null,
"preview_cached": false,
"preview_frame": null,
"preview_background": null,
"preview_sheet_path": null,
"preview_sheet_mime_type": null,
"preview_sheet_cached": false,
"preview_note": "Static image uses original file as preview.",
"preview_renderer": null,
"preview_renderer_version": null,
"warnings": [],
"recommended_view_path": "/home/example/.cache/telegram-sticker-mcp/<file_unique_id>.webp",
"recommended_view_kind": "image",
"width": 512,
"height": 512,
"cache_root": "/home/example/.cache/telegram-sticker-mcp",
"timings_ms": {
"telegram_get_file": 120,
"telegram_download": 240,
"file_write": 3,
"total": 380
}
}
Tool-level Telegram failures return structured errors instead of plain exceptions:
{
"ok": false,
"error_code": "telegram_get_file_failed",
"telegram_status": 400,
"retryable": false,
"message": "Telegram getFile failed with HTTP 400",
"request_id": "9fd8d7f1e44d4c0bad9e84ff1cc0fa3b",
"timings_ms": {
"telegram_get_file": 120,
"total": 125
}
}
Cache And Privacy
The cache can contain:
- Original sticker files returned by Telegram.
- Preview PNGs and preview sheets.
- Metadata sidecars for preview selection.
- A hashed
file_idindex for cache lookup. - OAuth store data when HTTP OAuth is enabled.
Put caches outside the repository or under ignored paths. If stickers may be sensitive, delete the cache periodically:
rm -rf "$HOME/.cache/telegram-sticker-mcp"
Platform Notes
Windows:
- Use
run_sticker_mcp.ps1or configure your MCP client to call Python directly. - Microsoft Edge is often available even when Chrome is not.
Linux:
- Chrome/Chromium improves TGS and WEBM previews.
- Root/server environments may need Chrome sandbox flags; this project includes root preview support for headless rendering.
macOS:
- Chrome is usually under
/Applications/Google Chrome.app/...; setCHROMEif auto-detection cannot find it.
Troubleshooting
TELEGRAM_BOT_TOKEN is required
Set TELEGRAM_BOT_TOKEN in .env or the environment that starts your MCP
server.
download_sticker tool is not visible
Check the MCP client config path, command, and args. Restart the agent or start a new conversation after changing MCP configuration.
.tgs preview is missing
Install npm dependencies with npm install and make sure Chrome, Chromium, or
Edge is available. The original .tgs file can still be returned even when
preview rendering falls back or fails.
Chrome/Edge not found
Install Chrome/Chromium/Edge or set CHROME to the executable path.
WEBM preview unavailable
The original .webm can still be cached and returned. Install Chrome/Edge for
PNG previews.
HTTP 400 getFile
The file_id may be invalid, expired, malformed, or unavailable to this bot.
Verify the channel is passing the sticker file_id from a message your bot can
access.
Agent says it cannot use tools
Restart the MCP client/agent, check allowlists such as includeTools, and make
sure the channel prompt actually contains file_id and emoji.
Test
python -m unittest discover -s tests
python -m py_compile telegram_sticker_mcp.py tests/test_downloader.py
npm test
git diff --check
Security Notes
- Keep Telegram bot tokens, OAuth connector secrets, access tokens, refresh tokens, and OAuth store files out of git.
- Use
.env.exampleas a template only; never commit a filled.env. - Put caches outside the repository or under ignored paths.
- If a real token is accidentally committed or shared, rotate it immediately.
License
MIT
Acknowledgements
Thanks to Claude for helping organize the product requirements and architecture, and to GPT/Codex for pairing on implementation, debugging, open-source cleanup, and validation notes.