Tool catalogue, scopes, storage schema, and release checklist for the mctl-telegram MCP connector.
https://tg-preview.mctl.ai/mcp. See landing → Install in ChatGPT for the full flow.https://tg-preview.mctl.ai/.well-known/oauth-authorization-server.https://tg-preview.mctl.ai/mcp and auth to OAuth.list_dialogs) before submitting for review.https://tg-preview.mctl.ai/, privacy https://tg-preview.mctl.ai/privacy, support [email protected]./, /docs, /security, and /privacy are accessible over HTTPS./.well-known/oauth-protected-resource on your host, then follow the authorization_servers URL it advertises and confirm that server's /.well-known/oauth-authorization-server resolves. In local-jwt mode that is your own host; in shared-hmac mode it is api.mctl.ai.initialize, list tools, and one read-only tool call with MCP Inspector or ChatGPT Developer Mode.ALLOW_SEND=false keeps all sends in dry-run until all opt-in gates are enabled.[email protected] published on landing and privacy pages.readOnlyHint, openWorldHint, and destructiveHint justifications for each tool in the submission form.| Tool | Mode | Scope required | Notes |
|---|---|---|---|
list_dialogs |
read | telegram:dialogs:read |
Inputs: limit (≤200, default 50), optional query. |
get_unread_messages |
read | telegram:messages:read |
Inputs: optional peer, limit (≤200). |
get_messages |
read | telegram:messages:read |
Full history of a specific peer, not just unread. |
send_message |
write | telegram:messages:send |
No mode argument — the gate decides. On tg.mctl.ai, ALLOW_SEND=false blocks real sends and returns a dry-run preview (sent=false, with dry_reason). A real send additionally requires identity scope and per-account send_enabled=true. |
pin_message |
write | telegram:messages:pin |
Inputs: peer, message_id, unpin (bool). |
disconnect_telegram_account |
write | any authenticated identity | Soft-revokes your session — see Your controls. |
delete_telegram_account |
write | any authenticated identity | Hard-deletes the encrypted session blob. |
list_telegram_identities |
read | admin:users |
Admin only. Roster of signed-in users with access tier and session state. |
set_telegram_access |
write | admin:users |
Admin only. Grant/revoke the client tier for a Telegram id. |
Scopes are derived from your Telegram identity. Operators on the admin allowlist
(TG_LOGIN_ADMINS) get the full platform-admins set.
Everyone else gets the client tier — the telegram:* tool
scopes for their own account, without
platform-admin capability. When AUTO_APPROVE_CLIENTS is enabled
(open registration) every signed-in user is a client automatically; otherwise
the client tier comes from the TG_LOGIN_CLIENTS allowlist or an
operator grant. An operator can revoke any user with
set_telegram_access.
| Telegram identity | Scopes granted |
|---|---|
Telegram id ∈ TG_LOGIN_ADMINS | all telegram:* scopes plus admin:users |
Telegram id ∈ TG_LOGIN_CLIENTS | telegram:* scopes (dialogs/messages read, send, pin) — no admin:users |
| Any other authenticated Telegram id | none — every tool call returns 403 until the operator opts you in |
For backward compatibility the server can still be run under
AUTH_MODE=shared-hmac-legacy, in which case the original
GitHub-group→scope mapping applies. The default mode is local-jwt.
| Row | Contents | Retention |
|---|---|---|
users |
telegram_login_id, telegram_username, telegram_display_name (synthetic github_login=tg:<id> kept for legacy joins). Legacy rows may still carry a real github_login. |
Until you call delete_telegram_account (cascades). |
telegram_accounts |
AES-256-GCM-sealed MTProto session blob, per-user HKDF-derived key. | Until you call disconnect (marked revoked) or delete (row removed). |
audit_logs |
Tool name, redacted peer reference, status, error. Never the message body, phone number, or session bytes. | Retained for 90 days, then removed by the audit-log sweeper (window configurable via AUDIT_RETENTION_DAYS; set to 0 to keep indefinitely). Ask the operator if you need an earlier purge. |
disconnect_telegram_account, or POST /api/account/disconnect. Marks the session revoked and immediately tears down the in-memory MTProto client.delete_telegram_account, or DELETE /api/account. Removes the encrypted session blob and all per-account metadata.GET /api/account returns connection state, display name, and the per-account send_enabled flag.get_my_audit_log MCP tool or GET /api/account/audit — newest-first, RFC3339 before cursor for keyset pagination.GET /api/account/audit/verify recomputes the SHA-256 hash chain over your rows and reports {ok, verified} or {ok:false, first_bad_id, reason}.Confirm the well-known and a JSON-RPC handshake before adding the connector:
curl -s https://tg-preview.mctl.ai/.well-known/oauth-protected-resource
curl -s -X POST https://tg-preview.mctl.ai/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-03-26","capabilities":{},
"clientInfo":{"name":"smoke","version":"0"}}}'
Sign-in via a ChatGPT App or Claude connector authenticates you with Telegram OIDC.
If the server has no MTProto session for your account yet, the connect flow continues
straight into an in-browser "Enable message access"
step: enter your phone number, type the login code Telegram sends you, and — if your
account uses it — your two-step verification password. The server then persists an
AES-256-GCM-encrypted MTProto session keyed to your Telegram identity, and the
connector is ready — no operator CLI step required. The bundled
mctl-telegram-login CLI remains available for operators as a fallback.
Full details in the repo
README.