[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"similar-chigwell--telegram-mcp":3,"tool-chigwell--telegram-mcp":62},[4,18,26,36,46,54],{"id":5,"name":6,"github_repo":7,"description_zh":8,"stars":9,"difficulty_score":10,"last_commit_at":11,"category_tags":12,"status":17},4358,"openclaw","openclaw\u002Fopenclaw","OpenClaw 是一款专为个人打造的本地化 AI 助手，旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚，能够直接接入你日常使用的各类通讯渠道，包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息，OpenClaw 都能即时响应，甚至支持在 macOS、iOS 和 Android 设备上进行语音交互，并提供实时的画布渲染功能供你操控。\n\n这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地，用户无需依赖云端服务即可享受快速、私密的智能辅助，真正实现了“你的数据，你做主”。其独特的技术亮点在于强大的网关架构，将控制平面与核心助手分离，确保跨平台通信的流畅性与扩展性。\n\nOpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者，以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力（支持 macOS、Linux 及 Windows WSL2），即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你",349277,3,"2026-04-06T06:32:30",[13,14,15,16],"Agent","开发框架","图像","数据工具","ready",{"id":19,"name":20,"github_repo":21,"description_zh":22,"stars":23,"difficulty_score":10,"last_commit_at":24,"category_tags":25,"status":17},3808,"stable-diffusion-webui","AUTOMATIC1111\u002Fstable-diffusion-webui","stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面，旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点，将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。\n\n无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师，还是想要深入探索模型潜力的开发者与研究人员，都能从中获益。其核心亮点在于极高的功能丰富度：不仅支持文生图、图生图、局部重绘（Inpainting）和外绘（Outpainting）等基础模式，还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外，它内置了 GFPGAN 和 CodeFormer 等人脸修复工具，支持多种神经网络放大算法，并允许用户通过插件系统无限扩展能力。即使是显存有限的设备，stable-diffusion-webui 也提供了相应的优化选项，让高质量的 AI 艺术创作变得触手可及。",162132,"2026-04-05T11:01:52",[14,15,13],{"id":27,"name":28,"github_repo":29,"description_zh":30,"stars":31,"difficulty_score":32,"last_commit_at":33,"category_tags":34,"status":17},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",159636,2,"2026-04-17T23:33:34",[14,13,35],"语言模型",{"id":37,"name":38,"github_repo":39,"description_zh":40,"stars":41,"difficulty_score":42,"last_commit_at":43,"category_tags":44,"status":17},8272,"opencode","anomalyco\u002Fopencode","OpenCode 是一款开源的 AI 编程助手（Coding Agent），旨在像一位智能搭档一样融入您的开发流程。它不仅仅是一个代码补全插件，而是一个能够理解项目上下文、自主规划任务并执行复杂编码操作的智能体。无论是生成全新功能、重构现有代码，还是排查难以定位的 Bug，OpenCode 都能通过自然语言交互高效完成，显著减少开发者在重复性劳动和上下文切换上的时间消耗。\n\n这款工具专为软件开发者、工程师及技术研究人员设计，特别适合希望利用大模型能力来提升编码效率、加速原型开发或处理遗留代码维护的专业人群。其核心亮点在于完全开源的架构，这意味着用户可以审查代码逻辑、自定义行为策略，甚至私有化部署以保障数据安全，彻底打破了传统闭源 AI 助手的“黑盒”限制。\n\n在技术体验上，OpenCode 提供了灵活的终端界面（Terminal UI）和正在测试中的桌面应用程序，支持 macOS、Windows 及 Linux 全平台。它兼容多种包管理工具，安装便捷，并能无缝集成到现有的开发环境中。无论您是追求极致控制权的资深极客，还是渴望提升产出的独立开发者，OpenCode 都提供了一个透明、可信",144296,1,"2026-04-16T14:50:03",[13,45],"插件",{"id":47,"name":48,"github_repo":49,"description_zh":50,"stars":51,"difficulty_score":32,"last_commit_at":52,"category_tags":53,"status":17},2271,"ComfyUI","Comfy-Org\u002FComfyUI","ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎，专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式，采用直观的节点式流程图界面，让用户通过连接不同的功能模块即可构建个性化的生成管线。\n\n这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景，也能自由组合模型、调整参数并实时预览效果，轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性，不仅支持 Windows、macOS 和 Linux 全平台，还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构，并率先支持 SDXL、Flux、SD3 等前沿模型。\n\n无论是希望深入探索算法潜力的研究人员和开发者，还是追求极致创作自由度的设计师与资深 AI 绘画爱好者，ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能，使其成为当前最灵活、生态最丰富的开源扩散模型工具之一，帮助用户将创意高效转化为现实。",108322,"2026-04-10T11:39:34",[14,15,13],{"id":55,"name":56,"github_repo":57,"description_zh":58,"stars":59,"difficulty_score":32,"last_commit_at":60,"category_tags":61,"status":17},6121,"gemini-cli","google-gemini\u002Fgemini-cli","gemini-cli 是一款由谷歌推出的开源 AI 命令行工具，它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言，它提供了一条从输入提示词到获取模型响应的最短路径，无需切换窗口即可享受智能辅助。\n\n这款工具主要解决了开发过程中频繁上下文切换的痛点，让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用，还是执行复杂的 Git 操作，gemini-cli 都能通过自然语言指令高效处理。\n\n它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口，具备出色的逻辑推理能力；内置 Google 搜索、文件操作及 Shell 命令执行等实用工具；更独特的是，它支持 MCP（模型上下文协议），允许用户灵活扩展自定义集成，连接如图像生成等外部能力。此外，个人谷歌账号即可享受免费的额度支持，且项目基于 Apache 2.0 协议完全开源，是提升终端工作效率的理想助手。",100752,"2026-04-10T01:20:03",[45,13,15,14],{"id":63,"github_repo":64,"name":65,"description_en":66,"description_zh":67,"ai_summary_zh":67,"readme_en":68,"readme_zh":69,"quickstart_zh":70,"use_case_zh":71,"hero_image_url":72,"owner_login":73,"owner_name":74,"owner_avatar_url":75,"owner_bio":76,"owner_company":77,"owner_location":78,"owner_email":79,"owner_twitter":79,"owner_website":80,"owner_url":81,"languages":82,"stars":91,"forks":92,"last_commit_at":93,"license":94,"difficulty_score":32,"env_os":95,"env_gpu":96,"env_ram":96,"env_deps":97,"category_tags":104,"github_topics":106,"view_count":32,"oss_zip_url":79,"oss_zip_packed_at":79,"status":17,"created_at":120,"updated_at":121,"faqs":122,"releases":151},8689,"chigwell\u002Ftelegram-mcp","telegram-mcp","Telegram MCP server powered by Telethon to let MCP clients read chats, manage groups, and send\u002Fmodify messages, media, contacts, and settings.","telegram-mcp 是一款基于 Telethon 构建的开源服务器，旨在让支持模型上下文协议（MCP）的 AI 客户端（如 Claude、Cursor）能够直接操控你的 Telegram 账号。它解决了传统 AI 助手无法深度介入即时通讯场景的痛点，将聊天阅读、群组管理、消息收发及媒体处理等复杂操作转化为自然语言指令，让用户能像与人对话一样指挥 AI 完成自动化任务。\n\n这款工具特别适合开发者、技术研究人员以及希望提升工作效率的高级用户。通过它，你可以轻松实现自动回复、聊天记录分析、社群成员管理甚至频道运营等流程，极大地扩展了 AI 在社交网络中的应用边界。其核心技术亮点在于全面集成了 Telethon 的强大功能，几乎覆盖了 Telegram 的所有主要特性，从基础的发送消息到复杂的权限管理（如封禁用户、设置管理员）均可通过标准化工具调用完成。此外，项目提供了完善的 Docker 部署方案与严格的代码质量监控，确保了运行的稳定性与安全性，是构建智能社交代理的理想基石。","\u003Cdiv align=\"center\">\n  \u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_98c571874352.png\" alt=\"Telegram MCP Server\" width=\"100%\" \u002F>\n\u003C\u002Fdiv>\n\n![MCP Badge](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_4ac9d1cb3d9e.png)\n[![License: Apache 2.0](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache%202.0-green?style=flat-square)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FApache-2.0)\n[![Python Lint & Format Check](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fpython-lint-format.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fpython-lint-format.yml)\n[![Docker Build & Compose Validation](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fdocker-build.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fdocker-build.yml)\n\n---\n\n## 🤖 MCP in Action\n\nHere's a demonstration of the Telegram MCP capabilities in [Claude](https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fagents-and-tools\u002Fmcp):\n\n **Basic usage example:**\n\n![Telegram MCP in action](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_801f95ac4c79.png)\n\n1. **Example: Asking Claude to analyze chat history and send a response:**\n\n![Telegram MCP Request](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_1a9eb4986b8d.png)\n\n2. **Successfully sent message to the group:**\n\n![Telegram MCP Result](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_fb142bc9cd2e.png)\n\nAs 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.\n\n---\n\nA full-featured Telegram integration for Claude, Cursor, and any MCP-compatible client, powered by [Telethon](https:\u002F\u002Fdocs.telethon.dev\u002F) and the [Model Context Protocol (MCP)](https:\u002F\u002Fmodelcontextprotocol.io\u002F). This project lets you interact with your Telegram account programmatically, automating everything from messaging to group management.\n\n\n---\n\n## 🚀 Features & Tools\n\nThis MCP server exposes a huge suite of Telegram tools. **Every major Telegram\u002FTelethon feature is available as a tool!**\n\n### Chat & Group Management\n- **get_chats(page, page_size)**: Paginated list of chats\n- **list_chats(chat_type, limit)**: List chats with metadata and filtering\n- **get_chat(chat_id)**: Detailed info about a chat\n- **create_group(title, user_ids)**: Create a new group\n- **invite_to_group(group_id, user_ids)**: Invite users to a group or channel\n- **create_channel(title, about, megagroup)**: Create a channel or supergroup\n- **edit_chat_title(chat_id, title)**: Change chat\u002Fgroup\u002Fchannel title\n- **delete_chat_photo(chat_id)**: Remove chat\u002Fgroup\u002Fchannel photo\n- **leave_chat(chat_id)**: Leave a group or channel\n- **get_participants(chat_id)**: List all participants\n- **get_admins(chat_id)**: List all admins\n- **get_banned_users(chat_id)**: List all banned users\n- **promote_admin(chat_id, user_id)**: Promote user to admin\n- **demote_admin(chat_id, user_id)**: Demote admin to user\n- **ban_user(chat_id, user_id)**: Ban user\n- **unban_user(chat_id, user_id)**: Unban user\n- **get_invite_link(chat_id)**: Get invite link\n- **export_chat_invite(chat_id)**: Export invite link\n- **import_chat_invite(hash)**: Join chat by invite hash\n- **join_chat_by_link(link)**: Join chat by invite link\n- **subscribe_public_channel(channel)**: Subscribe to a public channel or supergroup by username or ID\n\n### Messaging\n- **get_messages(chat_id, page, page_size)**: Paginated messages\n- **list_messages(chat_id, limit, search_query, from_date, to_date)**: Filtered messages\n- **list_topics(chat_id, limit, offset_topic, search_query)**: List forum topics in supergroups\n- **send_message(chat_id, message)**: Send a message\n- **reply_to_message(chat_id, message_id, text)**: Reply to a message\n- **edit_message(chat_id, message_id, new_text)**: Edit your message\n- **delete_message(chat_id, message_id)**: Delete a message\n- **forward_message(from_chat_id, message_id, to_chat_id)**: Forward a message\n- **pin_message(chat_id, message_id)**: Pin a message\n- **unpin_message(chat_id, message_id)**: Unpin a message\n- **mark_as_read(chat_id)**: Mark all as read\n- **get_message_context(chat_id, message_id, context_size)**: Context around a message\n- **get_history(chat_id, limit)**: Full chat history\n- **get_pinned_messages(chat_id)**: List pinned messages\n- **get_last_interaction(contact_id)**: Most recent message with a contact\n- **create_poll(chat_id, question, options, multiple_choice, quiz_mode, public_votes, close_date)**: Create a poll\n- **list_inline_buttons(chat_id, message_id, limit)**: Inspect inline keyboards to discover button text\u002Findex\n- **press_inline_button(chat_id, message_id, button_text, button_index)**: Trigger inline keyboard callbacks by label or index\n-  **send_reaction(chat_id, message_id, emoji, big=False)**: Add a reaction to a message\n-  **remove_reaction(chat_id, message_id)**: Remove a reaction from a message\n-  **get_message_reactions(chat_id, message_id, limit=50)**: Get all reactions on a message\n\n### Contact Management\n- **list_contacts()**: List all contacts\n- **search_contacts(query)**: Search contacts\n- **add_contact(phone, first_name, last_name)**: Add a contact\n- **delete_contact(user_id)**: Delete a contact\n- **block_user(user_id)**: Block a user\n- **unblock_user(user_id)**: Unblock a user\n- **import_contacts(contacts)**: Bulk import contacts\n- **export_contacts()**: Export all contacts as JSON\n- **get_blocked_users()**: List blocked users\n- **get_contact_ids()**: List all contact IDs\n- **get_direct_chat_by_contact(contact_query)**: Find direct chat with a contact\n- **get_contact_chats(contact_id)**: List all chats with a contact\n\n### User & Profile\n- **get_me()**: Get your user info\n- **update_profile(first_name, last_name, about)**: Update your profile\n- **set_profile_photo(file_path)**: Set a profile photo from an allowed root path\n- **delete_profile_photo()**: Remove your profile photo\n- **get_user_photos(user_id, limit)**: Get a user's profile photos\n- **get_user_status(user_id)**: Get a user's online status\n\n### Media\n- **get_media_info(chat_id, message_id)**: Get info about media in a message\n- **send_file(chat_id, file_path, caption)**: Send a local file from allowed roots\n- **download_media(chat_id, message_id, file_path)**: Save message media under allowed roots\n- **upload_file(file_path)**: Upload a local file and return upload metadata\n- **send_voice(chat_id, file_path)**: Send `.ogg\u002F.opus` voice note from allowed roots\n- **send_sticker(chat_id, file_path)**: Send `.webp` sticker from allowed roots\n- **edit_chat_photo(chat_id, file_path)**: Update chat photo from allowed roots\n\n### Search & Discovery\n- **search_public_chats(query, limit)**: Search public chats\u002Fchannels\u002Fbots with a configurable result limit\n- **search_messages(chat_id, query, limit)**: Search messages in a chat\n- **search_global(query, page, page_size)**: Search messages globally with pagination\n- **resolve_username(username)**: Resolve a username to ID\n\n### Stickers, GIFs, Bots\n- **get_sticker_sets()**: List sticker sets\n- **get_bot_info(bot_username)**: Get info about a bot\n- **set_bot_commands(bot_username, commands)**: Set bot commands (bot accounts only)\n\n### Privacy, Settings, and Misc\n- **get_privacy_settings()**: Get privacy settings\n- **set_privacy_settings(key, allow_users, disallow_users)**: Set privacy settings\n- **mute_chat(chat_id)**: Mute notifications\n- **unmute_chat(chat_id)**: Unmute notifications\n- **archive_chat(chat_id)**: Archive a chat\n- **unarchive_chat(chat_id)**: Unarchive a chat\n- **get_recent_actions(chat_id)**: Get recent admin actions\n\n### Drafts\n- **save_draft(chat_id, message, reply_to_msg_id, no_webpage)**: Save a draft message to a chat\u002Fchannel\n- **get_drafts()**: Get all draft messages across all chats\n- **clear_draft(chat_id)**: Clear\u002Fdelete a draft from a specific chat\n\n### Input Validation\n\nTo improve robustness, all functions accepting `chat_id` or `user_id` parameters now include input validation. You can use any of the following formats for these IDs:\n\n-   **Integer ID**: The direct integer ID for a user, chat, or channel (e.g., `123456789` or `-1001234567890`).\n-   **String ID**: The integer ID provided as a string (e.g., `\"123456789\"`).\n-   **Username**: The public username for a user or channel (e.g., `\"@username\"` or `\"username\"`).\n\nThe server will automatically validate the input and convert it to the correct format before making a request to Telegram. If the input is invalid, a clear error message will be returned.\n\n## File-path Tools Security Model\n\nFile-path tools are available, but **disabled by default** until allowed roots are configured.\n\nSupported file-path tools:\n- `send_file`, `download_media`, `set_profile_photo`, `edit_chat_photo`, `send_voice`, `send_sticker`, `upload_file`\n\nSecurity semantics (aligned with MCP filesystem server):\n- Server-side allowlist via CLI positional arguments (fallback when Roots API is unsupported).\n- Client-provided MCP Roots replace the server allowlist when available.\n- If the client returns an empty Roots list, file-path tools are disabled (deny-all).\n- All paths are resolved via realpath and must stay inside an allowed root.\n- Traversal\u002Fglob-like patterns are rejected (`..`, `*`, `?`, `~`, etc.).\n- Relative paths resolve against the first allowed root.\n- Write tools default to `\u003Cfirst_root>\u002Fdownloads\u002F` when `file_path` is omitted.\n\nExample server launch with allowlisted roots:\n```bash\nuv --directory \u002Ffull\u002Fpath\u002Fto\u002Ftelegram-mcp run main.py \u002Fdata\u002Ftelegram \u002Ftmp\u002Ftelegram-mcp\n```\n\nGIF tools are currently limited: `get_gif_search` and `send_gif` are available, while `get_saved_gifs` is not implemented due to reliability limits in Telethon\u002FTelegram API interactions.\n\n---\n\n## 📋 Requirements\n- Python 3.10+\n- [Telethon](https:\u002F\u002Fdocs.telethon.dev\u002F)\n- [MCP Python SDK](https:\u002F\u002Fmodelcontextprotocol.io\u002Fdocs\u002F)\n- [Claude Desktop](https:\u002F\u002Fclaude.ai\u002Fdesktop) or [Cursor](https:\u002F\u002Fcursor.so\u002F) (or any MCP client)\n\n---\n\n## 🔧 Installation & Setup\n\n### 1. Fork & Clone\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp.git\ncd telegram-mcp\n```\n\n### 2. Install Dependencies with uv\n\n```bash\nuv sync\n```\n\n### 3. Generate a Session String\n\n```bash\nuv run session_string_generator.py\n```\nFollow the prompts to authenticate and update your `.env` file.\n\n### 4. Configure .env\n\nCopy `.env.example` to `.env` and fill in your values:\n\n```\nTELEGRAM_API_ID=your_api_id_here\nTELEGRAM_API_HASH=your_api_hash_here\nTELEGRAM_SESSION_NAME=anon\nTELEGRAM_SESSION_STRING=your_session_string_here\n```\nGet your API credentials at [my.telegram.org\u002Fapps](https:\u002F\u002Fmy.telegram.org\u002Fapps).\n\n---\n\n## 🐳 Running with Docker\n\nIf you have Docker and Docker Compose installed, you can build and run the server in a container, simplifying dependency management.\n\n### 1. Build the Image\n\nFrom the project root directory, build the Docker image:\n\n```bash\ndocker build -t telegram-mcp:latest .\n```\n\n### 2. Running the Container\n\nYou have two options:\n\n**Option A: Using Docker Compose (Recommended for Local Use)**\n\nThis method uses the `docker-compose.yml` file and automatically reads your credentials from a `.env` file.\n\n1.  **Create `.env` File:** Ensure you have a `.env` file in the project root containing your `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`, and `TELEGRAM_SESSION_STRING` (or `TELEGRAM_SESSION_NAME`). Use `.env.example` as a template.\n2.  **Run Compose:**\n    ```bash\n    docker compose up --build\n    ```\n    *   Use `docker compose up -d` to run in detached mode (background).\n    *   Press `Ctrl+C` to stop the server.\n\n**Option B: Using `docker run`**\n\nYou can run the container directly, passing credentials as environment variables.\n\n```bash\ndocker run -it --rm \\\n  -e TELEGRAM_API_ID=\"YOUR_API_ID\" \\\n  -e TELEGRAM_API_HASH=\"YOUR_API_HASH\" \\\n  -e TELEGRAM_SESSION_STRING=\"YOUR_SESSION_STRING\" \\\n  telegram-mcp:latest\n```\n*   Replace placeholders with your actual credentials.\n*   Use `-e TELEGRAM_SESSION_NAME=your_session_file_name` instead of `TELEGRAM_SESSION_STRING` if you prefer file-based sessions (requires volume mounting, see `docker-compose.yml` for an example).\n*   The `-it` flags are crucial for interacting with the server.\n\n---\n\n## ⚙️ Configuration for Claude & Cursor\n\n### MCP Configuration\nEdit your Claude desktop config (e.g. `~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json`) or Cursor config (`~\u002F.cursor\u002Fmcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"telegram-mcp\": {\n      \"command\": \"uv\",\n      \"args\": [\n        \"--directory\",\n        \"\u002Ffull\u002Fpath\u002Fto\u002Ftelegram-mcp\",\n        \"run\",\n        \"main.py\"\n      ]\n    }\n  }\n}\n```\n\n## 📝 Tool Examples with Code & Output\n\nBelow are examples of the most commonly used tools with their implementation and sample output.\n\n### Getting Your Chats\n\n```python\n@mcp.tool()\nasync def get_chats(page: int = 1, page_size: int = 20) -> str:\n    \"\"\"\n    Get a paginated list of chats.\n    Args:\n        page: Page number (1-indexed).\n        page_size: Number of chats per page.\n    \"\"\"\n    try:\n        dialogs = await client.get_dialogs()\n        start = (page - 1) * page_size\n        end = start + page_size\n        if start >= len(dialogs):\n            return \"Page out of range.\"\n        chats = dialogs[start:end]\n        lines = []\n        for dialog in chats:\n            entity = dialog.entity\n            chat_id = entity.id\n            title = getattr(entity, \"title\", None) or getattr(entity, \"first_name\", \"Unknown\")\n            lines.append(f\"Chat ID: {chat_id}, Title: {title}\")\n        return \"\\n\".join(lines)\n    except Exception as e:\n        logger.exception(f\"get_chats failed (page={page}, page_size={page_size})\")\n        return \"An error occurred (code: GETCHATS-ERR-001). Check mcp_errors.log for details.\"\n```\n\nExample output:\n```\nChat ID: 123456789, Title: John Doe\nChat ID: -100987654321, Title: My Project Group\nChat ID: 111223344, Title: Jane Smith\nChat ID: -200123456789, Title: News Channel\n```\n\n### Sending Messages\n\n```python\n@mcp.tool()\nasync def send_message(chat_id: int, message: str) -> str:\n    \"\"\"\n    Send a message to a specific chat.\n    Args:\n        chat_id: The ID of the chat.\n        message: The message content to send.\n    \"\"\"\n    try:\n        entity = await client.get_entity(chat_id)\n        await client.send_message(entity, message)\n        return \"Message sent successfully.\"\n    except Exception as e:\n        logger.exception(f\"send_message failed (chat_id={chat_id})\")\n        return \"An error occurred (code: SENDMSG-ERR-001). Check mcp_errors.log for details.\"\n```\n\nExample output:\n```\nMessage sent successfully.\n```\n\n### Listing Inline Buttons\n\n```python\n@mcp.tool()\nasync def list_inline_buttons(\n    chat_id: Union[int, str],\n    message_id: Optional[int] = None,\n    limit: int = 20,\n) -> str:\n    \"\"\"\n    Discover inline keyboard layout, including button indices, callback availability, and URLs.\n    \"\"\"\n```\n\nExample usage:\n```\nlist_inline_buttons(chat_id=\"@sample_tasks_bot\")\n```\n\nThis returns something like:\n```\nButtons for message 42 (date 2025-01-01 12:00:00+00:00):\n[0] text='📋 View tasks', callback=yes\n[1] text='ℹ️ Help', callback=yes\n[2] text='🌐 Visit site', callback=no, url=https:\u002F\u002Fexample.org\n```\n\n### Pressing Inline Buttons\n\n```python\n@mcp.tool()\nasync def press_inline_button(\n    chat_id: Union[int, str],\n    message_id: Optional[int] = None,\n    button_text: Optional[str] = None,\n    button_index: Optional[int] = None,\n) -> str:\n    \"\"\"\n    Press an inline keyboard button by label or zero-based index.\n    If message_id is omitted, the server searches recent messages for the latest inline keyboard.\n    \"\"\"\n```\n\nExample usage:\n```\npress_inline_button(chat_id=\"@sample_tasks_bot\", button_text=\"📋 View tasks\")\n```\n\nUse `list_inline_buttons` first if you need to inspect available buttons—pass a bogus `button_text`\nto quickly list options or call `list_inline_buttons` directly. Once you know the text or index,\n`press_inline_button` sends the callback, just like tapping the button in a native Telegram client.\n\n### Subscribing to Public Channels\n\n```python\n@mcp.tool()\nasync def subscribe_public_channel(channel: Union[int, str]) -> str:\n    \"\"\"\n    Join a public channel or supergroup by username (e.g., \"@examplechannel\") or ID.\n    \"\"\"\n```\n\nExample usage:\n```\nsubscribe_public_channel(channel=\"@daily_updates_feed\")\n```\n\nIf the account is already a participant, the tool reports that instead of failing, making it safe to\nrun repeatedly in workflows that need idempotent joins.\n\n### Getting Chat Invite Links\n\nThe `get_invite_link` function is particularly robust with multiple fallback methods:\n\n```python\n@mcp.tool()\nasync def get_invite_link(chat_id: int) -> str:\n    \"\"\"\n    Get the invite link for a group or channel.\n    \"\"\"\n    try:\n        entity = await client.get_entity(chat_id)\n        \n        # Try using ExportChatInviteRequest first\n        try:\n            from telethon.tl import functions\n            result = await client(functions.messages.ExportChatInviteRequest(\n                peer=entity\n            ))\n            return result.link\n        except AttributeError:\n            # If the function doesn't exist in the current Telethon version\n            logger.warning(\"ExportChatInviteRequest not available, using alternative method\")\n        except Exception as e1:\n            # If that fails, log and try alternative approach\n            logger.warning(f\"ExportChatInviteRequest failed: {e1}\")\n            \n        # Alternative approach using client.export_chat_invite_link\n        try:\n            invite_link = await client.export_chat_invite_link(entity)\n            return invite_link\n        except Exception as e2:\n            logger.warning(f\"export_chat_invite_link failed: {e2}\")\n            \n        # Last resort: Try directly fetching chat info\n        try:\n            if isinstance(entity, (Chat, Channel)):\n                full_chat = await client(functions.messages.GetFullChatRequest(\n                    chat_id=entity.id\n                ))\n                if hasattr(full_chat, 'full_chat') and hasattr(full_chat.full_chat, 'invite_link'):\n                    return full_chat.full_chat.invite_link or \"No invite link available.\"\n        except Exception as e3:\n            logger.warning(f\"GetFullChatRequest failed: {e3}\")\n            \n        return \"Could not retrieve invite link for this chat.\"\n    except Exception as e:\n        logger.exception(f\"get_invite_link failed (chat_id={chat_id})\")\n        return f\"Error getting invite link: {e}\"\n```\n\nExample output:\n```\nhttps:\u002F\u002Ft.me\u002F+AbCdEfGhIjKlMnOp\n```\n\n### Joining Chats via Invite Links\n\n```python\n@mcp.tool()\nasync def join_chat_by_link(link: str) -> str:\n    \"\"\"\n    Join a chat by invite link.\n    \"\"\"\n    try:\n        # Extract the hash from the invite link\n        if '\u002F' in link:\n            hash_part = link.split('\u002F')[-1]\n            if hash_part.startswith('+'):\n                hash_part = hash_part[1:]  # Remove the '+' if present\n        else:\n            hash_part = link\n            \n        # Try checking the invite before joining\n        try:\n            # Try to check invite info first (will often fail if not a member)\n            invite_info = await client(functions.messages.CheckChatInviteRequest(hash=hash_part))\n            if hasattr(invite_info, 'chat') and invite_info.chat:\n                # If we got chat info, we're already a member\n                chat_title = getattr(invite_info.chat, 'title', 'Unknown Chat')\n                return f\"You are already a member of this chat: {chat_title}\"\n        except Exception:\n            # This often fails if not a member - just continue\n            pass\n            \n        # Join the chat using the hash\n        result = await client(functions.messages.ImportChatInviteRequest(hash=hash_part))\n        if result and hasattr(result, 'chats') and result.chats:\n            chat_title = getattr(result.chats[0], 'title', 'Unknown Chat')\n            return f\"Successfully joined chat: {chat_title}\"\n        return f\"Joined chat via invite hash.\"\n    except Exception as e:\n        err_str = str(e).lower()\n        if \"expired\" in err_str:\n            return \"The invite hash has expired and is no longer valid.\"\n        elif \"invalid\" in err_str:\n            return \"The invite hash is invalid or malformed.\"\n        elif \"already\" in err_str and \"participant\" in err_str:\n            return \"You are already a member of this chat.\"\n        logger.exception(f\"join_chat_by_link failed (link={link})\")\n        return f\"Error joining chat: {e}\"\n```\n\nExample output:\n```\nSuccessfully joined chat: Developer Community\n```\n\n### Searching Public Chats\n\n```python\n@mcp.tool()\nasync def search_public_chats(query: str, limit: int = 20) -> str:\n    \"\"\"\n    Search for public chats, channels, or bots by username or title.\n    \"\"\"\n    try:\n        result = await client(functions.contacts.SearchRequest(q=query, limit=limit))\n        entities = [format_entity(e) for e in result.chats + result.users]\n        return json.dumps(entities, indent=2)\n    except Exception as e:\n        return f\"Error searching public chats: {e}\"\n```\n\nExample output:\n```json\n[\n  {\n    \"id\": 123456789,\n    \"name\": \"TelegramBot\",\n    \"type\": \"user\",\n    \"username\": \"telegram_bot\"\n  },\n  {\n    \"id\": 987654321,\n    \"name\": \"Telegram News\",\n    \"type\": \"user\",\n    \"username\": \"telegram_news\"\n  }\n]\n```\n\n### Getting Direct Chats with Contacts\n\n```python\n@mcp.tool()\nasync def get_direct_chat_by_contact(contact_query: str) -> str:\n    \"\"\"\n    Find a direct chat with a specific contact by name, username, or phone.\n    \n    Args:\n        contact_query: Name, username, or phone number to search for.\n    \"\"\"\n    try:\n        # Fetch all contacts using the correct Telethon method\n        result = await client(functions.contacts.GetContactsRequest(hash=0))\n        contacts = result.users\n        found_contacts = []\n        for contact in contacts:\n            if not contact:\n                continue\n            name = f\"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}\".strip()\n            username = getattr(contact, 'username', '')\n            phone = getattr(contact, 'phone', '')\n            if (contact_query.lower() in name.lower() or \n                (username and contact_query.lower() in username.lower()) or \n                (phone and contact_query in phone)):\n                found_contacts.append(contact)\n        if not found_contacts:\n            return f\"No contacts found matching '{contact_query}'.\"\n        # If we found contacts, look for direct chats with them\n        results = []\n        dialogs = await client.get_dialogs()\n        for contact in found_contacts:\n            contact_name = f\"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}\".strip()\n            for dialog in dialogs:\n                if isinstance(dialog.entity, User) and dialog.entity.id == contact.id:\n                    chat_info = f\"Chat ID: {dialog.entity.id}, Contact: {contact_name}\"\n                    if getattr(contact, 'username', ''):\n                        chat_info += f\", Username: @{contact.username}\"\n                    if dialog.unread_count:\n                        chat_info += f\", Unread: {dialog.unread_count}\"\n                    results.append(chat_info)\n                    break\n        \n        if not results:\n            return f\"Found contacts matching '{contact_query}', but no direct chats with them.\"\n        \n        return \"\\n\".join(results)\n    except Exception as e:\n        return f\"Error searching for direct chat: {e}\"\n```\n\nExample output:\n```\nChat ID: 123456789, Contact: John Smith, Username: @johnsmith, Unread: 3\n```\n\n---\n\n## 🎮 Usage Examples\n\n- \"Show my recent chats\"\n- \"Send 'Hello world' to chat 123456789\"\n- \"Add contact with phone +1234567890, name John Doe\"\n- \"Create a group 'Project Team' with users 111, 222, 333\"\n- \"Download the media from message 42 in chat 123456789\"\n- \"Mute notifications for chat 123456789\"\n- \"Promote user 111 to admin in group 123456789\"\n- \"Search for public channels about 'news'\"\n- \"Join the Telegram group with invite link https:\u002F\u002Ft.me\u002F+AbCdEfGhIjK\"\n- \"Send a sticker to my Saved Messages\"\n- \"Get all my sticker sets\"\n\nYou can use these tools via natural language in Claude, Cursor, or any MCP-compatible client.\n\n---\n\n## 🧠 Error Handling & Robustness\n\nThis implementation includes comprehensive error handling:\n\n- **Session management**: Works with both file-based and string-based sessions\n- **Error reporting**: Detailed errors logged to `mcp_errors.log`\n- **Graceful degradation**: Multiple fallback approaches for critical functions\n- **User-friendly messages**: Clear, actionable error messages instead of technical errors\n- **Account type detection**: Functions that require bot accounts detect and notify when used with user accounts\n- **Invite link processing**: Handles various link formats and already-member cases\n\nThe code is designed to be robust against common Telegram API issues and limitations.\n\n---\n\n## 🛠️ Contribution Guide\n\n1. **Fork this repo:** [chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp)\n2. **Clone your fork:**\n   ```bash\n   git clone https:\u002F\u002Fgithub.com\u002F\u003Cyour-github-username>\u002Ftelegram-mcp.git\n   ```\n3. **Create a new branch:**\n   ```bash\n   git checkout -b my-feature\n   ```\n4. **Make your changes, add tests\u002Fdocs if needed.**\n5. **Push and open a Pull Request** to [chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp) with a clear description.\n6. **Tag @chigwell or @l1v0n1** in your PR for review.\n\n---\n\n## 🔒 Security Considerations\n- **Never commit your `.env` or session string.**\n- The session string gives full access to your Telegram account—keep it safe!\n- All processing is local; no data is sent anywhere except Telegram's API.\n- Use `.env.example` as a template and keep your actual `.env` file private.\n- Test files are automatically excluded in `.gitignore`.\n\n---\n\n## 🛠️ Troubleshooting\n- **Check logs** in your MCP client (Claude\u002FCursor) and the terminal for errors.\n- **Detailed error logs** can be found in `mcp_errors.log`.\n- **Interpreter errors?** Make sure your `.venv` is created and selected.\n- **Database lock?** Use session string authentication, not file-based sessions.\n- **iCloud\u002FDropbox issues?** Move your project to a local path without spaces if you see odd errors.\n- **Regenerate session string** if you change your Telegram password or see auth errors.\n- **Bot-only functions** will show clear messages when used with regular user accounts.\n- **Test script failures?** Check test configuration in `.env` for valid test accounts\u002Fgroups.\n\n---\n\n## 📄 License\n\nThis project is licensed under the [Apache 2.0 License](LICENSE).\n\n---\n\n## 🙏 Acknowledgements\n- [Telethon](https:\u002F\u002Fgithub.com\u002FLonamiWebs\u002FTelethon)\n- [Model Context Protocol](https:\u002F\u002Fmodelcontextprotocol.io\u002F)\n- [Claude](https:\u002F\u002Fwww.anthropic.com\u002F) and [Cursor](https:\u002F\u002Fcursor.so\u002F)\n- [chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp) (upstream)\n\n---\n\n**Maintained by [@chigwell](https:\u002F\u002Fgithub.com\u002Fchigwell) and [@l1v0n1](https:\u002F\u002Fgithub.com\u002Fl1v0n1). PRs welcome!**\n\n## Star History\n\n[![Star History Chart](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_69d29c8427a8.png)](https:\u002F\u002Fwww.star-history.com\u002F#chigwell\u002Ftelegram-mcp&Date)\n\n## Contributors\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fgraphs\u002Fcontributors\">\n  \u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_b8195bacd7ed.png\" \u002F>\n\u003C\u002Fa>\n","\u003Cdiv align=\"center\">\n  \u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_98c571874352.png\" alt=\"Telegram MCP Server\" width=\"100%\" \u002F>\n\u003C\u002Fdiv>\n\n![MCP徽章](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_4ac9d1cb3d9e.png)\n[![许可证：Apache 2.0](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache%202.0-green?style=flat-square)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FApache-2.0)\n[![Python代码风格检查与格式化](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fpython-lint-format.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fpython-lint-format.yml)\n[![Docker构建与Compose验证](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fdocker-build.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Factions\u002Fworkflows\u002Fdocker-build.yml)\n\n---\n\n## 🤖 MCP实战\n\n以下是Claude中Telegram MCP功能的演示（参考[Anthropic文档](https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fagents-and-tools\u002Fmcp)）：\n\n **基本使用示例：**\n\n![Telegram MCP实战](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_801f95ac4c79.png)\n\n1. **示例：让Claude分析聊天记录并发送回复：**\n\n![Telegram MCP请求](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_1a9eb4986b8d.png)\n\n2. **成功向群组发送消息：**\n\n![Telegram MCP结果](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_fb142bc9cd2e.png)\n\n正如你所见，AI可以无缝地与你的Telegram账号交互，以自然的方式获取并展示你的聊天、消息及其他数据。\n\n---\n\n一个功能齐全的Telegram集成工具，适用于Claude、Cursor以及任何兼容MCP的客户端，由[Telethon](https:\u002F\u002Fdocs.telethon.dev\u002F)和[模型上下文协议(MCP)](https:\u002F\u002Fmodelcontextprotocol.io\u002F)提供支持。该项目使你能够以编程方式与Telegram账号互动，自动化从消息发送到群组管理的各项操作。\n\n\n---\n\n## 🚀 功能与工具\n\n该MCP服务器提供了庞大的Telegram工具集。**所有主要的Telegram\u002FTelethon功能都可作为工具使用！**\n\n### 聊天与群组管理\n- **get_chats(page, page_size)**：分页显示聊天列表\n- **list_chats(chat_type, limit)**：按元数据和筛选条件列出聊天\n- **get_chat(chat_id)**：获取聊天的详细信息\n- **create_group(title, user_ids)**：创建新群组\n- **invite_to_group(group_id, user_ids)**：邀请用户加入群组或频道\n- **create_channel(title, about, megagroup)**：创建频道或超级群组\n- **edit_chat_title(chat_id, title)**：更改聊天\u002F群组\u002F频道标题\n- **delete_chat_photo(chat_id)**：移除聊天\u002F群组\u002F频道头像\n- **leave_chat(chat_id)**：退出群组或频道\n- **get_participants(chat_id)**：列出所有参与者\n- **get_admins(chat_id)**：列出所有管理员\n- **get_banned_users(chat_id)**：列出所有被禁用的用户\n- **promote_admin(chat_id, user_id)**：将用户提升为管理员\n- **demote_admin(chat_id, user_id)**：将管理员降级为普通用户\n- **ban_user(chat_id, user_id)**：封禁用户\n- **unban_user(chat_id, user_id)**：解封用户\n- **get_invite_link(chat_id)**：获取邀请链接\n- **export_chat_invite(chat_id)**：导出邀请链接\n- **import_chat_invite(hash)**：通过邀请哈希加入聊天\n- **join_chat_by_link(link)**：通过邀请链接加入聊天\n- **subscribe_public_channel(channel)**：通过用户名或ID订阅公开频道或超级群组\n\n### 消息发送\n- **get_messages(chat_id, page, page_size)**：分页显示消息\n- **list_messages(chat_id, limit, search_query, from_date, to_date)**：筛选消息\n- **list_topics(chat_id, limit, offset_topic, search_query)**：列出超级群组中的论坛主题\n- **send_message(chat_id, message)**：发送消息\n- **reply_to_message(chat_id, message_id, text)**：回复消息\n- **edit_message(chat_id, message_id, new_text)**：编辑自己的消息\n- **delete_message(chat_id, message_id)**：删除消息\n- **forward_message(from_chat_id, message_id, to_chat_id)**：转发消息\n- **pin_message(chat_id, message_id)**：置顶消息\n- **unpin_message(chat_id, message_id)**：取消置顶\n- **mark_as_read(chat_id)**：标记全部消息为已读\n- **get_message_context(chat_id, message_id, context_size)**：获取消息周围的上下文\n- **get_history(chat_id, limit)**：获取完整的聊天记录\n- **get_pinned_messages(chat_id)**：列出所有置顶消息\n- **get_last_interaction(contact_id)**：获取与联系人的最新消息\n- **create_poll(chat_id, question, options, multiple_choice, quiz_mode, public_votes, close_date)**：创建投票\n- **list_inline_buttons(chat_id, message_id, limit)**：查看内联键盘以发现按钮文本\u002F索引\n- **press_inline_button(chat_id, message_id, button_text, button_index)**：通过标签或索引触发内联键盘回调\n- **send_reaction(chat_id, message_id, emoji, big=False)**：为消息添加反应\n- **remove_reaction(chat_id, message_id)**：移除消息上的反应\n- **get_message_reactions(chat_id, message_id, limit=50)**：获取消息的所有反应\n\n### 联系人管理\n- **list_contacts()**：列出所有联系人\n- **search_contacts(query)**：搜索联系人\n- **add_contact(phone, first_name, last_name)**：添加联系人\n- **delete_contact(user_id)**：删除联系人\n- **block_user(user_id)**：阻止用户\n- **unblock_user(user_id)**：解除阻止\n- **import_contacts(contacts)**：批量导入联系人\n- **export_contacts()**：将所有联系人导出为JSON文件\n- **get_blocked_users()**：列出被阻止的用户\n- **get_contact_ids()**：列出所有联系人ID\n- **get_direct_chat_by_contact(contact_query)**：查找与特定联系人的直接聊天\n- **get_contact_chats(contact_id)**：列出与特定联系人的所有聊天\n\n### 用户与个人资料\n- **get_me()**：获取你的用户信息\n- **update_profile(first_name, last_name, about)**：更新个人资料\n- **set_profile_photo(file_path)**：从允许的根目录设置头像\n- **delete_profile_photo()**：移除头像\n- **get_user_photos(user_id, limit)**：获取用户的个人资料照片\n- **get_user_status(user_id)**：获取用户的在线状态\n\n### 媒体\n- **get_media_info(chat_id, message_id)**：获取消息中媒体的相关信息\n- **send_file(chat_id, file_path, caption)**：从允许的根目录发送本地文件\n- **download_media(chat_id, message_id, file_path)**：将消息中的媒体保存到允许的根目录下\n- **upload_file(file_path)**：上传本地文件并返回上传元数据\n- **send_voice(chat_id, file_path)**：从允许的根目录发送`.ogg\u002F.opus`语音消息\n- **send_sticker(chat_id, file_path)**：从允许的根目录发送`.webp`贴纸\n- **edit_chat_photo(chat_id, file_path)**：从允许的根目录更新聊天头像\n\n### 搜索与发现\n- **search_public_chats(query, limit)**：搜索公开聊天\u002F频道\u002F机器人，结果数量可配置\n- **search_messages(chat_id, query, limit)**：在聊天中搜索消息\n- **search_global(query, page, page_size)**：全球范围内分页搜索消息\n- **resolve_username(username)**：将用户名解析为ID\n\n### 贴纸、GIF、机器人\n- **get_sticker_sets()**: 列出贴纸集\n- **get_bot_info(bot_username)**: 获取机器人信息\n- **set_bot_commands(bot_username, commands)**: 设置机器人命令（仅限机器人账号）\n\n### 隐私、设置及其他\n- **get_privacy_settings()**: 获取隐私设置\n- **set_privacy_settings(key, allow_users, disallow_users)**: 设置隐私设置\n- **mute_chat(chat_id)**: 静音通知\n- **unmute_chat(chat_id)**: 取消静音通知\n- **archive_chat(chat_id)**: 归档聊天\n- **unarchive_chat(chat_id)**: 取消归档聊天\n- **get_recent_actions(chat_id)**: 获取最近的管理员操作\n\n### 草稿\n- **save_draft(chat_id, message, reply_to_msg_id, no_webpage)**: 将草稿消息保存到聊天或频道\n- **get_drafts()**: 获取所有聊天中的所有草稿消息\n- **clear_draft(chat_id)**: 清除\u002F删除特定聊天中的草稿\n\n### 输入验证\n\n为提高健壮性，所有接受 `chat_id` 或 `user_id` 参数的函数现在都包含输入验证。您可以使用以下任意格式来提供这些 ID：\n\n- **整数 ID**：用户、聊天或频道的直接整数 ID（例如 `123456789` 或 `-1001234567890`）。\n- **字符串 ID**：以字符串形式提供的整数 ID（例如 `\"123456789\"`）。\n- **用户名**：用户或频道的公开用户名（例如 `\"@username\"` 或 `\"username\"`）。\n\n服务器会自动验证输入并将其转换为正确的格式，然后再向 Telegram 发送请求。如果输入无效，则会返回明确的错误信息。\n\n## 文件路径工具安全模型\n\n文件路径工具现已可用，但默认处于禁用状态，直到配置了允许的根目录。\n\n支持的文件路径工具：\n- `send_file`, `download_media`, `set_profile_photo`, `edit_chat_photo`, `send_voice`, `send_sticker`, `upload_file`\n\n安全语义（与 MCP 文件系统服务器一致）：\n- 服务器端白名单通过 CLI 位置参数实现（当 Roots API 不受支持时作为后备）。\n- 当客户端提供的 MCP Roots 可用时，将替换服务器端白名单。\n- 如果客户端返回空的 Roots 列表，则文件路径工具将被禁用（拒绝所有）。\n- 所有路径都会通过 realpath 解析，并且必须位于允许的根目录内。\n- 拒绝遍历或类似 glob 的模式（`..`、`*`、`?`、`~` 等）。\n- 相对路径会解析到第一个允许的根目录下。\n- 写入工具在未指定 `file_path` 时，默认会将文件保存到 `\u003Cfirst_root>\u002Fdownloads\u002F`。\n\n示例服务器启动命令，包含已列入白名单的根目录：\n```bash\nuv --directory \u002Ffull\u002Fpath\u002Fto\u002Ftelegram-mcp run main.py \u002Fdata\u002Ftelegram \u002Ftmp\u002Ftelegram-mcp\n```\n\n目前 GIF 工具功能有限：`get_gif_search` 和 `send_gif` 可用，而由于 Telethon\u002FTelegram API 交互的可靠性限制，`get_saved_gifs` 尚未实现。\n\n---\n\n## 📋 需求\n- Python 3.10+\n- [Telethon](https:\u002F\u002Fdocs.telethon.dev\u002F)\n- [MCP Python SDK](https:\u002F\u002Fmodelcontextprotocol.io\u002Fdocs\u002F)\n- [Claude Desktop](https:\u002F\u002Fclaude.ai\u002Fdesktop) 或 [Cursor](https:\u002F\u002Fcursor.so\u002F)（或任何 MCP 客户端）\n\n---\n\n## 🔧 安装与设置\n\n### 1. 分支并克隆\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp.git\ncd telegram-mcp\n```\n\n### 2. 使用 uv 安装依赖\n\n```bash\nuv sync\n```\n\n### 3. 生成会话字符串\n\n```bash\nuv run session_string_generator.py\n```\n按照提示进行身份验证，并更新你的 `.env` 文件。\n\n### 4. 配置 .env\n\n复制 `.env.example` 到 `.env`，并填写你的值：\n\n```\nTELEGRAM_API_ID=your_api_id_here\nTELEGRAM_API_HASH=your_api_hash_here\nTELEGRAM_SESSION_NAME=anon\nTELEGRAM_SESSION_STRING=your_session_string_here\n```\n你可以在 [my.telegram.org\u002Fapps](https:\u002F\u002Fmy.telegram.org\u002Fapps) 获取你的 API 凭证。\n\n---\n\n## 🐳 使用 Docker 运行\n\n如果你已安装 Docker 和 Docker Compose，你可以将服务器构建并运行在容器中，从而简化依赖管理。\n\n### 1. 构建镜像\n\n从项目根目录构建 Docker 镜像：\n\n```bash\ndocker build -t telegram-mcp:latest .\n```\n\n### 2. 运行容器\n\n你有两种选择：\n\n**选项 A：使用 Docker Compose（推荐用于本地使用）**\n\n此方法使用 `docker-compose.yml` 文件，并自动从 `.env` 文件中读取你的凭据。\n\n1.  **创建 `.env` 文件：** 确保项目根目录下有一个包含 `TELEGRAM_API_ID`、`TELEGRAM_API_HASH` 和 `TELEGRAM_SESSION_STRING`（或 `TELEGRAM_SESSION_NAME`）的 `.env` 文件。可以使用 `.env.example` 作为模板。\n2.  **运行 Compose：**\n    ```bash\n    docker compose up --build\n    ```\n    *   使用 `docker compose up -d` 以分离模式（后台）运行。\n    *   按 `Ctrl+C` 停止服务器。\n\n**选项 B：使用 `docker run`**\n\n你可以直接运行容器，将凭据作为环境变量传递。\n\n```bash\ndocker run -it --rm \\\n  -e TELEGRAM_API_ID=\"YOUR_API_ID\" \\\n  -e TELEGRAM_API_HASH=\"YOUR_API_HASH\" \\\n  -e TELEGRAM_SESSION_STRING=\"YOUR_SESSION_STRING\" \\\n  telegram-mcp:latest\n```\n*   将占位符替换为你的真实凭据。\n*   如果你更倾向于基于文件的会话，可以使用 `-e TELEGRAM_SESSION_NAME=your_session_file_name` 代替 `TELEGRAM_SESSION_STRING`（需要挂载卷，可参考 `docker-compose.yml` 中的示例）。\n*   `-it` 标志对于与服务器交互至关重要。\n\n---\n\n## ⚙️ Claude 和 Cursor 的配置\n\n### MCP 配置\n编辑你的 Claude 桌面配置文件（例如 `~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json`）或 Cursor 配置文件（`~\u002F.cursor\u002Fmcp.json`）：\n\n```json\n{\n  \"mcpServers\": {\n    \"telegram-mcp\": {\n      \"command\": \"uv\",\n      \"args\": [\n        \"--directory\",\n        \"\u002Ffull\u002Fpath\u002Fto\u002Ftelegram-mcp\",\n        \"run\",\n        \"main.py\"\n      ]\n    }\n  }\n}\n```\n\n## 📝 工具示例及代码与输出\n\n以下是几个最常用工具的示例，包括其实现和示例输出。\n\n### 获取你的聊天列表\n\n```python\n@mcp.tool()\nasync def get_chats(page: int = 1, page_size: int = 20) -> str:\n    \"\"\"\n    获取分页显示的聊天列表。\n    参数：\n        page: 页码（从 1 开始）。\n        page_size: 每页显示的聊天数量。\n    \"\"\"\n    try:\n        dialogs = await client.get_dialogs()\n        start = (page - 1) * page_size\n        end = start + page_size\n        if start >= len(dialogs):\n            return \"页码超出范围。\"\n        chats = dialogs[start:end]\n        lines = []\n        for dialog in chats:\n            entity = dialog.entity\n            chat_id = entity.id\n            title = getattr(entity, \"title\", None) or getattr(entity, \"first_name\", \"未知\")\n            lines.append(f\"聊天 ID: {chat_id}, 标题: {title}\")\n        return \"\\n\".join(lines)\n    except Exception as e:\n        logger.exception(f\"get_chats 失败（page={page}, page_size={page_size}）\")\n        return \"发生错误（代码：GETCHATS-ERR-001）。请查看 mcp_errors.log 以获取详细信息。\"\n```\n\n示例输出：\n```\n聊天 ID: 123456789, 标题: John Doe\n聊天 ID: -100987654321, 标题: 我的项目组\n聊天 ID: 111223344, 标题: Jane Smith\n聊天 ID: -200123456789, 标题: 新闻频道\n```\n\n### 发送消息\n\n```python\n@mcp.tool()\nasync def send_message(chat_id: int, message: str) -> str:\n    \"\"\"\n    向指定聊天发送消息。\n    参数：\n        chat_id：聊天的ID。\n        message：要发送的消息内容。\n    \"\"\"\n    try:\n        entity = await client.get_entity(chat_id)\n        await client.send_message(entity, message)\n        return \"消息发送成功。\"\n    except Exception as e:\n        logger.exception(f\"send_message 失败 (chat_id={chat_id})\")\n        return \"发生错误（代码：SENDMSG-ERR-001）。请查看 mcp_errors.log 以获取详细信息。\"\n```\n\n示例输出：\n```\n消息发送成功。\n```\n\n### 列出内联按钮\n\n```python\n@mcp.tool()\nasync def list_inline_buttons(\n    chat_id: Union[int, str],\n    message_id: Optional[int] = None,\n    limit: int = 20,\n) -> str:\n    \"\"\"\n    查看内联键盘布局，包括按钮索引、是否支持回调以及 URL。\n    \"\"\"\n```\n\n使用示例：\n```\nlist_inline_buttons(chat_id=\"@sample_tasks_bot\")\n```\n\n返回结果类似如下：\n```\n消息 42 的按钮（日期：2025-01-01 12:00:00+00:00）：\n[0] 文本='📋 查看任务'，支持回调\n[1] 文本='ℹ️ 帮助'，支持回调\n[2] 文本='🌐 访问网站'，不支持回调，URL=https:\u002F\u002Fexample.org\n```\n\n### 点击内联按钮\n\n```python\n@mcp.tool()\nasync def press_inline_button(\n    chat_id: Union[int, str],\n    message_id: Optional[int] = None,\n    button_text: Optional[str] = None,\n    button_index: Optional[int] = None,\n) -> str:\n    \"\"\"\n    根据按钮文本或零基索引点击内联键盘按钮。\n    如果未指定 message_id，服务器会搜索最近的消息以找到最新的内联键盘。\n    \"\"\"\n```\n\n使用示例：\n```\npress_inline_button(chat_id=\"@sample_tasks_bot\", button_text=\"📋 查看任务\")\n```\n\n如果需要查看可用按钮，可以先使用 `list_inline_buttons`——传入一个不存在的 `button_text` 即可快速列出选项，或者直接调用 `list_inline_buttons`。确定按钮文本或索引后，`press_inline_button` 将发送相应的回调，就像在原生 Telegram 客户端中点击按钮一样。\n\n### 订阅公开频道\n\n```python\n@mcp.tool()\nasync def subscribe_public_channel(channel: Union[int, str]) -> str:\n    \"\"\"\n    通过用户名（例如：“@examplechannel”）或 ID 加入公开频道或超级群组。\n    \"\"\"\n```\n\n使用示例：\n```\nsubscribe_public_channel(channel=\"@daily_updates_feed\")\n```\n\n如果账号已经是参与者，该工具会报告这一情况而不是失败，因此可以在需要幂等加入的工作流中反复运行而不会出现问题。\n\n### 获取聊天邀请链接\n\n`get_invite_link` 函数采用了多种备用方法，非常稳健：\n\n```python\n@mcp.tool()\nasync def get_invite_link(chat_id: int) -> str:\n    \"\"\"\n    获取群组或频道的邀请链接。\n    \"\"\"\n    try:\n        entity = await client.get_entity(chat_id)\n        \n        # 首先尝试使用 ExportChatInviteRequest\n        try:\n            from telethon.tl import functions\n            result = await client(functions.messages.ExportChatInviteRequest(\n                peer=entity\n            ))\n            return result.link\n        except AttributeError:\n            # 如果当前版本的 Telethon 中没有此函数\n            logger.warning(\"ExportChatInviteRequest 不可用，正在使用替代方法\")\n        except Exception as e1:\n            # 如果失败，则记录日志并尝试其他方法\n            logger.warning(f\"ExportChatInviteRequest 失败：{e1}\")\n            \n        # 替代方法：使用 client.export_chat_invite_link\n        try:\n            invite_link = await client.export_chat_invite_link(entity)\n            return invite_link\n        except Exception as e2:\n            logger.warning(f\"export_chat_invite_link 失败：{e2}\")\n            \n        # 最后手段：直接获取聊天信息\n        try:\n            if isinstance(entity, (Chat, Channel)):\n                full_chat = await client(functions.messages.GetFullChatRequest(\n                    chat_id=entity.id\n                ))\n                if hasattr(full_chat, 'full_chat') and hasattr(full_chat.full_chat, 'invite_link'):\n                    return full_chat.full_chat.invite_link or \"无邀请链接可用。\"\n        except Exception as e3:\n            logger.warning(f\"GetFullChatRequest 失败：{e3}\")\n            \n        return \"无法获取此聊天的邀请链接。\"\n    except Exception as e:\n        logger.exception(f\"get_invite_link 失败 (chat_id={chat_id})\")\n        return f\"获取邀请链接时出错：{e}\"\n```\n\n示例输出：\n```\nhttps:\u002F\u002Ft.me\u002F+AbCdEfGhIjKlMnOp\n```\n\n### 通过邀请链接加入聊天\n\n```python\n@mcp.tool()\nasync def join_chat_by_link(link: str) -> str:\n    \"\"\"\n    通过邀请链接加入聊天。\n    \"\"\"\n    try:\n        # 从邀请链接中提取哈希值\n        if '\u002F' in link:\n            hash_part = link.split('\u002F')[-1]\n            if hash_part.startswith('+'):\n                hash_part = hash_part[1:]  # 去掉开头的 '+'\n        else:\n            hash_part = link\n            \n        # 尝试在加入前检查邀请\n        try:\n            # 先尝试检查邀请信息（如果不是成员通常会失败）\n            invite_info = await client(functions.messages.CheckChatInviteRequest(hash=hash_part))\n            if hasattr(invite_info, 'chat') and invite_info.chat:\n                # 如果获取到聊天信息，说明已经是成员\n                chat_title = getattr(invite_info.chat, 'title', '未知聊天')\n                return f\"您已经是该聊天的成员：{chat_title}\"\n        except Exception:\n            # 如果不是成员，通常会失败，继续执行\n            pass\n            \n        # 使用哈希值加入聊天\n        result = await client(functions.messages.ImportChatInviteRequest(hash=hash_part))\n        if result and hasattr(result, 'chats') and result.chats:\n            chat_title = getattr(result.chats[0], 'title', '未知聊天')\n            return f\"成功加入聊天：{chat_title}\"\n        return f\"已通过邀请哈希值加入聊天。\"\n    except Exception as e:\n        err_str = str(e).lower()\n        if \"expired\" in err_str:\n            return \"该邀请哈希值已过期，不再有效。\"\n        elif \"invalid\" in err_str:\n            return \"该邀请哈希值无效或格式错误。\"\n        elif \"already\" in err_str and \"participant\" in err_str:\n            return \"您已经是该聊天的成员。\"\n        logger.exception(f\"join_chat_by_link 失败 (link={link})\")\n        return f\"加入聊天时出错：{e}\"\n```\n\n示例输出：\n```\n成功加入聊天：开发者社区\n```\n\n### 搜索公开聊天\n\n```python\n@mcp.tool()\nasync def search_public_chats(query: str, limit: int = 20) -> str:\n    \"\"\"\n    根据用户名或标题搜索公开聊天、频道或机器人。\n    \"\"\"\n    try:\n        result = await client(functions.contacts.SearchRequest(q=query, limit=limit))\n        entities = [format_entity(e) for e in result.chats + result.users]\n        return json.dumps(entities, indent=2)\n    except Exception as e:\n        return f\"搜索公开聊天时出错：{e}\"\n```\n\n示例输出：\n```json\n[\n  {\n    \"id\": 123456789,\n    \"name\": \"TelegramBot\",\n    \"type\": \"user\",\n    \"username\": \"telegram_bot\"\n  },\n  {\n    \"id\": 987654321,\n    \"name\": \"Telegram News\",\n    \"type\": \"user\",\n    \"username\": \"telegram_news\"\n  }\n]\n```\n\n### 获取与联系人的直接聊天\n\n```python\n@mcp.tool()\nasync def get_direct_chat_by_contact(contact_query: str) -> str:\n    \"\"\"\n    通过姓名、用户名或电话号码查找与特定联系人的直接聊天。\n\n    参数：\n        contact_query：用于搜索的姓名、用户名或电话号码。\n    \"\"\"\n    try:\n        # 使用正确的 Telethon 方法获取所有联系人\n        result = await client(functions.contacts.GetContactsRequest(hash=0))\n        contacts = result.users\n        found_contacts = []\n        for contact in contacts:\n            if not contact:\n                continue\n            name = f\"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}\".strip()\n            username = getattr(contact, 'username', '')\n            phone = getattr(contact, 'phone', '')\n            if (contact_query.lower() in name.lower() or \n                (username and contact_query.lower() in username.lower()) or \n                (phone and contact_query in phone)):\n                found_contacts.append(contact)\n        if not found_contacts:\n            return f\"未找到匹配 '{contact_query}' 的联系人。\"\n        # 如果找到了联系人，则查找与他们的直接聊天\n        results = []\n        dialogs = await client.get_dialogs()\n        for contact in found_contacts:\n            contact_name = f\"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}\".strip()\n            for dialog in dialogs:\n                if isinstance(dialog.entity, User) and dialog.entity.id == contact.id:\n                    chat_info = f\"聊天ID：{dialog.entity.id}, 联系人：{contact_name}\"\n                    if getattr(contact, 'username', ''):\n                        chat_info += f\", 用户名：@{contact.username}\"\n                    if dialog.unread_count:\n                        chat_info += f\", 未读消息：{dialog.unread_count}\"\n                    results.append(chat_info)\n                    break\n        \n        if not results:\n            return f\"找到了匹配 '{contact_query}' 的联系人，但没有与他们相关的直接聊天。\"\n        \n        return \"\\n\".join(results)\n    except Exception as e:\n        return f\"搜索直接聊天时出错：{e}\"\n```\n\n示例输出：\n```\n聊天ID：123456789，联系人：John Smith，用户名：@johnsmith，未读消息：3条\n```\n\n---\n\n## 🎮 使用示例\n\n- “显示我最近的聊天”\n- “向聊天 123456789 发送‘Hello world’”\n- “添加电话为 +1234567890、姓名为 John Doe 的联系人”\n- “创建一个名为‘Project Team’的群组，成员为 111、222、333”\n- “下载聊天 123456789 中第 42 条消息的媒体文件”\n- “静音聊天 123456789 的通知”\n- “将用户 111 提升为聊天 123456789 的管理员”\n- “搜索关于‘新闻’的公开频道”\n- “加入邀请链接为 https:\u002F\u002Ft.me\u002F+AbCdEfGhIjK 的 Telegram 群组”\n- “向我的收藏消息发送贴纸”\n- “获取我所有的贴纸包”\n\n您可以通过自然语言在 Claude、Cursor 或任何兼容 MCP 的客户端中使用这些工具。\n\n---\n\n## 🧠 错误处理与鲁棒性\n\n本实现包含全面的错误处理机制：\n\n- **会话管理**：支持基于文件和基于字符串的会话\n- **错误报告**：详细的错误日志记录到 `mcp_errors.log`\n- **优雅降级**：关键功能提供多种回退方案\n- **用户友好提示**：提供清晰且可操作的错误信息，而非技术性报错\n- **账号类型检测**：要求机器人账号的功能会在用户账号下使用时发出警告并提示\n- **邀请链接处理**：能够处理各种格式的链接以及用户已加入的情况\n\n代码设计旨在应对常见的 Telegram API 问题及限制，具有较高的鲁棒性。\n\n---\n\n## 🛠️ 贡献指南\n\n1. **Fork 此仓库**：[chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp)\n2. **克隆您的分支**：\n   ```bash\n   git clone https:\u002F\u002Fgithub.com\u002F\u003Cyour-github-username>\u002Ftelegram-mcp.git\n   ```\n3. **创建新分支**：\n   ```bash\n   git checkout -b my-feature\n   ```\n4. **进行更改，并根据需要添加测试或文档。**\n5. **推送并打开 Pull Request** 至 [chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp)，并附上清晰的描述。\n6. **在 PR 中标记 @chigwell 或 @l1v0n1** 以供审核。\n\n---\n\n## 🔒 安全注意事项\n- **切勿提交您的 `.env` 文件或会话字符串。**\n- 会话字符串赋予对您 Telegram 账号的完全访问权限，请务必妥善保管！\n- 所有处理均在本地进行；除 Telegram API 外，不会将任何数据发送至其他地方。\n- 请使用 `.env.example` 作为模板，并确保您的实际 `.env` 文件保持私密。\n- 测试文件已在 `.gitignore` 中自动排除。\n\n---\n\n## 🛠️ 故障排除\n- **检查日志**：在您的 MCP 客户端（Claude\u002FCursor）和终端中查看错误信息。\n- **详细错误日志**可在 `mcp_errors.log` 中找到。\n- **解释器错误？** 确保已创建并激活了 `.venv` 环境。\n- **数据库锁定？** 请使用会话字符串认证，而非基于文件的会话。\n- **iCloud\u002FDropbox 问题？** 如果遇到奇怪的错误，请将项目移动到不含空格的本地路径。\n- **更换 Telegram 密码或出现认证错误时**，请重新生成会话字符串。\n- **仅限机器人使用的功能** 在普通用户账号下使用时会显示明确的提示信息。\n- **测试脚本失败？** 请检查 `.env` 文件中的测试配置，确保测试账号和群组有效。\n\n---\n\n## 📄 许可证\n\n本项目采用 [Apache 2.0 许可证](LICENSE)。\n\n---\n\n## 🙏 致谢\n- [Telethon](https:\u002F\u002Fgithub.com\u002FLonamiWebs\u002FTelethon)\n- [Model Context Protocol](https:\u002F\u002Fmodelcontextprotocol.io\u002F)\n- [Claude](https:\u002F\u002Fwww.anthropic.com\u002F) 和 [Cursor](https:\u002F\u002Fcursor.so\u002F)\n- [chigwell\u002Ftelegram-mcp](https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp)（上游）\n\n---\n\n**由 [@chigwell](https:\u002F\u002Fgithub.com\u002Fchigwell) 和 [@l1v0n1](https:\u002F\u002Fgithub.com\u002Fl1v0n1) 维护。欢迎提交 PR！**\n\n## 星标历史\n\n[![星标历史图](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_69d29c8427a8.png)](https:\u002F\u002Fwww.star-history.com\u002F#chigwell\u002Ftelegram-mcp&Date)\n\n## 贡献者\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fgraphs\u002Fcontributors\">\n  \u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_readme_b8195bacd7ed.png\" \u002F>\n\u003C\u002Fa>","# Telegram MCP 快速上手指南\n\nTelegram MCP 是一个基于 Model Context Protocol (MCP) 的服务器，允许 Claude、Cursor 等 AI 客户端直接通过自然语言操作你的 Telegram 账号（发送消息、管理群组、读取历史纪录等）。\n\n## 环境准备\n\n在开始之前，请确保你的开发环境满足以下要求：\n\n*   **操作系统**: Linux, macOS 或 Windows (WSL2 推荐)\n*   **Python 版本**: Python 3.10 或更高版本\n*   **包管理器**: 推荐使用 [`uv`](https:\u002F\u002Fgithub.com\u002Fastral-sh\u002Fuv) (极速 Python 包安装器)，也可使用 pip\n*   **AI 客户端**: 已安装支持 MCP 的客户端，如 [Claude Desktop](https:\u002F\u002Fclaude.ai\u002Fdesktop) 或 [Cursor](https:\u002F\u002Fcursor.so\u002F)\n*   **Telegram 账号**: 有效的手机号及接收验证码的能力\n\n> **国内开发者提示**：由于网络环境限制，连接 Telegram API 可能需要配置代理。请在运行前确保终端环境变量已设置好代理（如 `export https_proxy=http:\u002F\u002F127.0.0.1:7890`），或在代码中配置 Telethon 的代理参数。\n\n## 安装步骤\n\n### 1. 克隆项目\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp.git\ncd telegram-mcp\n```\n\n### 2. 安装依赖\n\n推荐使用 `uv` 进行依赖管理和环境同步：\n\n```bash\nuv sync\n```\n\n*(如果使用 pip: `pip install -r requirements.txt`)*\n\n### 3. 获取 Telegram API 凭证\n\n1. 访问 [my.telegram.org\u002Fapps](https:\u002F\u002Fmy.telegram.org\u002Fapps) 并登录。\n2. 创建一个新的 Application。\n3. 记录下 `API ID` 和 `API Hash`。\n\n### 4. 生成会话字符串 (Session String)\n\n运行官方提供的脚本进行身份验证，这将生成一个会话字符串，避免每次启动都需输入验证码：\n\n```bash\nuv run session_string_generator.py\n```\n\n按照终端提示输入手机号和收到的验证码。成功后，脚本会自动更新 `.env` 文件或输出会话字符串。\n\n### 5. 配置环境变量\n\n复制示例配置文件并填入你的凭证：\n\n```bash\ncp .env.example .env\n```\n\n编辑 `.env` 文件，填入以下内容：\n\n```ini\nTELEGRAM_API_ID=你的 API_ID\nTELEGRAM_API_HASH=你的 API_Hash\nTELEGRAM_SESSION_NAME=anon\nTELEGRAM_SESSION_STRING=上一步生成的会话字符串\n```\n\n## 基本使用\n\n### 方式一：直接运行服务器\n\n在终端中启动 MCP 服务器：\n\n```bash\nuv run main.py\n```\n\n此时服务器将在标准输出运行，等待 MCP 客户端连接。\n\n### 方式二：在 Claude Desktop 中集成\n\n1. 打开 Claude Desktop 的配置文件 (`claude_desktop_config.json`)。\n   *   **macOS**: `~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json`\n   *   **Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n2. 添加 `telegram-mcp` 配置项：\n\n```json\n{\n  \"mcpServers\": {\n    \"telegram\": {\n      \"command\": \"uv\",\n      \"args\": [\"--directory\", \"\u002F绝对路径\u002F到\u002Ftelegram-mcp\", \"run\", \"main.py\"],\n      \"env\": {\n        \"TELEGRAM_API_ID\": \"你的 API_ID\",\n        \"TELEGRAM_API_HASH\": \"你的 API_Hash\",\n        \"TELEGRAM_SESSION_STRING\": \"你的会话字符串\"\n      }\n    }\n  }\n}\n```\n*注意：请将 `\u002F绝对路径\u002F到\u002Ftelegram-mcp` 替换为你本地的实际项目路径。*\n\n3. 重启 Claude Desktop。\n\n### 使用示例\n\n连接成功后，你可以在对话框中直接使用自然语言指令，例如：\n\n*   **读取消息**: \"帮我列出最近 'Python 交流群' 里的 10 条消息。\"\n*   **发送消息**: \"给 @username 发送一条消息：'你好，这是测试内容'。\"\n*   **管理群组**: \"查看我管理的群组列表，并把用户 @bad_user 从 '测试组' 中移除。\"\n*   **搜索内容**: \"在所有聊天中搜索包含 '会议记录' 的消息。\"\n\n> **安全提示**: 涉及文件读写（如发送图片、下载媒体）的功能默认是禁用的，需要在启动命令中显式指定允许的根目录路径（allowed roots）才能使用。","某开源项目维护者每天需处理数百条来自全球开发者的 Telegram 社群反馈，并同步整理至项目看板。\n\n### 没有 telegram-mcp 时\n- **信息检索低效**：维护者必须手动在 Telegram 桌面端或手机端翻找历史消息，难以通过自然语言（如“上周关于 API 超时的报错”）快速定位关键讨论。\n- **响应流程割裂**：回复用户、置顶重要公告或移除广告机器人需要在不同界面间切换，无法在编写代码或查看文档的同一工作流中完成操作。\n- **社群管理滞后**：面对突发的大量垃圾信息或违规用户，无法即时批量执行禁言或踢出操作，依赖人工逐个点击，响应速度慢且易遗漏。\n- **数据沉淀困难**：有价值的技术讨论散落在聊天记录中，缺乏自动化手段将其提取并结构化存储到知识库或任务管理系统中。\n\n### 使用 telegram-mcp 后\n- **智能对话检索**：直接在 Claude 或 Cursor 中输入指令，telegram-mcp 即可自动筛选并总结特定时间段、关键词相关的聊天记录，瞬间呈现上下文。\n- **工作流无缝集成**：开发者在阅读代码的同时，可命令 AI 直接调用 `send_message` 回复用户、`pin_message` 置顶修复公告，实现“对话即操作”。\n- **自动化社群治理**：结合 AI 判断，自动调用 `ban_user` 或 `delete_message` 清理违规内容，甚至根据预设规则自动提升活跃贡献者为管理员 (`promote_admin`)。\n- **知识自动归档**：利用 `list_messages` 提取高质量讨论，由 AI 自动摘要并生成 Markdown 文档，一键同步至项目 Wiki 或 Issue 追踪系统。\n\ntelegram-mcp 将原本割裂的社群运营动作转化为自然的语言指令，让开发者能在编码环境中一站式完成从信息获取到社群治理的全闭环。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fchigwell_telegram-mcp_341b42ff.png","chigwell","Eugene Evstafev","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002Fchigwell_b71f8754.jpg","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Feugene-evstafev-716669181\u002F","University of Cambridge","UK, Peterborough",null,"https:\u002F\u002Feugene.plus\u002F","https:\u002F\u002Fgithub.com\u002Fchigwell",[83,87],{"name":84,"color":85,"percentage":86},"Python","#3572A5",99.1,{"name":88,"color":89,"percentage":90},"Dockerfile","#384d54",0.9,957,241,"2026-04-17T15:07:37","Apache-2.0","Linux, macOS, Windows","未说明",{"notes":98,"python":99,"dependencies":100},"该工具是一个 Telegram MCP 服务器，用于与 Claude、Cursor 等客户端集成。运行前需在 my.telegram.org 获取 API ID 和 Hash，并生成会话字符串 (Session String)。文件路径操作功能默认禁用，需配置允许根目录方可使用。支持通过 Docker 或本地 uv 环境运行。","3.10+",[101,102,103],"Telethon","MCP Python SDK","uv",[105,16,14,45,35],"其他",[107,108,109,110,111,112,113,114,115,116,117,118,119],"admin","api","chat-management","contacts","groups","mcp","media","messaging","search","telegram","telegram-api","telegram-client","telethon","2026-03-27T02:49:30.150509","2026-04-18T09:20:10.191650",[123,128,133,138,143,147],{"id":124,"question_zh":125,"answer_zh":126,"source_url":127},38917,"如何处理 `offset_date` 在正向和反向遍历消息时的不同行为？","`offset_date` 在不加 `reverse` 时用于获取该日期之前的消息（不包含该日期）；当设置 `reverse=True` 时，它作为起始点向后（时间增加方向）遍历。若要获取特定日期范围内的消息：仅设置 `to_date` 时，可将 `offset_date` 设为 `to_date + 1 微秒` 并反向迭代；仅设置 `from_date` 时，设 `offset_date=from_date` 并开启 `reverse=True`。注意时间戳应统一使用 UTC 格式。","https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fissues\u002F27",{"id":129,"question_zh":130,"answer_zh":131,"source_url":132},38913,"为什么连接应用会导致所有客户端（包括手机）被登出？","这通常是因为会话字符串（TELEGRAM_SESSION_STRING）在不同的服务器或 IP 地址之间移动导致的。解决方法是：在最终运行 MCP 服务器的同一台机器上，运行 `uv run session_string_generator.py` 来生成会话字符串，不要将其复制到其他环境。此外，尝试修改 `device_model`、`system_version` 和 `app_version` 的值也可能解决因设备指纹不匹配导致的认证问题。","https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fissues\u002F20",{"id":134,"question_zh":135,"answer_zh":136,"source_url":137},38914,"启动服务器时出现 'ImportError: cannot import name ToolAnnotations from mcp.types' 错误怎么办？","这是因为 `uv.lock` 文件锁定的 `mcp` 包版本（1.6.0）过旧，不包含 `ToolAnnotations` 类型。请更新依赖以获取包含该类型的最新版本 `mcp` 包。通常运行更新命令（如 `uv sync --upgrade` 或手动更新 lock 文件）即可解决此导入错误。","https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fissues\u002F36",{"id":139,"question_zh":140,"answer_zh":141,"source_url":142},38915,"如何安全地恢复需要文件系统访问的工具（如发送文件、下载媒体）？","可以通过配置允许列表（allowlist）来恢复这些工具，默认情况下应处于禁用状态以确保安全。支持两种方式：1) 命令行参数指定静态允许目录；2) 使用 MCP Roots 动态更新允许目录（推荐）。对于写入操作（如下载），若未指定路径，默认保存到第一个根目录下的专用文件夹（如 `\u003Croot>\u002Fdownloads\u002F`）。系统会强制执行路径解析检查，拒绝路径遍历（..）和通配符模式。","https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fissues\u002F39",{"id":144,"question_zh":145,"answer_zh":146,"source_url":127},38916,"在使用 Telethon 进行消息搜索和日期过滤时，为什么结果数量不符合预期或出现遗漏？","Telethon 的 `offset_date` 是分页锚点而非直接的服务器端过滤器。当结合 `search` 使用时，Telegram API 可能不会可靠地遵守 `offset_date`。最佳实践是：1) 仅按日期范围查询时，使用 `iter_messages(offset_date=from_date, reverse=True)` 并在客户端判断 `to_date` 停止；2) 同时使用搜索和日期时，不要在 `iter_messages` 中传入 `offset_date`，而是先获取搜索结果，然后在客户端代码中根据 `from_date` 和 `to_date` 进行过滤，并在满足数量限制后提前停止。",{"id":148,"question_zh":149,"answer_zh":150,"source_url":132},38918,"如果修改设备模型等参数仍无法解决登录被踢出的问题，具体应该设置什么值？","虽然没有固定的“正确”值，但关键是确保 `device_model`、`system_version` 和 `app_version` 的组合看起来像一个真实的、一致的客户端环境，且最好与生成会话字符串时的环境保持一致。随机更改有时无效，建议参考其他正常工作的 Telegram 客户端配置，或者严格遵循“在同一台机器生成并使用会话字符串”的原则，避免频繁切换设备指纹。",[152,157,162,167,172,177,182,187,192,197,202,207,212,217,222,227,232,237,242,247],{"id":153,"version":154,"summary_zh":155,"released_at":156},314841,"v2.0.41","## 变更内容\n* 修复：增强 `ensure_connected()` 的健壮性——通过 `ping` 进行验证，并在 TCP 连接失效时强制重新连接，由 @amprotopopov-a11y 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F98 中实现。\n\n## 新贡献者\n* @amprotopopov-a11y 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F98 中完成了首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.40...v2.0.41","2026-04-12T13:49:44",{"id":158,"version":159,"summary_zh":160,"released_at":161},314842,"v2.0.40","## 变更内容\n* 功能（工具）：新增 `send_contact` 工具，可通过 Telegram 发送手机联系人，由 @bunkerskyi 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F97 中实现。\n\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.39...v2.0.40","2026-04-09T08:33:55",{"id":163,"version":164,"summary_zh":165,"released_at":166},314843,"v2.0.39","## 变更内容\n* 修复（工具）：当机器人消息的 buttons 属性为 None 时，回退到 reply_markup，由 @bunkerskyi 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F95 中提出并实现。\n\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.38...v2.0.39","2026-04-09T08:31:31",{"id":168,"version":169,"summary_zh":170,"released_at":171},314844,"v2.0.38","## 变更内容\n* 修复（工具）：在 `get_messages` 输出中转义换行符，以保留基于行的格式，由 @bunkerskyi 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F96 中完成。\n\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.37...v2.0.38","2026-04-09T08:29:29",{"id":173,"version":174,"summary_zh":175,"released_at":176},314845,"v2.0.37","## 变更内容\n* 修复：在退出时优雅地断开 Telegram 客户端连接，由 @DzmingLi 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F94 中实现\n\n## 新贡献者\n* @DzmingLi 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F94 中完成了首次贡献\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.36...v2.0.37","2026-04-06T09:05:02",{"id":178,"version":179,"summary_zh":180,"released_at":181},314846,"v2.0.36","## 变更内容\n* 修复：在 `download_media` 中移除文件扩展名，以便自动检测真实文件类型，由 @jonasasx 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F86 中完成。\n\n## 新贡献者\n* @jonasasx 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F86 中完成了他们的首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.35...v2.0.36","2026-04-01T11:12:41",{"id":183,"version":184,"summary_zh":185,"released_at":186},314847,"v2.0.35","## 变更内容\n* 功能：在 `list_chats` 输出中显示未读提及数量，由 @dsvetlov 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F84 中实现。\n\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.34...v2.0.35","2026-03-31T15:36:50",{"id":188,"version":189,"summary_zh":190,"released_at":191},314848,"v2.0.34","## 变更内容\n* 功能：添加 `unread_only` 和 `unmuted_only` 筛选器以及静音状态到 `list_chats` 接口中，由 @dsvetlov 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F78 中实现。\n\n## 新贡献者\n* @dsvetlov 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F78 中完成了首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.33...v2.0.34","2026-03-31T15:28:36",{"id":193,"version":194,"summary_zh":195,"released_at":196},314849,"v2.0.33","## 变更内容\n* 文档：在 README 中添加“贡献者”章节，由 @chigwell 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F80 中完成。\n\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.32...v2.0.33","2026-03-27T17:20:43",{"id":198,"version":199,"summary_zh":200,"released_at":201},314850,"v2.0.32","## 变更内容\n* 在公开聊天搜索中添加 `limit` 参数，由 @mxl 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F75 中实现。\n* 添加全局消息搜索功能，由 @mxl 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F74 中实现。\n* 修复：解决使用 StringSession 的用户出现的实体缓存缺失问题，由 @nathanschram 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F77 中修复。\n\n## 新贡献者\n* @nathanschram 在 https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F77 中完成了首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.31...v2.0.32","2026-03-18T08:49:57",{"id":203,"version":204,"summary_zh":205,"released_at":206},314851,"v2.0.31","## What's Changed\r\n* fix: add support for shared folders (DialogFilterChatlist) in folder operations by @mxl in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F72\r\n* fix: include chats and channels in search_public_chats results by @mxl in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F73\r\n\r\n## New Contributors\r\n* @mxl made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F72\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.30...v2.0.31","2026-03-16T08:28:33",{"id":208,"version":209,"summary_zh":210,"released_at":211},314852,"v2.0.30","## What's Changed\r\n* Implement login via QR-code in session_string_generator; bump Telethon to 1.42.0 by @oplexz in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F69\r\n\r\n## New Contributors\r\n* @oplexz made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F69\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.29...v2.0.30","2026-03-05T08:15:40",{"id":213,"version":214,"summary_zh":215,"released_at":216},314853,"v2.0.29","## What's Changed\r\n* fix: redirect all print() to stderr to keep stdout clean for MCP stdio by @onsails in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F70\r\n\r\n## New Contributors\r\n* @onsails made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F70\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.28...v2.0.29","2026-03-04T19:48:05",{"id":218,"version":219,"summary_zh":220,"released_at":221},314854,"v2.0.28","## What's Changed\r\n* fix(delete_profile_photo): pass Photo object instead of int to DeletePhotosRequest by @bunkerskyi in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F67\r\n\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.27...v2.0.28","2026-02-26T09:19:06",{"id":223,"version":224,"summary_zh":225,"released_at":226},314855,"v2.0.27","## What's Changed\r\n* feat(tools): expose parse_mode in send_message and reply_to_message by @bunkerskyi in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F68\r\n\r\n## New Contributors\r\n* @bunkerskyi made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F68\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.26...v2.0.27","2026-02-26T08:54:50",{"id":228,"version":229,"summary_zh":230,"released_at":231},314856,"v2.0.26","## What's Changed\r\n* feat: secure file-path tools with allowlisted roots (issue #39) by @iqdoctor in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F64\r\n\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.25...v2.0.26","2026-02-25T08:06:27",{"id":233,"version":234,"summary_zh":235,"released_at":236},314857,"v2.0.25","## What's Changed\r\n* Fix supergroup type in get_folder and unify chat type mapping by @yarreg in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F62\r\n\r\n## New Contributors\r\n* @yarreg made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F62\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.24...v2.0.25","2026-02-12T13:20:23",{"id":238,"version":239,"summary_zh":240,"released_at":241},314858,"v2.0.24","## What's Changed\r\n* feat: Add support for adding contacts by username without phone number by @artgas1 in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F57\r\n\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.23...v2.0.24","2026-02-12T12:23:34",{"id":243,"version":244,"summary_zh":245,"released_at":246},314859,"v2.0.23","## What's Changed\r\n* fix: use correct Telegram API for archive\u002Funarchive chat by @artgas1 in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F60\r\n\r\n## New Contributors\r\n* @artgas1 made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F60\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.22...v2.0.23","2026-02-09T10:09:48",{"id":248,"version":249,"summary_zh":250,"released_at":251},314860,"v2.0.22","## What's Changed\r\n* feat(folders): add 7 tools for Telegram folder management by @smixs in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F53\r\n\r\n## New Contributors\r\n* @smixs made their first contribution in https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fpull\u002F53\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fchigwell\u002Ftelegram-mcp\u002Fcompare\u002Fv2.0.21...v2.0.22","2026-01-27T10:06:52"]