telegram: make MCP config portable across machines
- .mcp.json: switch telegram-* args to relative path (scripts/telegram-mcp.sh) so the committed config no longer pins a single user's home directory - telegram-mcp.sh / regen_telegram_session.sh: drop hardcoded fallbacks for TELEGRAM_MCP_BIN / TELEGRAM_MCP_DIR; require them from .env with explicit error messages naming the missing variable - .env.example: document per-machine path variables and per-account session strings, with a warning not to copy sessions between devices (Telegram revokes the auth key when one session is used from two IPs) - CLAUDE.md: add a Bootstrap-on-a-new-machine section with the setup steps, the portability rationale, and a troubleshooting table for the common MCP / session failure modes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
80c918d282
commit
f4b75ebb7d
20
.env.example
20
.env.example
|
|
@ -1,5 +1,25 @@
|
||||||
|
# Copy this file to .env and fill in the values on each machine.
|
||||||
|
# .env is gitignored — secrets and per-machine paths never leave the device.
|
||||||
|
|
||||||
|
# --- Trello (shared across machines) ---
|
||||||
TRELLO_API_KEY=your_trello_api_key_here
|
TRELLO_API_KEY=your_trello_api_key_here
|
||||||
TRELLO_TOKEN=your_trello_token_here
|
TRELLO_TOKEN=your_trello_token_here
|
||||||
|
|
||||||
|
# --- Telegram API credentials (shared across machines: one app registration) ---
|
||||||
TELEGRAM_API_ID=
|
TELEGRAM_API_ID=
|
||||||
TELEGRAM_API_HASH=
|
TELEGRAM_API_HASH=
|
||||||
|
|
||||||
|
# --- Per-machine: absolute paths to the telegram-mcp install on THIS machine ---
|
||||||
|
# TELEGRAM_MCP_DIR — root of the telegram-mcp checkout (used by the session generator)
|
||||||
|
# TELEGRAM_MCP_BIN — the telegram-mcp executable inside that checkout's .venv
|
||||||
|
TELEGRAM_MCP_DIR=/absolute/path/to/telegram
|
||||||
|
TELEGRAM_MCP_BIN=/absolute/path/to/telegram/.venv/bin/telegram-mcp
|
||||||
|
|
||||||
|
# --- Per-machine Telegram session strings ---
|
||||||
|
# DO NOT copy these between machines. Each device/IP must have its own session,
|
||||||
|
# or Telegram will permanently revoke the auth key.
|
||||||
|
# Generate on THIS machine with:
|
||||||
|
# pnpm tg:session:usulsu -> writes TELEGRAM_SESSION_STRING
|
||||||
|
# pnpm tg:session:helper -> writes TELEGRAM_SESSION_STRING_HELPER
|
||||||
TELEGRAM_SESSION_STRING=
|
TELEGRAM_SESSION_STRING=
|
||||||
|
TELEGRAM_SESSION_STRING_HELPER=
|
||||||
|
|
|
||||||
10
.mcp.json
10
.mcp.json
|
|
@ -18,17 +18,11 @@
|
||||||
},
|
},
|
||||||
"telegram-usulpro": {
|
"telegram-usulpro": {
|
||||||
"command": "bash",
|
"command": "bash",
|
||||||
"args": [
|
"args": ["scripts/telegram-mcp.sh", "usulsu"]
|
||||||
"/home/usul/workspace/projects/cv-2026/scripts/telegram-mcp.sh",
|
|
||||||
"usulsu"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"telegram-helper": {
|
"telegram-helper": {
|
||||||
"command": "bash",
|
"command": "bash",
|
||||||
"args": [
|
"args": ["scripts/telegram-mcp.sh", "helper"]
|
||||||
"/home/usul/workspace/projects/cv-2026/scripts/telegram-mcp.sh",
|
|
||||||
"helper"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
CLAUDE.md
51
CLAUDE.md
|
|
@ -136,6 +136,57 @@ After a run, triage `telegram_inbox.json` and promote promising postings to [`tr
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Bootstrap on a new machine
|
||||||
|
|
||||||
|
This project runs on multiple machines (VPS, laptops) with different filesystem paths. The committed config is fully portable; everything machine-specific lives in `.env` and `.secrets/` (both gitignored). When Oleg sets up a new device, or when something Telegram-related breaks ("MCP not connecting", "session revoked", "TELEGRAM_MCP_BIN not set", etc.), walk through this.
|
||||||
|
|
||||||
|
### One-time setup on a fresh checkout
|
||||||
|
|
||||||
|
1. **`.env`** — copy from the template, then fill in:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
Required keys:
|
||||||
|
- `TRELLO_API_KEY`, `TRELLO_TOKEN` — same across machines (copy from another device's `.env`).
|
||||||
|
- `TELEGRAM_API_ID`, `TELEGRAM_API_HASH` — same across machines (one app registration).
|
||||||
|
- `TELEGRAM_MCP_DIR` — **per-machine** absolute path to the `telegram-mcp` checkout on THIS machine.
|
||||||
|
- `TELEGRAM_MCP_BIN` — **per-machine** absolute path to the `telegram-mcp` executable, typically `$TELEGRAM_MCP_DIR/.venv/bin/telegram-mcp`.
|
||||||
|
- `TELEGRAM_SESSION_STRING`, `TELEGRAM_SESSION_STRING_HELPER` — leave empty; generated in step 3.
|
||||||
|
|
||||||
|
2. **Node deps**:
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Generate Telegram sessions on THIS machine** (one per account):
|
||||||
|
```bash
|
||||||
|
pnpm tg:session:usulsu # QR-login as @usulpro (main)
|
||||||
|
pnpm tg:session:helper # QR-login as @samuishka (helper)
|
||||||
|
```
|
||||||
|
Each command opens a QR code in the terminal. Scan it from the corresponding Telegram account on Oleg's phone. The script writes the session string into `.env` and a copy into `.secrets/session_<account>.txt`.
|
||||||
|
|
||||||
|
**Critical rule — sessions are per-device:** never copy `TELEGRAM_SESSION_STRING*` between machines. A Telegram auth key used from two IPs gets permanently revoked, and **both** devices lose access until re-authorized. Always run the regen script on each new machine.
|
||||||
|
|
||||||
|
4. **Reconnect MCP servers** in Claude Code (`/mcp` → reconnect both `telegram-usulpro` and `telegram-helper`), or restart Claude Code.
|
||||||
|
|
||||||
|
### How paths stay portable
|
||||||
|
|
||||||
|
- `.mcp.json` uses a relative path (`scripts/telegram-mcp.sh`) — Claude Code launches project-scoped MCP servers with the project root as CWD, so this resolves correctly on any machine.
|
||||||
|
- `scripts/telegram-mcp.sh` and `scripts/regen_telegram_session.sh` read `TELEGRAM_MCP_BIN` / `TELEGRAM_MCP_DIR` from `.env`. They fail with an explicit error message if the variable is missing or points at a non-existent path — never guess a default.
|
||||||
|
|
||||||
|
### Troubleshooting cheat sheet
|
||||||
|
|
||||||
|
| Symptom | Cause | Fix |
|
||||||
|
|---|---|---|
|
||||||
|
| MCP server `telegram-usulpro` / `telegram-helper` won't start | `.env` missing, or `TELEGRAM_MCP_BIN` not set / not executable on this machine | Check the server's stderr in Claude Code logs; the script prints exactly what's missing. Fill in `.env`. |
|
||||||
|
| `session string for 'usulsu' is empty in .env` | Sessions weren't generated on this machine yet | `pnpm tg:session:usulsu` (and/or `:helper`) |
|
||||||
|
| `generator not found at .../.venv/bin/python` | `TELEGRAM_MCP_DIR` points at the wrong place, or `.venv` not created in the telegram-mcp checkout | Fix the path in `.env`; in the telegram-mcp checkout run its venv setup |
|
||||||
|
| Telegram suddenly logs us out / revokes the key | A session string got reused across two machines/IPs | Regen on each affected machine separately with `pnpm tg:session:<account>`; never copy session strings |
|
||||||
|
| `scripts/telegram-mcp.sh: No such file or directory` from Claude Code | `.mcp.json` got hardcoded back to an absolute path | Restore relative form: `"args": ["scripts/telegram-mcp.sh", "usulsu"]` |
|
||||||
|
| `list_telegram_channels.py` / `fetch_telegram_jobs.py` fail to auth | `TELEGRAM_SESSION_STRING` in `.env` doesn't match the usulsu account (these direct Telethon scripts always use usulsu) | Regen with `pnpm tg:session:usulsu` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Folder layout
|
## Folder layout
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -27,20 +27,27 @@ case "$ACCOUNT" in
|
||||||
esac
|
esac
|
||||||
|
|
||||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
TELEGRAM_DIR="${TELEGRAM_MCP_DIR:-/home/usul/workspace/projects/my-utils/telegram}"
|
|
||||||
ENV_FILE="$PROJECT_ROOT/.env"
|
ENV_FILE="$PROJECT_ROOT/.env"
|
||||||
SECRETS_DIR="$PROJECT_ROOT/.secrets"
|
SECRETS_DIR="$PROJECT_ROOT/.secrets"
|
||||||
OUT_FILE="$SECRETS_DIR/session_${ACCOUNT}.txt"
|
OUT_FILE="$SECRETS_DIR/session_${ACCOUNT}.txt"
|
||||||
|
|
||||||
[ -f "$ENV_FILE" ] || { echo "missing $ENV_FILE" >&2; exit 1; }
|
[ -f "$ENV_FILE" ] || { echo "missing $ENV_FILE (copy .env.example and fill it in)" >&2; exit 1; }
|
||||||
set -a; . "$ENV_FILE"; set +a
|
set -a; . "$ENV_FILE"; set +a
|
||||||
if [ -z "${TELEGRAM_API_ID:-}" ] || [ -z "${TELEGRAM_API_HASH:-}" ]; then
|
if [ -z "${TELEGRAM_API_ID:-}" ] || [ -z "${TELEGRAM_API_HASH:-}" ]; then
|
||||||
echo "TELEGRAM_API_ID / TELEGRAM_API_HASH missing in $ENV_FILE" >&2
|
echo "TELEGRAM_API_ID / TELEGRAM_API_HASH missing in $ENV_FILE" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
TELEGRAM_DIR="${TELEGRAM_MCP_DIR:-}"
|
||||||
|
if [ -z "$TELEGRAM_DIR" ]; then
|
||||||
|
echo "TELEGRAM_MCP_DIR not set in $ENV_FILE" >&2
|
||||||
|
echo "point it at the telegram-mcp checkout on THIS machine, e.g.:" >&2
|
||||||
|
echo " TELEGRAM_MCP_DIR=/path/to/telegram" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
[ -x "$TELEGRAM_DIR/.venv/bin/python" ] || {
|
[ -x "$TELEGRAM_DIR/.venv/bin/python" ] || {
|
||||||
echo "generator not found at $TELEGRAM_DIR/.venv/bin/python" >&2
|
echo "generator not found at $TELEGRAM_DIR/.venv/bin/python" >&2
|
||||||
echo "set TELEGRAM_MCP_DIR to your telegram-mcp checkout" >&2; exit 1; }
|
echo "check TELEGRAM_MCP_DIR in $ENV_FILE and that its .venv is created" >&2; exit 1; }
|
||||||
|
|
||||||
mkdir -p "$SECRETS_DIR"
|
mkdir -p "$SECRETS_DIR"
|
||||||
tmp="$(mktemp)"; trap 'rm -f "$tmp"' EXIT
|
tmp="$(mktemp)"; trap 'rm -f "$tmp"' EXIT
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Launch the telegram-mcp server for one account, reading API creds and the
|
# Launch the telegram-mcp server for one account, reading API creds and the
|
||||||
# session string from the project .env. Used by .mcp.json so that NO secrets
|
# session string from the project .env. Used by .mcp.json so that NO secrets
|
||||||
# are hardcoded in the committed config.
|
# and NO machine-specific paths are hardcoded in the committed config.
|
||||||
#
|
#
|
||||||
# Usage (from .mcp.json):
|
# Usage (from .mcp.json):
|
||||||
# bash scripts/telegram-mcp.sh usulsu # main account -> TELEGRAM_SESSION_STRING
|
# bash scripts/telegram-mcp.sh usulsu # main account -> TELEGRAM_SESSION_STRING
|
||||||
# bash scripts/telegram-mcp.sh helper # samuishechka -> TELEGRAM_SESSION_STRING_HELPER
|
# bash scripts/telegram-mcp.sh helper # samuishechka -> TELEGRAM_SESSION_STRING_HELPER
|
||||||
#
|
#
|
||||||
# The telegram-mcp binary path can be overridden with TELEGRAM_MCP_BIN.
|
# Per-machine config (must live in .env, not committed):
|
||||||
|
# TELEGRAM_MCP_BIN absolute path to the telegram-mcp executable on THIS machine
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ACCOUNT="${1:?usage: telegram-mcp.sh <usulsu|helper>}"
|
ACCOUNT="${1:?usage: telegram-mcp.sh <usulsu|helper>}"
|
||||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
BIN="${TELEGRAM_MCP_BIN:-/home/usul/workspace/projects/my-utils/telegram/.venv/bin/telegram-mcp}"
|
|
||||||
|
|
||||||
[ -f "$PROJECT_ROOT/.env" ] || { echo "missing $PROJECT_ROOT/.env" >&2; exit 1; }
|
[ -f "$PROJECT_ROOT/.env" ] || { echo "missing $PROJECT_ROOT/.env (copy .env.example and fill it in)" >&2; exit 1; }
|
||||||
set -a; . "$PROJECT_ROOT/.env"; set +a
|
set -a; . "$PROJECT_ROOT/.env"; set +a
|
||||||
|
|
||||||
case "$ACCOUNT" in
|
case "$ACCOUNT" in
|
||||||
|
|
@ -28,9 +28,19 @@ if [ -z "${TELEGRAM_API_ID:-}" ] || [ -z "${TELEGRAM_API_HASH:-}" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ -z "${TELEGRAM_SESSION_STRING:-}" ]; then
|
if [ -z "${TELEGRAM_SESSION_STRING:-}" ]; then
|
||||||
echo "session string for '$ACCOUNT' is empty in .env — regenerate it with:" >&2
|
echo "session string for '$ACCOUNT' is empty in .env — regenerate it on THIS machine with:" >&2
|
||||||
echo " pnpm tg:session:$ACCOUNT" >&2
|
echo " pnpm tg:session:$ACCOUNT" >&2
|
||||||
|
echo "(do not copy session strings between machines — Telegram revokes the key)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
BIN="${TELEGRAM_MCP_BIN:-}"
|
||||||
|
if [ -z "$BIN" ]; then
|
||||||
|
echo "TELEGRAM_MCP_BIN not set in $PROJECT_ROOT/.env" >&2
|
||||||
|
echo "point it at the telegram-mcp executable on THIS machine, e.g.:" >&2
|
||||||
|
echo " TELEGRAM_MCP_BIN=/path/to/telegram/.venv/bin/telegram-mcp" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[ -x "$BIN" ] || { echo "TELEGRAM_MCP_BIN=$BIN is not executable on THIS machine" >&2; exit 1; }
|
||||||
|
|
||||||
exec "$BIN"
|
exec "$BIN"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue