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

@watzon/tgmcp

v0.1.2

Published

MCP server that automates a Telegram user account through the user API.

Readme

tgmcp

npm ci node license

MCP server that automates one Telegram user account through the Telegram user API (mtcute). It is not a bot.

The public tool list is an inbox: list chats, read, send, and search. Everything else lives in an action catalog behind telegram search / describe / invoke. Empty catalog search shows inbox and lookup actions only. Join, leave, and profile edits stay hidden until you search for them.

tgmcp runs on Node.js 20 or newer. npx and bunx both work.

Install

One-shot (no global install):

npx @watzon/tgmcp login
bunx @watzon/tgmcp login

Global install:

npm install -g @watzon/tgmcp
# or
bun add -g @watzon/tgmcp

That puts tgmcp on your PATH.

From a clone:

git clone https://github.com/watzon/tgmcp.git
cd tgmcp
bun install
bun run login

Sign in

  1. Create an application at my.telegram.org and copy api_id / api_hash.
  2. Run tgmcp login (or bun run login in a clone).
  3. Finish the page that opens on 127.0.0.1. The hash, login code, and 2FA stay in the browser. They never enter the model.

Both login paths write storage/credentials.json (api id, hash, owner id) and the mtcute session under the data home.

[!TIP] Local browser login is the one you want. On a remote host, start the MCP server unsigned and use the auth tool: set_credentials, then send_code / sign_in, or start_qr. You can also call auth with browser and open that URL on the machine that runs tgmcp (SSH port-forward if you are not on that host).

Optional: put TELEGRAM_API_ID and TELEGRAM_API_HASH in .env in the data home. Env values override the credentials file.

Check the session with tgmcp status.

Telegram proxy (blocked datacenter IPs)

Many cloud VMs and datacenter hosts cannot reach Telegram's user-API DCs directly. send_code, QR login, and even an existing session copied from another machine will time out with errors like "Telegram did not respond in time" until traffic routes through a proxy that can reach Telegram.

Run an MTProxy (mtg, the official MTProxy, or similar) or a SOCKS5 proxy on a host with normal Telegram access — often a home connection or a VPS outside blocked ranges. Point tgmcp at that endpoint; tgmcp does not provide the proxy itself.

Set the proxy URL in either place (env wins when both are set):

  1. TGMCP_PROXY in .env or the MCP host environment
  2. telegram.proxy in tgmcp.config.json

Supported forms:

# SOCKS5 / SOCKS4
TGMCP_PROXY=socks5://user:[email protected]:1080

# HTTP(S) CONNECT proxy
TGMCP_PROXY=http://proxy.example.com:8080

# MTProxy (query or fragment secret)
TGMCP_PROXY=mtproxy://proxy.example.com:443?secret=HEX
TGMCP_PROXY=mtproxy://proxy.example.com:443#HEX

# Official Telegram share link
TGMCP_PROXY=tg://proxy?server=proxy.example.com&port=443&secret=HEX

auth status reports proxy: { type, host, port } when configured. Secrets and proxy passwords are never logged or returned in tool results.

An existing session file still needs Telegram reachable through the proxy on every connect — copying storage/session alone is not enough if the host cannot talk to Telegram.

Run the MCP server

tgmcp
# same thing:
tgmcp serve

The process speaks MCP on stdio. Point your host at that command. Host snippets for Claude Code, Cursor, OpenClaw, and Hermes are in agent instructions.

Agent instructions

You are installing tgmcp. It is an MCP server that automates one Telegram user account through the Telegram user API. It is not a bot. Do not ask for a bot token.

Requirements

  • Node.js 20 or newer on the machine that will run the server. Prefer npx -y @watzon/tgmcp. bunx @watzon/tgmcp also works.
  • An api_id and api_hash from my.telegram.org. The user already has these, or they get them there.

Do not clone the repo unless the user asked for a development checkout.

Wire the host

Generic stdio, Claude Code, Cursor, and OpenClaw:

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": ["-y", "@watzon/tgmcp"]
    }
  }
}

bunx @watzon/tgmcp is the same command if you prefer Bun.

Hermes:

mcp_servers:
  telegram:
    command: "npx"
    args: ["-y", "@watzon/tgmcp"]

Default data home is ~/.tgmcp. Set TGMCP_HOME in the host env only if the user wants a different directory. From a clone, bun src/index.ts with cwd set to the repo still works.

Sign in

  1. On the same machine as the server, run npx @watzon/tgmcp login (or tgmcp login if it is installed). A page binds to 127.0.0.1. The user finishes it in a browser. Do not ask them to paste apiHash, the login code, or a 2FA password into chat.
  2. On a remote host, start the server unsigned. Call auth with command: "status" first. Then set_credentials, then send_code / sign_in, or start_qr. Prefer auth command: "browser" if they can open or port-forward that URL.
  3. Never echo apiHash, login codes, or 2FA passwords in tool results, logs, or later messages.

After it is connected

  • Call auth with command: "status" once per session before other tools. The tool list does not change with auth state.
  • Use list_chats to get a numeric chatId. Pass that chatId on every chat-scoped call. Groups and channels are negative.
  • Inbox tools: list_chats, read_messages, send_message, search_messages.
  • Longer tail goes through telegram with command search, describe, or invoke. Empty search lists inbox and lookup actions only. Search join, leave, folder, or profile for account-admin actions.

Example:

telegram { command: "search", query: "pin topic" }
telegram { command: "describe", name: "pin" }
telegram { command: "invoke", name: "pin", params: { chatId: "-100123", messageId: 42 } }

Tools

| Tool | Role | | --- | --- | | list_chats | Resolve a title to a numeric chatId | | read_messages | Recent history. Does not mark read | | send_message | Send or reply in a chat | | search_messages | Find messages inside one chat | | telegram | Catalog knife: search, describe, invoke | | auth | Sign-in. Prefer browser locally. Use set_credentials + phone/QR on a remote host. |

Chat-scoped work needs an explicit numeric chatId. Use list_chats first.

Example catalog flow:

telegram { command: "search", query: "pin topic" }
telegram { command: "describe", name: "pin" }
telegram { command: "invoke", name: "pin", params: { chatId: "-100123", messageId: 42 } }

Empty telegram search lists inbox and lookup actions (react, edit, pin, media, user info, topics). Search for join, leave, folder, or profile when you need those.

Data home

Published runs store state in ~/.tgmcp unless you say otherwise:

| Path | What | | --- | --- | | tgmcp.config.json | Denylist, rate limits, relative paths | | storage/credentials.json | api id, hash, owner id (mode 0600) | | storage/session | mtcute SQLite session | | data/tgmcp.db | Append-only action ledger | | data/downloads/ | Saved media |

Resolution order:

  1. TGMCP_HOME if set
  2. The current directory, if it already has tgmcp.config.json (this is how a clone works)
  3. ~/.tgmcp, created on first run

Copy .env.example to .env in that directory if you want env overrides.

Config

tgmcp.config.json looks like this:

{
  "ownerId": "",
  "telegram": {
    "sessionPath": "storage/session",
    "credentialsPath": "storage/credentials.json"
  },
  "ledgerPath": "data/tgmcp.db",
  "downloadsDir": "data/downloads",
  "denylist": [],
  "rateLimits": {
    "perChatMs": 2000,
    "globalPerHour": 120
  }
}

ownerId is filled in after the first login. If you set it yourself, tgmcp refuses to start as a different account.

Optional telegram.proxy holds a proxy URL (same formats as TGMCP_PROXY). Env overrides the file when both are set. See Telegram proxy.

Safety

  • Mutations go through a denylist, per-chat spacing, a global hourly cap, one flood-wait retry, and an append-only ledger.
  • Secrets stay on disk or in .env. The MCP transport is stdio, so logs go to stderr only.
  • This process does not run an agent loop and does not ingest incoming chats on its own.
  • Treat storage/session like a logged-in browser profile. Do not commit it.

Development

bun install
bun test
bun run typecheck
bun run build
node dist/cli.js help
bun run login
bun src/index.ts

CONTEXT.md has the project vocabulary and boundaries.