Skip to content

Commit f4214c6

Browse files
authored
Merge pull request #124 from chigwell/123-resolve-unable-to-start-telegram-mcp-authentication
fix: improve error handling for unauthorized Telegram clients and update troubleshooting instructions
2 parents ba63fe8 + a63d3e4 commit f4214c6

3 files changed

Lines changed: 61 additions & 1 deletion

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,10 @@ Telegram messages, display names, chat titles, and button labels are untrusted c
380380
## Troubleshooting
381381

382382
- **No Telegram session configured:** set `TELEGRAM_SESSION_STRING`, `TELEGRAM_SESSION_NAME`, or suffixed multi-account variants.
383+
- **Session is not authorized:** run `uv run session_string_generator.py` outside
384+
the MCP server, use QR login when possible, then set `TELEGRAM_SESSION_STRING`
385+
in `.env`. The MCP server does not perform interactive phone-code login over
386+
stdio.
383387
- **Invalid API credentials:** verify `TELEGRAM_API_ID` and `TELEGRAM_API_HASH` at [my.telegram.org/apps](https://my.telegram.org/apps).
384388
- **Database is locked:** prefer string sessions, or make sure no other process is using the same file session.
385389
- **File tools are disabled:** pass allowed roots or configure MCP Roots in your client.

telegram_mcp/runner.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,27 @@
1111
import telegram_mcp.tools # noqa: F401 - registers MCP tools via decorators
1212

1313

14+
async def _connect_authorized_client(label, client) -> None:
15+
await client.connect()
16+
if await client.is_user_authorized():
17+
return
18+
19+
raise RuntimeError(
20+
f"Telegram client '{label}' is not authorized. Interactive phone login "
21+
"is disabled for the MCP server because it runs over stdio. Generate a "
22+
"session string with `uv run session_string_generator.py`, then set "
23+
"TELEGRAM_SESSION_STRING or TELEGRAM_SESSION_STRING_<LABEL> in .env. "
24+
"For existing file sessions, run the login outside the MCP server first."
25+
)
26+
27+
1428
async def _main() -> None:
1529
try:
1630
labels = ", ".join(clients.keys())
1731
print(f"Starting {len(clients)} Telegram client(s) ({labels})...", file=sys.stderr)
18-
await asyncio.gather(*(cl.start() for cl in clients.values()))
32+
await asyncio.gather(
33+
*(_connect_authorized_client(label, cl) for label, cl in clients.items())
34+
)
1935

2036
# Warm entity caches — StringSession has no persistent cache,
2137
# so fetch all dialogs once per client to populate them

tests/test_runner.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pytest
2+
3+
from telegram_mcp import runner
4+
5+
6+
class _FakeClient:
7+
def __init__(self, *, authorized: bool):
8+
self.authorized = authorized
9+
self.connected = False
10+
self.started = False
11+
12+
async def connect(self):
13+
self.connected = True
14+
15+
async def is_user_authorized(self):
16+
return self.authorized
17+
18+
async def start(self):
19+
self.started = True
20+
21+
22+
@pytest.mark.asyncio
23+
async def test_connect_authorized_client_uses_existing_session_without_interactive_start():
24+
client = _FakeClient(authorized=True)
25+
26+
await runner._connect_authorized_client("default", client)
27+
28+
assert client.connected is True
29+
assert client.started is False
30+
31+
32+
@pytest.mark.asyncio
33+
async def test_connect_authorized_client_rejects_unauthorized_session():
34+
client = _FakeClient(authorized=False)
35+
36+
with pytest.raises(RuntimeError, match="Interactive phone login is disabled"):
37+
await runner._connect_authorized_client("default", client)
38+
39+
assert client.connected is True
40+
assert client.started is False

0 commit comments

Comments
 (0)