Telegram MCP setup: connect your AI agent to a channel
Wire an AI agent to your Telegram channel over MCP: what to prepare, the steps for claude.ai, ChatGPT, Claude Code and Cursor, and what to do when it refuses.
TL;DR. Three things have to be true before any client connects: the workspace has its own bot, that bot is an administrator in the channel, and the owner has pressed Start in their private chat with it. Then pick a route — the server address
https://backend-git-production-cb93.up.railway.app/mcpas a custom connector with a Telegram sign-in, or a key in anAuthorizationheader from Settings → AI agents (MCP). Fourteen tools follow: five read the channel, seven work on posts, two read the audience. Nothing about products, orders or private chats, and nothing without a bot. Client steps checked 8 September 2026.
This is the practical half of the comparison of Telegram MCP servers: that piece decides whether the bot route is the one you want, this one gets you connected and covers the cases where it does not.
Before you connect
Most failures happen here, before a single tool is called.
The workspace needs its own bot. AdminHub’s MCP server publishes through the bot the channel owner created for their own channel — never a shared AdminHub bot and never your personal account. Without one the tools do not degrade quietly: they refuse with bot_required and a link that creates the bot in one tap, telegram.me/tg_adminhub_bot?startapp=bot. get_workspace is the exception and answers anyway, so an agent can discover what is missing.
The bot must be an administrator of the channel. A bot that is merely a member cannot post, and Telegram says nothing about it until a send fails. list_channels carries a bot_is_admin flag on every channel for exactly this reason, and create_post rejects a channel where it is false, with channel_not_postable, rather than accepting a post that would be lost later.
The owner’s private chat with the bot must be open. This matters only for images, and the rule is Telegram’s rather than ours: a bot can obtain a file id only for a file it has itself sent. So add_post_image downloads the picture, relays it once through the owner’s own chat with the bot to get that id, attaches it to the post and deletes the relayed message. If the owner never pressed Start there, the tool refuses before downloading anything, with owner_bot_not_started.
The side effect is worth saying out loud: every image an agent attaches arrives, briefly and with a notification, in the owner’s chat with their own bot. It is deleted afterwards, but it was delivered, and someone who did not ask for a picture will wonder where it came from. get_workspace reports owner_dm_open, so this is checkable ahead of a failed call.
Two ways to connect
By server address, with no key. For claude.ai, ChatGPT, Claude Desktop and Claude Code. Add a custom connector pointing at https://backend-git-production-cb93.up.railway.app/mcp; an AdminHub page opens, and you sign in with Telegram, choose a workspace and press Allow. A workspace with no bot is listed but cannot be chosen — there would be nothing to publish through. Access covers all three permissions at once: channel:read, posts:write and audience:read.
By key in a header. For Claude Code, Cursor and anything else that sends an Authorization header. Open Settings → AI agents (MCP) → Create key. It is shown exactly once and there is no second look: the database keeps only a hash. Both routes are revoked in the same place, and a revoked connection stops working immediately.
Plan for one thing: a key and an address-based connection both count as connections, and Free allows one.
claude.ai
Customize → Connectors → Add custom connector → paste the address → Add. The authentication defaults are fine: the server accepts both Anthropic’s hosted client metadata and dynamic registration, so there is nothing to fill in by hand. Then connect it, complete the Telegram sign-in and switch it on in the chat where you want it.
Custom connectors work on Free, Pro, Max, Team and Enterprise, with Free limited to one. On Team and Enterprise only an Owner adds one, from Organization settings → Connectors; everyone else connects to it afterwards from their own Connectors page.
ChatGPT
Connectors became Apps in July 2026, and a custom MCP server also needs developer mode: Settings → Security and login → Developer mode, then create the app from Apps, giving it the server address with OAuth as the authentication mechanism. In a workspace an admin enables developer mode under Permissions & Roles and publishes the app from workspace settings.
Two limits to know first: this is a web feature with no mobile support, and full MCP — the half that writes — is currently for Business and Enterprise/Edu accounts, while a Pro account connects a server with read and fetch permissions only. On Pro, expect the reading tools to work and the publishing ones not to.
Claude Desktop
The same Connectors flow as claude.ai, not a config file — claude_desktop_config.json is for local stdio servers, which this is not. Claude reaches a remote connector from Anthropic’s own infrastructure rather than from your machine, which changes nothing here because this address is public.
Claude Code
Claude Code does it either way, worth knowing before creating a key you may not need. With one:
claude mcp add --transport http adminhub https://backend-git-production-cb93.up.railway.app/mcp --header "Authorization: Bearer <key>"
Without one, add the same server with no header and let Claude Code run the sign-in itself:
claude mcp add --transport http adminhub https://backend-git-production-cb93.up.railway.app/mcp
then run /mcp and follow the browser flow. Take the key if the connection should outlive a browser session; take the sign-in to keep a secret out of a config file.
Cursor and other header-based clients
Cursor reads ~/.cursor/mcp.json for every project and .cursor/mcp.json for one. A remote server is an entry with url and headers — there is no transport field; url is what makes it remote:
{
"mcpServers": {
"adminhub": {
"url": "https://backend-git-production-cb93.up.railway.app/mcp",
"headers": {
"Authorization": "Bearer ${env:ADMINHUB_MCP_KEY}"
}
}
}
}
Cursor interpolates ${env:...} inside url and headers, so the key can live in the environment rather than a file you might commit. Anything else speaking Streamable HTTP connects the same way: the address, plus the key as a bearer token.
The fourteen tools
| Tool | What it does |
|---|---|
get_workspace | Workspace, plan, bot status, owner_dm_open, MCP posts used this month |
list_channels | Every channel, with subscriber count, bot_is_admin and is_active |
get_channel_stats | Totals and day-by-day joins and leaves, up to 90 days |
list_posts | Recent posts, filterable by channel or status |
get_post | One post’s text, per-channel delivery status and error |
create_post | Text to one or more channels: draft, scheduled or sent now |
publish_post | Sends a saved draft |
update_post | Rewrites a draft, scheduled or failed post’s text, title or time |
edit_published_post | Rewrites a post already in the channel |
cancel_post | Deletes a draft, scheduled or failed post — published ones stay |
retry_post_delivery | Retries the channels where delivery failed or was cancelled |
add_post_image | Attaches one image from a URL, relayed through the owner’s chat |
list_subscribers | A channel’s subscribers by name, username and Telegram id |
get_subscriber | The same for one person |
Post text is Telegram HTML, never Markdown, and scheduled times carry a UTC offset. Publishing is queued: the writing tools return at once and delivery follows within a minute, so the result is read back from get_post.
What it will not do
No products, no orders, no mini-CRM, no knowledge base — the commerce and AI-support halves of AdminHub are not exposed over MCP at all. No private chats, no arbitrary chats, no message history: no tool here touches a conversation, which is the whole difference between this and a userbot server.
Audience data deserves its own line, because the boundary inside it is easy to miss. Names, usernames and Telegram ids come back under audience:read; spend and lifetime value do not come with them, appearing only when the agent passes include_spend on that call. It is a deliberate border, and the time to weigh it is before connecting, not after an agent has summarised your best customers.
When it does not work
Every tool refuses with bot_required. The workspace has no bot. The error carries the link, and nothing else works until the bot exists.
A post was created but never arrived. Wait a minute — delivery is queued — then call get_post and read the per-channel status and error. The usual cause is a bot that is no longer an administrator there. Restore the rights, then retry_post_delivery.
An image will not attach. owner_bot_not_started means the owner has never opened a private chat with the workspace bot. Ask them to open it and press Start; owner_dm_open on get_workspace confirms it. owner_unreachable is the neighbour — the chat was open and the bot has since been blocked.
plan_limit_reached. Free allows one connection and thirty posts created through MCP a month. The counter counts creation, so drafts count too; posts whose delivery failed do not. The connection limit spans both routes — a key and an address-based connection each take the slot — and the second one is refused at creation rather than at call time. Pro has neither limit.
The agent cannot see subscribers. Either the connection has no audience:read — keys issued before that permission existed carry only the older two, and the fix is a new key — or the client asked for a partial set of permissions during sign-in, which this server refuses outright rather than granting silently narrowed access. Reconnect asking for all three.
The MCP page carries the address, the tool list and the FAQ; the key is two taps away in Settings.
Sources
Client steps checked 8 September 2026 against each vendor’s own docs: Anthropic’s help centre and connector documentation for claude.ai and Claude Desktop, the Claude Code MCP docs for claude mcp add, OpenAI’s developer-mode guide and help centre for ChatGPT apps, and Cursor’s MCP docs for the mcp.json shape. AdminHub’s own behaviour — the fourteen tools, the refusals named above, the permissions and the Free limits — is from the MCP page.
What people usually ask
- What do I need before connecting the AdminHub MCP server?
- Three things, and all three are about the bot. The workspace needs its own Telegram bot, because MCP publishes through it and never through a shared AdminHub bot — without one every tool refuses with bot_required. That bot has to be an administrator in each channel you want posted to, or create_post rejects the channel outright. And the owner's private chat with that bot has to be open, meaning they pressed Start at least once, which is what makes attaching images possible.
- Do I need an API key to connect?
- Only for clients that connect by header. claude.ai, ChatGPT, Claude Desktop and Claude Code can take the server address on its own and run a sign-in of their own: an AdminHub page opens, you sign in with Telegram, pick a workspace and allow access. Claude Code, Cursor and anything else that sends an Authorization header can use a key instead. The key is created in Settings, AI agents (MCP), Create key, and it is shown once — the database keeps only a hash, so a lost key is replaced rather than recovered.
- What can the agent see about my subscribers?
- Names, usernames and Telegram ids, and only under the separate audience:read permission — a connection without it gets a scope error rather than an empty list. Money fields, meaning total spend, lifetime value and payment count, are left out unless the agent passes include_spend on that call. The split is deliberate: reading who is subscribed and reading what they paid are two different questions, and the second one has to be asked out loud.
- What does the Free plan allow over MCP?
- One connection and thirty posts created through MCP a month. Both numbers are counted the way they are worded. A key and an address-based connection are both connections, so Free gets one or the other, not both. The post counter counts posts created, drafts included, rather than posts delivered — and posts whose delivery failed are not counted at all. Pro removes both limits.
- The agent says the post went out, but the channel is empty. Why?
- Publishing is queued, so give it a minute, then call get_post — it reports a status and an error for each channel separately. The usual cause is that the bot is no longer an administrator in that channel: create_post refuses a channel the bot cannot post to, so the case that survives to delivery is a bot demoted after the post was created. Restore the admin rights and call retry_post_delivery.