@overpod/mcp-telegram 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/cli.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +17 -2
- package/dist/qr-login-cli.d.ts +2 -0
- package/dist/telegram-client.d.ts +111 -0
- package/dist/telegram-client.js +14 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -83,9 +83,13 @@ claude mcp add telegram -s user \
|
|
|
83
83
|
-- npx @overpod/mcp-telegram
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
### Claude Desktop
|
|
86
|
+
### Claude Desktop
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
1. Open your config file:
|
|
89
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
90
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
91
|
+
|
|
92
|
+
2. Add the Telegram server:
|
|
89
93
|
|
|
90
94
|
```json
|
|
91
95
|
{
|
|
@@ -102,6 +106,18 @@ Add to your MCP configuration file:
|
|
|
102
106
|
}
|
|
103
107
|
```
|
|
104
108
|
|
|
109
|
+
3. Restart Claude Desktop.
|
|
110
|
+
|
|
111
|
+
4. Ask Claude: **"Run telegram-login"** -- a QR code will appear. If the image is not visible, Claude will provide a browser link to view the QR code. Scan it in Telegram (**Settings > Devices > Link Desktop Device**).
|
|
112
|
+
|
|
113
|
+
5. Ask Claude: **"Run telegram-status"** to verify the connection.
|
|
114
|
+
|
|
115
|
+
> **Note**: No terminal required! Login works entirely through Claude Desktop.
|
|
116
|
+
|
|
117
|
+
### Cursor / VS Code
|
|
118
|
+
|
|
119
|
+
Add the same JSON config above to your MCP settings (Cursor Settings > MCP, or VS Code MCP config).
|
|
120
|
+
|
|
105
121
|
### Mastra
|
|
106
122
|
|
|
107
123
|
```typescript
|
package/dist/cli.d.ts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -48,8 +48,11 @@ server.tool("telegram-status", "Check Telegram connection status", {}, async ()
|
|
|
48
48
|
});
|
|
49
49
|
server.tool("telegram-login", "Login to Telegram via QR code. Returns QR image. IMPORTANT: pass the entire result to user without modifications.", {}, async () => {
|
|
50
50
|
let qrDataUrl = "";
|
|
51
|
+
let qrRawUrl = "";
|
|
51
52
|
const loginPromise = telegram.startQrLogin((dataUrl) => {
|
|
52
53
|
qrDataUrl = dataUrl;
|
|
54
|
+
}, (url) => {
|
|
55
|
+
qrRawUrl = url;
|
|
53
56
|
});
|
|
54
57
|
// Wait for first QR to be generated
|
|
55
58
|
const startTime = Date.now();
|
|
@@ -68,8 +71,20 @@ server.tool("telegram-login", "Login to Telegram via QR code. Returns QR image.
|
|
|
68
71
|
console.error(`[mcp-telegram] Login failed: ${result.message}`);
|
|
69
72
|
}
|
|
70
73
|
});
|
|
71
|
-
// Return as MCP image content +
|
|
74
|
+
// Return as MCP image content + text with fallback options
|
|
72
75
|
const base64 = qrDataUrl.replace(/^data:image\/png;base64,/, "");
|
|
76
|
+
const qrApiUrl = qrRawUrl
|
|
77
|
+
? `https://api.qrserver.com/v1/create-qr-code/?size=256x256&data=${encodeURIComponent(qrRawUrl)}`
|
|
78
|
+
: "";
|
|
79
|
+
const instructions = [
|
|
80
|
+
"Scan this QR code in Telegram: **Settings → Devices → Link Desktop Device**.",
|
|
81
|
+
"",
|
|
82
|
+
qrApiUrl ? `If the QR image is not visible, open this link in your browser:\n${qrApiUrl}` : "",
|
|
83
|
+
"",
|
|
84
|
+
"After scanning, run **telegram-status** to verify the connection.",
|
|
85
|
+
]
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
.join("\n");
|
|
73
88
|
return {
|
|
74
89
|
content: [
|
|
75
90
|
{
|
|
@@ -79,7 +94,7 @@ server.tool("telegram-login", "Login to Telegram via QR code. Returns QR image.
|
|
|
79
94
|
},
|
|
80
95
|
{
|
|
81
96
|
type: "text",
|
|
82
|
-
text:
|
|
97
|
+
text: instructions,
|
|
83
98
|
},
|
|
84
99
|
],
|
|
85
100
|
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export declare class TelegramService {
|
|
2
|
+
private client;
|
|
3
|
+
private apiId;
|
|
4
|
+
private apiHash;
|
|
5
|
+
private sessionString;
|
|
6
|
+
private connected;
|
|
7
|
+
lastError: string;
|
|
8
|
+
constructor(apiId: number, apiHash: string);
|
|
9
|
+
loadSession(): Promise<boolean>;
|
|
10
|
+
/** Set session string in memory (for programmatic / hosted use) */
|
|
11
|
+
setSessionString(session: string): void;
|
|
12
|
+
/** Get the current session string (for external persistence) */
|
|
13
|
+
getSessionString(): string;
|
|
14
|
+
private saveSession;
|
|
15
|
+
connect(): Promise<boolean>;
|
|
16
|
+
clearSession(): Promise<void>;
|
|
17
|
+
/** Ensure connection is active, auto-reconnect if session exists */
|
|
18
|
+
ensureConnected(): Promise<boolean>;
|
|
19
|
+
disconnect(): Promise<void>;
|
|
20
|
+
isConnected(): boolean;
|
|
21
|
+
startQrLogin(onQrDataUrl: (dataUrl: string) => void, onQrUrl?: (url: string) => void): Promise<{
|
|
22
|
+
success: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
}>;
|
|
25
|
+
getMe(): Promise<{
|
|
26
|
+
id: string;
|
|
27
|
+
username?: string;
|
|
28
|
+
firstName?: string;
|
|
29
|
+
}>;
|
|
30
|
+
sendMessage(chatId: string, text: string, replyTo?: number, parseMode?: "md" | "html"): Promise<void>;
|
|
31
|
+
sendFile(chatId: string, filePath: string, caption?: string): Promise<void>;
|
|
32
|
+
downloadMedia(chatId: string, messageId: number, downloadPath: string): Promise<string>;
|
|
33
|
+
pinMessage(chatId: string, messageId: number, silent?: boolean): Promise<void>;
|
|
34
|
+
unpinMessage(chatId: string, messageId: number): Promise<void>;
|
|
35
|
+
getDialogs(limit?: number, offsetDate?: number, filterType?: "private" | "group" | "channel"): Promise<Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
type: string;
|
|
39
|
+
unreadCount: number;
|
|
40
|
+
}>>;
|
|
41
|
+
getUnreadDialogs(limit?: number): Promise<Array<{
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
unreadCount: number;
|
|
46
|
+
}>>;
|
|
47
|
+
markAsRead(chatId: string): Promise<void>;
|
|
48
|
+
forwardMessage(fromChatId: string, toChatId: string, messageIds: number[]): Promise<void>;
|
|
49
|
+
editMessage(chatId: string, messageId: number, newText: string): Promise<void>;
|
|
50
|
+
deleteMessages(chatId: string, messageIds: number[]): Promise<void>;
|
|
51
|
+
getChatInfo(chatId: string): Promise<{
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
type: string;
|
|
55
|
+
username?: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
membersCount?: number;
|
|
58
|
+
}>;
|
|
59
|
+
/** Extract media info from a message */
|
|
60
|
+
private extractMediaInfo;
|
|
61
|
+
/** Resolve sender ID to a display name */
|
|
62
|
+
private resolveSenderName;
|
|
63
|
+
getMessages(chatId: string, limit?: number, offsetId?: number, minDate?: number, maxDate?: number): Promise<Array<{
|
|
64
|
+
id: number;
|
|
65
|
+
text: string;
|
|
66
|
+
sender: string;
|
|
67
|
+
date: string;
|
|
68
|
+
media?: {
|
|
69
|
+
type: string;
|
|
70
|
+
fileName?: string;
|
|
71
|
+
size?: number;
|
|
72
|
+
};
|
|
73
|
+
}>>;
|
|
74
|
+
searchChats(query: string, limit?: number): Promise<Array<{
|
|
75
|
+
id: string;
|
|
76
|
+
name: string;
|
|
77
|
+
type: string;
|
|
78
|
+
username?: string;
|
|
79
|
+
}>>;
|
|
80
|
+
searchMessages(chatId: string, query: string, limit?: number, minDate?: number, maxDate?: number): Promise<Array<{
|
|
81
|
+
id: number;
|
|
82
|
+
text: string;
|
|
83
|
+
sender: string;
|
|
84
|
+
date: string;
|
|
85
|
+
media?: {
|
|
86
|
+
type: string;
|
|
87
|
+
fileName?: string;
|
|
88
|
+
size?: number;
|
|
89
|
+
};
|
|
90
|
+
}>>;
|
|
91
|
+
getContacts(limit?: number): Promise<Array<{
|
|
92
|
+
id: string;
|
|
93
|
+
name: string;
|
|
94
|
+
username?: string;
|
|
95
|
+
phone?: string;
|
|
96
|
+
}>>;
|
|
97
|
+
getChatMembers(chatId: string, limit?: number): Promise<Array<{
|
|
98
|
+
id: string;
|
|
99
|
+
name: string;
|
|
100
|
+
username?: string;
|
|
101
|
+
}>>;
|
|
102
|
+
getProfile(userId: string): Promise<{
|
|
103
|
+
id: string;
|
|
104
|
+
name: string;
|
|
105
|
+
username?: string;
|
|
106
|
+
phone?: string;
|
|
107
|
+
bio?: string;
|
|
108
|
+
photo: boolean;
|
|
109
|
+
lastSeen?: string;
|
|
110
|
+
}>;
|
|
111
|
+
}
|
package/dist/telegram-client.js
CHANGED
|
@@ -27,9 +27,22 @@ export class TelegramService {
|
|
|
27
27
|
}
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
|
+
/** Set session string in memory (for programmatic / hosted use) */
|
|
31
|
+
setSessionString(session) {
|
|
32
|
+
this.sessionString = session;
|
|
33
|
+
}
|
|
34
|
+
/** Get the current session string (for external persistence) */
|
|
35
|
+
getSessionString() {
|
|
36
|
+
return this.sessionString;
|
|
37
|
+
}
|
|
30
38
|
async saveSession(session) {
|
|
31
39
|
this.sessionString = session;
|
|
32
|
-
|
|
40
|
+
try {
|
|
41
|
+
await writeFile(SESSION_FILE, session, "utf-8");
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// File write may fail in containerized environments — session string is still in memory
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
async connect() {
|
|
35
48
|
if (this.connected && this.client)
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@overpod/mcp-telegram",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP server for Telegram userbot — 20 tools for messages, media, contacts & more. Built on GramJS/MTProto.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/index.js",
|
|
9
|
+
"./service": "./dist/telegram-client.js"
|
|
10
|
+
},
|
|
7
11
|
"bin": {
|
|
8
12
|
"mcp-telegram": "dist/cli.js"
|
|
9
13
|
},
|