tgreader-mcp
by ramich2077
README.md
# tgreader-mcp
Telegram channel reader MCP server — exposes Telegram channels as [MCP](https://modelcontextprotocol.io) tools via Telethon MTProto.
Designed for use with [Hermes Agent](https://hermes-agent.nousresearch.com), Claude Desktop, and any MCP-compatible client.
## Features
- **List channels** — discover channels the account is subscribed to, with optional RegExp search filter
- **Read messages** — fetch posts from any channel by `@username` or numeric ID, with date-based pagination and text search
- **Multi-account** — configure multiple Telegram accounts, switch between them per call
- **MCP stdio transport** — works out of the box with any MCP client
- **Security-hardened** — session files `0600`, config `0600`, sanitized error messages, ReDoS protection via `regex` library with per-match timeout
## Requirements
- Python ≥ 3.11 (developed on 3.13)
- [uv](https://docs.astral.sh/uv/) (recommended) or `pip`
- Telegram `api_id` / `api_hash` — get them at <https://my.telegram.org>
## Quick start
```bash
git clone <repo-url> tgreader && cd tgreader
# Create venv and install deps (runtime + dev, editable)
./setup.sh
# or: make setup
# Activate
source .venv/bin/activate
# Login with your Telegram account
tgreader login --account main --phone +79001234567
# Check status
tgreader status
```
### Register with Hermes Agent
Add to `~/.hermes/config.yaml`:
```yaml
mcp_servers:
tgreader:
command: /home/<user>/telegram_reader/.venv/bin/tgreader-mcp
args: []
```
### Install the Hermes skill
The repo ships a ready-to-use Hermes Agent skill at `skills/tgreader/SKILL.md`.
Install it so the agent knows how to use the MCP tools:
```bash
# Copy (recommended)
cp -r skills/tgreader ~/.hermes/skills/tgreader
# Or symlink (tracks the repo, auto-updates on git pull)
ln -s ~/telegram_reader/skills/tgreader ~/.hermes/skills/tgreader
```
The skill teaches the agent when and how to call `list_channels` / `read_messages`,
including example workflows (find vacancies, read by date range, search across
channels) and pitfalls (FloodWait, session expiry, ReDoS-protected search).
### Register with Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"tgreader": {
"command": "/home/<user>/telegram_reader/.venv/bin/tgreader-mcp"
}
}
}
```
## MCP tools
### `list_channels`
List Telegram channels the account is subscribed to.
| Parameter | Type | Default | Description |
|------------|--------|---------|--------------------------------------------------|
| `account` | str | — | Account name (default: configured default) |
| `search` | str | — | RegExp pattern to filter by title/username (max 200 chars) |
| `limit` | int | 100 | Max channels to return (max 500) |
Returns: `{"count": N, "channels": [{"id", "title", "username", "type", "participants_count"}]}`
### `read_messages`
Read messages from a Telegram channel.
| Parameter | Type | Default | Description |
|---------------|--------|---------|----------------------------------------------------------|
| `channel` | str | — | Channel `@username` or numeric ID (**required**) |
| `account` | str | — | Account name (default: configured default) |
| `limit` | int | 20 | Max messages when `offset_date` is None (max 1000) |
| `offset_date` | str | — | ISO 8601 datetime — read messages before this date |
| `search` | str | — | RegExp pattern to filter message text (max 200 chars) |
Returns: `{"count": N, "channel": {"id", "title", "username"}, "messages": [{"id", "date", "text", "views", "reactions", "media_type", "link"}]}`
## CLI
```bash
# Login (creates session, saves to config)
tgreader login --account main --phone +79001234567
# Account management
tgreader accounts list
tgreader accounts add --name work --phone +790011122233 --label "Work account"
tgreader accounts remove main
tgreader accounts default main
# Check session status
tgreader status
tgreader status --account work
# Start MCP server (stdio)
tgreader run
# or: tgreader-mcp
```
## Configuration
Config lives at `~/.config/tgreader/config.json` (XDG-aware):
```json
{
"api_id": 123456,
"api_hash": "your_api_hash_here",
"default_account": "main",
"accounts": {
"main": {
"phone": "+79001234567",
"label": ""
}
}
}
```
Session files (`.session`) are stored at `~/.config/tgreader/sessions/` with `0600` permissions.
## Development
```bash
# Setup
make setup # create .venv, install deps
# Tests
make test # full suite (113 tests)
make test-fast # without isolation (debugging)
# Lint
make lint # py_compile syntax check
# Run server
make run
# Clean
make clean # remove .venv and caches
```
### Test suite
- **113 tests** — unit + integration + BDD (pytest-bdd with Gherkin `.feature` files)
- BDD features cover: login flow, channel listing, message reading
- Security tests: ReDoS, error sanitization, session permissions, config validation
### Project structure
```
tgreader-mcp/
├── src/tgreader_mcp/
│ ├── __init__.py # version
│ ├── server.py # FastMCP server — tool definitions
│ ├── client.py # Telethon client — channel/message logic
│ ├── config.py # Config load/save, account management
│ └── cli.py # Click CLI — login, accounts, status
├── skills/tgreader/
│ └── SKILL.md # Hermes Agent skill — tool usage guide
├── tests/
│ ├── test_server.py # MCP tool tests
│ ├── test_client.py # Telegram client tests
│ ├── test_config.py # Config validation tests
│ ├── test_security.py # ReDoS, sanitization, permissions
│ ├── test_cli.py # CLI command tests
│ ├── features/ # Gherkin .feature files
│ └── test_steps/ # pytest-bdd step implementations
├── pyproject.toml
├── Makefile
├── setup.sh
└── .python-version
```
## Security
- **Session files** — `0600` permissions, stored in `~/.config/tgreader/sessions/`
- **Config file** — `0600` permissions, atomic write (tmp → rename)
- **Error sanitization** — internal exceptions (Telethon, network) are caught; only safe, generalized messages reach the LLM
- **ReDoS protection** — `regex` library (not stdlib `re`) with 2s per-match timeout; `RegexTimeoutError` is caught and surfaced safely
- **Config validation** — full type checking on load; malformed config raises `ConfigError` with a clear message
## License
MIT © Andrey RomanchukTDQS
A4.5/5.0
Scored across 2 tools
Disambiguation5/5
The two tools are completely distinct: one lists channels, the other reads messages from a specific channel. There is no overlap or ambiguity.
Naming Consistency5/5
Both tool names follow the verb_noun pattern ('list_channels', 'read_messages'), making them predictable and easy to understand.
Tool Count4/5
With only 2 tools, the set is minimal but well-suited for a read-only Telegram client. It could benefit from additional tools like a channel info getter, but it is not overly sparse.
Completeness4/5
The tools cover the core read operations: listing channels and reading messages. Missing features like retrieving a single channel's details or searching across channels are minor gaps for a focused read-only tool.
Maintenance
ActivityInactive
ResponsivenessNo issues