@overpod/mcp-telegram 1.39.1 → 1.40.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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.40.0](https://github.com/mcp-telegram/mcp-telegram/compare/v1.39.1...v1.40.0) (2026-06-23)
9
+
10
+
11
+ ### Added
12
+
13
+ * **media:** add thumbnail option to downloadMediaAsBuffer ([#64](https://github.com/mcp-telegram/mcp-telegram/issues/64)) ([d9f302c](https://github.com/mcp-telegram/mcp-telegram/commit/d9f302c8efde73a8d86467b23d05b8a12650662f))
14
+
8
15
  ## [1.39.1](https://github.com/mcp-telegram/mcp-telegram/compare/v1.39.0...v1.39.1) (2026-06-21)
9
16
 
10
17
 
@@ -142,9 +142,30 @@ export declare class TelegramService {
142
142
  ids: number[];
143
143
  }>;
144
144
  downloadMedia(chatId: string, messageId: number, downloadPath: string): Promise<string>;
145
- downloadMediaAsBuffer(chatId: string, messageId: number): Promise<{
145
+ /**
146
+ * Download a message's media into memory.
147
+ *
148
+ * When `options.thumb` is given, GramJS fetches that thumbnail size instead of
149
+ * the full file (`0` = smallest, larger indexes = bigger previews). This keeps
150
+ * payloads tiny — useful for callers that inline the bytes and pay per byte
151
+ * (e.g. base64 in an LLM context). If the message has no thumbnail at that
152
+ * index, GramJS returns an empty/`undefined` buffer; we transparently fall
153
+ * back to the full file so the caller always gets bytes. `isThumb` reports
154
+ * which one was served.
155
+ *
156
+ * Note: GramJS signals "no bytes" inconsistently — `undefined` for a missing
157
+ * thumbnail, but `Buffer.alloc(0)` for undownloadable media (geo/poll/dice,
158
+ * documents without a file, and several failure paths). An empty Buffer is
159
+ * truthy, so we guard on `.length`, not truthiness, in both the fallback and
160
+ * the final failure check — otherwise a 0-byte buffer would be returned as a
161
+ * "successful" (but garbage) download.
162
+ */
163
+ downloadMediaAsBuffer(chatId: string, messageId: number, options?: {
164
+ thumb?: number;
165
+ }): Promise<{
146
166
  buffer: Buffer;
147
167
  mimeType: string;
168
+ isThumb: boolean;
148
169
  }>;
149
170
  /** Detect MIME type from buffer magic bytes, falling back to media metadata */
150
171
  private detectMimeType;
@@ -708,7 +708,25 @@ export class TelegramService {
708
708
  await writeFile(downloadPath, buffer);
709
709
  return downloadPath;
710
710
  }
711
- async downloadMediaAsBuffer(chatId, messageId) {
711
+ /**
712
+ * Download a message's media into memory.
713
+ *
714
+ * When `options.thumb` is given, GramJS fetches that thumbnail size instead of
715
+ * the full file (`0` = smallest, larger indexes = bigger previews). This keeps
716
+ * payloads tiny — useful for callers that inline the bytes and pay per byte
717
+ * (e.g. base64 in an LLM context). If the message has no thumbnail at that
718
+ * index, GramJS returns an empty/`undefined` buffer; we transparently fall
719
+ * back to the full file so the caller always gets bytes. `isThumb` reports
720
+ * which one was served.
721
+ *
722
+ * Note: GramJS signals "no bytes" inconsistently — `undefined` for a missing
723
+ * thumbnail, but `Buffer.alloc(0)` for undownloadable media (geo/poll/dice,
724
+ * documents without a file, and several failure paths). An empty Buffer is
725
+ * truthy, so we guard on `.length`, not truthiness, in both the fallback and
726
+ * the final failure check — otherwise a 0-byte buffer would be returned as a
727
+ * "successful" (but garbage) download.
728
+ */
729
+ async downloadMediaAsBuffer(chatId, messageId, options) {
712
730
  if (!this.client || !this.connected)
713
731
  throw new Error(NOT_CONNECTED_ERROR);
714
732
  const resolved = await this.resolvePeer(chatId);
@@ -718,11 +736,19 @@ export class TelegramService {
718
736
  throw new Error(`Message ${messageId} not found`);
719
737
  if (!message.media)
720
738
  throw new Error(`Message ${messageId} has no media`);
721
- const buffer = (await this.client.downloadMedia(message));
722
- if (!buffer)
739
+ let isThumb = false;
740
+ let buffer;
741
+ if (options?.thumb !== undefined) {
742
+ buffer = (await this.client.downloadMedia(message, { thumb: options.thumb }));
743
+ isThumb = !!buffer?.length;
744
+ }
745
+ // No thumb requested, or this media has no thumbnail at that size → full file.
746
+ if (!buffer?.length)
747
+ buffer = (await this.client.downloadMedia(message));
748
+ if (!buffer?.length)
723
749
  throw new Error("Failed to download media");
724
750
  const mimeType = this.detectMimeType(buffer, message.media);
725
- return { buffer, mimeType };
751
+ return { buffer, mimeType, isThumb };
726
752
  }
727
753
  /** Detect MIME type from buffer magic bytes, falling back to media metadata */
728
754
  detectMimeType(buffer, media) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@overpod/mcp-telegram",
3
- "version": "1.39.1",
3
+ "version": "1.40.0",
4
4
  "description": "MCP server for Telegram userbot — messages, media, reactions, polls & more. Built on GramJS/MTProto.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",