Skip to content

type account param as Optional[str] to fix single-account tool failures - #137

Merged
chigwell merged 1 commit into
chigwell:mainfrom
srijanAtGithub:fix/optional-account-param
Jun 3, 2026
Merged

type account param as Optional[str] to fix single-account tool failures#137
chigwell merged 1 commit into
chigwell:mainfrom
srijanAtGithub:fix/optional-account-param

Conversation

@srijanAtGithub

Copy link
Copy Markdown
Contributor

Problem

All tool functions declare the account parameter as account: str = None.

In Pydantic v2, this generates a JSON schema that marks account as a required
string field — despite the None default. When an LLM-backed MCP client receives
this schema, it treats account as required and passes an empty string "" when
it has no value to supply.

get_client("") then raises: ValueError: Unknown account ''. Available accounts: default

This breaks every tool call in single-account setups, which is the most common
configuration and is documented as supported.


How to reproduce

Set up the server in single-account mode. Connect any LLM-backed MCP client.
Then try these two prompts back to back:

Prompt 1 — fails:

"What is the last message from my contact named Alice?"

The LLM picks list_contacts or get_contact_ids, passes account="", and gets
a CONTACT-ERR-* error. The tool never executes.

Prompt 2 — works (same intent, split into two steps):

"Is there a contact named Alice in Telegram?"
(after it responds) "Get her last message."

In step one, the LLM picks search_contacts which has a query param to focus
on, so it omits account entirely. get_client(None) auto-selects the only
configured account and succeeds. Step two then uses chat_id directly, also
bypassing the account problem.

Same underlying intent. Same tools available. The only difference is whether
the LLM feels obligated to fill account.


Root cause

Pydantic v2 no longer infers Optional from field: str = None. The correct
annotation is Optional[str].

# Before — Pydantic v2 emits {"type": "string"} — looks required to the client
async def list_contacts(account: str = None) -> str:

# After — emits {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null}
async def list_contacts(account: Optional[str] = None) -> str:

With the correct annotation, LLM clients see account as optional and omit it.
get_client(None) then auto-selects the single configured account, as intended.
No logic in runtime.py needed to change.


Change

account: str = Noneaccount: Optional[str] = None across all tool files.
No behavior change. No logic change. Purely a type annotation correction.

Files changed:

  • telegram_mcp/tools/contacts.py

  • (will change other files in the similar manner after testing and verifying that no new issues are introduced)


Affected users

Anyone running single-account mode with an LLM-backed MCP client
(Claude Desktop via langchain-mcp-adapters, Cursor, or similar).
Direct programmatic callers are unaffected.

@chigwell
chigwell merged commit 4a5c7c1 into chigwell:main Jun 3, 2026
4 checks passed
KiaroSama pushed a commit to KiaroSama/telegram-mcp that referenced this pull request Aug 25, 2026
…unt-param

type account param as Optional[str] to fix single-account tool failures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants