Featured MCP Servers
Explore pre-built MCP servers for popular enterprise systems that connect AI assistants to your data sources.
Telegram MCP Server
<div class="markdown-heading"><h1 class="heading-element">Telegram MCP Server</h1><a id="user-content-telegram-mcp-server" class="anchor" aria-label="Permalink: Telegram MCP Server" href="#telegram-mcp-server"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/16993b00a5060330fd9ce7dfb8887813e41d… src="https://camo.githubusercontent.com/16993b00a5060330fd9ce7dfb8887813e41d…; alt="MCP Badge" data-canonical-src="https://badge.mcpx.dev" style="max-width: 100%;"></a>
<a href="https://opensource.org/licenses/Apache-2.0" rel="nofollow"><img src="https://camo.githubusercontent.com/41a3bb992d2808d6ddea9f1ed7b7bc8da6d9…; alt="License: Apache 2.0" data-canonical-src="https://img.shields.io/badge/license-Apache%202.0-green?style=flat-squa…; style="max-width: 100%;"></a>
<a href="https://github.com/chigwell/telegram-mcp/actions/workflows/python-lint-… src="https://github.com/chigwell/telegram-mcp/actions/workflows/python-lint-…; alt="Python Lint & Format Check" style="max-width: 100%;"></a>
<a href="https://github.com/chigwell/telegram-mcp/actions/workflows/docker-build… src="https://github.com/chigwell/telegram-mcp/actions/workflows/docker-build…; alt="Docker Build & Compose Validation" style="max-width: 100%;"></a></p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🤖 MCP in Action</h2><a id="user-content--mcp-in-action" class="anchor" aria-label="Permalink: 🤖 MCP in Action" href="#-mcp-in-action"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>Here's a demonstration of the Telegram MCP capabilities in <a href="https://docs.anthropic.com/en/docs/agents-and-tools/mcp" rel="nofollow">Claude</a>:</p>
<p><strong>Basic usage example:</strong></p>
<p><a target="_blank" rel="noopener noreferrer" href="screenshots/1.png"><img src="screenshots/1.png" alt="Telegram MCP in action" style="max-width: 100%;"></a></p>
<ol>
<li><strong>Example: Asking Claude to analyze chat history and send a response:</strong></li>
</ol>
<p><a target="_blank" rel="noopener noreferrer" href="screenshots/2.png"><img src="screenshots/2.png" alt="Telegram MCP Request" style="max-width: 100%;"></a></p>
<ol start="2">
<li><strong>Successfully sent message to the group:</strong></li>
</ol>
<p><a target="_blank" rel="noopener noreferrer" href="screenshots/3.png"><img src="screenshots/3.png" alt="Telegram MCP Result" style="max-width: 100%;"></a></p>
<p>As you can see, the AI can seamlessly interact with your Telegram account, retrieving and displaying your chats, messages, and other data in a natural way.</p>
<hr>
<p>A full-featured Telegram integration for Claude, Cursor, and any MCP-compatible client, powered by <a href="https://docs.telethon.dev/" rel="nofollow">Telethon</a> and the <a href="https://modelcontextprotocol.io/" rel="nofollow">Model Context Protocol (MCP)</a>. This project lets you interact with your Telegram account programmatically, automating everything from messaging to group management.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🚀 Features & Tools</h2><a id="user-content--features--tools" class="anchor" aria-label="Permalink: 🚀 Features & Tools" href="#-features--tools"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>This MCP server exposes a huge suite of Telegram tools. <strong>Every major Telegram/Telethon feature is available as a tool!</strong></p>
<div class="markdown-heading"><h3 class="heading-element">Chat & Group Management</h3><a id="user-content-chat--group-management" class="anchor" aria-label="Permalink: Chat & Group Management" href="#chat--group-management"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_chats(page, page_size)</strong>: Paginated list of chats</li>
<li>
<strong>list_chats(chat_type, limit)</strong>: List chats with metadata and filtering</li>
<li>
<strong>get_chat(chat_id)</strong>: Detailed info about a chat</li>
<li>
<strong>create_group(title, user_ids)</strong>: Create a new group</li>
<li>
<strong>create_channel(title, about, megagroup)</strong>: Create a channel or supergroup</li>
<li>
<strong>edit_chat_title(chat_id, title)</strong>: Change chat/group/channel title</li>
<li>
<strong>delete_chat_photo(chat_id)</strong>: Remove chat/group/channel photo</li>
<li>
<strong>leave_chat(chat_id)</strong>: Leave a group or channel</li>
<li>
<strong>get_participants(chat_id)</strong>: List all participants</li>
<li>
<strong>get_admins(chat_id)</strong>: List all admins</li>
<li>
<strong>get_banned_users(chat_id)</strong>: List all banned users</li>
<li>
<strong>promote_admin(chat_id, user_id)</strong>: Promote user to admin</li>
<li>
<strong>demote_admin(chat_id, user_id)</strong>: Demote admin to user</li>
<li>
<strong>ban_user(chat_id, user_id)</strong>: Ban user</li>
<li>
<strong>unban_user(chat_id, user_id)</strong>: Unban user</li>
<li>
<strong>get_invite_link(chat_id)</strong>: Get invite link</li>
<li>
<strong>export_chat_invite(chat_id)</strong>: Export invite link</li>
<li>
<strong>import_chat_invite(hash)</strong>: Join chat by invite hash</li>
<li>
<strong>join_chat_by_link(link)</strong>: Join chat by invite link</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Messaging</h3><a id="user-content-messaging" class="anchor" aria-label="Permalink: Messaging" href="#messaging"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_messages(chat_id, page, page_size)</strong>: Paginated messages</li>
<li>
<strong>list_messages(chat_id, limit, search_query, from_date, to_date)</strong>: Filtered messages</li>
<li>
<strong>send_message(chat_id, message)</strong>: Send a message</li>
<li>
<strong>reply_to_message(chat_id, message_id, text)</strong>: Reply to a message</li>
<li>
<strong>edit_message(chat_id, message_id, new_text)</strong>: Edit your message</li>
<li>
<strong>delete_message(chat_id, message_id)</strong>: Delete a message</li>
<li>
<strong>forward_message(from_chat_id, message_id, to_chat_id)</strong>: Forward a message</li>
<li>
<strong>pin_message(chat_id, message_id)</strong>: Pin a message</li>
<li>
<strong>unpin_message(chat_id, message_id)</strong>: Unpin a message</li>
<li>
<strong>mark_as_read(chat_id)</strong>: Mark all as read</li>
<li>
<strong>get_message_context(chat_id, message_id, context_size)</strong>: Context around a message</li>
<li>
<strong>get_history(chat_id, limit)</strong>: Full chat history</li>
<li>
<strong>get_pinned_messages(chat_id)</strong>: List pinned messages</li>
<li>
<strong>get_last_interaction(contact_id)</strong>: Most recent message with a contact</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Contact Management</h3><a id="user-content-contact-management" class="anchor" aria-label="Permalink: Contact Management" href="#contact-management"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>list_contacts()</strong>: List all contacts</li>
<li>
<strong>search_contacts(query)</strong>: Search contacts</li>
<li>
<strong>add_contact(phone, first_name, last_name)</strong>: Add a contact</li>
<li>
<strong>delete_contact(user_id)</strong>: Delete a contact</li>
<li>
<strong>block_user(user_id)</strong>: Block a user</li>
<li>
<strong>unblock_user(user_id)</strong>: Unblock a user</li>
<li>
<strong>import_contacts(contacts)</strong>: Bulk import contacts</li>
<li>
<strong>export_contacts()</strong>: Export all contacts as JSON</li>
<li>
<strong>get_blocked_users()</strong>: List blocked users</li>
<li>
<strong>get_contact_ids()</strong>: List all contact IDs</li>
<li>
<strong>get_direct_chat_by_contact(contact_query)</strong>: Find direct chat with a contact</li>
<li>
<strong>get_contact_chats(contact_id)</strong>: List all chats with a contact</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">User & Profile</h3><a id="user-content-user--profile" class="anchor" aria-label="Permalink: User & Profile" href="#user--profile"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_me()</strong>: Get your user info</li>
<li>
<strong>update_profile(first_name, last_name, about)</strong>: Update your profile</li>
<li>
<strong>delete_profile_photo()</strong>: Remove your profile photo</li>
<li>
<strong>get_user_photos(user_id, limit)</strong>: Get a user's profile photos</li>
<li>
<strong>get_user_status(user_id)</strong>: Get a user's online status</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Media</h3><a id="user-content-media" class="anchor" aria-label="Permalink: Media" href="#media"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_media_info(chat_id, message_id)</strong>: Get info about media in a message</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Search & Discovery</h3><a id="user-content-search--discovery" class="anchor" aria-label="Permalink: Search & Discovery" href="#search--discovery"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>search_public_chats(query)</strong>: Search public chats/channels/bots</li>
<li>
<strong>search_messages(chat_id, query, limit)</strong>: Search messages in a chat</li>
<li>
<strong>resolve_username(username)</strong>: Resolve a username to ID</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Stickers, GIFs, Bots</h3><a id="user-content-stickers-gifs-bots" class="anchor" aria-label="Permalink: Stickers, GIFs, Bots" href="#stickers-gifs-bots"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_sticker_sets()</strong>: List sticker sets</li>
<li>
<strong>get_bot_info(bot_username)</strong>: Get info about a bot</li>
<li>
<strong>set_bot_commands(bot_username, commands)</strong>: Set bot commands (bot accounts only)</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Privacy, Settings, and Misc</h3><a id="user-content-privacy-settings-and-misc" class="anchor" aria-label="Permalink: Privacy, Settings, and Misc" href="#privacy-settings-and-misc"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>get_privacy_settings()</strong>: Get privacy settings</li>
<li>
<strong>set_privacy_settings(key, allow_users, disallow_users)</strong>: Set privacy settings</li>
<li>
<strong>mute_chat(chat_id)</strong>: Mute notifications</li>
<li>
<strong>unmute_chat(chat_id)</strong>: Unmute notifications</li>
<li>
<strong>archive_chat(chat_id)</strong>: Archive a chat</li>
<li>
<strong>unarchive_chat(chat_id)</strong>: Unarchive a chat</li>
<li>
<strong>get_recent_actions(chat_id)</strong>: Get recent admin actions</li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Removed Functionality</h2><a id="user-content-removed-functionality" class="anchor" aria-label="Permalink: Removed Functionality" href="#removed-functionality"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>Please note that tools requiring direct file path access on the server (<code>send_file</code>, <code>download_media</code>, <code>set_profile_photo</code>, <code>edit_chat_photo</code>, <code>send_voice</code>, <code>send_sticker</code>, <code>upload_file</code>) have been removed from <code>main.py</code>. This is due to limitations in the current MCP environment regarding handling file attachments and local file system paths.</p>
<p>Additionally, GIF-related tools (<code>get_gif_search</code>, <code>get_saved_gifs</code>, <code>send_gif</code>) have been removed due to ongoing issues with reliability in the Telethon library or Telegram API interactions.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">📋 Requirements</h2><a id="user-content--requirements" class="anchor" aria-label="Permalink: 📋 Requirements" href="#-requirements"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>Python 3.10+</li>
<li><a href="https://docs.telethon.dev/" rel="nofollow">Telethon</a></li>
<li><a href="https://modelcontextprotocol.io/docs/" rel="nofollow">MCP Python SDK</a></li>
<li>
<a href="https://claude.ai/desktop" rel="nofollow">Claude Desktop</a> or <a href="https://cursor.so/" rel="nofollow">Cursor</a> (or any MCP client)</li>
</ul>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🔧 Installation & Setup</h2><a id="user-content--installation--setup" class="anchor" aria-label="Permalink: 🔧 Installation & Setup" href="#-installation--setup"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="markdown-heading"><h3 class="heading-element">1. Fork & Clone</h3><a id="user-content-1-fork--clone" class="anchor" aria-label="Permalink: 1. Fork & Clone" href="#1-fork--clone"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-shell"><pre>git clone https://github.com/chigwell/telegram-mcp.git
<span class="pl-c1">cd</span> telegram-mcp</pre></div>
<div class="markdown-heading"><h3 class="heading-element">2. Create a Virtual Environment</h3><a id="user-content-2-create-a-virtual-environment" class="anchor" aria-label="Permalink: 2. Create a Virtual Environment" href="#2-create-a-virtual-environment"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-shell"><pre>python3 -m venv .venv
<span class="pl-c1">source</span> .venv/bin/activate <span class="pl-c"><span class="pl-c">#</span> On Windows: .venv\Scripts\activate</span>
pip install -r requirements.txt</pre></div>
<div class="markdown-heading"><h3 class="heading-element">3. Generate a Session String</h3><a id="user-content-3-generate-a-session-string" class="anchor" aria-label="Permalink: 3. Generate a Session String" href="#3-generate-a-session-string"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-shell"><pre>python3 session_string_generator.py</pre></div>
<p>Follow the prompts to authenticate and update your <code>.env</code> file.</p>
<div class="markdown-heading"><h3 class="heading-element">4. Configure .env</h3><a id="user-content-4-configure-env" class="anchor" aria-label="Permalink: 4. Configure .env" href="#4-configure-env"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>Copy <code>.env.example</code> to <code>.env</code> and fill in your values:</p>
<pre><code>TELEGRAM_API_ID=your_api_id_here
TELEGRAM_API_HASH=your_api_hash_here
TELEGRAM_SESSION_NAME=anon
TELEGRAM_SESSION_STRING=your_session_string_here
</code></pre>
<p>Get your API credentials at <a href="https://my.telegram.org/apps" rel="nofollow">my.telegram.org/apps</a>.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🐳 Running with Docker</h2><a id="user-content--running-with-docker" class="anchor" aria-label="Permalink: 🐳 Running with Docker" href="#-running-with-docker"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>If you have Docker and Docker Compose installed, you can build and run the server in a container, simplifying dependency management.</p>
<div class="markdown-heading"><h3 class="heading-element">1. Build the Image</h3><a id="user-content-1-build-the-image" class="anchor" aria-label="Permalink: 1. Build the Image" href="#1-build-the-image"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>From the project root directory, build the Docker image:</p>
<div class="highlight highlight-source-shell"><pre>docker build -t telegram-mcp:latest <span class="pl-c1">.</span></pre></div>
<div class="markdown-heading"><h3 class="heading-element">2. Running the Container</h3><a id="user-content-2-running-the-container" class="anchor" aria-label="Permalink: 2. Running the Container" href="#2-running-the-container"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>You have two options:</p>
<p><strong>Option A: Using Docker Compose (Recommended for Local Use)</strong></p>
<p>This method uses the <code>docker-compose.yml</code> file and automatically reads your credentials from a <code>.env</code> file.</p>
<ol>
<li>
<strong>Create <code>.env</code> File:</strong> Ensure you have a <code>.env</code> file in the project root containing your <code>TELEGRAM_API_ID</code>, <code>TELEGRAM_API_HASH</code>, and <code>TELEGRAM_SESSION_STRING</code> (or <code>TELEGRAM_SESSION_NAME</code>). Use <code>.env.example</code> as a template.</li>
<li>
<strong>Run Compose:</strong>
<div class="highlight highlight-source-shell"><pre>docker compose up --build</pre></div>
<ul>
<li>Use <code>docker compose up -d</code> to run in detached mode (background).</li>
<li>Press <code>Ctrl+C</code> to stop the server.</li>
</ul>
</li>
</ol>
<p><strong>Option B: Using <code>docker run</code></strong></p>
<p>You can run the container directly, passing credentials as environment variables.</p>
<div class="highlight highlight-source-shell"><pre>docker run -it --rm \
-e TELEGRAM_API_ID=<span class="pl-s"><span class="pl-pds">"</span>YOUR_API_ID<span class="pl-pds">"</span></span> \
-e TELEGRAM_API_HASH=<span class="pl-s"><span class="pl-pds">"</span>YOUR_API_HASH<span class="pl-pds">"</span></span> \
-e TELEGRAM_SESSION_STRING=<span class="pl-s"><span class="pl-pds">"</span>YOUR_SESSION_STRING<span class="pl-pds">"</span></span> \
telegram-mcp:latest</pre></div>
<ul>
<li>Replace placeholders with your actual credentials.</li>
<li>Use <code>-e TELEGRAM_SESSION_NAME=your_session_file_name</code> instead of <code>TELEGRAM_SESSION_STRING</code> if you prefer file-based sessions (requires volume mounting, see <code>docker-compose.yml</code> for an example).</li>
<li>The <code>-it</code> flags are crucial for interacting with the server.</li>
</ul>
<hr>
<div class="markdown-heading"><h2 class="heading-element">⚙️ Configuration for Claude & Cursor</h2><a id="user-content-️-configuration-for-claude--cursor" class="anchor" aria-label="Permalink: ⚙️ Configuration for Claude & Cursor" href="#️-configuration-for-claude--cursor"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="markdown-heading"><h3 class="heading-element">MCP Configuration</h3><a id="user-content-mcp-configuration" class="anchor" aria-label="Permalink: MCP Configuration" href="#mcp-configuration"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>Edit your Claude desktop config (e.g. <code>~/Library/Application Support/Claude/claude_desktop_config.json</code>) or Cursor config (<code>~/.cursor/mcp.json</code>):</p>
<div class="highlight highlight-source-json"><pre>{
<span class="pl-ent">"mcpServers"</span>: {
<span class="pl-ent">"telegram-mcp"</span>: {
<span class="pl-ent">"command"</span>: <span class="pl-s"><span class="pl-pds">"</span>uv<span class="pl-pds">"</span></span>,
<span class="pl-ent">"args"</span>: [
<span class="pl-s"><span class="pl-pds">"</span>--directory<span class="pl-pds">"</span></span>,
<span class="pl-s"><span class="pl-pds">"</span>/full/path/to/telegram-mcp<span class="pl-pds">"</span></span>,
<span class="pl-s"><span class="pl-pds">"</span>run<span class="pl-pds">"</span></span>,
<span class="pl-s"><span class="pl-pds">"</span>main.py<span class="pl-pds">"</span></span>
]
}
}
}</pre></div>
<div class="markdown-heading"><h2 class="heading-element">📝 Tool Examples with Code & Output</h2><a id="user-content--tool-examples-with-code--output" class="anchor" aria-label="Permalink: 📝 Tool Examples with Code & Output" href="#-tool-examples-with-code--output"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>Below are examples of the most commonly used tools with their implementation and sample output.</p>
<div class="markdown-heading"><h3 class="heading-element">Getting Your Chats</h3><a id="user-content-getting-your-chats" class="anchor" aria-label="Permalink: Getting Your Chats" href="#getting-your-chats"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">get_chats</span>(<span class="pl-s1">page</span>: <span class="pl-smi">int</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span>, <span class="pl-s1">page_size</span>: <span class="pl-smi">int</span> <span class="pl-c1">=</span> <span class="pl-c1">20</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Get a paginated list of chats.</span>
<span class="pl-s"> Args:</span>
<span class="pl-s"> page: Page number (1-indexed).</span>
<span class="pl-s"> page_size: Number of chats per page.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-s1">dialogs</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">get_dialogs</span>()
<span class="pl-s1">start</span> <span class="pl-c1">=</span> (<span class="pl-s1">page</span> <span class="pl-c1">-</span> <span class="pl-c1">1</span>) <span class="pl-c1">*</span> <span class="pl-s1">page_size</span>
<span class="pl-s1">end</span> <span class="pl-c1">=</span> <span class="pl-s1">start</span> <span class="pl-c1">+</span> <span class="pl-s1">page_size</span>
<span class="pl-k">if</span> <span class="pl-s1">start</span> <span class="pl-c1">>=</span> <span class="pl-en">len</span>(<span class="pl-s1">dialogs</span>):
<span class="pl-k">return</span> <span class="pl-s">"Page out of range."</span>
<span class="pl-s1">chats</span> <span class="pl-c1">=</span> <span class="pl-s1">dialogs</span>[<span class="pl-s1">start</span>:<span class="pl-s1">end</span>]
<span class="pl-s1">lines</span> <span class="pl-c1">=</span> []
<span class="pl-k">for</span> <span class="pl-s1">dialog</span> <span class="pl-c1">in</span> <span class="pl-s1">chats</span>:
<span class="pl-s1">entity</span> <span class="pl-c1">=</span> <span class="pl-s1">dialog</span>.<span class="pl-c1">entity</span>
<span class="pl-s1">chat_id</span> <span class="pl-c1">=</span> <span class="pl-s1">entity</span>.<span class="pl-c1">id</span>
<span class="pl-s1">title</span> <span class="pl-c1">=</span> <span class="pl-en">getattr</span>(<span class="pl-s1">entity</span>, <span class="pl-s">"title"</span>, <span class="pl-c1">None</span>) <span class="pl-c1">or</span> <span class="pl-en">getattr</span>(<span class="pl-s1">entity</span>, <span class="pl-s">"first_name"</span>, <span class="pl-s">"Unknown"</span>)
<span class="pl-s1">lines</span>.<span class="pl-c1">append</span>(<span class="pl-s">f"Chat ID: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">chat_id</span><span class="pl-kos">}</span></span>, Title: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">title</span><span class="pl-kos">}</span></span>"</span>)
<span class="pl-k">return</span> <span class="pl-s">"<span class="pl-cce">\n</span>"</span>.<span class="pl-c1">join</span>(<span class="pl-s1">lines</span>)
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-s1">logger</span>.<span class="pl-c1">exception</span>(<span class="pl-s">f"get_chats failed (page=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">page</span><span class="pl-kos">}</span></span>, page_size=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">page_size</span><span class="pl-kos">}</span></span>)"</span>)
<span class="pl-k">return</span> <span class="pl-s">"An error occurred (code: GETCHATS-ERR-001). Check mcp_errors.log for details."</span></pre></div>
<p>Example output:</p>
<pre><code>Chat ID: 123456789, Title: John Doe
Chat ID: -100987654321, Title: My Project Group
Chat ID: 111223344, Title: Jane Smith
Chat ID: -200123456789, Title: News Channel
</code></pre>
<div class="markdown-heading"><h3 class="heading-element">Sending Messages</h3><a id="user-content-sending-messages" class="anchor" aria-label="Permalink: Sending Messages" href="#sending-messages"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">send_message</span>(<span class="pl-s1">chat_id</span>: <span class="pl-smi">int</span>, <span class="pl-s1">message</span>: <span class="pl-smi">str</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Send a message to a specific chat.</span>
<span class="pl-s"> Args:</span>
<span class="pl-s"> chat_id: The ID of the chat.</span>
<span class="pl-s"> message: The message content to send.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-s1">entity</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">get_entity</span>(<span class="pl-s1">chat_id</span>)
<span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">send_message</span>(<span class="pl-s1">entity</span>, <span class="pl-s1">message</span>)
<span class="pl-k">return</span> <span class="pl-s">"Message sent successfully."</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-s1">logger</span>.<span class="pl-c1">exception</span>(<span class="pl-s">f"send_message failed (chat_id=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">chat_id</span><span class="pl-kos">}</span></span>)"</span>)
<span class="pl-k">return</span> <span class="pl-s">"An error occurred (code: SENDMSG-ERR-001). Check mcp_errors.log for details."</span></pre></div>
<p>Example output:</p>
<pre><code>Message sent successfully.
</code></pre>
<div class="markdown-heading"><h3 class="heading-element">Getting Chat Invite Links</h3><a id="user-content-getting-chat-invite-links" class="anchor" aria-label="Permalink: Getting Chat Invite Links" href="#getting-chat-invite-links"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>The <code>get_invite_link</code> function is particularly robust with multiple fallback methods:</p>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">get_invite_link</span>(<span class="pl-s1">chat_id</span>: <span class="pl-smi">int</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Get the invite link for a group or channel.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-s1">entity</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">get_entity</span>(<span class="pl-s1">chat_id</span>)
<span class="pl-c"># Try using ExportChatInviteRequest first</span>
<span class="pl-k">try</span>:
<span class="pl-k">from</span> <span class="pl-s1">telethon</span>.<span class="pl-s1">tl</span> <span class="pl-k">import</span> <span class="pl-s1">functions</span>
<span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">messages</span>.<span class="pl-c1">ExportChatInviteRequest</span>(
<span class="pl-s1">peer</span><span class="pl-c1">=</span><span class="pl-s1">entity</span>
))
<span class="pl-k">return</span> <span class="pl-s1">result</span>.<span class="pl-c1">link</span>
<span class="pl-k">except</span> <span class="pl-v">AttributeError</span>:
<span class="pl-c"># If the function doesn't exist in the current Telethon version</span>
<span class="pl-s1">logger</span>.<span class="pl-c1">warning</span>(<span class="pl-s">"ExportChatInviteRequest not available, using alternative method"</span>)
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e1</span>:
<span class="pl-c"># If that fails, log and try alternative approach</span>
<span class="pl-s1">logger</span>.<span class="pl-c1">warning</span>(<span class="pl-s">f"ExportChatInviteRequest failed: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e1</span><span class="pl-kos">}</span></span>"</span>)
<span class="pl-c"># Alternative approach using client.export_chat_invite_link</span>
<span class="pl-k">try</span>:
<span class="pl-s1">invite_link</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">export_chat_invite_link</span>(<span class="pl-s1">entity</span>)
<span class="pl-k">return</span> <span class="pl-s1">invite_link</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e2</span>:
<span class="pl-s1">logger</span>.<span class="pl-c1">warning</span>(<span class="pl-s">f"export_chat_invite_link failed: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e2</span><span class="pl-kos">}</span></span>"</span>)
<span class="pl-c"># Last resort: Try directly fetching chat info</span>
<span class="pl-k">try</span>:
<span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">entity</span>, (<span class="pl-v">Chat</span>, <span class="pl-v">Channel</span>)):
<span class="pl-s1">full_chat</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">messages</span>.<span class="pl-c1">GetFullChatRequest</span>(
<span class="pl-s1">chat_id</span><span class="pl-c1">=</span><span class="pl-s1">entity</span>.<span class="pl-c1">id</span>
))
<span class="pl-k">if</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">full_chat</span>, <span class="pl-s">'full_chat'</span>) <span class="pl-c1">and</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">full_chat</span>.<span class="pl-c1">full_chat</span>, <span class="pl-s">'invite_link'</span>):
<span class="pl-k">return</span> <span class="pl-s1">full_chat</span>.<span class="pl-c1">full_chat</span>.<span class="pl-c1">invite_link</span> <span class="pl-c1">or</span> <span class="pl-s">"No invite link available."</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e3</span>:
<span class="pl-s1">logger</span>.<span class="pl-c1">warning</span>(<span class="pl-s">f"GetFullChatRequest failed: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e3</span><span class="pl-kos">}</span></span>"</span>)
<span class="pl-k">return</span> <span class="pl-s">"Could not retrieve invite link for this chat."</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-s1">logger</span>.<span class="pl-c1">exception</span>(<span class="pl-s">f"get_invite_link failed (chat_id=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">chat_id</span><span class="pl-kos">}</span></span>)"</span>)
<span class="pl-k">return</span> <span class="pl-s">f"Error getting invite link: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span></pre></div>
<p>Example output:</p>
<pre><code>https://t.me/+AbCdEfGhIjKlMnOp
</code></pre>
<div class="markdown-heading"><h3 class="heading-element">Joining Chats via Invite Links</h3><a id="user-content-joining-chats-via-invite-links" class="anchor" aria-label="Permalink: Joining Chats via Invite Links" href="#joining-chats-via-invite-links"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">join_chat_by_link</span>(<span class="pl-s1">link</span>: <span class="pl-smi">str</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Join a chat by invite link.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-c"># Extract the hash from the invite link</span>
<span class="pl-k">if</span> <span class="pl-s">'/'</span> <span class="pl-c1">in</span> <span class="pl-s1">link</span>:
<span class="pl-s1">hash_part</span> <span class="pl-c1">=</span> <span class="pl-s1">link</span>.<span class="pl-c1">split</span>(<span class="pl-s">'/'</span>)[<span class="pl-c1">-</span><span class="pl-c1">1</span>]
<span class="pl-k">if</span> <span class="pl-s1">hash_part</span>.<span class="pl-c1">startswith</span>(<span class="pl-s">'+'</span>):
<span class="pl-s1">hash_part</span> <span class="pl-c1">=</span> <span class="pl-s1">hash_part</span>[<span class="pl-c1">1</span>:] <span class="pl-c"># Remove the '+' if present</span>
<span class="pl-k">else</span>:
<span class="pl-s1">hash_part</span> <span class="pl-c1">=</span> <span class="pl-s1">link</span>
<span class="pl-c"># Try checking the invite before joining</span>
<span class="pl-k">try</span>:
<span class="pl-c"># Try to check invite info first (will often fail if not a member)</span>
<span class="pl-s1">invite_info</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">messages</span>.<span class="pl-c1">CheckChatInviteRequest</span>(<span class="pl-s1">hash</span><span class="pl-c1">=</span><span class="pl-s1">hash_part</span>))
<span class="pl-k">if</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">invite_info</span>, <span class="pl-s">'chat'</span>) <span class="pl-c1">and</span> <span class="pl-s1">invite_info</span>.<span class="pl-c1">chat</span>:
<span class="pl-c"># If we got chat info, we're already a member</span>
<span class="pl-s1">chat_title</span> <span class="pl-c1">=</span> <span class="pl-en">getattr</span>(<span class="pl-s1">invite_info</span>.<span class="pl-c1">chat</span>, <span class="pl-s">'title'</span>, <span class="pl-s">'Unknown Chat'</span>)
<span class="pl-k">return</span> <span class="pl-s">f"You are already a member of this chat: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">chat_title</span><span class="pl-kos">}</span></span>"</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span>:
<span class="pl-c"># This often fails if not a member - just continue</span>
<span class="pl-k">pass</span>
<span class="pl-c"># Join the chat using the hash</span>
<span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">messages</span>.<span class="pl-c1">ImportChatInviteRequest</span>(<span class="pl-s1">hash</span><span class="pl-c1">=</span><span class="pl-s1">hash_part</span>))
<span class="pl-k">if</span> <span class="pl-s1">result</span> <span class="pl-c1">and</span> <span class="pl-en">hasattr</span>(<span class="pl-s1">result</span>, <span class="pl-s">'chats'</span>) <span class="pl-c1">and</span> <span class="pl-s1">result</span>.<span class="pl-c1">chats</span>:
<span class="pl-s1">chat_title</span> <span class="pl-c1">=</span> <span class="pl-en">getattr</span>(<span class="pl-s1">result</span>.<span class="pl-c1">chats</span>[<span class="pl-c1">0</span>], <span class="pl-s">'title'</span>, <span class="pl-s">'Unknown Chat'</span>)
<span class="pl-k">return</span> <span class="pl-s">f"Successfully joined chat: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">chat_title</span><span class="pl-kos">}</span></span>"</span>
<span class="pl-k">return</span> <span class="pl-s">f"Joined chat via invite hash."</span>
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-s1">err_str</span> <span class="pl-c1">=</span> <span class="pl-en">str</span>(<span class="pl-s1">e</span>).<span class="pl-c1">lower</span>()
<span class="pl-k">if</span> <span class="pl-s">"expired"</span> <span class="pl-c1">in</span> <span class="pl-s1">err_str</span>:
<span class="pl-k">return</span> <span class="pl-s">"The invite hash has expired and is no longer valid."</span>
<span class="pl-k">elif</span> <span class="pl-s">"invalid"</span> <span class="pl-c1">in</span> <span class="pl-s1">err_str</span>:
<span class="pl-k">return</span> <span class="pl-s">"The invite hash is invalid or malformed."</span>
<span class="pl-k">elif</span> <span class="pl-s">"already"</span> <span class="pl-c1">in</span> <span class="pl-s1">err_str</span> <span class="pl-c1">and</span> <span class="pl-s">"participant"</span> <span class="pl-c1">in</span> <span class="pl-s1">err_str</span>:
<span class="pl-k">return</span> <span class="pl-s">"You are already a member of this chat."</span>
<span class="pl-s1">logger</span>.<span class="pl-c1">exception</span>(<span class="pl-s">f"join_chat_by_link failed (link=<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">link</span><span class="pl-kos">}</span></span>)"</span>)
<span class="pl-k">return</span> <span class="pl-s">f"Error joining chat: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span></pre></div>
<p>Example output:</p>
<pre><code>Successfully joined chat: Developer Community
</code></pre>
<div class="markdown-heading"><h3 class="heading-element">Searching Public Chats</h3><a id="user-content-searching-public-chats" class="anchor" aria-label="Permalink: Searching Public Chats" href="#searching-public-chats"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">search_public_chats</span>(<span class="pl-s1">query</span>: <span class="pl-smi">str</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Search for public chats, channels, or bots by username or title.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">contacts</span>.<span class="pl-c1">SearchRequest</span>(<span class="pl-s1">q</span><span class="pl-c1">=</span><span class="pl-s1">query</span>, <span class="pl-s1">limit</span><span class="pl-c1">=</span><span class="pl-c1">20</span>))
<span class="pl-k">return</span> <span class="pl-s1">json</span>.<span class="pl-c1">dumps</span>([<span class="pl-en">format_entity</span>(<span class="pl-s1">u</span>) <span class="pl-k">for</span> <span class="pl-s1">u</span> <span class="pl-c1">in</span> <span class="pl-s1">result</span>.<span class="pl-c1">users</span>], <span class="pl-s1">indent</span><span class="pl-c1">=</span><span class="pl-c1">2</span>)
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-k">return</span> <span class="pl-s">f"Error searching public chats: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span></pre></div>
<p>Example output:</p>
<div class="highlight highlight-source-json"><pre>[
{
<span class="pl-ent">"id"</span>: <span class="pl-c1">123456789</span>,
<span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>TelegramBot<span class="pl-pds">"</span></span>,
<span class="pl-ent">"type"</span>: <span class="pl-s"><span class="pl-pds">"</span>user<span class="pl-pds">"</span></span>,
<span class="pl-ent">"username"</span>: <span class="pl-s"><span class="pl-pds">"</span>telegram_bot<span class="pl-pds">"</span></span>
},
{
<span class="pl-ent">"id"</span>: <span class="pl-c1">987654321</span>,
<span class="pl-ent">"name"</span>: <span class="pl-s"><span class="pl-pds">"</span>Telegram News<span class="pl-pds">"</span></span>,
<span class="pl-ent">"type"</span>: <span class="pl-s"><span class="pl-pds">"</span>user<span class="pl-pds">"</span></span>,
<span class="pl-ent">"username"</span>: <span class="pl-s"><span class="pl-pds">"</span>telegram_news<span class="pl-pds">"</span></span>
}
]</pre></div>
<div class="markdown-heading"><h3 class="heading-element">Getting Direct Chats with Contacts</h3><a id="user-content-getting-direct-chats-with-contacts" class="anchor" aria-label="Permalink: Getting Direct Chats with Contacts" href="#getting-direct-chats-with-contacts"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<div class="highlight highlight-source-python"><pre><span class="pl-en">@<span class="pl-s1">mcp</span>.<span class="pl-c1">tool</span>()</span>
<span class="pl-k">async</span> <span class="pl-k">def</span> <span class="pl-en">get_direct_chat_by_contact</span>(<span class="pl-s1">contact_query</span>: <span class="pl-smi">str</span>) <span class="pl-c1">-></span> <span class="pl-smi">str</span>:
<span class="pl-s">"""</span>
<span class="pl-s"> Find a direct chat with a specific contact by name, username, or phone.</span>
<span class="pl-s"> </span>
<span class="pl-s"> Args:</span>
<span class="pl-s"> contact_query: Name, username, or phone number to search for.</span>
<span class="pl-s"> """</span>
<span class="pl-k">try</span>:
<span class="pl-c"># Fetch all contacts using the correct Telethon method</span>
<span class="pl-s1">result</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-en">client</span>(<span class="pl-s1">functions</span>.<span class="pl-c1">contacts</span>.<span class="pl-c1">GetContactsRequest</span>(<span class="pl-s1">hash</span><span class="pl-c1">=</span><span class="pl-c1">0</span>))
<span class="pl-s1">contacts</span> <span class="pl-c1">=</span> <span class="pl-s1">result</span>.<span class="pl-c1">users</span>
<span class="pl-s1">found_contacts</span> <span class="pl-c1">=</span> []
<span class="pl-k">for</span> <span class="pl-s1">contact</span> <span class="pl-c1">in</span> <span class="pl-s1">contacts</span>:
<span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-s1">contact</span>:
<span class="pl-k">continue</span>
<span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-s">f"<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'first_name'</span>, <span class="pl-s">''</span>)<span class="pl-kos">}</span></span> <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'last_name'</span>, <span class="pl-s">''</span>)<span class="pl-kos">}</span></span>"</span>.<span class="pl-c1">strip</span>()
<span class="pl-s1">username</span> <span class="pl-c1">=</span> <span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'username'</span>, <span class="pl-s">''</span>)
<span class="pl-s1">phone</span> <span class="pl-c1">=</span> <span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'phone'</span>, <span class="pl-s">''</span>)
<span class="pl-k">if</span> (<span class="pl-s1">contact_query</span>.<span class="pl-c1">lower</span>() <span class="pl-c1">in</span> <span class="pl-s1">name</span>.<span class="pl-c1">lower</span>() <span class="pl-c1">or</span>
(<span class="pl-s1">username</span> <span class="pl-c1">and</span> <span class="pl-s1">contact_query</span>.<span class="pl-c1">lower</span>() <span class="pl-c1">in</span> <span class="pl-s1">username</span>.<span class="pl-c1">lower</span>()) <span class="pl-c1">or</span>
(<span class="pl-s1">phone</span> <span class="pl-c1">and</span> <span class="pl-s1">contact_query</span> <span class="pl-c1">in</span> <span class="pl-s1">phone</span>)):
<span class="pl-s1">found_contacts</span>.<span class="pl-c1">append</span>(<span class="pl-s1">contact</span>)
<span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-s1">found_contacts</span>:
<span class="pl-k">return</span> <span class="pl-s">f"No contacts found matching '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">contact_query</span><span class="pl-kos">}</span></span>'."</span>
<span class="pl-c"># If we found contacts, look for direct chats with them</span>
<span class="pl-s1">results</span> <span class="pl-c1">=</span> []
<span class="pl-s1">dialogs</span> <span class="pl-c1">=</span> <span class="pl-k">await</span> <span class="pl-s1">client</span>.<span class="pl-c1">get_dialogs</span>()
<span class="pl-k">for</span> <span class="pl-s1">contact</span> <span class="pl-c1">in</span> <span class="pl-s1">found_contacts</span>:
<span class="pl-s1">contact_name</span> <span class="pl-c1">=</span> <span class="pl-s">f"<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'first_name'</span>, <span class="pl-s">''</span>)<span class="pl-kos">}</span></span> <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'last_name'</span>, <span class="pl-s">''</span>)<span class="pl-kos">}</span></span>"</span>.<span class="pl-c1">strip</span>()
<span class="pl-k">for</span> <span class="pl-s1">dialog</span> <span class="pl-c1">in</span> <span class="pl-s1">dialogs</span>:
<span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">dialog</span>.<span class="pl-c1">entity</span>, <span class="pl-v">User</span>) <span class="pl-c1">and</span> <span class="pl-s1">dialog</span>.<span class="pl-c1">entity</span>.<span class="pl-c1">id</span> <span class="pl-c1">==</span> <span class="pl-s1">contact</span>.<span class="pl-c1">id</span>:
<span class="pl-s1">chat_info</span> <span class="pl-c1">=</span> <span class="pl-s">f"Chat ID: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">dialog</span>.<span class="pl-c1">entity</span>.<span class="pl-c1">id</span><span class="pl-kos">}</span></span>, Contact: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">contact_name</span><span class="pl-kos">}</span></span>"</span>
<span class="pl-k">if</span> <span class="pl-en">getattr</span>(<span class="pl-s1">contact</span>, <span class="pl-s">'username'</span>, <span class="pl-s">''</span>):
<span class="pl-s1">chat_info</span> <span class="pl-c1">+=</span> <span class="pl-s">f", Username: @<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">contact</span>.<span class="pl-c1">username</span><span class="pl-kos">}</span></span>"</span>
<span class="pl-k">if</span> <span class="pl-s1">dialog</span>.<span class="pl-c1">unread_count</span>:
<span class="pl-s1">chat_info</span> <span class="pl-c1">+=</span> <span class="pl-s">f", Unread: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">dialog</span>.<span class="pl-c1">unread_count</span><span class="pl-kos">}</span></span>"</span>
<span class="pl-s1">results</span>.<span class="pl-c1">append</span>(<span class="pl-s1">chat_info</span>)
<span class="pl-k">break</span>
<span class="pl-k">if</span> <span class="pl-c1">not</span> <span class="pl-s1">results</span>:
<span class="pl-k">return</span> <span class="pl-s">f"Found contacts matching '<span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">contact_query</span><span class="pl-kos">}</span></span>', but no direct chats with them."</span>
<span class="pl-k">return</span> <span class="pl-s">"<span class="pl-cce">\n</span>"</span>.<span class="pl-c1">join</span>(<span class="pl-s1">results</span>)
<span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
<span class="pl-k">return</span> <span class="pl-s">f"Error searching for direct chat: <span class="pl-s1"><span class="pl-kos">{</span><span class="pl-s1">e</span><span class="pl-kos">}</span></span>"</span></pre></div>
<p>Example output:</p>
<pre><code>Chat ID: 123456789, Contact: John Smith, Username: @johnsmith, Unread: 3
</code></pre>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🎮 Usage Examples</h2><a id="user-content--usage-examples" class="anchor" aria-label="Permalink: 🎮 Usage Examples" href="#-usage-examples"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>"Show my recent chats"</li>
<li>"Send 'Hello world' to chat 123456789"</li>
<li>"Add contact with phone +1234567890, name John Doe"</li>
<li>"Create a group 'Project Team' with users 111, 222, 333"</li>
<li>"Download the media from message 42 in chat 123456789"</li>
<li>"Mute notifications for chat 123456789"</li>
<li>"Promote user 111 to admin in group 123456789"</li>
<li>"Search for public channels about 'news'"</li>
<li>"Join the Telegram group with invite link <a href="https://t.me/+AbCdEfGhIjK" rel="nofollow">https://t.me/+AbCdEfGhIjK</a>"</li>
<li>"Send a sticker to my Saved Messages"</li>
<li>"Get all my sticker sets"</li>
</ul>
<p>You can use these tools via natural language in Claude, Cursor, or any MCP-compatible client.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🧠 Error Handling & Robustness</h2><a id="user-content--error-handling--robustness" class="anchor" aria-label="Permalink: 🧠 Error Handling & Robustness" href="#-error-handling--robustness"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>This implementation includes comprehensive error handling:</p>
<ul>
<li>
<strong>Session management</strong>: Works with both file-based and string-based sessions</li>
<li>
<strong>Error reporting</strong>: Detailed errors logged to <code>mcp_errors.log</code>
</li>
<li>
<strong>Graceful degradation</strong>: Multiple fallback approaches for critical functions</li>
<li>
<strong>User-friendly messages</strong>: Clear, actionable error messages instead of technical errors</li>
<li>
<strong>Account type detection</strong>: Functions that require bot accounts detect and notify when used with user accounts</li>
<li>
<strong>Invite link processing</strong>: Handles various link formats and already-member cases</li>
</ul>
<p>The code is designed to be robust against common Telegram API issues and limitations.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🛠️ Contribution Guide</h2><a id="user-content-️-contribution-guide" class="anchor" aria-label="Permalink: 🛠️ Contribution Guide" href="#️-contribution-guide"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ol>
<li>
<strong>Fork this repo:</strong> <a href="https://github.com/chigwell/telegram-mcp">chigwell/telegram-mcp</a>
</li>
<li>
<strong>Clone your fork:</strong>
<div class="highlight highlight-source-shell"><pre>git clone https://github.com/<span class="pl-k"><</span>your-github-username<span class="pl-k">></span>/telegram-mcp.git</pre></div>
</li>
<li>
<strong>Create a new branch:</strong>
<div class="highlight highlight-source-shell"><pre>git checkout -b my-feature</pre></div>
</li>
<li><strong>Make your changes, add tests/docs if needed.</strong></li>
<li>
<strong>Push and open a Pull Request</strong> to <a href="https://github.com/chigwell/telegram-mcp">chigwell/telegram-mcp</a> with a clear description.</li>
<li>
<strong>Tag @chigwell or @l1v0n1</strong> in your PR for review.</li>
</ol>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🔒 Security Considerations</h2><a id="user-content--security-considerations" class="anchor" aria-label="Permalink: 🔒 Security Considerations" href="#-security-considerations"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li><strong>Never commit your <code>.env</code> or session string.</strong></li>
<li>The session string gives full access to your Telegram account—keep it safe!</li>
<li>All processing is local; no data is sent anywhere except Telegram's API.</li>
<li>Use <code>.env.example</code> as a template and keep your actual <code>.env</code> file private.</li>
<li>Test files are automatically excluded in <code>.gitignore</code>.</li>
</ul>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🛠️ Troubleshooting</h2><a id="user-content-️-troubleshooting" class="anchor" aria-label="Permalink: 🛠️ Troubleshooting" href="#️-troubleshooting"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li>
<strong>Check logs</strong> in your MCP client (Claude/Cursor) and the terminal for errors.</li>
<li>
<strong>Detailed error logs</strong> can be found in <code>mcp_errors.log</code>.</li>
<li>
<strong>Interpreter errors?</strong> Make sure your <code>.venv</code> is created and selected.</li>
<li>
<strong>Database lock?</strong> Use session string authentication, not file-based sessions.</li>
<li>
<strong>iCloud/Dropbox issues?</strong> Move your project to a local path without spaces if you see odd errors.</li>
<li>
<strong>Regenerate session string</strong> if you change your Telegram password or see auth errors.</li>
<li>
<strong>Bot-only functions</strong> will show clear messages when used with regular user accounts.</li>
<li>
<strong>Test script failures?</strong> Check test configuration in <code>.env</code> for valid test accounts/groups.</li>
</ul>
<hr>
<div class="markdown-heading"><h2 class="heading-element">📄 License</h2><a id="user-content--license" class="anchor" aria-label="Permalink: 📄 License" href="#-license"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p>This project is licensed under the <a href="LICENSE">Apache 2.0 License</a>.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">🙏 Acknowledgements</h2><a id="user-content--acknowledgements" class="anchor" aria-label="Permalink: 🙏 Acknowledgements" href="#-acknowledgements"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<ul>
<li><a href="https://github.com/LonamiWebs/Telethon">Telethon</a></li>
<li><a href="https://modelcontextprotocol.io/" rel="nofollow">Model Context Protocol</a></li>
<li>
<a href="https://www.anthropic.com/" rel="nofollow">Claude</a> and <a href="https://cursor.so/" rel="nofollow">Cursor</a>
</li>
<li>
<a href="https://github.com/chigwell/telegram-mcp">chigwell/telegram-mcp</a> (upstream)</li>
</ul>
<hr>
<p><strong>Maintained by <a href="https://github.com/chigwell">@chigwell</a> and <a href="https://github.com/l1v0n1">@l1v0n1</a>. PRs welcome!</strong></p>
<div class="markdown-heading"><h2 class="heading-element">Star History</h2><a id="user-content-star-history" class="anchor" aria-label="Permalink: Star History" href="#star-history"><span aria-hidden="true" class="octicon octicon-link"></span></a></div>
<p><a href="https://www.star-history.com/#chigwell/telegram-mcp&Date" rel="nofollow"><img src="https://camo.githubusercontent.com/306fadc6b980dfe16effdfbc9a919120fd79…; alt="Star History Chart" data-canonical-src="https://api.star-history.com/svg?repos=chigwell/telegram-mcp&type=D…; style="max-width: 100%;"></a></p>
Browse by Category
Explore pre-built MCP servers for popular enterprise systems that connect AI assistants to your data sources.
Get Started with MCP
Begin building and testing MCP connectors today to enhance your AI applications with context-aware capabilities.
Join the Community
Contribute to our open-source repositories and implementations.
Build Your First Server
Follow our quickstart guide to build a custom MCP server.
Install Pre-built Servers
Get started quickly with pre-built MCP servers for popular systems.
Key Benefits
The Model Context Protocol provides a simpler, more reliable way to give AI systems access to the data they need.
Secure Integration
Build secure, two-way connections between your data sources and AI-powered tools with controlled access.
Universal Connectivity
Replace fragmented integrations with a single protocol that connects to multiple data sources.
Context-Aware AI
Enable AI assistants to access relevant information from your systems to produce better, more accurate responses.