@overpod/mcp-telegram 1.4.0 → 1.5.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/dist/index.js CHANGED
@@ -419,9 +419,7 @@ server.tool("telegram-get-profile", "Get detailed profile info of a Telegram use
419
419
  }
420
420
  });
421
421
  server.tool("telegram-join-chat", "Join a Telegram group or channel by username or invite link", {
422
- target: z
423
- .string()
424
- .describe("Username (@group), link (t.me/group), or invite link (t.me/+xxx)"),
422
+ target: z.string().describe("Username (@group), link (t.me/group), or invite link (t.me/+xxx)"),
425
423
  }, async ({ target }) => {
426
424
  const err = await requireConnection();
427
425
  if (err)
@@ -443,6 +441,72 @@ server.tool("telegram-join-chat", "Join a Telegram group or channel by username
443
441
  };
444
442
  }
445
443
  });
444
+ server.tool("telegram-send-reaction", "Send an emoji reaction to a message. Pass emoji to react, omit to remove reaction", {
445
+ chatId: z.string().describe("Chat ID or username"),
446
+ messageId: z.number().describe("Message ID to react to"),
447
+ emoji: z.string().optional().describe("Reaction emoji (e.g. 👍❤️🔥😂🎉). Omit to remove reaction"),
448
+ }, async ({ chatId, messageId, emoji }) => {
449
+ const err = await requireConnection();
450
+ if (err)
451
+ return { content: [{ type: "text", text: err }] };
452
+ try {
453
+ await telegram.sendReaction(chatId, messageId, emoji);
454
+ const action = emoji ? `Reacted ${emoji} to` : "Removed reaction from";
455
+ return { content: [{ type: "text", text: `${action} message ${messageId} in ${chatId}` }] };
456
+ }
457
+ catch (e) {
458
+ return { content: [{ type: "text", text: `Reaction error: ${e.message}` }] };
459
+ }
460
+ });
461
+ server.tool("telegram-send-scheduled", "Send a scheduled message to a Telegram chat. The message will be delivered at the specified time by Telegram servers", {
462
+ chatId: z.string().describe("Chat ID or username (use 'me' or 'self' for Saved Messages)"),
463
+ text: z.string().describe("Message text"),
464
+ scheduleDate: z.number().describe("Unix timestamp when to send the message (must be in the future)"),
465
+ replyTo: z.number().optional().describe("Message ID to reply to"),
466
+ parseMode: z.enum(["md", "html"]).optional().describe("Message format: md (Markdown) or html"),
467
+ }, async ({ chatId, text, scheduleDate, replyTo, parseMode }) => {
468
+ const err = await requireConnection();
469
+ if (err)
470
+ return { content: [{ type: "text", text: err }] };
471
+ // Resolve 'me'/'self' to Saved Messages
472
+ let target = chatId;
473
+ if (target === "me" || target === "self") {
474
+ try {
475
+ const me = await telegram.getMe();
476
+ target = me.id;
477
+ }
478
+ catch {
479
+ return { content: [{ type: "text", text: "Failed to resolve Saved Messages" }] };
480
+ }
481
+ }
482
+ try {
483
+ await telegram.sendScheduledMessage(target, text, scheduleDate, replyTo, parseMode);
484
+ const date = new Date(scheduleDate * 1000).toISOString();
485
+ return { content: [{ type: "text", text: `Message scheduled for ${date} in ${chatId}` }] };
486
+ }
487
+ catch (e) {
488
+ return { content: [{ type: "text", text: `Schedule error: ${e.message}` }] };
489
+ }
490
+ });
491
+ server.tool("telegram-create-poll", "Create a poll in a Telegram chat", {
492
+ chatId: z.string().describe("Chat ID or username"),
493
+ question: z.string().describe("Poll question"),
494
+ answers: z.array(z.string()).min(2).max(10).describe("Answer options (2-10)"),
495
+ multipleChoice: z.boolean().default(false).describe("Allow multiple answers"),
496
+ quiz: z.boolean().default(false).describe("Quiz mode (one correct answer)"),
497
+ correctAnswer: z.number().optional().describe("Index of correct answer (0-based, required for quiz mode)"),
498
+ }, async ({ chatId, question, answers, multipleChoice, quiz, correctAnswer }) => {
499
+ const err = await requireConnection();
500
+ if (err)
501
+ return { content: [{ type: "text", text: err }] };
502
+ try {
503
+ const msgId = await telegram.createPoll(chatId, question, answers, { multipleChoice, quiz, correctAnswer });
504
+ return { content: [{ type: "text", text: `Poll created in ${chatId}${msgId ? ` (message #${msgId})` : ""}` }] };
505
+ }
506
+ catch (e) {
507
+ return { content: [{ type: "text", text: `Poll error: ${e.message}` }] };
508
+ }
509
+ });
446
510
  // --- Start ---
447
511
  async function main() {
448
512
  // Try to auto-connect with saved session
@@ -119,6 +119,13 @@ export declare class TelegramService {
119
119
  photo: boolean;
120
120
  lastSeen?: string;
121
121
  }>;
122
+ sendReaction(chatId: string, messageId: number, emoji?: string): Promise<void>;
123
+ sendScheduledMessage(chatId: string, text: string, scheduleDate: number, replyTo?: number, parseMode?: "md" | "html"): Promise<void>;
124
+ createPoll(chatId: string, question: string, answers: string[], options?: {
125
+ multipleChoice?: boolean;
126
+ quiz?: boolean;
127
+ correctAnswer?: number;
128
+ }): Promise<number>;
122
129
  joinChat(target: string): Promise<{
123
130
  id: string;
124
131
  title: string;
@@ -603,6 +603,63 @@ export class TelegramService {
603
603
  lastSeen,
604
604
  };
605
605
  }
606
+ async sendReaction(chatId, messageId, emoji) {
607
+ if (!this.client || !this.connected)
608
+ throw new Error("Not connected");
609
+ const peer = await this.client.getInputEntity(chatId);
610
+ const reaction = emoji ? [new Api.ReactionEmoji({ emoticon: emoji })] : []; // empty = remove reaction
611
+ await this.client.invoke(new Api.messages.SendReaction({
612
+ peer,
613
+ msgId: messageId,
614
+ reaction,
615
+ }));
616
+ }
617
+ async sendScheduledMessage(chatId, text, scheduleDate, replyTo, parseMode) {
618
+ if (!this.client || !this.connected)
619
+ throw new Error("Not connected");
620
+ await this.client.sendMessage(chatId, {
621
+ message: text,
622
+ schedule: scheduleDate,
623
+ ...(replyTo ? { replyTo } : {}),
624
+ ...(parseMode ? { parseMode: parseMode === "html" ? "html" : "md" } : {}),
625
+ });
626
+ }
627
+ async createPoll(chatId, question, answers, options) {
628
+ if (!this.client || !this.connected)
629
+ throw new Error("Not connected");
630
+ const peer = await this.client.getInputEntity(chatId);
631
+ const pollAnswers = answers.map((text, i) => new Api.PollAnswer({
632
+ text: new Api.TextWithEntities({ text, entities: [] }),
633
+ option: Buffer.from([i]),
634
+ }));
635
+ const poll = new Api.Poll({
636
+ id: bigInt(Date.now()),
637
+ question: new Api.TextWithEntities({ text: question, entities: [] }),
638
+ answers: pollAnswers,
639
+ multipleChoice: options?.multipleChoice ?? false,
640
+ quiz: options?.quiz ?? false,
641
+ });
642
+ const result = await this.client.invoke(new Api.messages.SendMedia({
643
+ peer,
644
+ media: new Api.InputMediaPoll({
645
+ poll,
646
+ ...(options?.quiz && options.correctAnswer != null
647
+ ? { correctAnswers: [Buffer.from([options.correctAnswer])] }
648
+ : {}),
649
+ }),
650
+ message: "",
651
+ randomId: bigInt(Math.floor(Math.random() * 1e15)),
652
+ }));
653
+ // Extract message ID from result
654
+ if (result instanceof Api.Updates || result instanceof Api.UpdatesCombined) {
655
+ for (const update of result.updates) {
656
+ if (update instanceof Api.UpdateMessageID) {
657
+ return update.id;
658
+ }
659
+ }
660
+ }
661
+ return 0;
662
+ }
606
663
  async joinChat(target) {
607
664
  if (!this.client)
608
665
  throw new Error("Not connected");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@overpod/mcp-telegram",
3
- "version": "1.4.0",
4
- "description": "MCP server for Telegram userbot — 20 tools for messages, media, contacts & more. Built on GramJS/MTProto.",
3
+ "version": "1.5.0",
4
+ "description": "MCP server for Telegram userbot — 24 tools for messages, media, contacts & more. Built on GramJS/MTProto.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "exports": {