Telegram MTProto debug and invoke CLI
Call any TL method, trace API calls with correlation IDs, and expose Telegram as an MCP server for LLM-driven interaction.
Install • Quick start • Commands • MCP Setup • Session Management • Configuration
- Invoke any TL method — call the full Telegram API from the terminal with JSON parameters
- Persistent listener — long-running client with IPC server for fast repeated invocations
- Lifecycle tracing — correlation IDs link updates to API calls to responses
- MCP server — expose Telegram as tools for Claude, GPT, or any MCP-compatible LLM
- Multiple auth methods — bot token, phone login, session string, or SQLite database
- Auto-completion — shell completions for bash, zsh, and fish with full method discovery
go install github.com/pageton/gotg-cli/cmd/tgdev@latestOr build from source:
go build -o tgdev ./cmd/tgdev/With version info:
go build -ldflags "-X main.version=$(git describe --tags --always) \
-X main.commit=$(git rev-parse --short HEAD) \
-X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o tgdev ./cmd/tgdev/Requires Go 1.25+.
# Terminal 1 — start a persistent listener
tgdev listen --db ~/tgdev.db --api-id 12345 --api-hash YOUR_HASH --bot-token YOUR_TOKEN
# Terminal 2 — invoke through the listener (fast, reuses connection)
tgdev invoke messages.sendMessage '{"Message":"hello","Peer":{"_":"inputPeerUser","UserID":123,"AccessHash":"..."}}'Tip
When tgdev listen is running, all invoke calls go through a Unix domain socket — no reconnection overhead. Without a listener, invoke creates a standalone connection (slower, requires auth flags).
- Log in at my.telegram.org
- Go to API Development Tools
- Create an application to get your
api_idandapi_hash
tgdev getme --api-id 12345 --api-hash YOUR_HASH --bot-token YOUR_TOKENOr through a running listener:
tgdev getme| Command | Description |
|---|---|
tgdev invoke <method> [json] |
Invoke a TL method via listener or standalone connection |
tgdev listen |
Start persistent client with update stream and IPC server |
tgdev trace |
Full lifecycle tracing with correlation IDs |
tgdev methods [prefix] |
List available TL methods |
tgdev getme |
Get current user/bot info (users.getFullUser) |
tgdev export-session |
Export session string from SQLite database |
tgdev mcp |
Start MCP server (stdio or HTTP) |
tgdev completion <shell> |
Generate shell completions (bash, zsh, fish) |
tgdev version |
Print version |
tgdev help |
Show usage |
# Through a running listener
tgdev invoke users.getFullUser '{"ID":{"_":"inputUserSelf"}}'
# Standalone (no listener needed)
tgdev invoke users.getFullUser '{"ID":{"_":"inputUserSelf"}}' --api-id 12345 --api-hash HASH --bot-token TOKEN
# JSON output
tgdev invoke --format json users.getFullUser '{"ID":{"_":"inputUserSelf"}}'Starts a persistent Telegram client that logs incoming updates and accepts invoke commands over IPC.
tgdev listen --db ~/tgdev.db --api-id 12345 --api-hash HASH --bot-token TOKENLike listen, but adds correlation IDs that link updates, handler invocations, API calls, and responses together.
tgdev trace --db ~/tgdev.db --api-id 12345 --api-hash HASH --bot-token TOKENOutput example:
[1] >> messages.sendMessage
[1] {Message:"hello", Peer:{...}}
[1] << messages.sendMessage [12ms]
[1] {ID:42, Date:1709123456}
[2] UPDATE updateNewMessage
# List all methods
tgdev methods
# Filter by prefix
tgdev methods messages.
# JSON output
tgdev methods --format json messages.sendtgdev exposes Telegram as an MCP server, letting LLMs call any TL method as a tool.
stdio mode (Claude Code, Cursor, local MCP clients):
tgdev mcp --api-id 12345 --api-hash YOUR_HASH --bot-token YOUR_TOKENHTTP mode (remote/multi-client):
tgdev mcp --http :8080 --api-id 12345 --api-hash YOUR_HASH --bot-token YOUR_TOKENWith persistent listener (fastest, reuses connection):
# Terminal 1: start listener
tgdev listen --db ~/tgdev.db --api-id 12345 --api-hash YOUR_HASH --bot-token YOUR_TOKEN
# Terminal 2: start MCP server
tgdev mcpTip
When tgdev listen or tgdev trace is running, MCP tools route through the listener's IPC socket.
Otherwise, the MCP server creates its own standalone connection.
For detailed setup instructions, configuration examples, and troubleshooting:
- Complete MCP Setup Guide — stdio/HTTP modes, auth methods, client configs, security
Claude Code (.claude/mcp.json):
{
"mcpServers": {
"tgdev": {
"command": "tgdev",
"args": ["mcp"],
"env": {
"TGDEV_API_ID": "12345",
"TGDEV_API_HASH": "YOUR_HASH",
"TGDEV_BOT_TOKEN": "YOUR_TOKEN"
}
}
}
}Cursor (~/.cursor/mcp.json):
{
"mcpServers": {
"tgdev": {
"command": "tgdev",
"args": ["mcp"]
}
}
}Important
Prefer environment variables (TGDEV_*) over CLI flags for secrets.
CLI args are visible in ps aux output.
| Tool | Description |
|---|---|
tgdev_list_methods |
List TL methods with prefix filtering and cursor pagination |
tgdev_describe_method |
Show fields, types, and constructor hints for a method |
tgdev_invoke |
Invoke any TL method with JSON params |
tgdev_get_me |
Get current account info |
tgdev_listener_status |
Check if a listener is reachable on the IPC socket |
tgdev_config_info |
Show non-secret MCP configuration |
Interface fields (like InputPeer, InputUser) use a "_" constructor key:
{
"Peer": {"_": "inputPeerUser", "UserID": 123, "AccessHash": "..."},
"Message": "Hello!"
}To discover constructor names: use tgdev_describe_method tool.
tgdev supports multiple session formats. Use telegram-tools (client-side web app) to:
- Generate session strings via Telegram auth (phone or bot token) in gotg, GramJS, Kurigram, mtcute, or Telethon formats
- Convert between formats — paste a session string, auto-detect its format, convert to any other
- Analyze session strings — decode and inspect DC, auth key, user ID, isBot flag
- Test DC connectivity — ping all Telegram production and test data centers
Note
Session strings grant full account access — treat them like passwords.
Prefer environment variables (TGDEV_SESSION) or config file over CLI flags to avoid exposing in ps aux.
-
Visit telegram-tools (client-side, no backend)
-
Authenticate with phone number or bot token
-
Export session in gotg format
-
Use with tgdev:
# Via CLI flag (visible in ps aux) tgdev listen --session "YOUR_SESSION_STRING" --api-id 12345 --api-hash HASH # Via environment variable (recommended) export TGDEV_SESSION="YOUR_SESSION_STRING" tgdev listen --api-id 12345 --api-hash HASH # Via config file (safest) echo '{"session": "YOUR_SESSION_STRING", "api_id": 12345, "api_hash": "HASH"}' > ~/.tgdev.json chmod 0600 ~/.tgdev.json tgdev listen
| Format | Source | Detection Method |
|---|---|---|
| gotg native | session.StringSession() |
JSON, standard base64 |
| Pyrogram | session.PyrogramSession() |
URL-safe base64, 271 bytes decoded |
| Telethon | session.TelethonSession() |
Prefix 1 + URL-safe base64, 263/275 bytes |
| GramJS | session.GramjsSession() |
Prefix 1 + standard base64 |
| mtcute | session.MtcuteSession() |
URL-safe base64, prefix byte 0x03 |
tgdev auto-detects session format via detectSessionFormat() in cmd/tgdev/main.go.
If you already have a SQLite database from tgdev listen --db ~/tgdev.db:
tgdev export-session --db ~/tgdev.dbThe output is a gotg-compatible session string. Use --session-type to specify format if auto-detection fails.
- Never commit session strings to version control
- Use
chmod 0600 ~/.tgdev.jsonfor config file - IPC socket is mode 0600 (owner-only access)
--debuglogs full API payloads to stderr — contains session tokens
Config file: ~/.tgdev.json (auto-restricted to 0600 permissions).
{
"api_id": 12345,
"api_hash": "your_api_hash",
"bot_token": "123:ABC",
"database_path": "~/tgdev.db"
}| Method | Flag | Notes |
|---|---|---|
| Bot token | --bot-token |
Fastest for bots |
| Phone number | --phone |
Interactive user login |
| Session string | --session |
Telethon/Pyrogram/gotg format |
| SQLite database | --db |
Persistent sessions (recommended) |
CLI flags > environment variables > config file.
| Variable | Maps to |
|---|---|
TGDEV_API_ID |
--api-id |
TGDEV_API_HASH |
--api-hash |
TGDEV_BOT_TOKEN |
--bot-token |
TGDEV_SESSION |
--session |
TGDEV_PHONE |
--phone |
--api-id INT Telegram API ID
--api-hash STRING Telegram API Hash
--session STRING Session string
--bot-token STRING Bot token
--phone STRING Phone number
--db PATH SQLite database path for persistent sessions
--db-name STRING Session name within the database (default: "default")
--socket PATH Unix socket path for IPC (default: $XDG_RUNTIME_DIR/tgdev.sock)
--config PATH Config file path (default: ~/.tgdev.json)
--no-color Disable colored output
--debug Enable verbose debug output (logs full request/response payloads)
--format FORMAT Output format: text (default), json
Warning
--debug logs full API request and response payloads to stderr. Do not use in shared terminals
or redirect to persistent logs — the output may contain session tokens and other sensitive data.
.
├── cmd/tgdev/ CLI entrypoint and command implementations
│ ├── main.go Command dispatch, flag parsing, client creation
│ └── version.go Build version variables (injected via ldflags)
├── invoke/ TL method registry, JSON unmarshal, invocation, response formatting
│ ├── registry.go Bidirectional lookup: TL schema names ↔ Go types
│ ├── invoke.go Generic TL method invocation via raw RPC
│ ├── invoker.go DebugInvoker middleware: logging, timing, correlation
│ ├── unmarshal.go JSON → gotd struct with interface constructor resolution
│ ├── format.go InvokeJSON: JSON-serialized response path
│ └── pretty.go Color definitions and duration formatting
├── internal/
│ ├── config/ Config loading, validation, credential layering
│ │ └── config.go CLI flags > env vars > config file (~/.tgdev.json)
│ ├── ipc/ Unix domain socket IPC server and client
│ │ └── ipc.go InvokeRequest/Response JSON protocol
│ └── mcpserver/ MCP server with tool definitions
│ └── server.go tgdev_list_methods, tgdev_invoke, etc.
├── trace/ Correlation ID tracing, update listener, RPC middleware
│ ├── tracer.go Tracer: combines invoke logging + update tracking
│ └── listener.go UpdateListener for gotg dispatcher
├── tg-dev-agent/ Skill: Telegram bot testing via tgdev + MCP
├── go.mod Module: github.com/pageton/gotg-cli (Go 1.25.0)
└── README.md User-facing documentation
The invoke package provides bidirectional lookup between TL schema names and gotd Go types using reflection over the full tg.TypesMap() and tg.TypesConstructorMap() registries. The trace package adds correlation IDs that link updates to handler invocations to API calls to responses.
- gotd/td — MTProto client library
- pageton/gotg — Telegram framework (local replace directive)
- modelcontextprotocol/go-sdk — MCP server SDK
- fatih/color — Colored terminal output
- modernc.org/sqlite — Pure-Go SQLite driver