bn-telegram-mcp-server
v0.0.6
Published
Stateless MCP Server for Telegram via TDLib
Readme
Telegram MCP Server Tools
Quick Reference Table
| Tool | Description | Key Input | Key Output |
|------|-------------|-----------|------------|
| getMe | Current user info | none | {id, name, status} |
| getChat | Get/list chats | chat?, limit? | {id, title, type} or {chats[], summary} |
| getMessages | Get messages (history/specific/search) | chat?, mode, query? | {messages[], total_count} |
| getMessageContext | Get surrounding messages for context | chat, mode, message_id?, query? | {contexts[], summary} |
| sendMessage | Send/forward messages | chat, action, text? | {id, content, date} |
| getUser | User profile | user (name/ID) | {id, name, status} |
| getContacts | List/search contacts | query?, limit? | {contacts[], total_count} |
| getFile | Get file metadata | file_id | {id, size, remote_id} |
| getGroup | Group info (basic/super) | group, type? | {id, name, member_count} |
| getChatMembers | Chat members with filters | chat, filter? | {members[], total_count} |
1. getMe
Description: Get information about the current Telegram user (the authenticated user). Returns name, username, phone, status, and profile info.
Input Schema
{
"type": "object",
"properties": {}
}No parameters required.
Output Schema
{
id: number; // User's numeric ID
name: string; // Full name (e.g., "John Doe")
username?: string; // @username if set
phone?: string; // Phone number if visible
status: string; // Online status (e.g., "online", "last seen 2 hours ago")
is_contact: boolean;
is_premium: boolean;
is_verified: boolean;
}Use Cases
Use Case 1: Check authenticated user
# Input
{}
# Output
{
"id": 111222333,
"name": "John Doe",
"phone": "+1234567890",
"status": "online",
"is_contact": false,
"is_premium": false,
"is_verified": false
}Use Case 2: Verify connection status
# Call getMe to verify the Telegram session is active
# If successful, returns user info; if failed, session needs re-authentication2. getChat
Description: Get chat information - either a specific chat or list all chats. When chat is provided, returns single chat details. When chat is omitted, returns list of all chats.
Input Schema
{
"type": "object",
"properties": {
"chat": {
"type": ["number", "string"],
"description": "Optional: Chat identifier (name/title or numeric ID). If omitted, lists all chats."
},
"chat_list": {
"type": "string",
"enum": ["main", "archive"],
"description": "Which chat list to retrieve (default: main)"
},
"limit": {
"type": "number",
"description": "Maximum chats when listing (default: 100, max: 4000)"
}
}
}Output Schema (Single Chat)
{
id: number;
title: string;
type: string; // "private", "group", "supergroup", "channel"
unread_count: number;
last_message?: {
preview: string;
sender: string;
date: string;
date_relative: string;
};
is_pinned: boolean;
is_muted: boolean;
}Output Schema (List Chats)
{
chats: Array<{
id: number;
title: string;
type: string;
unread_count: number;
last_message?: { preview, sender, date, date_relative };
is_pinned: boolean;
is_muted: boolean;
}>;
total_count: number;
summary: string; // e.g., "15 chats loaded, 3 unread messages"
}Use Cases
Use Case 1: List all chats
# Input
{"limit": 10}
# Output
{
"chats": [
{
"id": 555666777,
"title": "John Doe",
"type": "private",
"unread_count": 0,
"last_message": {
"preview": "Test message",
"sender": "User 111222333",
"date": "2025-12-04T08:41:54.000Z",
"date_relative": "4 hours ago"
}
}
],
"total_count": 15,
"summary": "10 chats loaded, 0 unread messages"
}Use Case 2: Get specific chat by name
# Input
{"chat": "John Doe"}
# Output
{
"id": 555666777,
"title": "John Doe",
"type": "private",
"unread_count": 0,
"is_pinned": false,
"is_muted": false
}Use Case 3: Get archived chats
# Input
{"chat_list": "archive", "limit": 50}3. getMessages
Description: Get messages from a chat using different modes: paginated history, specific message IDs, or text search. Supports both chat-specific and global search.
Input Schema
{
"type": "object",
"properties": {
"chat": {
"type": ["number", "string"],
"description": "Chat identifier. Required for 'history'/'specific' modes, optional for 'search'"
},
"mode": {
"type": "string",
"enum": ["history", "specific", "search"],
"description": "Mode: 'history' (default), 'specific', or 'search'"
},
"from_message_id": {
"type": "number",
"description": "(history/chat search mode) Start from this message ID (0 for latest)"
},
"offset": {
"type": "number",
"description": "(history mode) Numeric pagination offset"
},
"limit": {
"type": "number",
"description": "Max messages to return (default: 50, max: 100)"
},
"only_local": {
"type": "boolean",
"description": "(history mode) Only return cached messages"
},
"message_ids": {
"type": "array",
"items": { "type": "number" },
"description": "(specific mode) Array of message IDs to retrieve"
},
"query": {
"type": "string",
"description": "(search mode) Search query text"
},
"next_offset": {
"type": "string",
"description": "(search mode) Cursor for pagination - pass the next_offset from previous response"
}
}
}Output Schema (History/Search)
{
messages: Array<{
id: number;
chat_id: number;
sender: string;
sender_id: number;
content: string;
content_type: string; // "Text", "Photo", "Video", etc.
date: string;
date_relative: string;
is_outgoing: boolean;
is_pinned: boolean;
file_id?: number;
}>;
total_count: number;
chat_title?: string; // (history mode)
search_query?: string; // (search mode)
next_offset?: string; // (search mode) For pagination
}Use Cases
Use Case 1: Get chat history
# Input
{"chat": "John Doe", "mode": "history", "limit": 5}
# Output
{
"messages": [
{
"id": 14680064,
"chat_id": 555666777,
"sender": "User 111222333",
"content": "Test message from script",
"content_type": "Text",
"date": "2025-12-04T08:41:54.000Z",
"date_relative": "4 hours ago",
"is_outgoing": true
}
],
"total_count": 1,
"chat_title": "John Doe"
}Use Case 2: Get specific messages by IDs
# Input
{"chat": "John Doe", "mode": "specific", "message_ids": [9437184, 9437185]}
# Output
{
"messages": [...],
"count": 2,
"chat_title": "John Doe"
}Use Case 3: Search messages globally
# Input
{"mode": "search", "query": "meeting", "limit": 10}
# Output
{
"messages": [...],
"total_count": 5,
"search_query": "meeting"
}Use Case 4: Search in specific chat
# Input
{"chat": "Project Team", "mode": "search", "query": "deadline"}Use Case 5: Search with pagination
# First request
{"mode": "search", "query": "meeting", "limit": 10}
# Response includes next_offset
{
"messages": [...],
"total_count": 50,
"next_offset": "abc123xyz",
"search_query": "meeting"
}
# Next page - pass the next_offset from previous response
{"mode": "search", "query": "meeting", "limit": 10, "next_offset": "abc123xyz"}4. getMessageContext
Description: Get surrounding messages for context around a specific message or search results. Returns messages before and after the target to understand the full conversation flow. Useful when you need to understand the context of a particular message.
Input Schema
{
"type": "object",
"properties": {
"chat": {
"type": ["number", "string"],
"description": "Chat identifier. Required for 'message_id' mode, optional for 'search' mode (global search if omitted)"
},
"mode": {
"type": "string",
"enum": ["message_id", "search"],
"description": "Mode: 'message_id' (default) or 'search'"
},
"message_id": {
"type": "number",
"description": "(message_id mode) The message ID to get context around"
},
"query": {
"type": "string",
"description": "(search mode) Search query to find messages"
},
"search_limit": {
"type": "number",
"description": "(search mode) Max search results to get context for (default: 5, max: 20)"
},
"context_count": {
"type": "number",
"description": "Messages to fetch before AND after target (default: 5, max: 50)"
}
}
}Output Schema
{
contexts: Array<{
messages: Array<{ // Single chronological array (easier for LLMs)
id: number;
chat_id: number;
sender: string;
content: string;
content_type: string;
date: string;
date_relative: string;
is_target: boolean; // true for the target message
}>;
target_message_id: number; // ID of the target message
context_count: number;
chat_id: number;
chat_title?: string;
}>;
total_matches: number;
search_query?: string; // Only present in search mode
summary: string; // Human-readable summary
}Use Cases
Use Case 1: Get context around a specific message
# Input
{"chat": "Project Team", "mode": "message_id", "message_id": 12345, "context_count": 3}
# Output - Single chronological array with is_target flag
{
"contexts": [
{
"messages": [
{"id": 12342, "content": "Good morning everyone", "is_target": false, ...},
{"id": 12343, "content": "Hi team", "is_target": false, ...},
{"id": 12344, "content": "Ready for the standup?", "is_target": false, ...},
{"id": 12345, "content": "Let's discuss the deadline", "is_target": true, ...},
{"id": 12346, "content": "Sure, what about Friday?", "is_target": false, ...},
{"id": 12347, "content": "Friday works for me", "is_target": false, ...},
{"id": 12348, "content": "Let's set it for 3pm", "is_target": false, ...}
],
"target_message_id": 12345,
"context_count": 3,
"chat_title": "Project Team"
}
],
"total_matches": 1,
"summary": "Showing context for 1 message(s) (7 total messages)"
}Use Case 2: Search and get context for each match
# Input
{"chat": "Project Team", "mode": "search", "query": "deadline", "search_limit": 3, "context_count": 2}
# Output
{
"contexts": [
{
"messages": [
{"id": 12343, "content": "Hi team", "is_target": false, ...},
{"id": 12344, "content": "Ready for the standup?", "is_target": false, ...},
{"id": 12345, "content": "Let's discuss the deadline", "is_target": true, ...},
{"id": 12346, "content": "Sure, what about Friday?", "is_target": false, ...},
{"id": 12347, "content": "Friday works for me", "is_target": false, ...}
],
"target_message_id": 12345,
"chat_title": "Project Team"
},
{
"messages": [
{"id": 9874, "content": "Any updates?", "is_target": false, ...},
{"id": 9875, "content": "Yes, checking now", "is_target": false, ...},
{"id": 9876, "content": "The deadline is next week", "is_target": true, ...},
{"id": 9877, "content": "Got it, thanks", "is_target": false, ...},
{"id": 9878, "content": "I'll prepare the report", "is_target": false, ...}
],
"target_message_id": 9876,
"chat_title": "Project Team"
}
],
"total_matches": 5,
"search_query": "deadline",
"summary": "Found 5 match(es) for \"deadline\", showing context for 2 result(s) (10 total messages)"
}Use Case 3: Global search with context
# Input - search across all chats
{"mode": "search", "query": "urgent", "search_limit": 5, "context_count": 3}
# Output - results may come from different chats
{
"contexts": [
{
"messages": [
{"id": 553, "content": "Please review", "is_target": false, ...},
{"id": 554, "content": "Will do", "is_target": false, ...},
{"id": 555, "content": "This is urgent!", "is_target": true, ...},
{"id": 556, "content": "On it now", "is_target": false, ...}
],
"target_message_id": 555,
"chat_id": 1111111,
"chat_title": "Work Group"
},
{
"messages": [
{"id": 775, "content": "Schedule update", "is_target": false, ...},
{"id": 776, "content": "What time?", "is_target": false, ...},
{"id": 777, "content": "Urgent meeting tomorrow", "is_target": true, ...},
{"id": 778, "content": "I'll be there", "is_target": false, ...}
],
"target_message_id": 777,
"chat_id": 2222222,
"chat_title": "Project Team"
}
],
"total_matches": 12,
"search_query": "urgent",
"summary": "Found 12 match(es) for \"urgent\", showing context for 2 result(s) (8 total messages)"
}5. sendMessage
Description: Send or forward messages to a chat. Use action="send" to compose new messages, or action="forward" to forward existing messages from another chat.
Input Schema
{
"type": "object",
"properties": {
"chat": {
"type": ["number", "string"],
"description": "Target chat: name/title or numeric ID"
},
"action": {
"type": "string",
"enum": ["send", "forward"],
"description": "Action type (default: 'send')"
},
"text": {
"type": "string",
"description": "(send action) Text content of the message"
},
"reply_to_message_id": {
"type": "number",
"description": "(send action) ID of message to reply to"
},
"from_chat": {
"type": ["number", "string"],
"description": "(forward action) Source chat to forward from"
},
"message_ids": {
"type": "array",
"items": { "type": "number" },
"description": "(forward action) Message IDs to forward"
},
"send_copy": {
"type": "boolean",
"description": "(forward action) Send copies without forwarding header"
},
"remove_caption": {
"type": "boolean",
"description": "(forward action) Remove media captions"
}
},
"required": ["chat"]
}Output Schema (Send)
{
id: number;
chat_id: number;
sender: string;
content: string;
content_type: string;
date: string;
date_relative: string;
is_outgoing: true;
is_pinned: boolean;
}Output Schema (Forward)
{
forwarded: Array<{
id: number;
chat_id: number;
sender: string;
content: string;
date: string;
is_outgoing: boolean;
}>;
count: number;
}Use Cases
Use Case 1: Send a new message
# Input
{"chat": "John Doe", "text": "Hello from MCP!"}
# Output
{
"id": 14680065,
"chat_id": 555666777,
"sender": "User 111222333",
"content": "Hello from MCP!",
"content_type": "Text",
"date": "2025-12-04T12:45:00.000Z",
"date_relative": "just now",
"is_outgoing": true
}Use Case 2: Reply to a message
# Input
{"chat": "Project Team", "text": "I agree!", "reply_to_message_id": 12345}Use Case 3: Forward messages
# Input
{
"chat": "John Doe",
"action": "forward",
"from_chat": "Project Team",
"message_ids": [100, 101, 102]
}
# Output
{
"forwarded": [...],
"count": 3
}Use Case 4: Forward as copy (no "Forwarded from" header)
# Input
{
"chat": "John Doe",
"action": "forward",
"from_chat": "Project Team",
"message_ids": [100],
"send_copy": true
}6. getUser
Description: Get information about a Telegram user. You can use their name, @username, or numeric user ID.
Input Schema
{
"type": "object",
"properties": {
"user": {
"type": ["number", "string"],
"description": "User identifier: name, @username, or numeric ID"
}
},
"required": ["user"]
}Output Schema
{
id: number;
name: string;
username?: string;
phone?: string;
status: string; // "online", "last seen 2 hours ago", etc.
is_contact: boolean;
is_premium: boolean;
is_verified: boolean;
}Use Cases
Use Case 1: Get user by numeric ID
# Input
{"user": 555666777}
# Output
{
"id": 555666777,
"name": "John Doe",
"phone": "+1234567890",
"status": "last seen 2 hours ago",
"is_contact": true,
"is_premium": false,
"is_verified": false
}Use Case 2: Get user by username
# Input
{"user": "@johndoe"}7. getContacts
Description: Get contacts - either list all contacts or search by name/username. When query is provided, searches contacts; otherwise returns all contacts.
Input Schema
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Optional: Search query to filter contacts"
},
"limit": {
"type": "number",
"description": "Max results when searching (default: 50, max: 200)"
}
}
}Output Schema
{
contacts: Array<{
id: number;
name: string;
username?: string;
phone?: string;
status: string;
}>;
total_count: number;
query?: string; // Only present when searching
}Use Cases
Use Case 1: List all contacts
# Input
{}
# Output
{
"contacts": [
{
"id": 555666777,
"name": "John Doe",
"phone": "+1234567890",
"status": "last seen 2 hours ago"
},
{
"id": 123456789,
"name": "John Doe",
"username": "johndoe",
"status": "online"
}
],
"total_count": 2
}Use Case 2: Search contacts
# Input
{"query": "John", "limit": 10}
# Output
{
"contacts": [
{
"id": 555666777,
"name": "John Doe",
"phone": "+1234567890",
"status": "last seen 2 hours ago"
}
],
"total_count": 1,
"query": "John"
}8. getFile
Description: Get file metadata (size, remote ID). Note: Download is not supported in stateless mode since session files are cleaned up after each request.
Input Schema
{
"type": "object",
"properties": {
"file_id": {
"type": "number",
"description": "Identifier of the file to get metadata for"
}
},
"required": ["file_id"]
}Output Schema
{
id: number;
size: string; // Human-readable (e.g., "1.5 MB")
size_bytes: number;
remote_id?: string; // Remote file identifier
}Use Cases
Use Case 1: Get file metadata
# Input
{"file_id": 33}
# Output
{
"id": 33,
"size": "1.00 MB",
"size_bytes": 1024000,
"remote_id": "AgACAgEAAxk..."
}Use Case 2: Get file info from a message
# First, get messages to find a file_id
{"chat": "John Doe", "mode": "history", "limit": 5}
# Response includes file_id in messages with media
# Then get file metadata
{"file_id": 45}9. getGroup
Description: Get information about a group (basic group, supergroup, or channel). Use type="auto" to detect automatically, or specify type="supergroup" or type="basic_group" explicitly.
Input Schema
{
"type": "object",
"properties": {
"group": {
"type": ["number", "string"],
"description": "Group identifier: name or numeric ID"
},
"type": {
"type": "string",
"enum": ["auto", "supergroup", "basic_group"],
"description": "Group type (default: 'auto')"
}
},
"required": ["group"]
}Output Schema
{
id: number;
name: string;
type: "basic_group" | "supergroup" | "channel";
member_count: number;
is_verified?: boolean; // supergroups only
is_scam?: boolean; // supergroups only
join_date?: string;
}Use Cases
Use Case 1: Get group with auto-detection
# Input
{"group": "Project Team"}
# Output
{
"id": 1234567890,
"name": "Project Team",
"type": "supergroup",
"member_count": 15,
"is_verified": false,
"is_scam": false
}Use Case 2: Get basic group explicitly
# Input
{"group": "Family Group", "type": "basic_group"}
# Output
{
"id": 9876543210,
"name": "Family Group",
"type": "basic_group",
"member_count": 5
}Use Case 3: Get supergroup by ID
# Input
{"group": 1234567890, "type": "supergroup"}10. getChatMembers
Description: Get members of a chat with filtering options. Supports filtering by role (administrators, banned, bots) or searching by name.
Input Schema
{
"type": "object",
"properties": {
"chat": {
"type": ["number", "string"],
"description": "Chat identifier: name/title or numeric ID"
},
"filter": {
"type": "string",
"enum": ["recent", "administrators", "banned", "bots", "search"],
"description": "Filter type (default: 'recent')"
},
"query": {
"type": "string",
"description": "Search query (for 'search' and 'banned' filters)"
},
"offset": {
"type": "number",
"description": "Pagination offset"
},
"limit": {
"type": "number",
"description": "Max members to return (default: 200, max: 200)"
}
},
"required": ["chat"]
}Output Schema
{
members: Array<{
user_id: number;
name: string;
username?: string;
status: string;
role: string; // "owner", "administrator", "member", etc.
joined_date?: string;
}>;
total_count: number;
chat_title?: string;
}Use Cases
Use Case 1: Get recent members
# Input
{"chat": "Project Team", "limit": 10}
# Output
{
"members": [
{
"user_id": 111222333,
"name": "John Doe",
"status": "member",
"role": "creator"
},
{
"user_id": 123456789,
"name": "John Doe",
"username": "johndoe",
"status": "member",
"role": "member"
}
],
"total_count": 15,
"chat_title": "Project Team"
}Use Case 2: Get only administrators
# Input
{"chat": "Project Team", "filter": "administrators"}
# Output
{
"members": [
{
"user_id": 111222333,
"name": "John Doe",
"status": "administrator",
"role": "owner"
}
],
"total_count": 1,
"chat_title": "Project Team"
}Use Case 3: Search members by name
# Input
{"chat": "Project Team", "filter": "search", "query": "john"}Use Case 4: Get bot members
# Input
{"chat": "Project Team", "filter": "bots"}