agentleFS
n24q02mn24q02m/better-telegram-mcp/CLAUDE.md

better-telegram-mcp

CLAUDE.md11 starsChanged 21 days agoApache-2.0View on GitHub

MCP Server cho Telegram. Python 3.13, uv, hatchling, src layout. Dual-mode: Bot API (httpx) + MTProto (Telethon). 7 tools: message, chat, media, contact, config, help, config_openrelay. Stdio mode (default): local single-user mode. Bot mode uses TELEGRAMBOTTOKEN; user mode can be configured with the local auth CLI (login is a deprecated alias). HTTP mode (--http / MCPTRANSPORT=http): mcp-core runhttpserver serves the local OAuth AS at /authorize. The custom credential form collects bottoken OR phone, posts to /save, and chains OTP /…

We split this CLAUDE.md into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Commit message: enforce Conventional Commits

    line 88

≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

CLAUDE.md - telegram

MCP Server cho Telegram. Python 3.13, uv, hatchling, src layout. Dual-mode: Bot API (httpx) + MTProto (Telethon). 7 tools: message, chat, media, contact, config, help, config__open_relay.

Commands

uv sync --group dev          # Setup
uv run ruff check .          # Lint
uv run ruff format --check . # Format check
uv run ty check              # Type check
uv run pytest                # Test (integration excluded)
uv run ruff check --fix . && uv run ruff format .  # Fix

Cau truc

src/telegram/
  config.py            # Pydantic Settings, env prefix TELEGRAM_
  server.py            # FastMCP + lifespan + auth mode switching
  credential_state.py  # save_credentials/on_step_submitted callbacks +
                       # _current_sub contextvar (multi-user routing)
  auth/
    telegram_auth_provider.py  # Per-sub Telethon backend lifecycle
    in_memory_session_store.py # bearer/sub -> SessionInfo (RAM only)
  backends/            # TelegramBackend ABC -> BotBackend (httpx), UserBackend (Telethon)
  backends/security.py # validate_url, validate_file_path, validate_output_dir
  relay_setup.py       # Shared error sanitization, field constants
  relay_schema.py      # Relay schema + TELEGRAM_TABS layout + render_telegram_form
                       # (Bot/User tabs drawn by mcp-core render_credential_form)
  transports/
    http.py            # _start_single_user_http + _start_multi_user_http
                       # (both via mcp-core run_http_server)
    credential_store.py# Master-secret resolution helper
  tools/               # messages, chats, media, contacts, config_tool, help

Auth flow

Stdio mode (default): local single-user mode. Bot mode uses TELEGRAM_BOT_TOKEN; user mode can be configured with the local auth CLI (login is a deprecated alias).

HTTP mode (--http / MCP_TRANSPORT=http): mcp-core run_http_server serves the local OAuth AS at /authorize. The custom credential form collects bot_token OR phone, posts to /save, and chains OTP / 2FA via /otp.

  • Single-user: writes to config.enc, hot-reloads the global Telethon backend in server.py.
  • Multi-user remote (PUBLIC_URL + MCP_DCR_SERVER_SECRET set; legacy DCR_SERVER_SECRET still accepted): per-sub Telethon backends managed by TelegramAuthProvider; the auth_scope middleware (_per_request_sub_scope) pins the JWT sub + per-user backend into contextvars before each MCP tool call.

Session persist: ~/.telegram/<name>.session, permission 600 (moved once from the pre-rename ~/.better-telegram-mcp/ by config.resolve_default_data_dir(); ~/.telegram-mcp written by mcp-core PerPluginStore is a separate dir, unchanged).

Env vars

  • TELEGRAM_BOT_TOKEN -- bot mode
  • TELEGRAM_API_ID + TELEGRAM_API_HASH -- user mode (built-in defaults, override optional)
  • TELEGRAM_PHONE -- phone for local auth or the HTTP relay form
  • TELEGRAM_SESSION_NAME, TELEGRAM_DATA_DIR -- optional
  • MCP_TRANSPORT / TRANSPORT_MODE -- set to http to opt into HTTP mode (default wire transport is stdio); --http CLI flag does the same
  • PUBLIC_URL -- deployed hostname; presence flips on the multi-user OAuth branch (with the DCR secret + api_id/api_hash)
  • MCP_DCR_SERVER_SECRET -- multi-user remote OAuth shared secret (with PUBLIC_URL); legacy DCR_SERVER_SECRET still accepted

No TELEGRAM_AUTH_URL -- auth is not configured through a URL environment variable. HTTP user setup is served by mcp-core's OAuth AS and relay form, locally or under PUBLIC_URL; local single-user setup uses the auth CLI.

NO TELEGRAM_PASSWORD -- HTTP relay 2FA nhap qua web UI; local CLI auth prompts interactively, KHONG luu env.

Release & Deploy

  • Conventional Commits. Tag format: v{version}
  • CD: PSR v10 -> PyPI n24q02m-telegram (uv publish) -> Docker multi-arch (amd64 + arm64) -> MCP Registry
  • Docker images: n24q02m/telegram (Docker Hub) + ghcr.io/n24q02m/telegram

Pre-commit hooks

  1. Ruff lint (--fix) + format
  2. ty type check
  3. pytest (--tb=short -q)
  4. Commit message: enforce Conventional Commits

Luu y

  • Config tool: status|set|cache_clear|setup_* (HTTP user auth lives in mcp-core's OAuth AS; local single-user auth uses the auth CLI)
  • Security: SSRF, path traversal, error sanitization, rate limiting on relay
  • Secrets: skret SSM namespace /better-telegram-mcp/prod (region ap-southeast-1)

Known bugs

(All 2026-04-18 E2E findings have been resolved. Section retained as a short audit trail with the fix commit so future investigators do not re-open closed issues.)

  1. Bot token leak via httpx INFO logs -- RESOLVED. server.py:24 sets logging.getLogger("httpx").setLevel(logging.WARNING) so request URLs (which include the bot token) never reach stderr at INFO level.
  2. User mode OTP/2FA multi-step flow -- RESOLVED. mcp-core's shared credential form (schema-level tabs, mcp-core >=1.20.0b1) renders the Bot/User tabs; its showStepInput JS handles next_step.type === "otp_required" + password_required. Wired into mcp-core's local OAuth AS via run_http_server(..., custom_credential_form_html=render_telegram_form, on_step_submitted=on_step_submitted) — render_telegram_form (relay_schema.py) declares TELEGRAM_TABS + the initial_tab hint and delegates rendering to render_credential_form. After phone submit, the same page re-renders the OTP input, posts to /otp, and chains to the 2FA password step if Telethon reports it. The forked credential_form.py was dropped once the tabs capability landed in mcp-core.
  3. Setup-complete UI redirect -- RESOLVED via mcp-core feedback_relay_form_must_follow_redirect.md fix; the form follows redirect_url instead of showing a static "close tab" page.

E2E

Driven by mcp-core/scripts/e2e/ (matrix-locked, 15 configs). Run a single config from this repo via make e2e (proxy) or directly:

cd ../mcp-core && uv run --project scripts/e2e python -m e2e.driver <config-id>

Configs for this repo: telegram-bot, telegram-user.

telegram-user is t2-interaction (browser-form OTP + 2FA, 600s timeout).

Tier policy:

  • T0 (precommit + CI on PR / main push) - runs without upstream identity. Skret keys not required.
  • T2 non-interaction (make e2e-config CONFIG=<id> locally) - driver pre-fills relay form from skret AWS SSM /better-telegram-mcp/prod (ap-southeast-1). No user gate.
  • T2 interaction - driver fills relay form, then prints upstream user-gate URL; user signs in / types OTP at provider. Driver enforces per-flow timeouts (device-code 900s, oauth-redirect 300s, browser-form 600s) and emits [poll] elapsed=Xs remaining=Ys status=<body> every 30s. On timeout, container logs + last setup-status are saved to <tmp>/e2e-diag/ BEFORE teardown for post-mortem.

Multi-user remote mode (deployment property; not a separate config) requires MCP_DCR_SERVER_SECRET (legacy DCR_SERVER_SECRET still accepted) in the same skret namespace - driver refuses to start the container without it when PUBLIC_URL is set.

References: mcp-core/scripts/e2e/matrix.yaml, ~/.claude/skills/mcp-dev/references/e2e-full-matrix.md (harness-readiness gate), ~/.claude/skills/mcp-dev/references/secrets-skret.md (per-server credential layout), ~/.claude/skills/mcp-dev/references/multi-user-pattern.md (per-JWT-sub isolation).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.