Developer reference
Connection details, tool catalogue, scopes, and account controls for the MCTL MCP server.
On this page: connect · tools · scopes · storage · controls · smoke test · Local Bridge
Connect a client
- Claude (claude.ai, desktop, mobile): Customize → Connectors → Add custom connector, name
MCTL Assistant, MCP server URLhttps://tg.mctl.ai/mcp, default sign-in settings. Team and Enterprise Owners add it under Organization settings → Connectors. Step by step: Connect in Claude. - Claude Code:
claude mcp add --transport http --scope user mctl https://tg.mctl.ai/mcp, then/mcpto sign in. - ChatGPT and other clients: add
https://tg.mctl.ai/mcpas a remote MCP server with OAuth; in ChatGPT that is Plugins → Personal → Add → Add custom MCP server, nameMCTL Assistant, Create as a plugin. Per-client notes: Other MCP clients. MCTL is not listed in the public plugin directory; adding it as your own plugin is the supported path. Cursor, VS Code and Windsurf are not yet tested against tg.mctl.ai.
OAuth
- Discovery: MCTL is its own authorization server. Clients find it through https://tg.mctl.ai/.well-known/oauth-protected-resource and
https://tg.mctl.ai/.well-known/oauth-authorization-server. - Client registration: tg.mctl.ai supports both Client ID Metadata Documents (CIMD — what Claude uses by default) and Dynamic Client Registration, so no client ID or secret has to be entered by hand. A self-hosted deployment advertises CIMD only when it is enabled; /platforms shows this deployment's live setting. Authorization code with PKCE
S256only. Platforms that connect many users: see /platforms.
First sign-in
- Sign in with Telegram in the browser window your client opens (Telegram's own OpenID Connect login).
- Permissions: if the server has no Telegram session for you yet, choose Read only (the default) or Read + send. You can change it later with
set_send_consentor on the manage page. - Phone number: enter it, then the login code Telegram sends to your Telegram app, and your two-step verification password if you use one. The server stores an AES-256-GCM-encrypted MTProto session keyed to your Telegram identity, and the connector is ready.
Available tools
A connection sees only the tools its scopes allow: tools/list is filtered by the token, and a call to any other tool is refused as an unknown tool. The full surface, with input schemas and readOnlyHint/destructiveHint annotations, is committed as docs/tool-descriptors.json, and every change to it is announced in product updates.
| Tool | Mode | Scope required | Notes |
|---|---|---|---|
list_dialogs | read | telegram:dialogs:read | Your chats with type, title, username and unread count. limit (default 50, up to 200), optional query. |
get_messages | read | telegram:messages:read | Recent history of one chat, not just unread. |
get_unread_messages | read | telegram:messages:read | Unread messages, optionally for one chat. limit up to 200. |
search_messages | read | telegram:messages:read | query, optional peer, limit (default 20, up to 100), min_date/max_date (inclusive UTC, RFC 3339 or YYYY-MM-DD). Newest first. |
prepare_get_media, get_media | read | telegram:messages:read | Inspect a message's media, then download it with the returned confirmation_id. |
send_message, prepare_send_message | write | telegram:messages:send | Send a text message; prepare_send_message snapshots it for confirmation first. No mode argument — the send gate decides: a real send needs ALLOW_SEND=true on the server (on for tg.mctl.ai), the scope, and your own send_enabled=true (a new read-only account has send_enabled=false). Otherwise it returns a preview (sent=false with dry_reason). |
send_media | write | telegram:messages:send | Photo, video, document, animation or voice note with an optional caption. Same send gate. |
edit_message, delete_messages, forward_messages, set_reaction | write | telegram:messages:send | Edit your own message, delete, forward between chats, add or remove a reaction. Same send gate. |
prepare_pin_message, pin_message | write | telegram:messages:pin | Pin or unpin after a confirmation step. Needs pin rights in the chat and the same send gate. |
draft_reply, send_reply | write | telegram:messages:send | Only on connections bound to the restricted core-reply profile. draft_reply sends nothing and returns the exact recipient and text; send_reply takes only the server-issued confirmation and sends once. |
get_my_identity, get_my_send_status, get_my_audit_log | read | any signed-in connection | Who you are signed in as, whether a send would really be delivered, and your own audit log. |
set_send_consent | write | account:manage | Turn real sending on or off for your own account. |
get_my_notification_preferences, set_my_notification_preferences | read write | account:manage | Product update, maintenance and security notices from the login bot. |
disconnect_telegram_account, delete_telegram_account | write | account:manage | Soft revoke or hard delete — see Your controls. |
revoke_local_bridge_device | write | account:manage | Revoke one of your Local Bridge devices and evict a live daemon. See owner controls. |
Operator tools (admin:users, admin:users:read) and broadcast tools (admin:broadcast) are listed in the descriptor file and are never shown to a regular user's connection.
Scopes and permissions
Scopes come from your Telegram identity. On tg.mctl.ai registration is open, so every
signed-in user is in the client tier (a self-hosted deployment may instead
require an operator grant, see below) and gets the scopes below for their
own account. A client asks for a subset by naming
scopes in the authorization request; omitting scope grants the full
entitled set. Administrative scopes cannot be requested.
| Scope | Grants |
|---|---|
telegram:dialogs:read | List chats |
telegram:messages:read | Read, search and download media |
telegram:messages:send | Send, edit, delete, forward and react — subject to your own send consent |
telegram:messages:pin | Pin and unpin, through a confirmation step |
account:manage | Your own account: send consent, notifications, Local Bridge devices, disconnect and delete |
An operator can also bind a client to a restricted tool profile, which
can only remove tools: core-readonly (reads only) or core-reply
(reads plus the two-step draft_reply/send_reply). The design is in
docs/design/core-profiles.md.
Self-hosting: operators on TG_LOGIN_ADMINS also get admin:users
(and admin:broadcast when listed in BROADCAST_OPERATORS);
TG_LOGIN_LOOKUP_ADMINS get only the read-only admin:users:read.
Without AUTO_APPROVE_CLIENTS, the client tier comes from
TG_LOGIN_CLIENTS or an operator grant, and an operator can revoke any user
with set_telegram_access.
What we store
- Telegram session: an AES-256-GCM-sealed MTProto session blob with a per-user HKDF-derived key, kept until you disconnect (marked revoked) or delete (removed).
- Audit log: tool name, redacted peer reference, status and error — never the message body, phone number, or session bytes. Kept for 90 days by default.
- Account row: your Telegram id and access tier. Deleting your account clears your username, names and last-seen time; the id stays so a later sign-in is matched and an authorization code issued before the delete cannot be used after it.
The complete inventory, with every table and its retention, is in the privacy policy.
Your controls
- Disconnect (soft): call MCP tool
disconnect_telegram_account, orPOST /api/account/disconnect, from a connection grantedaccount:manage; or, on deployments with the Telegram manage page enabled, sign in at/telegram/connect/managein a browser and press Disconnect, which works whatever a connector was narrowed to. Marks the session revoked and immediately tears down the in-memory MTProto client. - Delete (hard): call MCP tool
delete_telegram_account, orDELETE /api/account, from a connection grantedaccount:manage. Removes the encrypted session blob and all per-account metadata, and revokes every credential issued for the account: every OAuth client's refresh tokens, every worker token, and every Local Bridge device with its credential. - Status:
GET /api/accountreturns connection state, display name, and the per-accountsend_enabledflag. - Audit log:
get_my_audit_logMCP tool orGET /api/account/audit— newest-first, RFC3339beforecursor for keyset pagination. - Verify your audit chain:
GET /api/account/audit/verifyrecomputes the SHA-256 hash chain over your rows and reports{ok, verified}or{ok:false, first_bad_id, reason}. - Revoke from Telegram's side: Telegram app → Settings → Devices → close the session named after this app. This will not delete data here but will sever the MTProto link Telegram-side.
- Read-only and device credentials: worker tokens and Local Bridge device credentials never carry
account:manage, so they cannot disconnect or delete the account they were issued for. The refusal is a403on the HTTP paths, the tool is not listed over MCP, and every refusal is recorded in your audit log.
Smoke-test from your terminal
Confirm the well-known and a JSON-RPC handshake before adding the connector:
curl -s https://tg.mctl.ai/.well-known/oauth-protected-resource
curl -s -X POST https://tg.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"}}}'
Local Bridge (beta)
Local Bridge is an optional mode in which the Telegram session lives on a machine you
control and this server forwards each tool call to a daemon running there, instead of
opening Telegram itself. It costs you a machine that stays on, so it is not part of the
standard install path — but a new account can be provisioned so this server never holds
a session at all, and turning it on is self-service: init,
login, activate, daemon. Migrating an existing
hosted account into this mode still uses set_account_mode (support, not
onboarding).
- Overview: /docs/local-bridge — when to use it and what it changes.
- Quick start: /docs/local-bridge/quickstart — install and the four commands.
- Owner: /docs/local-bridge/owner —
set_send_consent, manage page, revoke a device. - How it works: /docs/local-bridge/how-it-works — activation, proof of possession, read-only first token.
- Support: /docs/local-bridge/support — migration, troubleshooting, emergency. Not onboarding.
- Legacy: /docs/local-bridge/legacy —
connect --token.