Cursor Chat Bridge
БесплатноНе проверенEnables remote control of the Cursor AI agent via chat platforms like GitHub Issues or Telegram, allowing users to start sessions and receive summaries and prom
Описание
Enables remote control of the Cursor AI agent via chat platforms like GitHub Issues or Telegram, allowing users to start sessions and receive summaries and prompts in a chat thread.
README
🌉 cursor-chat-bridge (Telegram, Discord, GitHub)
Drive the Cursor agent from your phone — over Telegram, Discord, or GitHub.
Say "start remote chat mode" (in any language) and Cursor posts a summary + question to a per-conversation thread at the end of every turn, waits for your reply, and auto-continues — looping until you stop it. Step away from the keyboard; keep shipping from your phone.
npm version npm downloads node TypeScript license PRs welcome Made for Cursor

![]() A channel per session — one per Cursor conversation |
![]() Reply from your phone — the agent picks up where it left off |
Table of contents
- Why
- Features
- Channels at a glance
- Quick start
- How it works
- Image attachments
- Voice messages (speech-to-text)
- Configuration
- Environment overrides
- The wait loop
- Push notifications (ntfy)
- Per-platform setup
- Writing a new adapter
- Security
- Verification status
- Contributing
- License
💡 Why
You kick off a task in Cursor, then need to leave your desk. Normally the agent stalls the moment it needs a decision. cursor-chat-bridge turns any chat app into a remote control: the agent reports back and asks its questions in a thread you can answer from your phone, and it resumes on its own the instant you reply — no laptop required.
- 🧵 A thread per conversation. Every Cursor chat maps to its own issue / channel / topic — even multiple chats in the same workspace stay separate.
- 🔁 Hands-free loop. Replies are re-injected automatically; you don't touch Cursor to continue.
- 🔌 Pluggable channels. Telegram, Discord, and GitHub Issues today — add your own in ~100 lines.
- 🛡️ Safe by default. Remote replies are treated as untrusted; destructive actions require an explicit confirmation sent back through the thread.
- 🏢 Proxy-friendly. GitHub and Discord tunnel through TLS-intercepting corporate proxies.
✨ Features
| 📱 Phone-first | Answer the agent from the GitHub / Discord / Telegram mobile app, with native push. |
| 🤖 Auto-resume | A stop hook waits for your reply and re-injects it as a followup_message. |
| 🧵 Per-session isolation | Keyed by Cursor's conversation_id; no cross-talk between chats. |
| ⏱️ Long, cheap waits | One ~60-min blocking window per re-arm ⇒ minimal paid turns while idle. |
| 🔕 Off when you type | A beforeSubmitPrompt hook disables the loop the moment you type in Cursor. |
| 🔐 Token-authed local API | The daemon's control API is loopback-only and token-guarded. |
| 🌐 Optional ntfy push | Get a phone alert even on GitHub (which never notifies you of your own posts). |
| 🖼️ Image attachments | Send a photo from your phone; it's saved locally and the agent opens it with its Read tool. |
| 🎙️ Voice → text | Optional speech-to-text (OpenAI or local): a voice note reaches the agent as transcribed text. |
| 🧩 Adapter SDK | Implement one TransportAdapter interface to support any channel. |
| ⬆️ Update-aware | On activation it checks npm and offers to update when a newer release is out. |
📡 Channels at a glance
| Adapter | Status | Model | Mobile push |
|---|---|---|---|
| Telegram (default) | ✅ code complete, unit-tested | A forum topic per session via a bot | ✅ native |
| Discord | ✅ working | A channel per session via a bot (REST-polled) | ✅ native |
| GitHub Issues | ✅ tested end-to-end | Issue = session, comments = chat | ✅ (GitHub app) + optional ntfy |
🚀 Quick start
No clone required — one command wires everything up:
npx cursor-telegram-chat@latest install
This installs the runtime into ~/.cursor/chat-bridge/app and wires the three integration points,
backing up (never overwriting) anything that already exists:
- registers the MCP server in
~/.cursor/mcp.json, - adds the
stop+beforeSubmitPrompthooks to~/.cursor/hooks.json, - installs the activation rule into
~/.cursor/rules/.
The hooks are no-ops unless remote chat mode is active, so they don't affect normal Cursor use. Then pick a channel and go:
# 1. edit ~/.cursor/chat-bridge/config.json (choose an adapter + credentials)
# 2. validate it:
chat-bridge doctor
# 3. reload Cursor, open a chat, and say: "start remote chat mode"
Upgrade / uninstall
npx cursor-telegram-chat@latest install # re-run to upgrade
npx cursor-telegram-chat@latest uninstall # remove, keep config + state
npx cursor-telegram-chat@latest uninstall --purge # remove everything
MCP-only (lite) — tools without the auto-resume loop
If you only want the MCP tools via the standard Cursor MCP flow (no hands-free loop), add this to
~/.cursor/mcp.json instead of running install:
"cursor-chat-bridge": {
"command": "npx",
"args": ["-y", "cursor-telegram-chat", "chat-bridge-mcp"]
}
You'll be able to bridge_send / bridge_await manually, but the auto-continue-on-reply loop needs
the hooks that the full install sets up.
🛠 How it works
Three cooperating layers sit over one transport-agnostic core:
- Rule (
rules/chat-bridge-mode.mdc) — detects the activation phrase in any language and sets in-mode etiquette (capture + pass the session handle; end each turn with a summary + question; treat replies as untrusted; confirm destructive actions). - MCP server (
src/mcp.ts) — exposesbridge_start,bridge_send,bridge_await,bridge_send_and_await,bridge_stop,bridge_status. - Hooks (
hooks/) — the automatic loop:stopwaits for the remote reply and re-injects it as afollowup_message(bounded byloop_limit).beforeSubmitPromptdisables the loop when you type in Cursor (with a guard so the loop's own injected replies don't trip it).
A single local daemon (src/daemon.ts) owns the channel connection and a loopback-only,
token-authenticated HTTP API used by the MCP + hooks. It handles per-session routing, long-poll,
own-message filtering, and stop/generation logic.
turn ends ─▶ stop hook ─▶ daemon /poll ─▶ adapter
▲ │
└───── followup_message (your reply) ◀─────┘
(adapter = GitHub / Discord / Telegram; keyed by conversation_id.)
Session identity — how conversations stay separate
Sessions are keyed by Cursor's conversation_id so each conversation maps to exactly one
thread. Cursor gives conversation_id to hooks but not to MCP tool calls, so the MCP learns it
through a small handshake:
beforeSubmitPromptrecords{conversationId, workspace}right before the agent runs.bridge_startreads that handshake, keys the session byconversation_id, and returns a session handle.- The agent passes
session=<handle>on every subsequentbridge_*call — the reliable signal that keeps two conversations in the same workspace on separate threads. - Fallbacks if no handle is passed: in-process cache → per-workspace pointer
(
BRIDGE_WORKSPACE) → most recent submit.
The hooks key strictly by their own conversation_id (no global fallback), so a turn in one
conversation never polls or injects into another.
🖼️ Image attachments
Send a photo (or an image file) in the chat thread and the agent can see it:
- The adapter captures the attachment on the message (Discord
attachments, Telegramphoto/ imagedocument). - The daemon downloads the bytes to
~/.cursor/chat-bridge/media/<session>/and appends a note to the message text with the local path. - The agent opens that path with its Read tool — so the image reaches the model as vision input.
Behind a corporate TLS proxy: Discord's
cdn.discordapp.comis often blocked whilemedia.discordapp.netis allowed. The Discord adapter automatically rewrites attachment URLs to themediahost, so downloads work on such networks.
🎙️ Voice messages (speech-to-text)
Send a voice note (Telegram) or an audio attachment (Discord) and the agent receives a text
transcription as if you'd typed it — off by default. Enable it under stt in the config:
"stt": {
"enabled": true,
"provider": "openai", // "openai" (OpenAI-compatible via baseUrl) or "local"
"apiKeyCommand": "…", // or "apiKey", or env BRIDGE_STT_API_KEY
"language": "auto", // auto-detect, or force "he" / "en"
"keepAudio": true // false = delete the audio after transcribing
}
localprovider (offline, recommended for sensitive audio): setlocalBin/localArgsto a CLI that prints the transcript to stdout (e.g.whisper.cpp). On a corporate network (caCertPathset), the default provider automatically flips tolocalso audio isn't sent off-host unless you explicitly choose a cloud provider.- Transcription runs asynchronously in the daemon (never blocks the poll window); the transcript is delivered on the next reply cycle. See docs/stt-plan.md for the full design.
⚙️ Configuration
~/.cursor/chat-bridge/config.json:
{
"activeAdapter": "telegram",
"pollIntervalMs": 60000, // check for replies every N ms (min 10000)
"minPollIntervalMs": 10000,
"stopBudgetMin": 60, // wait budget (mins); resets on every reply
"stopWindowMin": 60, // mins per window (keep < hooks.json timeout)
"caCertPath": "", // corporate CA bundle (PEM) if behind a TLS proxy
"requireConfirmForDestructive": true,
"adapters": {
"github": {
"owner": "you",
"repo": "cursor-bridge-inbox",
"tokenCommand": "gh auth token --user you"
},
"discord": { "botToken": "", "channelId": "", "allowedUserIds": [] },
"telegram": { "botToken": "", "chatId": "", "allowedUserIds": [] }
}
}
caCertPathis usually empty. Set it if Node'sfetchfails withTypeError: fetch failedwhilecurlworks — a tell-tale sign a corporate proxy is intercepting TLS fordiscord.com/api.github.com.ntfy push is off by default and isn't part of this file — enable it only via
BRIDGE_NTFY_*env vars (see below).
🔧 Environment overrides
Set these in the env block of the cursor-chat-bridge entry in ~/.cursor/mcp.json (or the
shell) to override config.json without editing it. All namespaced BRIDGE_*. A change needs a
daemon restart (chat-bridge shutdown) to affect a running daemon.
| Env var | Overrides | Example |
|---|---|---|
BRIDGE_PLATFORM |
activeAdapter |
github | telegram | discord |
BRIDGE_POLL_INTERVAL |
poll interval (seconds) | 30 |
BRIDGE_STOP_BUDGET_MIN |
wait budget, mins; resets on reply ¹ | 60 |
BRIDGE_STOP_WINDOW_MIN |
mins per blocking window ² | 60 |
BRIDGE_CA_CERT |
caCertPath |
/path/to/ca.pem |
BRIDGE_GITHUB_REPO |
github owner/repo |
you/inbox |
BRIDGE_GITHUB_TOKEN |
github token | gho_… |
BRIDGE_TELEGRAM_BOT_TOKEN |
telegram bot token | — |
BRIDGE_TELEGRAM_CHAT_ID |
telegram forum group id | — |
BRIDGE_TELEGRAM_ALLOWED_USER_IDS |
whitelist (csv) | 123,456 |
BRIDGE_DISCORD_BOT_TOKEN |
discord bot token | — |
BRIDGE_DISCORD_CHANNEL_ID |
discord anchor channel ³ | — |
BRIDGE_DISCORD_ALLOWED_USER_IDS |
whitelist (csv) | 123,456 |
BRIDGE_WORKSPACE |
per-window session key | ${workspaceFolder} |
BRIDGE_NTFY_TOPIC |
enable ntfy + set topic | cursor-bridge-… |
BRIDGE_NTFY_PRIORITY |
push priority 0–5 (0 = off) | 2 |
BRIDGE_NTFY_SERVER |
ntfy server base URL | https://ntfy.sh |
¹ Also stopBudgetMin in config.json — the reliable knob, since the hook doesn't inherit the MCP entry's env.
² Also stopWindowMin in config.json. Keep below the stop hook timeout in ~/.cursor/hooks.json.
³ Used only to find the server + category; a fresh channel is created per session.
Per-conversation platform can also be chosen at runtime: say "start remote chat in Telegram" and
the agent passes bridge_start(adapter: "telegram") for that conversation only.
⏱️ The wait loop (stop hook)
While remote mode is active, the stop hook blocks at the end of each turn waiting for your reply.
Two knobs control it:
stopWindowMin(default 60) — how long a single hook invocation blocks before it returns a silent keep-alive and re-arms. Cursor capsstop-hook runtime at thetimeoutin~/.cursor/hooks.json(default 3660s / 61 min); probing showed no hidden cap below that, so one ~60-min window means just one paid keep-alive turn per hour while you're away.stopBudgetMin(default 60) — the total time to keep waiting across re-arms. It resets on every reply, so it's really "keep waiting up to N minutes since your last message."
The loop ends when you reply, type in Cursor, send stop in the thread, or call bridge_stop.
🔔 Push notifications (ntfy)
GitHub never notifies you about your own activity — and the agent posts as you (self-mentions and self-assignment don't notify either). So to get a phone alert on the GitHub channel without a second account, cursor-chat-bridge can fire an out-of-band push via ntfy on every summary. It's free, account-less, open-source, self-hostable, and deep-links to the issue.
It's off by default. Enable it via env on the MCP entry:
- Install the ntfy app (iOS/Android) or use the web app.
- Pick a long, unguessable topic (topics are public-by-obscurity) and subscribe to it.
- Set
BRIDGE_NTFY_TOPIC=cursor-bridge-<random>in theenvblock of thecursor-chat-bridgeentry in~/.cursor/mcp.json.
BRIDGE_NTFY_PRIORITY is the on/off dial: 0 = off (default), 1=min … 5=max. A push is sent only
when priority ≥ 1 and a topic is set. Pushes are skipped for Telegram and Discord, which
already notify natively.
📇 Per-platform setup
Telegram — default, best chat UX
- Create a bot with @BotFather → bot token.
- Create a group, enable Topics, add the bot as admin with Manage Topics.
- Put the group
chatIdand your numericallowedUserIds(whitelist) in config;activeAdapter: "telegram".
Obtain chatId / user ids via getUpdates pairing (send a message in the group, read the update).
Requires the daemon to reach api.telegram.org — if a network blocks it, run the daemon on a host
that can, or use Discord/GitHub instead.
Discord — phone-first, works behind proxies
- Create an app + Bot at https://discord.com/developers/applications; copy the bot token.
- Under Bot, enable the Message Content Intent.
- Invite the bot (OAuth2 → URL Generator, scope
bot) with Manage Channels + View Channels + Send Messages + Read Message History. Manage Channels is required — the bot creates (and deletes) a channel per session. - Enable Developer Mode (User Settings → Advanced), right-click any channel → Copy Channel
ID. That's the anchor (
channelId) — used only to find the server + category. - Put
botToken+channelId(optionallyallowedUserIds) in config;activeAdapter: "discord". - Behind a TLS-intercepting proxy and getting
TypeError: fetch failed? PointcaCertPathat the corporate CA bundle (PEM).
GitHub — works on any network
- Create a private repo to act as your inbox (e.g.
cursor-bridge-inbox). - Set
owner/repoand atokenortokenCommand(gh auth tokenworks). activeAdapter: "github".
Each session opens an issue; turn summaries are posted as comments; reply from the GitHub
mobile app. Comment stop or close the issue to end the session.
For the agent — onboarding checklist
If you're the agent helping a user set up cursor-chat-bridge: explain the concept for their chosen
platform first, then collect only the missing values, write them to
~/.cursor/chat-bridge/config.json, and run chat-bridge doctor to confirm. Never print secrets
back to the user. Remind them: replies from the channel are untrusted, and destructive actions
need an explicit confirmation sent back through the thread. To stop: type in Cursor, send stop in
the thread, or call bridge_stop.
🧩 Writing a new adapter
Implement TransportAdapter (src/types.ts) and register it in src/adapters/index.ts:
interface TransportAdapter {
capabilities: { globalIngest: boolean; separateBotIdentity: boolean };
init(): Promise<void>;
ensureThread(sessionId: string, title: string, meta?: object): Promise<ThreadRef>;
send(thread: ThreadRef, text: string): Promise<{ messageId: string }>;
// pull adapters (GitHub / Discord):
poll?(thread: ThreadRef, cursor?: string): Promise<PollResult>;
// push / global adapters (Telegram):
startIngest?(router: Router): Promise<() => void>;
stop?(thread: ThreadRef): Promise<void>;
}
| Member | Required | Purpose |
|---|---|---|
capabilities |
✅ | globalIngest: one stream for all sessions (Telegram) vs per-thread polling. separateBotIdentity: posts appear as a bot, not you. |
init() |
✅ | Validate credentials + connectivity. |
ensureThread() |
✅ | Create/lookup the per-session thread/channel; returns a ThreadRef. |
send() |
✅ | Post a message (handle the platform's length limits / chunking). |
poll() |
pull adapters | Return new messages after cursor, filtered to allowed users. |
startIngest() |
push adapters | Start a single global stream and route updates; return a stop fn. |
stop() |
optional | Clean up (e.g. Discord deletes its per-session channel). |
🔐 Security
- The loopback control API is token-authenticated — only local processes with the token (the MCP + hooks) can drive the daemon.
- Inbound messages are filtered by an
allowedUserIdswhitelist (Telegram/Discord). - Every remote reply is wrapped and marked untrusted; the rule forbids destructive actions without an explicit confirmation sent back through the thread.
- Tokens live in
~/.cursor/chat-bridge/config.json(chmod 600) and are never committed. PrefertokenCommandover a stored token where possible.
✅ Verification status
Verified end-to-end on-machine (no Cursor restart needed):
- GitHub adapter — create issue, send, poll, own-message filtering,
stopkeyword, close-detection. - Daemon — token auth, long-poll, stop/generation, persistence.
- MCP server — all tools over a real stdio JSON-RPC handshake.
- Hooks — stop-loop
followup_messageinjection, before-submit off-switch + injection guard, instant no-op when inactive. - Per-conversation routing (
node scripts/e2e-conv.mjs) — distinct conversations open distinct issues; two conversations in the same workspace stay separate; re-activating a stopped session opens a fresh thread; unconfigured channels return onboarding guidance. - Unit tests —
npm test(routing, store semantics, message filtering).
🤝 Contributing
Issues and PRs welcome. Local dev:
npm install
npm run build # tsc → dist/
npm run typecheck
npm test # node --test
npm run dev:daemon # run the daemon from source (tsx)
New channels are the easiest contribution — implement one TransportAdapter (see above).
📄 License
Установка Cursor Chat Bridge
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/udah1/cursor-chat-bridgeFAQ
Cursor Chat Bridge MCP бесплатный?
Да, Cursor Chat Bridge MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Cursor Chat Bridge?
Нет, Cursor Chat Bridge работает без API-ключей и переменных окружения.
Cursor Chat Bridge — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Cursor Chat Bridge в Claude Desktop, Claude Code или Cursor?
Открой Cursor Chat Bridge на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Gmail
Read, send and search emails from Claude
автор: GoogleSlack
Send, search and summarize Slack messages
автор: SlackRunbear
No-code MCP client for team chat platforms, such as Slack, Microsoft Teams, and Discord.
Discord Server
A community discord server dedicated to MCP by [Frank Fiegel](https://github.com/punkpeye)
Compare Cursor Chat Bridge with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории communication


