tdl-mcp
Read-only access to your own Telegram account — list chats, read recent messages, and download media via the local tdl CLI (never sends, edits, or deletes anything).
Check session status (
tg_status) — report whether the local tdl session is logged in and usable; never errors, returns a hint if not logged in.List chats (
tg_chats) — enumerate dialogs as{id, type, name, username}, with an optional case-insensitive substringfilteron name/username/id.Read messages (
tg_messages) — export recent media messages from a chat as compact{id, date, file, text}objects; control the range withlast_n(default 50, max 500) orsince_idfor incremental reads, and toggle text withwith_text.Download media from a chat (
tg_download) — pull files from a chat to a local directory, optionally filtered byextensions(e.g."xlsx,pdf"),last_n(default 100), orsince_id; returns absolute paths and skips already-downloaded files (--skip-same).Download media by link (
tg_download_url) — fetch the media of specifichttps://t.me/...message links (validated), optionally filtered byextensions, into a chosen destination.No api_id/api_hash or in-server login — authentication is done once by you via
tdl login -T qr; the server only runs the tdl binary locally.
Provides read-only access to a personal Telegram account, enabling listing chats, reading recent messages, and downloading media files, without sending or modifying any data.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@tdl-mcpShow the last 10 messages from @technews"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
tdl-mcp
Read-only Telegram access for Claude and other MCP hosts, powered by the
tdl CLI.
List your chats, read recent messages, and download media — from your own Telegram account — with five simple tools. It never sends messages, never modifies anything, and never touches your login.
🇰🇷 한국어 문서는 여기 있습니다 → README.ko.md
Why tdl-mcp?
Most Telegram MCP servers embed an MTProto library (Telethon, gramjs, …),
ask you to create your own Telegram application at my.telegram.org to get an
api_id/api_hash, and many of them can send messages on your behalf.
tdl-mcp takes a different, deliberately boring approach:
Read-only by design. The server can list chats, export messages and download files. That's all. There is no code path that sends, edits, deletes, or logs in.
No
api_id/api_hashsetup. Login is handled once, by you, in your terminal withtdl login -T qr— scan a QR code with your phone and you're done. No Telegram app registration needed.Built on a battle-tested downloader.
tdl(7.5k+ ⭐) does the heavy lifting: fast parallel downloads, resume,--skip-samededuplication.Tiny and auditable. One plain-JavaScript file, two dependencies (
@modelcontextprotocol/sdk,zod), no build step. You can read the whole server in five minutes.
Claude / MCP host ←stdio→ tdl-mcp (Node) →subprocess→ tdl CLI →MTProto→ TelegramRelated MCP server: Telegram MCP Server
Quick start
1. Install tdl
# macOS
brew install telegram-downloader
# Linux / WSL
curl -sSL https://docs.iyear.me/tdl/install.sh | sudo bash
# Windows (PowerShell)
iwr -useb https://docs.iyear.me/tdl/install.ps1 | iexAny version from the one pinned in .tdl-version upward
should work — CI continuously tests against that pin (see
Compatibility).
2. Log in to Telegram (once)
tdl login -T qrScan the QR code with the Telegram mobile app
(Settings → Devices → Link Desktop Device). The session is stored in
~/.tdl on your machine and shared by every MCP host — you log in exactly
once. tdl-mcp itself never performs or refreshes logins.
3. Add the server to your MCP host
You need Node.js ≥ 22.
Claude Code:
claude mcp add --scope user telegram -- npx -y tdl-mcpClaude Desktop / any other MCP host (generic mcpServers JSON):
{
"mcpServers": {
"telegram": {
"command": "npx",
"args": ["-y", "tdl-mcp"]
}
}
}4. Try it
Ask your assistant things like:
"What Telegram chats do I have? Find the one about quant trading."
"Show me the last 20 messages in @some_channel."
"Download every PDF posted in that channel since message 1500 to ~/Papers."
If a tool reports that you are not logged in, run tdl login -T qr in a
terminal and retry — that's the only manual step there is.
Tools
Tool | Arguments | What it does |
| — | Checks whether the tdl session is logged in. Never errors: returns |
|
| Lists dialogs as |
|
| Exports recent media messages from a chat as compact |
|
| Downloads media from a chat with |
|
| Downloads the media of specific messages by link. Validates every url starts with |
chat accepts either a numeric id or an @username/domain, exactly as shown
by tg_chats.
Environment variables
Variable | Effect |
| Path to the tdl binary. Default: |
| tdl namespace, passed as |
Set them in your host's server config, e.g.:
{
"mcpServers": {
"telegram": {
"command": "npx",
"args": ["-y", "tdl-mcp"],
"env": { "TDL_NS": "work" }
}
}
}Compatibility & staying up to date
tdl-mcp shells out to the tdl CLI, so its real dependency is tdl's
command-line surface. That surface is guarded automatically:
.tdl-versionpins the tdl release this package is tested against.scripts/contract.mjsverifies — without logging in — that every flag the server uses (chat ls -o json,chat export -c/-T/-i/-o/--with-content,dl -f/-u/-i/-d/--skip-same, global-n) still exists in that tdl binary. CI runs it on every push and PR.A scheduled workflow watches tdl releases. When a new version appears it runs the contract test against the new binary and scans the release notes for breaking-change markers. Routine updates become a simple version-bump PR; anything suspicious is escalated to an AI-assisted upgrade PR that adapts the wrapper code.
So if you're on a newer tdl than the pin, chances are excellent everything just works — and if it ever wouldn't, this repo finds out before you do.
Development
git clone https://github.com/rixile9999/tdl-mcp.git
cd tdl-mcp
npm install
npm test # smoke (MCP protocol, login-free) + contract (tdl CLI surface)npm run smokespawns the server over stdio and checks the tool catalog,tg_statusshape, and input validation — passes whether or not you are logged in.npm run contractchecks the installed tdl binary against the CLI surface the server uses.scripts/install-tdl.sh [vX.Y.Z]installs a specific (checksum-verified) tdl release if you want to test against another version.
PRs welcome. Please keep the server read-only — tools that send, edit or delete are out of scope for this project.
Security notes
The tdl session in
~/.tdlis a full user-account credential — anyone who can read it can act as your Telegram account. Protect it like an SSH key: don't copy it into repos, shared backups, or other machines.tdl-mcpnever reads or transmits the session itself; it only runs thetdlbinary locally. Nothing leaves your machine except tdl's own Telegram traffic.Downloads go to a directory you choose (
dest), defaulting to~/Downloads/telegram.
Telegram terms-of-service note
tdl drives a regular user session (MTProto), not a bot. Quiet, read-only,
personal-use automation of your own account is generally tolerated, but
aggressive crawling can get an account limited: keep ranges modest
(last_n, since_id), avoid large parallel pulls, and let --skip-same do
its job instead of re-downloading.
License
MIT for everything in this repository.
tdl itself is a separate project licensed under
AGPL-3.0. tdl-mcp does
not bundle, link, or modify tdl — it invokes the binary you installed as a
separate process, so the AGPL applies to tdl, not to this wrapper. You install
tdl yourself through official channels (step 1 above).
Available Tools
5 toolstg_chatsList Telegram chatsA
List the Telegram dialogs (chats/channels/groups/users) visible to the logged-in session, as [{id, type, name, username}]. Use it to find the chat id or @username to pass as chat to tg_messages / tg_download. Optional filter does a case-insensitive substring match on name/username/id.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | Case-insensitive substring to match against chat name, username or id |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does reasonably well: it discloses the session scope ('visible to the logged-in session'), the returned fields, and the matching semantics of the filter. It does not mention authentication prerequisites, pagination, or result limits, which are minor gaps for a read-only listing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences, front-loaded with the resource and scope, followed by the usage purpose and the optional filter. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although there is no output schema, the description supplies the return field set, the session scoping, and the routing purpose, which is everything an agent needs to call and consume this single-optional-parameter listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the parameter is already fully documented. The description's note that `filter` does a case-insensitive substring match on name/username/id largely restates the schema, adding no new syntax or format detail. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (Telegram dialogs/chats/channels/groups/users) scoped to the logged-in session, and even previews the return shape [{id, type, name, username}]. It is clearly distinguishable from siblings like tg_messages and tg_download, which it names as downstream consumers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('Use it to find the chat id or @username to pass as `chat` to tg_messages / tg_download'), which routes the agent correctly. There is no explicit when-not or negative case, but the usage context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tg_downloadDownload Telegram media from a chatA
Download media files from one chat (by id or @username) to a local directory and return the absolute paths of newly downloaded files. Use extensions (csv, e.g. 'xlsx,pdf') to fetch only certain file types; since_id for 'everything new after message X'; last_n for 'the latest N media messages' (default 100). Already-present files are skipped (--skip-same).
| Name | Required | Description | Default |
|---|---|---|---|
| chat | Yes | Chat id or @username/domain (as shown by tg_chats) | |
| dest | No | Destination directory (default ~/Downloads/telegram) | |
| last_n | No | How many recent media messages to consider (default 100) | |
| since_id | No | Only messages with id > since_id (overrides last_n) | |
| extensions | No | Comma-separated file extensions to include, e.g. 'xlsx,pdf' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses the skip-existing behavior ('Already-present files are skipped'), the default of 100, and that since_id overrides last_n. It omits operational context such as Telegram auth/login requirements, rate limits, and whether the destination directory is created automatically.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and return value before the parameter notes, and every clause is functional. It is slightly dense with parenthetical parameter guidance, but there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly states the return ('absolute paths of newly downloaded files'), and it covers the key filters and skip behavior. The main gap for a network-dependent tool is the absence of any authentication or failure-mode context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond the schema by translating parameters into intent phrases ('everything new after message X', 'the latest N media messages'), which helps an agent map a natural request onto the right parameter rather than merely matching names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Download media files from one chat'), names accepted chat identifiers, and specifies what is returned (absolute paths of newly downloaded files). It is clear and testable, but does not explicitly differentiate itself from the sibling tg_download_url, which an agent could confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: extensions for filtering by file type, since_id for incremental fetching, last_n for the latest N. There is no explicit 'use this when / use tg_download_url instead when' guidance against the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tg_download_urlDownload Telegram media by t.me linkA
Download the media of specific Telegram messages given their t.me links (e.g. https://t.me/channel/123) and return the absolute paths of newly downloaded files. Use when you already have message links rather than a chat to scan. Already-present files are skipped (--skip-same).
| Name | Required | Description | Default |
|---|---|---|---|
| dest | No | Destination directory (default ~/Downloads/telegram) | |
| urls | Yes | Telegram message links; each must start with https://t.me/ | |
| extensions | No | Comma-separated file extensions to include, e.g. 'xlsx,pdf' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose two useful traits — it returns absolute paths of newly downloaded files and skips already-present files (--skip-same) — which is real idempotency information. But it says nothing about authentication/prerequisites for Telegram access, partial-failure behavior, or whether downloads are network-bound, leaving meaningful gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, no filler; the core action and return value come first and the routing hint and skip behavior follow in priority order. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a fully described schema and no output schema, the definition covers the essentials: what it downloads, from what input, and what it returns. It falls short only on prerequisites (auth/session) and failure behavior for what is a file-writing, network-dependent operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so dest, urls, and extensions are already fully documented in the schema, including the https://t.me/ prefix requirement. The description adds no extra semantics about these parameters, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Download the media of specific Telegram messages given their t.me links') and pins the input form with a concrete example URL. The clause 'rather than a chat to scan' implicitly separates it from the chat-scanning sibling tg_download, so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit selection condition: 'Use when you already have message links rather than a chat to scan.' That clearly signals when this tool applies and implies the alternative (bulk chat scanning) is a different tool, though it never names tg_download explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tg_messagesRead recent Telegram messagesA
Export recent media messages from one chat (by id or @username) and return them as compact {id, date, file, text} objects — newest range exported via tdl. Use last_n for 'the last N media messages', or since_id to fetch only messages after a known message id (incremental reads). Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| chat | Yes | Chat id or @username/domain (as shown by tg_chats) | |
| last_n | No | How many recent media messages to export (default 50, max 500) | |
| since_id | No | Only messages with id > since_id (overrides last_n; for incremental reads) | |
| with_text | No | Include message text content (default true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the full behavioral burden. It discloses the 'Read-only' safety profile and that export is done via tdl, but says nothing about auth requirements, rate limits, or error behavior. It adds useful context beyond structured fields but leaves real gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that covers purpose, parameters, and return shape without fluff. It is dense with parenthetical asides but every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param read tool with no output schema, the description usefully describes the returned object shape and the backend. It omits auth/pagination/failure detail, but the core information an agent needs to invoke it is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter is already documented, including the since_id-overrides-last_n relationship. The description reinforces intended usage of last_n and since_id but adds no syntax or format detail beyond the schema, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (export) and resource (recent media messages from one chat) and even specifies the return shape {id, date, file, text}. This clearly distinguishes it from siblings tg_chats (listing chats) and tg_download (fetching files).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains when to use last_n ('the last N media messages') versus since_id (incremental reads after a known id). It does not name sibling alternatives like tg_download for a specific message, but the parameter-selection guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tg_statusTelegram session statusA
Check whether the local tdl Telegram session is logged in and usable. Call this first if another tg_* tool fails or before starting Telegram work. Never errors — returns {logged_in:false, hint} when the session is missing.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description carries full burden. It discloses that the tool never errors and returns {logged_in:false, hint} when missing, covering error handling and output format. However, it omits details about side effects or performance, but these are minimal for a status check.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no wasted words. The first sentence states purpose, the second adds usage guidance and behavior. Front-loaded and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters, no output schema, and low complexity, the description covers purpose, usage, and behavior. It lacks explanation of what 'hint' contains or what 'usable' means, but these are minor gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist, so schema coverage is 100% and the description need not add parameter info. Baseline 4 is appropriate as the description adds no parameter details but doesn't need to.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Check') and resource ('local tdl Telegram session'), clearly stating its function to verify login status. It distinguishes itself from siblings by being a diagnostic tool to call before other tg_* tools, though not explicitly mentioning what it doesn't do.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly advises calling this tool first if another tg_* tool fails or before starting Telegram work, providing clear context for when to use it. No alternatives are needed given its singular purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v1.1.0- Changed
tg_chats1 field changed- removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
tg_download2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / since_id / maximumAdded value: +9007199254740991
- Changed
tg_download_url1 field changed- removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
tg_messages2 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / since_id / maximumAdded value: +9007199254740991
5 tool updates
v1.0.0- First observed
tg_chats - First observed
tg_download - First observed
tg_download_url - First observed
tg_messages - First observed
tg_status
TDQS
Scored across 5 tools
tg_messages and tg_download both center on media messages but are distinguished by one returning read-only metadata vs. the other downloading files. tg_download vs tg_download_url are clearly separated by input type (chat scan vs. specific t.me links), though the overlap between listing and downloading media could cause occasional misselection.
All tools share the tg_ prefix and are readable, but the suffix convention mixes nouns (chats, messages, status) with verbs (download, download_url), so it is not a strict verb_noun pattern. Still predictable enough that intent is clear.
Five tools is well-scoped for a Telegram media export/download utility. Each tool earns its place: discovery, metadata listing, two download paths, and a session check.
The surface covers the read-only media lifecycle: find chats, list media, download by chat or by link, and verify session. Gaps exist (no text/non-media message export, no search), but they are minor for the apparent media-export scope.
Maintenance
Related MCP Connectors
Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.
Hosted Telegram MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Let Claude or ChatGPT search, read and send your WhatsApp messages over MCP. OAuth sign-in.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA read-only Telegram MCP server that retrieves messages from your DMs, groups, and channels, enabling Claude to generate executive briefings from Telegram conversations.MIT
- AlicenseNot gradedqualityBmaintenanceA Telegram integration for Claude, Cursor, and other MCP-compatible clients. It exposes Telegram account, chat, message, contact, media, folder, and admin operations through the Model Context Protocol using Telethon.Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants like Claude to read, search, and send messages through your personal Telegram account via MCP tools.MIT
- AlicenseNot gradedqualityBmaintenanceA Telegram integration for Claude, Cursor, and other MCP-compatible clients. It exposes Telegram account, chat, message, contact, media, folder, and admin operations through the Model Context Protocol using Telethon.Apache 2.0