Telegram Lead Analysis MCP
by zeropennyads
README.md
# Telegram Lead Analysis MCP
A read-only [MCP](https://modelcontextprotocol.io) server that exposes a team's
Telegram **lead conversations** to Claude for sales analysis — lead summary,
intent, stage, objections, next/missed follow-ups, hot/warm/cold, action items.
The server does **no reasoning and calls no LLM**. It returns clean, structured
message data; the connected Claude client does the thinking.
## Status
- **Data source today:** a Telegram Desktop JSON export (frozen snapshot).
- **Data source later:** a live Telethon connection (same interface, no tool
changes). The `TelethonLeadDataSource` stub is already in place.
## Guarantees
- **Read-only by construction.** There is no send/edit/delete code path anywhere.
- **Whitelist enforced at the data layer** (`datasource/base.py`), not just in
the tools — a tool physically cannot return a non-whitelisted chat.
- **Every tool call is logged** with the chat it touched to `logs/access.log`.
- **No credentials in code.** The live source reads `TELEGRAM_API_ID`,
`TELEGRAM_API_HASH`, `TELEGRAM_SESSION` from the environment only.
## Project layout
```
server.py MCP server + tool definitions
datasource/
base.py LeadDataSource interface (whitelist + text normalize)
json_source.py JSONLeadDataSource (active)
telethon_source.py TelethonLeadDataSource (stub for live access)
config/whitelist.json JSON list of in-scope lead chat names
data/leads_export.json the export (sample fixture ships; replace with real)
logs/access.log access log (created at runtime)
requirements.txt
```
## Go live with Edrian's account (copy-paste runbook)
You have his `api_id`, `api_hash`, and session string. Do this once:
**1. Paste the 3 values into `.env`** (open the `.env` file in the project root):
```
TELEGRAM_API_ID=1234567
TELEGRAM_API_HASH=abc123...
TELEGRAM_SESSION=1Aa...
```
**2. List his chats so you can pick the leads:**
```powershell
.\.venv\Scripts\python.exe list_all_chats.py
```
**3. Put the lead chat names into `config/whitelist.json`** (exactly as printed), e.g.:
```json
["Acme Corp", "Beta Logistics"]
```
**4. Test it end-to-end** against the live account:
```powershell
.\.venv\Scripts\python.exe -c "import server; print(server.list_chats())"
```
That's it — the server auto-detects the credentials and uses the live account
(`LEADS_SOURCE=auto`). To go back to the sample export for testing, set
`LEADS_SOURCE=json` in `.env`. The session string lives only in `.env` (which is
gitignored) — never in code.
## Setup
Requires Python 3.10+.
```bash
# from the project root
python -m venv .venv
# Windows PowerShell: .venv\Scripts\Activate.ps1
# macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt
```
### 1. Provide the data
Replace `data/leads_export.json` with the **slimmed** lead-chat export (lead
chats only — not a full account dump). The loader accepts the standard Telegram
Desktop shapes: `{"chats": {"list": [...]}}`, a top-level list, or a single-chat
`{"name", "messages"}` object.
A sample fixture ships in the repo so you can run the server immediately.
### 2. Set the whitelist
Edit `config/whitelist.json` — a JSON array of the exact chat names that are
leads. Anything not listed is invisible to every tool.
```json
["Acme Corp — Jordan", "Beta Logistics — Priya"]
```
Tip: run `list_chats` after pointing the loader at the full export to see the
names, then narrow the whitelist to the real leads.
## Tools
| Tool | Status | What it does |
|------|--------|--------------|
| `list_chats` | ✅ | Whitelisted chats: name, message count, last message date. |
| `get_chat_messages(chat_name, limit=100, since_date=None)` | ✅ | Cleaned message history for one whitelisted chat. |
| `analyze_lead_conversation(chat_name)` | ✅ | Full thread as ordered `{sender, timestamp, text}` for the client to analyze. |
| `search_chats` | 🚧 stub | Keyword search across whitelisted chats. |
| `extract_followups` | 🚧 stub | Promised/missed follow-ups. |
| `summarize_conversation` | 🚧 stub | Server-side summary (deferred). |
| `create_task_or_note` | 🚧 stub | Task/note creation (write path, inert). |
## Run / smoke test
```bash
# Verify the data layer and tools without an MCP client:
python smoke_test.py
```
To run the MCP server directly (it speaks stdio and waits for a client):
```bash
python server.py
```
## Deploy to Railway (remote URL connector)
For connecting Claude to a hosted URL instead of running locally. The server
auto-switches to **HTTP transport** when a `PORT` env var is present (Railway
sets it), so no code change is needed.
**1. Push this repo to GitHub** (done) and create a Railway project **from the repo**.
**2. Set environment variables in Railway** (Settings → Variables) — these
replace the local `.env`, which is never committed:
| Variable | Value |
|----------|-------|
| `TELEGRAM_API_ID` | Edrian's api_id |
| `TELEGRAM_API_HASH` | Edrian's api_hash |
| `TELEGRAM_SESSION` | the session string |
| `LEADS_WHITELIST_JSON` | *(optional)* inline JSON array of lead chat names; overrides the committed `config/whitelist.json` so client names need not live in git |
| `TELEGRAM_FETCH_LIMIT` | *(optional)* default `500` |
Railway provides `PORT` automatically — don't set it.
**3. Deploy.** Railway builds via Nixpacks (`requirements.txt`) and runs
`python server.py` (see `Procfile` / `railway.json`). The MCP endpoint is:
```
https://<your-app>.up.railway.app/mcp
```
**4. Connect Claude** (claude.ai → Settings → Connectors → Add custom connector)
to that `/mcp` URL.
> ⚠️ **Security:** this endpoint exposes the account's lead chats to anyone who
> can reach the URL — it has no built-in auth. Keep the URL private, and prefer
> putting an auth layer (or Railway private networking) in front of it before
> sharing. The session string is full account access; treat the deployment as
> sensitive.
## Register with Claude Desktop
Add this to your Claude Desktop config
(`%APPDATA%\Claude\claude_desktop_config.json` on Windows,
`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS).
Use **absolute paths**.
```json
{
"mcpServers": {
"telegram-lead-analysis": {
"command": "d:\\ZeroPenny\\Telegram MCP\\.venv\\Scripts\\python.exe",
"args": ["d:\\ZeroPenny\\Telegram MCP\\server.py"]
}
}
}
```
Restart Claude Desktop, then ask it to "list my Telegram lead chats" or
"analyze the Acme Corp lead".
### Switching to live Telegram (later)
1. Implement the `_raw_*` hooks in `datasource/telethon_source.py`.
2. In `server.py`, swap the one line in `build_data_source()` from
`JSONLeadDataSource(...)` to `TelethonLeadDataSource(whitelist)`.
3. Set `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`, `TELEGRAM_SESSION` in the
environment (e.g. via the Claude Desktop config `"env"` block). No tool
definitions change.
## A note on the export Edrian sent
The export received was the **entire account** (672 chats, contacts, stories,
phone number) — far more than the lead chats and a privacy over-share. Treat it
as a throwaway test fixture only. For the real build we need just the specific
lead chats plus the session credentials. Tell Edrian he over-shared.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing