npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@safra36/telegram-mcp-server

v0.1.1

Published

Full-capability Telegram MCP server (stdio + Streamable HTTP) backed by your user account via mtcute.

Readme

telegram-mcp-server

Full-capability Telegram MCP (Model Context Protocol) server backed by your Telegram user account via mtcute. Drop it into Claude Desktop, Claude Code, Cursor, or any MCP host and let the model read your dialogs, search history, send messages, manage chats, and download media — with allowlists and rate limits keeping it on a leash.

Speaks both transports the spec defines:

  • stdio — local subprocess (default for desktop hosts)
  • Streamable HTTP — remote / multi-client, bearer-authed

⚠️ This is a Telegram user client, not a bot. It logs in with your phone number and can do anything you can. Read the Safety section before pointing an LLM at it.


Features

~40 tools across six categories. Write tools are hidden in the default read-only mode.

| Category | Tools | | --- | --- | | Read | list_dialogs, get_history, get_message, search_messages, get_chat_info, resolve_peer, get_user_info, get_chat_members, list_contacts, get_pinned_messages, get_message_reactions | | Write | send_message, reply_to, edit_message, delete_messages, forward_messages, copy_message, pin_message, unpin_message, mark_read, send_reaction, send_typing | | Media | send_media, send_album, download_media | | Admin | join_chat, leave_chat, create_group, create_channel, set_chat_title, set_chat_description, ban_member, unban_member, kick_member, create_invite_link, revoke_invite_link, add_contact, remove_contact, block_user, unblock_user, delete_history | | Account | get_me, get_common_chats, update_profile, set_username | | Updates | wait_for_message |

Plus MCP resources (telegram://me, telegram://chat/{id}) and prompts (summarize_chat, draft_reply).

Guardrails:

  • Allowlist per-category (send / delete / admin) with * wildcard
  • Token-bucket rate limit: global + per-chat
  • FloodWait auto-retry for short waits, surfaces longer ones as errors
  • Log redaction of message text, captions, phone numbers, codes, tokens
  • Mode gating: in read-only mode write tools aren't even registered (the model can't call what it can't see)

Quick start

1. Install

npm install -g @safra36/telegram-mcp-server

Or run from source:

git clone https://github.com/safra36/telegram-mcp-server
cd telegram-mcp-server
npm install
npm run build

2. Get Telegram API credentials

Go to https://my.telegram.org/apps, sign in, create an app, and grab api_id + api_hash.

3. Configure

Two equally supported ways to feed config in. Pick whichever fits how you're invoking the server.

A. --config JSON argument — best for MCP host config blocks:

telegram-mcp-server start --config '{"apiId":1234567,"apiHash":"abc...","session":"./tg.session","mode":"read-only"}'

Or point at a JSON file:

telegram-mcp-server start --config ./tg-mcp.json

B. Environment variables — best for shell/dev use or hosts that prefer env:

export TG_API_ID=1234567
export TG_API_HASH=abc...
export TG_SESSION=./tg.session
telegram-mcp-server start

Precedence is --config > env vars > defaults, applied per-key. So you can put secrets in env and non-secret settings in JSON, or vice versa.

The server does not auto-load a .env file — that's the host's job, not a library's. If you want one anyway: npx dotenv -e .env -- telegram-mcp-server start.

Minimum required: apiId + apiHash. See the config reference for the full shape.

4. Log in (one-time)

telegram-mcp-server login

This walks you through phone → code → optional 2FA password and writes the session file. You only need to do this once per session file.

5. Verify

telegram-mcp-server doctor

Connects with your session and prints your user info.

6. Wire it into a host

telegram-mcp-server mcp-config --host claude-desktop

Copy the printed JSON block into your host config. For Claude Desktop on Windows, that's %APPDATA%\Claude\claude_desktop_config.json; for macOS ~/Library/Application Support/Claude/claude_desktop_config.json.

Recommended shape — config inlined into args (no env block needed, all settings in one place):

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": [
        "-y", "@safra36/telegram-mcp-server", "start",
        "--config", "{\"apiId\":1234567,\"apiHash\":\"abc...\",\"session\":\"C:/Users/you/tg.session\",\"mode\":\"read-only\"}"
      ]
    }
  }
}

Or, equivalently, via env (use mcp-config --format env to generate):

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": ["-y", "@safra36/telegram-mcp-server", "start"],
      "env": {
        "TG_API_ID": "1234567",
        "TG_API_HASH": "abc...",
        "TG_SESSION": "C:/Users/you/tg.session",
        "TG_MODE": "read-only"
      }
    }
  }
}

Transports

stdio (default)

telegram-mcp-server start

The host spawns this as a subprocess and talks JSON-RPC over stdin/stdout. Logs go to stderr.

Streamable HTTP

telegram-mcp-server start --transport http

Requires TG_HTTP_TOKEN (≥16 chars) in the environment. Defaults to 127.0.0.1:7878. The server warns if you bind to a non-loopback address — you really want a reverse proxy with TLS in front of it if you do that.

Clients hit POST/GET/DELETE /mcp with Authorization: Bearer <token>. Sessions are tracked via Mcp-Session-Id per the Streamable HTTP spec.

CORS is allowlist-based (TG_HTTP_CORS_ORIGINS, comma-separated).


Modes & allowlists

TG_MODE controls what categories of tools are even registered:

  • read-only (default, recommended) — only read tools. The LLM literally cannot send a message.
  • read-write — registers all tools, but write tools still gate on allowlists.

Allowlists (comma-separated; chat ids or usernames; * = any):

TG_ALLOWLIST_SEND=me,@my_test_group,-1001234567890
TG_ALLOWLIST_DELETE=me
TG_ALLOWLIST_ADMIN=

If an allowlist is empty, that category is denied for every chat. If it's *, it's allowed everywhere — use with care.


Rate limiting

Token-bucket, refilled per-second:

TG_RATE_GLOBAL_PER_SEC=2
TG_RATE_GLOBAL_BURST=5
TG_RATE_CHAT_PER_SEC=1
TG_RATE_CHAT_BURST=3

When exhausted, the tool returns an error result with the suggested retryAfterMs — the model can back off and try again.


FloodWait handling

Telegram returns FLOOD_WAIT_<n> when you're being too chatty. The server auto-retries once for short waits:

TG_FLOOD_WAIT_MAX_AUTO_RETRY_SEC=10

Longer waits surface as errors (with the wait duration) so the model can decide whether to wait or do something else.


Configuration reference

Every setting has both a JSON key (for --config) and an env var. Either form works.

| JSON key | Env var | Default | Purpose | | --- | --- | --- | --- | | apiId | TG_API_ID | — | Required. From my.telegram.org | | apiHash | TG_API_HASH | — | Required. From my.telegram.org | | session | TG_SESSION | ./tg-session | mtcute session file/dir path | | mode | TG_MODE | read-only | read-only | read-write | | allowlist.send | TG_ALLOWLIST_SEND | (empty) | Chats where sending is allowed (* = any) | | allowlist.delete | TG_ALLOWLIST_DELETE | (empty) | Chats where deleting is allowed | | allowlist.admin | TG_ALLOWLIST_ADMIN | (empty) | Chats where admin ops are allowed | | rateLimit.globalPerMin | TG_RATE_GLOBAL_PER_MIN | 20 | Global rate cap | | rateLimit.perChatPerMin | TG_RATE_PER_CHAT_PER_MIN | 5 | Per-chat rate cap | | floodWait.maxAutoRetrySec | TG_FLOODWAIT_MAX_RETRY_SEC | 30 | Auto-retry FloodWait up to this many seconds | | downloadDir | TG_DOWNLOAD_DIR | ./downloads | Where download_media writes files | | http.host | TG_HTTP_HOST | 127.0.0.1 | HTTP bind address | | http.port | TG_HTTP_PORT | — | Set to enable HTTP transport | | http.token | TG_HTTP_TOKEN | — | Bearer token, required when HTTP is on (≥16 chars) | | http.cors | TG_HTTP_CORS | (empty) | CORS allowlist (env: comma-separated) | | log.file | TG_LOG_FILE | — | Optional log file (otherwise stderr only) | | log.redact | TG_LOG_REDACT | true | Redact message text / phone / token fields in logs | | proxy | TG_PROXY_URL | — | Proxy URL — SOCKS4/5, HTTP/HTTPS, or MTProxy. See Proxy support |

Env vars taking lists (TG_ALLOWLIST_*, TG_HTTP_CORS) are comma-separated. JSON equivalents are arrays.


Proxy support

The server can route Telegram traffic through SOCKS4/5, HTTP/HTTPS, or MTProxy. Pass a URL in proxy / TG_PROXY_URL:

socks5://user:[email protected]:1080
socks4://1.2.3.4:1080
http://user:[email protected]:8080
https://user:[email protected]:443
https://t.me/proxy?server=example.com&port=443&secret=3dpBFlW2hP6Hq_WOwiNeKBY

The MTProxy form accepts both the raw secret hex and Telegram's t.me/proxy?... share URLs (including Fake TLS variants).

Proxy credentials in the URL are redacted by doctor output and the structured logger.


Safety

Read this.

  1. You are giving an LLM access to your Telegram account. Anything you can do, it can do. Start in read-only mode. Graduate to read-write only after you've watched it behave for a while, and only with a tight allowlist.
  2. Use a dedicated test chat for write experiments. Set allowlist.send to just ["@my_llm_sandbox"] and nothing else.
  3. delete_messages and delete_history are irreversible. Keep allowlist.delete empty unless you really mean it.
  4. Session file = full account access. Treat it like a password. Don't commit it. Don't sync it to cloud storage.
  5. Logs may contain message metadata even with redaction on. Set log.file carefully.
  6. HTTP transport on non-loopback = exposure. Bind to 127.0.0.1 and tunnel via SSH, or put a TLS-terminating reverse proxy in front with the bearer token enforced.

Programmatic use

import { buildServer, loadConfig, startServerClient, createLogger } from '@safra36/telegram-mcp-server'

const config = loadConfig()
const log = createLogger(config.log)
const client = await startServerClient(config, log)
const server = buildServer({ client, config, log })

// Connect your own transport here

License

MIT