Telegram MCP 桥接器
一个服务器,它通过与MCP兼容的主机(如桌面版的克劳德)直接启用与Telegram聊天的交互,提供检索聊天记录、获取消息和发送消息的工具。
服务介绍
Telegram MCP 服务器
🤖 MCP 实际应用
这里是 Claude 中的 Telegram MCP 功能演示:
基本使用示例:

- 示例:要求 Claude 分析聊天记录并发送回复:

- 成功向群组发送消息:

如您所见,AI 可以无缝地与您的 Telegram 账号互动,以自然的方式检索和显示您的聊天、消息和其他数据。
这是一个为 Claude、Cursor 和任何兼容 MCP 的客户端提供的功能齐全的 Telegram 集成,由 Telethon 和 模型上下文协议 (MCP) 提供支持。该项目允许您以编程方式与您的 Telegram 账号进行交互,自动化从消息传递到群组管理的所有内容。
🚀 功能与工具
此 MCP 服务器提供了大量的 Telegram 工具。每个主要的 Telegram/Telethon 功能都作为工具提供!
聊天与群组管理
- get_chats(page, page_size): 分页列出聊天
- list_chats(chat_type, limit): 列出带有元数据和过滤条件的聊天
- get_chat(chat_id): 获取关于某个聊天的详细信息
- create_group(title, user_ids): 创建一个新的群组
- create_channel(title, about, megagroup): 创建频道或超级群组
- edit_chat_title(chat_id, title): 更改聊天/群组/频道标题
- edit_chat_photo(chat_id, file_path): 设置聊天/群组/频道照片
- delete_chat_photo(chat_id): 移除聊天/群组/频道照片
- leave_chat(chat_id): 退出群组或频道
- get_participants(chat_id): 列出所有参与者
- get_admins(chat_id): 列出所有管理员
- get_banned_users(chat_id): 列出所有被封禁的用户
- promote_admin(chat_id, user_id): 将用户提升为管理员
- demote_admin(chat_id, user_id): 将管理员降级为普通用户
- ban_user(chat_id, user_id): 封禁用户
- unban_user(chat_id, user_id): 解封用户
- get_invite_link(chat_id): 获取邀请链接
- export_chat_invite(chat_id): 导出邀请链接
- import_chat_invite(hash): 通过邀请哈希加入聊天
- join_chat_by_link(link): 通过邀请链接加入聊天
消息处理
- get_messages(chat_id, page, page_size): 分页消息
- list_messages(chat_id, limit, search_query, from_date, to_date): 过滤后的消息
- send_message(chat_id, message): 发送消息
- reply_to_message(chat_id, message_id, text): 回复消息
- edit_message(chat_id, message_id, new_text): 编辑消息
- delete_message(chat_id, message_id): 删除消息
- forward_message(from_chat_id, message_id, to_chat_id): 转发消息
- pin_message(chat_id, message_id): 置顶消息
- unpin_message(chat_id, message_id): 取消置顶消息
- mark_as_read(chat_id): 标记全部已读
- get_message_context(chat_id, message_id, context_size): 消息上下文
- get_history(chat_id, limit): 完整聊天记录
- get_pinned_messages(chat_id): 列出所有置顶消息
联系人管理
- list_contacts(): 列出所有联系人
- search_contacts(query): 搜索联系人
- add_contact(phone, first_name, last_name): 添加联系人
- delete_contact(user_id): 删除联系人
- block_user(user_id): 封锁用户
- unblock_user(user_id): 解封用户
- import_contacts(contacts): 批量导入联系人
- export_contacts(): 导出所有联系人为 JSON
- get_blocked_users(): 列出被封锁的用户
- get_contact_ids(): 列出所有联系人 ID
- get_direct_chat_by_contact(contact_query): 通过联系人查找直接对话
- get_contact_chats(contact_id): 列出与该联系人的所有对话
- get_last_interaction(contact_id): 与联系人的最近一条消息
用户与个人资料
- get_me(): 获取您的用户信息
- update_profile(first_name, last_name, about): 更新您的个人资料
- set_profile_photo(file_path): 设置个人头像
- delete_profile_photo(): 移除个人头像
- get_user_photos(user_id, limit): 获取用户的个人头像
- get_user_status(user_id): 获取用户的在线状态
媒体
- send_file(chat_id, file_path, caption): 发送文件
- send_voice(chat_id, file_path): 发送语音消息
- download_media(chat_id, message_id, file_path): 下载媒体文件
- upload_file(file_path): 上传文件到 Telegram 服务器
- get_media_info(chat_id, message_id): 获取消息中的媒体信息
搜索与发现
- search_public_chats(query): 搜索公开的聊天/频道/机器人
- search_messages(chat_id, query, limit): 在聊天中搜索消息
- resolve_username(username): 通过用户名解析为 ID
表情包、GIF 和机器人
- get_sticker_sets(): 列出表情包集合
- send_sticker(chat_id, file_path): 发送表情包
- get_gif_search(query, limit): 搜索 GIF
- send_gif(chat_id, gif_id): 发送 GIF
- get_bot_info(bot_username): 获取关于机器人的信息
- set_bot_commands(bot_username, commands): 设置机器人命令(仅限机器人账户)
隐私、设置及其他
- get_privacy_settings(): 获取隐私设置
- set_privacy_settings(key, allow_users, disallow_users): 设置隐私设置
- mute_chat(chat_id): 静音通知
- unmute_chat(chat_id): 取消静音通知
- archive_chat(chat_id): 归档聊天
- unarchive_chat(chat_id): 取消归档聊天
- get_recent_actions(chat_id): 获取最近的管理员操作
📋 要求
- Python 3.10+
- Telethon
- MCP Python SDK
- Claude Desktop 或 Cursor(或任何 MCP 客户端)
🔧 安装与设置
1. Fork & 克隆
git clone https://github.com/chigwell/telegram-mcp.git
cd telegram-mcp
2. 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
3. 生成会话字符串
python3 session_string_generator.py
按照提示进行身份验证并更新您的 .env 文件。
4. 配置 .env
将 .env.example 复制为 .env 并填写您的值:
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
在 my.telegram.org/apps 获取您的 API 凭证。
⚙️ Claude 和 Cursor 的配置
MCP 配置
编辑您的 Claude 桌面配置(例如 ~/Library/Application Support/Claude/claude_desktop_config.json)或 Cursor 配置(~/.cursor/mcp.json):
{
"mcpServers": {
"telegram-mcp": {
"command": "uv",
"args": [
"--directory",
"/full/path/to/telegram-mcp-server",
"run",
"main.py"
]
}
}
}
📝 工具示例及代码和输出
以下是使用最常用的工具及其实现和示例输出。
获取您的聊天
@mcp.tool()
async def get_chats(page: int = 1, page_size: int = 20) -> str:
"""
Get a paginated list of chats.
Args:
page: Page number (1-indexed).
page_size: Number of chats per page.
"""
try:
dialogs = await client.get_dialogs()
start = (page - 1) * page_size
end = start + page_size
if start >= len(dialogs):
return "Page out of range."
chats = dialogs[start:end]
lines = []
for dialog in chats:
entity = dialog.entity
chat_id = entity.id
title = getattr(entity, "title", None) or getattr(entity, "first_name", "Unknown")
lines.append(f"Chat ID: {chat_id}, Title: {title}")
return "\n".join(lines)
except Exception as e:
logger.exception(f"get_chats failed (page={page}, page_size={page_size})")
return "An error occurred (code: GETCHATS-ERR-001). Check mcp_errors.log for details."
示例输出:
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
发送消息
@mcp.tool()
async def send_message(chat_id: int, message: str) -> str:
"""
Send a message to a specific chat.
Args:
chat_id: The ID of the chat.
message: The message content to send.
"""
try:
entity = await client.get_entity(chat_id)
await client.send_message(entity, message)
return "Message sent successfully."
except Exception as e:
logger.exception(f"send_message failed (chat_id={chat_id})")
return "An error occurred (code: SENDMSG-ERR-001). Check mcp_errors.log for details."
示例输出:
Message sent successfully.
获取聊天邀请链接
get_invite_link 函数特别强大,具有多种备用方法:
@mcp.tool()
async def get_invite_link(chat_id: int) -> str:
"""
Get the invite link for a group or channel.
"""
try:
entity = await client.get_entity(chat_id)
# Try using ExportChatInviteRequest first
try:
from telethon.tl import functions
result = await client(functions.messages.ExportChatInviteRequest(
peer=entity
))
return result.link
except AttributeError:
# If the function doesn't exist in the current Telethon version
logger.warning("ExportChatInviteRequest not available, using alternative method")
except Exception as e1:
# If that fails, log and try alternative approach
logger.warning(f"ExportChatInviteRequest failed: {e1}")
# Alternative approach using client.export_chat_invite_link
try:
invite_link = await client.export_chat_invite_link(entity)
return invite_link
except Exception as e2:
logger.warning(f"export_chat_invite_link failed: {e2}")
# Last resort: Try directly fetching chat info
try:
if isinstance(entity, (Chat, Channel)):
full_chat = await client(functions.messages.GetFullChatRequest(
chat_id=entity.id
))
if hasattr(full_chat, 'full_chat') and hasattr(full_chat.full_chat, 'invite_link'):
return full_chat.full_chat.invite_link or "No invite link available."
except Exception as e3:
logger.warning(f"GetFullChatRequest failed: {e3}")
return "Could not retrieve invite link for this chat."
except Exception as e:
logger.exception(f"get_invite_link failed (chat_id={chat_id})")
return f"Error getting invite link: {e}"
示例输出:
https://t.me/+AbCdEfGhIjKlMnOp
通过邀请链接加入聊天
@mcp.tool()
async def join_chat_by_link(link: str) -> str:
"""
Join a chat by invite link.
"""
try:
# Extract the hash from the invite link
if '/' in link:
hash_part = link.split('/')[-1]
if hash_part.startswith('+'):
hash_part = hash_part[1:] # Remove the '+' if present
else:
hash_part = link
# Try checking the invite before joining
try:
# Try to check invite info first (will often fail if not a member)
invite_info = await client(functions.messages.CheckChatInviteRequest(hash=hash_part))
if hasattr(invite_info, 'chat') and invite_info.chat:
# If we got chat info, we're already a member
chat_title = getattr(invite_info.chat, 'title', 'Unknown Chat')
return f"You are already a member of this chat: {chat_title}"
except Exception:
# This often fails if not a member - just continue
pass
# Join the chat using the hash
result = await client(functions.messages.ImportChatInviteRequest(hash=hash_part))
if result and hasattr(result, 'chats') and result.chats:
chat_title = getattr(result.chats[0], 'title', 'Unknown Chat')
return f"Successfully joined chat: {chat_title}"
return f"Joined chat via invite hash."
except Exception as e:
err_str = str(e).lower()
if "expired" in err_str:
return "The invite hash has expired and is no longer valid."
elif "invalid" in err_str:
return "The invite hash is invalid or malformed."
elif "already" in err_str and "participant" in err_str:
return "You are already a member of this chat."
logger.exception(f"join_chat_by_link failed (link={link})")
return f"Error joining chat: {e}"
示例输出:
Successfully joined chat: Developer Community
搜索公共聊天
@mcp.tool()
async def search_public_chats(query: str) -> str:
"""
Search for public chats, channels, or bots by username or title.
"""
try:
result = await client(functions.contacts.SearchRequest(q=query, limit=20))
return json.dumps([format_entity(u) for u in result.users], indent=2)
except Exception as e:
return f"Error searching public chats: {e}"
示例输出:
[
{
"id": 123456789,
"name": "TelegramBot",
"type": "user",
"username": "telegram_bot"
},
{
"id": 987654321,
"name": "Telegram News",
"type": "user",
"username": "telegram_news"
}
]
获取与联系人的直接聊天
@mcp.tool()
async def get_direct_chat_by_contact(contact_query: str) -> str:
"""
Find a direct chat with a specific contact by name, username, or phone.
Args:
contact_query: Name, username, or phone number to search for.
"""
try:
# Fetch all contacts using the correct Telethon method
result = await client(functions.contacts.GetContactsRequest(hash=0))
contacts = result.users
found_contacts = []
for contact in contacts:
if not contact:
continue
name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
username = getattr(contact, 'username', '')
phone = getattr(contact, 'phone', '')
if (contact_query.lower() in name.lower() or
(username and contact_query.lower() in username.lower()) or
(phone and contact_query in phone)):
found_contacts.append(contact)
if not found_contacts:
return f"No contacts found matching '{contact_query}'."
# If we found contacts, look for direct chats with them
results = []
dialogs = await client.get_dialogs()
for contact in found_contacts:
contact_name = f"{getattr(contact, 'first_name', '')} {getattr(contact, 'last_name', '')}".strip()
for dialog in dialogs:
if isinstance(dialog.entity, User) and dialog.entity.id == contact.id:
chat_info = f"Chat ID: {dialog.entity.id}, Contact: {contact_name}"
if getattr(contact, 'username', ''):
chat_info += f", Username: @{contact.username}"
if dialog.unread_count:
chat_info += f", Unread: {dialog.unread_count}"
results.append(chat_info)
break
if not results:
return f"Found contacts matching '{contact_query}', but no direct chats with them."
return "\n".join(results)
except Exception as e:
return f"Error searching for direct chat: {e}"
示例输出:
Chat ID: 123456789, Contact: John Smith, Username: @johnsmith, Unread: 3
🎮 使用示例
- "显示我最近的聊天"
- "向聊天 123456789 发送 'Hello world'"
- "添加电话 +1234567890、姓名 John Doe 的联系人"
- "创建一个名为 'Project Team' 的群组,包含用户 111, 222, 333"
- "从聊天 123456789 中下载消息 42 的媒体"
- "静音聊天 123456789 的通知"
- "在群组 123456789 中提升用户 111 为管理员"
- "搜索关于 'news' 的公共频道"
- "通过邀请链接 https://t.me/+AbCdEfGhIjK 加入 Telegram 群组"
- "向我的保存的消息发送贴纸"
- "获取我所有的贴纸集"
您可以通过自然语言在 Claude、Cursor 或任何兼容 MCP 的客户端中使用这些工具。
🧠 错误处理与鲁棒性
此实现包括全面的错误处理:
- 会话管理:支持基于文件和基于字符串的会话
- 错误报告:详细错误记录在
mcp_errors.log中 - 优雅降级:关键功能的多种回退方法
- 用户友好消息:清晰、可操作的错误消息,而不是技术性错误
- 账户类型检测:需要机器人账号的功能会在使用用户账号时检测并通知
- 邀请链接处理:处理各种链接格式和已经是成员的情况
代码设计为能够抵御常见的 Telegram API 问题和限制。
🛠️ 贡献指南
- Fork 此仓库: chigwell/telegram-mcp
- 克隆你的 Fork:
git clone https://github.com/<your-github-username>/telegram-mcp.git - 创建新分支:
git checkout -b my-feature - 进行更改,如有需要添加测试/文档。
- 推送并打开 Pull Request 到 chigwell/telegram-mcp,附上清晰的描述。
- 在 PR 中标记 @chigwell 或 @l1v0n1 进行审查。
🔒 安全注意事项
- 不要提交你的
.env或会话字符串。 - 会话字符串提供了对你 Telegram 账号的完全访问权限——请妥善保管!
- 所有处理都是本地进行的;除了发送到 Telegram 的 API 之外,没有数据会被发送到其他地方。
- 使用
.env.example作为模板,并将实际的.env文件保持私密。 - 测试文件在
.gitignore中自动被排除。
🛠️ 故障排查
- 检查日志 在你的 MCP 客户端(Claude/Cursor)和终端中查找错误。
- 详细的错误日志 可以在
mcp_errors.log中找到。 - 解释器错误? 确保你的
.venv已创建并已选择。 - 数据库锁定? 使用会话字符串认证,而不是基于文件的会话。
- iCloud/Dropbox 问题? 如果看到奇怪的错误,请将项目移动到一个不包含空格的本地路径。
- 更改了 Telegram 密码或遇到认证错误? 重新生成会话字符串。
- 仅限机器人功能 在使用普通用户账号时会显示清晰的消息。
- 测试脚本失败? 检查
.env中的测试配置是否具有有效的测试账号/群组。
📄 许可证
此项目根据 Apache 2.0 License 许可。
🙏 致谢
由 @chigwell 和 @l1v0n1 维护。欢迎 PR!