Commit graph

196 commits

Author SHA1 Message Date
michaotic
2ee39ee069 Disable write operations for read-only mode
Some checks failed
Docker Build & Compose Validation / Build Docker Image (push) Has been cancelled
Python Lint & Format Check / Check Linting & Formatting (push) Has been cancelled
Docker Build & Compose Validation / Build & Validate Docker Compose (push) Has been cancelled
- Commented out all @mcp.tool decorators without readOnlyHint=True
- 47 write tools disabled (send_message, create_group, ban_user, etc.)
- 47 read-only tools remain active (get_chats, get_messages, search_messages, etc.)
- Created Python script to automate disabling process
- Now completely read-only - no accidental message sending possible
2026-04-12 03:22:25 +03:00
Eugene Evstafev
ef01a39159
Merge pull request #97 from bunkerskyi/feat/send-contact
feat(tools): add send_contact tool to send phone contacts via Telegram
2026-04-09 09:33:26 +01:00
Eugene Evstafev
589fa53c7d
Merge pull request #95 from bunkerskyi/fix/inline-buttons-reply-markup-fallback
fix(tools): fall back to reply_markup when buttons property is None for bot messages
2026-04-09 09:31:03 +01:00
Eugene Evstafev
62d5be5ed5
Merge pull request #96 from bunkerskyi/fix/get-messages-json-output
fix(tools): escape newlines in get_messages output to preserve line-based format
2026-04-09 09:28:54 +01:00
Ivan Kolodrivskyi
e2ca3c78fe style: apply black formatting to send_contact 2026-04-09 09:23:14 +03:00
Ivan Kolodrivskyi
b2c3a865d8 style: apply black formatting to list_inline_buttons 2026-04-09 09:20:43 +03:00
Ivan Kolodrivskyi
cf6888e000 fix: fall back to reply_markup when buttons property is None for bot messages
Telethon's client.get_messages(entity, ids=N) sometimes returns bot messages
with buttons=None and reply_markup=None, even when the message has inline
keyboard buttons. The same message fetched via history (limit=N) includes
the full ReplyInlineMarkup.

Changes:
- Add fallback: when message fetched by ID has no inline buttons, re-fetch
  via history and match by ID
- Check both msg.buttons and msg.reply_markup.rows when searching for
  messages with buttons
- Access .data/.url/.text directly on button objects (works for both
  MessageButton wrappers and raw KeyboardButtonCallback objects)
2026-04-09 08:35:20 +03:00
Ivan Kolodrivskyi
b38051a9ee fix: escape newlines in get_messages instead of switching to JSON
Replace the JSON output approach with a non-breaking fix: escape newlines
in message text (\n → \\n) to preserve the existing pipe-delimited format.
This fixes multi-line message parsing without breaking downstream consumers.
2026-04-09 08:34:50 +03:00
Ivan Kolodrivskyi
ff37abdb01 fix: return JSON from get_messages to preserve multi-line message text
The pipe-delimited text format (ID: N | ... | Message: <text>) breaks when
messages contain newlines, since \n serves as both record separator and can
appear inside message text. Downstream parsers that split on \n only capture
the first line

Switch to a JSON array output with fields: id, sender, date, text,
reply_to (optional), and engagement (optional, with views/forwards/reactions)

This is a breaking change for MCP clients that parse the old text format.
Since MCP tool results are typically consumed by LLMs which handle JSON
natively, this should be transparent for most consumers
2026-04-09 08:34:38 +03:00
Ivan Kolodrivskyi
0185e2e36b feat: add send_contact tool to send phone contacts via MCP 2026-04-08 19:29:26 +03:00
Eugene Evstafev
e96a6a8ca2
Merge pull request #94 from DzmingLi/fix/graceful-disconnect
fix: gracefully disconnect Telegram client on exit
2026-04-06 10:04:12 +01:00
Dzming Li
53589ba836 fix: gracefully disconnect Telegram client on exit
Without calling `client.disconnect()`, the TCP connection to Telegram's
servers is abandoned when the process exits. If the server restarts
quickly (common with MCP stdio servers), Telegram sees two connections
using the same auth key simultaneously and permanently revokes it with
`AuthKeyDuplicatedError`, requiring the user to regenerate their session.

Add a `finally` block to `_main()` so `client.disconnect()` is always
called on exit, allowing Telegram's servers to clean up the connection
state promptly.
2026-04-06 05:20:47 +08:00
Eugene Evstafev
a050889fc8
Merge pull request #86 from jonasasx/fix/download-media-extension-detection
fix: strip extension in download_media to auto-detect real file type
2026-04-01 12:12:10 +01:00
Ivan Volynkin
130631f4ae fix: strip extension in download_media to auto-detect real file type
When a caller passes a file_path with an explicit extension (e.g. ticket.jpg),
Telethon honours that extension verbatim even if the actual media is a PDF.
Stripping the suffix before calling client.download_media() lets Telethon
append the correct extension based on the real file content.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 20:44:21 +03:00
Eugene Evstafev
0b1e2b48fd
Merge pull request #84 from dsvetlov/feat/unread-mentions-count
feat: show unread mentions count in list_chats output
2026-03-31 16:34:11 +01:00
Daniil Svetlov
8d13a45a67 merge: resolve conflict with upstream main
Keep both Muted status from upstream and Unread mentions from this branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 18:32:14 +03:00
Eugene Evstafev
67079db905
Merge pull request #78 from dsvetlov/feat/list-chats-filters
feat: add unread_only, unmuted_only filters and mute status to list_chats
2026-03-31 16:28:04 +01:00
Daniil Svetlov
1be48cc6fd feat: show unread mentions count in list_chats output
Display unread_mentions_count for each chat when it is greater than zero.
The value is already available on the dialog object from Telegram API,
so this adds no extra API calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 18:25:34 +03:00
Daniil Svetlov
73c45f9106 style: format list_chats with black
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 18:23:00 +03:00
Kamil
f2deb6a33a
Merge pull request #80 from chigwell/chigwell-patch-3 2026-03-27 20:20:04 +03:00
Eugene Evstafev
3502aa9ec6
docs: add Contributors section to README 2026-03-27 17:00:36 +00:00
Daniil Svetlov
a718a2262d feat: add unread_only, unmuted_only filters and mute status to list_chats
Add filtering capabilities to the list_chats tool:
- unread_only: filter to show only chats with unread messages
- unmuted_only: filter to show only unmuted chats
- Display mute status in chat info output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 02:20:47 +03:00
Eugene Evstafev
71cdefa55c
Merge pull request #77 from nathanschram/fix/entity-resolution-stringsession
fix: resolve entity cache miss for StringSession users
2026-03-18 08:49:18 +00:00
Nathan Schram
2e87007da2 fix: restore parse_mode and safe-path handling
Address review feedback from @chigwell and @l1v0n1:

- Restore parse_mode=parse_mode in send_message and reply_to_message
- Restore _resolve_readable_file_path() in send_file, send_voice,
  send_sticker, and edit_chat_photo
- Use str(safe_path) instead of raw file_path in upload_file calls

The entity cache fix (resolve_entity/resolve_input_entity) is preserved
in all affected functions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:36:27 +11:00
Eugene Evstafev
dad686a2d5
Merge branch 'main' into fix/entity-resolution-stringsession 2026-03-17 09:33:58 +00:00
Eugene Evstafev
a39a7c99ae
Merge pull request #74 from mxl/feat/global-message-search
Add global message search
2026-03-17 09:29:45 +00:00
Eugene Evstafev
418cc8bbd1
Merge pull request #75 from mxl/feat/search-public-chats-pagination
Add limit parameter to public chat search
2026-03-17 09:28:46 +00:00
Nathan Schram
a5da0d6b6b fix: resolve entity cache miss for StringSession users
StringSession has no persistent entity cache. After each MCP server
restart, client.get_entity(positive_int) fails for basic group chats
because Telethon interprets positive integers as PeerUser IDs when
they're not in the cache.

Fix:
- Add resolve_entity() / resolve_input_entity() helpers that retry
  after warming cache via get_dialogs() on ValueError
- Warm entity cache on startup in _main()
- Replace all ~72 client.get_entity() / client.get_input_entity()
  call sites with the new helpers

Tested: 60/60 pass across 6 basic group chats (send_message,
get_history, reply, edit, draft, reactions, search, mark_as_read,
delete) with cold cache -> warm cache transition verified.

Fixes chigwell/telegram-mcp#76
2026-03-17 14:10:47 +11:00
mxl
8273ade003 Add pagination to global message search 2026-03-16 19:17:10 -07:00
mxl
0840b76a67 Update README for public chat search limit 2026-03-16 19:00:50 -07:00
mxl
e7421759bd Add limit parameter to public chat search 2026-03-16 18:34:12 -07:00
Eugene Evstafev
49c912d6eb
Merge pull request #73 from mxl/fix/search-public-chats-include-chats
fix: include chats and channels in search_public_chats results
2026-03-16 08:28:02 +00:00
Eugene Evstafev
14d1235bc2
Merge pull request #72 from mxl/fix/shared-folders-chatlist-support
fix: add support for shared folders (DialogFilterChatlist) in folder operations
2026-03-16 08:27:46 +00:00
mxl
51b71f1dce fix: include chats and channels in search_public_chats results
contacts.SearchRequest returns both result.users and result.chats,
but only users were returned. Chats (channels, groups) are now
included, making search work by channel/group title as intended.
2026-03-16 09:48:42 +03:00
mxl
b0b568bf82 fix: add support for shared folders (DialogFilterChatlist) in folder operations
Shared folders in Telegram use DialogFilterChatlist type instead of
DialogFilter. Previously, all folder operations (list, get, create,
add/remove chat) silently ignored shared folders. This fix ensures
they are recognized and handled correctly alongside regular folders.
2026-03-16 06:50:02 +03:00
Eugene Evstafev
26b1287a5b
Merge pull request #69 from oplexz/main
Implement login via QR-code in session_string_generator; bump Telethon to 1.42.0
2026-03-05 08:15:15 +00:00
Daniil Isakov
03f3321942 style: format session_string_generator.py with black 2026-03-05 02:55:57 +03:00
Daniil Isakov
c39cde69f7 Merge remote-tracking branch 'upstream/main' 2026-03-05 02:55:07 +03:00
Eugene Evstafev
dbb0a47808
Merge pull request #70 from onsails/fix/stderr-startup-messages
fix: redirect all print() to stderr to keep stdout clean for MCP stdio
2026-03-04 19:47:43 +00:00
Andrey Kuznetsov
a53d807146
fix: redirect all print() to stderr to keep stdout clean for MCP stdio
MCP clients (e.g. ZeroClaw) communicate via JSON-RPC over stdin/stdout.
Startup messages and warnings written to stdout corrupt the protocol
stream, causing parse failures. Redirect all print() calls to stderr.
2026-03-04 23:16:23 +04:00
Daniil Isakov
6d5e548937 chore(dependencies): update uv.lock 2026-02-28 04:14:38 +03:00
Daniil Isakov
fa11aaaf88 feat(session_string_generator): implement QR code and phone number login methods for Telegram session generation 2026-02-28 04:14:22 +03:00
Daniil Isakov
021298dae5 chore(dependencies): update telethon to 1.42.0 and add qrcode dependency 2026-02-28 04:14:15 +03:00
Daniil Isakov
876506e038 chore(dependencies): update telethon to version 1.42.0 and add qrcode dependency 2026-02-28 04:14:08 +03:00
Eugene Evstafev
61924fb2a1
Merge pull request #67 from bunkerskyi/fix/delete-profile-photo
fix(delete_profile_photo): pass Photo object instead of int to DeletePhotosRequest
2026-02-26 09:18:40 +00:00
Eugene Evstafev
c13982b173
Merge pull request #68 from bunkerskyi/feat/parse-mode-in-send-message
feat(tools): expose parse_mode in send_message and reply_to_message
2026-02-26 08:54:04 +00:00
Ivan Kolodrivskyi
fb620cd670 feat(tools): expose parse_mode in send_message and reply_to_message 2026-02-26 08:52:28 +02:00
Ivan Kolodrivskyi
2e1bfc3d94 fix(delete_profile_photo): pass Photo object instead of int to DeletePhotosRequest
Telethon's DeletePhotosRequest requires InputPhoto objects, which it derives
from Photo objects via get_input_photo(). Passing photo.id (an int) causes:
  AttributeError: 'int' object has no attribute 'SUBCLASS_OF_ID'
  TypeError: Cannot cast int to any kind of InputPhoto.

Fix: pass the Photo object directly (photos.photos[0]) so Telethon can
convert it to InputPhoto internally.
2026-02-26 08:42:05 +02:00
Eugene Evstafev
8c4b671c12
Merge pull request #64 from iqdoctor/feat/issue-39-filepath-roots
feat: secure file-path tools with allowlisted roots (issue #39)
2026-02-25 08:05:45 +00:00
vp
6ec5c95c91 fix: harden roots unsupported fallback and deny-all messaging 2026-02-24 23:02:38 +03:00