A Telegram bot for a group chat.
It is a general chat bot: the personality is in lib/prompts.py (the prompts) and what it can look up is in mcp_servers.json (the MCP servers and their tools). The example servers are finance data, so it answers questions about stocks and portfolios when asked, but the prompts don't steer a conversation towards them.
- Answers @mentions, replies and DMs with an LLM, using the group's recent messages as context.
- Live data from MCP servers (Yahoo Finance, Sharesight) and web search.
- Draws charts from that data when asked: two y axes, several series on each, either axis inverted.
- Reads images posted in the chat, if the model supports images.
- Runs on xAI (Grok) or OpenRouter, chosen by which API key you set.
- Create a bot with @BotFather. Run
/setprivacyand choose Disable, so the bot sees every message in a group (remove and re-add it to groups it is already in). Who may use the bot is controlled in Telegram/BotFather; the bot itself has no allow-list.- If the bot has access to Sharesight, enable "Restrict bot usage" in BotFather to enable user whitelisting. (Sharesight access is always read-only, but still relatively private.)
- Install into a virtualenv in the checkout, with Python 3.13.5 (plus Node.js for npx-based MCP servers such as
Yahoo Finance):
python3.13 -m venv .venv .venv/bin/pip install -r requirements.txt - Export
TELEGRAM_BOT_TOKENand exactly one ofXAI_API_KEYorOPENROUTER_API_KEY. .venv/bin/python bot.py
To keep it running, see Running under systemd.
The bot's data tools come from MCP servers listed in mcp_servers.json, remote (url) or started by the bot
(command). For example:
{"mcpServers": {
"weather": {
"url": "https://example.com/mcp",
"headers": {"Authorization": "Bearer …"},
"allowed_tools": ["get_forecast", "get_alerts"],
"chat_commands": {
"forecast": {"tool": "get_forecast", "require_arg": true},
"alerts": {"tool": "get_alerts"}
}
},
"files": {"command": "uvx", "args": ["some-mcp-server"], "env": {"KEY": "value"}, "blocked_tools": ["delete_file"]}
}}chat_commands turn a server's tools into slash commands. /forecast sydney this weekend asks the model, which is
offered only that tool and made to call it. With require_arg, a bare /forecast gets a usage reply from the bot
without asking the model. Every key is listed in How it works.
- Configuration: providers, every environment variable, choosing a model.
- How it works: how it answers, search, MCP data tools (
mcp_servers.json), formatting. - Features and commands: charts, holding-news DM, movers replies, DM buttons,
/usage. - Caching and token saving: the Sharesight history cache and the token-saving heuristics.
- Running the bot: systemd, several instances, logs.
- Troubleshooting: startup errors, silent bots, MCP servers down.
- Development: tests, fixtures and the code layout.