Skip to content

Commit 694e5f8

Browse files
vishalhabib99claude
andcommitted
fix(tools): accept null for optional arguments that default to None
130 arguments on 111 tools (`account` on 111 of them) were annotated `str`/`int`/`bool` with a `None` default. The schema advertises `"default": null` but types them non-nullable, so a client that sends the advertised default gets a validation error before the tool runs. Annotate them `Optional[T]` and add a schema test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 9760717 commit 694e5f8

7 files changed

Lines changed: 179 additions & 127 deletions

File tree

‎telegram_mcp/tools/chats.py‎

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def from_reader(cls, reader):
156156

157157
@mcp.tool(annotations=ToolAnnotations(title="Get Chats", openWorldHint=True, readOnlyHint=True))
158158
@with_account(readonly=True)
159-
async def get_chats(account: str = None, page: int = 1, page_size: int = 20) -> str:
159+
async def get_chats(account: Optional[str] = None, page: int = 1, page_size: int = 20) -> str:
160160
"""
161161
Get a paginated list of chats.
162162
Args:
@@ -204,7 +204,7 @@ async def get_chats(account: str = None, page: int = 1, page_size: int = 20) ->
204204
)
205205
@with_account(readonly=False)
206206
@validate_id("channel")
207-
async def subscribe_public_channel(channel: Union[int, str], account: str = None) -> str:
207+
async def subscribe_public_channel(channel: Union[int, str], account: Optional[str] = None) -> str:
208208
"""
209209
Subscribe (join) to a public channel or supergroup by username or ID.
210210
@@ -236,8 +236,8 @@ async def list_topics(
236236
chat_id: Union[int, str],
237237
limit: int = 200,
238238
offset_topic: int = 0,
239-
search_query: str = None,
240-
account: str = None,
239+
search_query: Optional[str] = None,
240+
account: Optional[str] = None,
241241
) -> str:
242242
"""
243243
Retrieve forum topics from a supergroup with the forum feature enabled.
@@ -329,7 +329,7 @@ async def list_topics(
329329
@with_account(readonly=False)
330330
@validate_id("chat_id")
331331
async def enable_forum_topics(
332-
chat_id: Union[int, str], tabs: bool = True, account: str = None
332+
chat_id: Union[int, str], tabs: bool = True, account: Optional[str] = None
333333
) -> str:
334334
"""
335335
Enable Telegram forum topics for a supergroup.
@@ -374,9 +374,9 @@ async def enable_forum_topics(
374374
async def create_forum_topic(
375375
chat_id: Union[int, str],
376376
title: str,
377-
icon_color: int = None,
378-
icon_emoji_id: int = None,
379-
account: str = None,
377+
icon_color: Optional[int] = None,
378+
icon_emoji_id: Optional[int] = None,
379+
account: Optional[str] = None,
380380
) -> str:
381381
"""
382382
Create a Telegram forum topic in a forum-enabled supergroup.
@@ -479,11 +479,11 @@ def _forum_supergroup_error(entity) -> Optional[str]:
479479
async def edit_forum_topic(
480480
chat_id: Union[int, str],
481481
topic_id: int,
482-
title: str = None,
483-
icon_emoji_id: int = None,
484-
closed: bool = None,
485-
hidden: bool = None,
486-
account: str = None,
482+
title: Optional[str] = None,
483+
icon_emoji_id: Optional[int] = None,
484+
closed: Optional[bool] = None,
485+
hidden: Optional[bool] = None,
486+
account: Optional[str] = None,
487487
) -> str:
488488
"""
489489
Edit a forum topic in a forum-enabled supergroup. Pass only the fields to change.
@@ -556,7 +556,7 @@ async def edit_forum_topic(
556556
async def delete_forum_topic(
557557
chat_id: Union[int, str],
558558
topic_id: int,
559-
account: str = None,
559+
account: Optional[str] = None,
560560
) -> str:
561561
"""
562562
Delete a forum topic together with all of its messages. This cannot be undone.
@@ -605,13 +605,13 @@ async def delete_forum_topic(
605605
@mcp.tool(annotations=ToolAnnotations(title="List Chats", openWorldHint=True, readOnlyHint=True))
606606
@with_account(readonly=True)
607607
async def list_chats(
608-
chat_type: str = None,
608+
chat_type: Optional[str] = None,
609609
limit: int = 20,
610610
unread_only: bool = False,
611611
unmuted_only: bool = False,
612-
archived: bool = None,
612+
archived: Optional[bool] = None,
613613
with_about: bool = False,
614-
account: str = None,
614+
account: Optional[str] = None,
615615
) -> str:
616616
"""
617617
List available chats with metadata.
@@ -754,7 +754,7 @@ async def list_chats(
754754
@mcp.tool(annotations=ToolAnnotations(title="Get Chat", openWorldHint=True, readOnlyHint=True))
755755
@with_account(readonly=True)
756756
@validate_id("chat_id")
757-
async def get_chat(chat_id: Union[int, str], account: str = None) -> str:
757+
async def get_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
758758
"""
759759
Get detailed information about a specific chat.
760760
@@ -867,7 +867,7 @@ async def get_chat(chat_id: Union[int, str], account: str = None) -> str:
867867
annotations=ToolAnnotations(title="Search Public Chats", openWorldHint=True, readOnlyHint=True)
868868
)
869869
@with_account(readonly=True)
870-
async def search_public_chats(query: str, limit: int = 20, account: str = None) -> str:
870+
async def search_public_chats(query: str, limit: int = 20, account: Optional[str] = None) -> str:
871871
"""
872872
Search for public chats, channels, or bots by username or title.
873873
"""
@@ -888,7 +888,7 @@ async def search_public_chats(query: str, limit: int = 20, account: str = None)
888888
annotations=ToolAnnotations(title="Resolve Username", openWorldHint=True, readOnlyHint=True)
889889
)
890890
@with_account(readonly=True)
891-
async def resolve_username(username: str, account: str = None) -> str:
891+
async def resolve_username(username: str, account: Optional[str] = None) -> str:
892892
"""
893893
Resolve a username to a user or chat ID.
894894
"""
@@ -906,7 +906,7 @@ async def resolve_username(username: str, account: str = None) -> str:
906906
)
907907
@with_account(readonly=True)
908908
@validate_id("chat_id")
909-
async def get_full_chat(chat_id: Union[int, str], account: str = None) -> str:
909+
async def get_full_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
910910
"""
911911
Get full info of a channel or group including description/about text.
912912
@@ -974,7 +974,7 @@ async def get_full_chat(chat_id: Union[int, str], account: str = None) -> str:
974974
)
975975
@with_account(readonly=False)
976976
@validate_id("chat_id")
977-
async def mute_chat(chat_id: Union[int, str], account: str = None) -> str:
977+
async def mute_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
978978
"""
979979
Mute notifications for a chat.
980980
"""
@@ -1017,7 +1017,7 @@ async def mute_chat(chat_id: Union[int, str], account: str = None) -> str:
10171017
)
10181018
@with_account(readonly=False)
10191019
@validate_id("chat_id")
1020-
async def unmute_chat(chat_id: Union[int, str], account: str = None) -> str:
1020+
async def unmute_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
10211021
"""
10221022
Unmute notifications for a chat.
10231023
"""
@@ -1060,7 +1060,7 @@ async def unmute_chat(chat_id: Union[int, str], account: str = None) -> str:
10601060
)
10611061
@with_account(readonly=False)
10621062
@validate_id("chat_id")
1063-
async def archive_chat(chat_id: Union[int, str], account: str = None) -> str:
1063+
async def archive_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
10641064
"""
10651065
Archive a chat.
10661066
"""
@@ -1085,7 +1085,7 @@ async def archive_chat(chat_id: Union[int, str], account: str = None) -> str:
10851085
)
10861086
@with_account(readonly=False)
10871087
@validate_id("chat_id")
1088-
async def unarchive_chat(chat_id: Union[int, str], account: str = None) -> str:
1088+
async def unarchive_chat(chat_id: Union[int, str], account: Optional[str] = None) -> str:
10891089
"""
10901090
Unarchive a chat.
10911091
"""
@@ -1109,7 +1109,7 @@ async def unarchive_chat(chat_id: Union[int, str], account: str = None) -> str:
11091109
@with_account(readonly=True)
11101110
@validate_id("user_id")
11111111
async def get_common_chats(
1112-
user_id: Union[int, str], limit: int = 100, max_id: int = 0, account: str = None
1112+
user_id: Union[int, str], limit: int = 100, max_id: int = 0, account: Optional[str] = None
11131113
) -> str:
11141114
"""
11151115
List chats shared with a specific user.
@@ -1163,7 +1163,7 @@ async def get_common_chats(
11631163
@with_account(readonly=True)
11641164
@validate_id("chat_id")
11651165
async def get_message_read_by(
1166-
chat_id: Union[int, str], message_id: int, account: str = None
1166+
chat_id: Union[int, str], message_id: int, account: Optional[str] = None
11671167
) -> str:
11681168
"""
11691169
List user IDs who have read a specific message.
@@ -1251,7 +1251,7 @@ async def get_message_read_by(
12511251
@with_account(readonly=True)
12521252
@validate_id("chat_id")
12531253
async def get_message_link(
1254-
chat_id: Union[int, str], message_id: int, thread: bool = False, account: str = None
1254+
chat_id: Union[int, str], message_id: int, thread: bool = False, account: Optional[str] = None
12551255
) -> str:
12561256
"""
12571257
Export a t.me/... link for a specific message.

‎telegram_mcp/tools/folders.py‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def _folder_state(f, self_id=None):
155155
annotations=ToolAnnotations(title="Get Folder Limits", openWorldHint=True, readOnlyHint=True)
156156
)
157157
@with_account(readonly=True)
158-
async def get_folder_limits(account: str = None) -> str:
158+
async def get_folder_limits(account: Optional[str] = None) -> str:
159159
"""Read effective Premium-aware folder, explicit-chat and pin limits from app config.
160160
161161
Missing/unusable values are null, never invented defaults. Title limit uses UTF-16 units.
@@ -170,7 +170,7 @@ async def get_folder_limits(account: str = None) -> str:
170170
annotations=ToolAnnotations(title="Get Folder Snapshot", openWorldHint=True, readOnlyHint=True)
171171
)
172172
@with_account(readonly=True)
173-
async def get_folder_snapshot(account: str = None) -> str:
173+
async def get_folder_snapshot(account: Optional[str] = None) -> str:
174174
"""Read complete folder definitions and order without chat content or access hashes.
175175
176176
Private definition objects can be passed as update_folder patches to restore state.
@@ -294,7 +294,7 @@ async def update_folder(
294294
folder_id: int,
295295
patch: Dict[str, Any],
296296
expected_revision: Optional[str] = None,
297-
account: str = None,
297+
account: Optional[str] = None,
298298
) -> str:
299299
"""Patch an existing PRIVATE folder by ID, preserving every omitted field.
300300
@@ -423,7 +423,7 @@ async def update_folder(
423423

424424
@mcp.tool(annotations=ToolAnnotations(title="List Folders", openWorldHint=True, readOnlyHint=True))
425425
@with_account(readonly=True)
426-
async def list_folders(account: str = None) -> str:
426+
async def list_folders(account: Optional[str] = None) -> str:
427427
"""
428428
Get all dialog folders (filters) with their IDs, names, and emoji.
429429
Returns a list of folders that can be used with other folder tools.
@@ -489,7 +489,7 @@ async def list_folders(account: str = None) -> str:
489489

490490
@mcp.tool(annotations=ToolAnnotations(title="Get Folder", openWorldHint=True, readOnlyHint=True))
491491
@with_account(readonly=True)
492-
async def get_folder(folder_id: int, account: str = None) -> str:
492+
async def get_folder(folder_id: int, account: Optional[str] = None) -> str:
493493
"""
494494
Get detailed information about a specific folder including all included chats.
495495
@@ -612,7 +612,7 @@ async def create_folder(
612612
exclude_muted: bool = False,
613613
exclude_read: bool = False,
614614
exclude_archived: bool = True,
615-
account: str = None,
615+
account: Optional[str] = None,
616616
) -> str:
617617
"""
618618
Create a new dialog folder.
@@ -724,7 +724,7 @@ async def add_chat_to_folder(
724724
folder_id: int,
725725
chat_id: Union[int, str],
726726
pinned: bool = False,
727-
account: str = None,
727+
account: Optional[str] = None,
728728
) -> str:
729729
"""
730730
Add a chat to an existing folder.
@@ -827,7 +827,7 @@ async def add_chat_to_folder(
827827
@with_account(readonly=False)
828828
@validate_id("chat_id")
829829
async def remove_chat_from_folder(
830-
folder_id: int, chat_id: Union[int, str], account: str = None
830+
folder_id: int, chat_id: Union[int, str], account: Optional[str] = None
831831
) -> str:
832832
"""
833833
Remove a chat from a folder.
@@ -931,7 +931,7 @@ async def remove_chat_from_folder(
931931
)
932932
)
933933
@with_account(readonly=False)
934-
async def delete_folder(folder_id: int, account: str = None) -> str:
934+
async def delete_folder(folder_id: int, account: Optional[str] = None) -> str:
935935
"""
936936
Delete a folder. Chats in the folder are preserved, only the folder is removed.
937937
@@ -977,7 +977,7 @@ async def delete_folder(folder_id: int, account: str = None) -> str:
977977
)
978978
)
979979
@with_account(readonly=False)
980-
async def reorder_folders(folder_ids: List[int], account: str = None) -> str:
980+
async def reorder_folders(folder_ids: List[int], account: Optional[str] = None) -> str:
981981
"""
982982
Change the order of folders in the folder list.
983983

0 commit comments

Comments
 (0)