npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cursor-telegram-mcp

v0.9.3

Published

Manage Cursor from your phone over Telegram: an MCP server + auto-spawned local worker that notifies you, asks you questions, and (optionally) runs headless Cursor agents you text it. Local, bring-your-own-bot, runs entirely on your machine.

Downloads

1,527

Readme

cursor-telegram-mcp

Manage Cursor from your phone over Telegram. A local MCP server plus an auto-started background worker that lets a Cursor agent talk to you on Telegram, and lets you drive work from your phone:

  • When the agent finishes a task, it messages you (finish notification).
  • When the agent is blocked on a decision, it mirrors the question to Telegram and keeps working / waiting until your reply comes back.
  • Command mode: text a task to the bot and a headless Cursor agent plans it, sends you the plan, and runs it once you reply YES - so you can leave the laptop on the charger and drive work entirely from your phone.

Local and bring-your-own-bot: each person installs the package, creates their own Telegram bot, and everything runs on their own machine. There is no shared server and nothing shared between users. It uses the official Telegram Bot API over HTTPS - no QR, no eSIM, no SIM. Pending questions are persisted to disk, so a worker restart restores any still-open questions instead of dropping them.

Add to Cursor (one click)

Add to Cursor

This adds the server to your global ~/.cursor/mcp.json (the "Installed MCP Servers" list in Cursor Settings → Tools & MCP). It runs npx -y cursor-telegram-mcp, so it requires the package to be published to npm. After adding, run npx cursor-telegram-mcp setup once to connect your bot.

Prefer it under "Plugin MCP Servers" / the Cursor marketplace? See As a Cursor plugin below.

Quick start

The goal: your bot is online whenever your computer is on — no need to open Cursor or start anything by hand.

1. Install (one time)

npm i -g cursor-telegram-mcp

A global install gives the always-on service a stable location. (You can also run everything via npx cursor-telegram-mcp …, but the always-on installer needs a global install so its launch agent doesn't point at a temporary cache.)

2. Configure + go always-on

cursor-telegram-mcp setup

The wizard creates a bot with @BotFather, validates the token, captures your chat id (you message the bot once), optionally enables command mode with a Cursor API key, and then offers to install the always-on service (macOS launchd: starts at login, restarts itself, plus a watchdog). Config is saved to ~/.config/cursor-telegram/config.json (or %APPDATA%\cursor-telegram\config.json on Windows).

That's it — text your bot to test it. Run cursor-telegram-mcp doctor anytime to check status, and cursor-telegram-mcp install / uninstall to toggle the always-on service.

3. (optional) Let Cursor agents message you

Add this to a project's .cursor/mcp.json (or Cursor Settings -> Tools & MCP), then reload MCP:

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": ["-y", "cursor-telegram-mcp"]
    }
  }
}

The bot itself runs from the always-on service regardless of Cursor; this step just lets in-IDE agents send you notifications and questions.

Architecture

flowchart TD
  cursor["Cursor agent"] -->|"MCP stdio (npx)"| mcp["MCP server (thin) dist/index.js"]
  mcp -->|"GET /health"| check{"worker up?"}
  check -->|no| spawn["spawn detached worker (singleton)"]
  check -->|yes| reuse["reuse running worker"]
  spawn --> worker["worker dist/worker.js"]
  reuse --> worker
  worker --> store["persisted question store (questions.json)"]
  worker -->|"command mode (optional)"| agent["headless Cursor agent (cursor-agent CLI)"]
  worker -->|"Bot API: sendMessage / getUpdates"| tg["Telegram"]
  tg -->|"your reply / texted task"| worker
  phone["Your phone (Telegram app)"] --> tg

The worker owns the Telegram connection and survives Cursor/MCP reloads. The MCP server is a thin client Cursor launches per project; it auto-spawns the worker if one is not already running (the worker's port guard keeps it a singleton, so multiple projects safely share one worker). For non-blocking questions, ask_human_for_guidance returns a questionId immediately and the agent polls check_human_response (or long-polls with waitMs). For blocking decisions, ask_human_and_wait long-polls the worker and returns as soon as you reply on Telegram (no fixed 30-second sleep after your answer).

Security

  • Only your chat can drive the bot. Every inbound Telegram message and button tap is checked against your configured TELEGRAM_CHAT_ID and dropped otherwise.
  • No inbound internet exposure. The worker uses Telegram long-polling (not a webhook) and binds its HTTP API to 127.0.0.1 only.
  • The local HTTP API is authenticated. A random 64-char secret (TG_WORKER_SECRET) is generated on first run, stored 0600 in the config file, and required on every request (Authorization: Bearer …). Without it the worker returns 401; /health returns only a bare {ok:true} liveness ping. The MCP server, watchdog, doctor, and mirror hook all read the same secret automatically — you never set it by hand. After upgrading, reload Cursor once so already-running MCP clients pick up the secret (they also self-heal on a 401).
  • DNS-rebinding hardening. Requests whose Host header is not loopback get a 403, so a browser pointed at a domain resolving to localhost can't reach it.
  • Treat the bot token like a password, and enable 2FA on your Telegram account: in command mode, anyone who can post into your chat can run code on your machine. The token and secret live in a 0600 config file.

Timeouts (three different values)

  • getUpdates 30s: worker receive path only (Bot API long poll for inbound messages).
  • waitMs / ask_human_and_wait: agent wait path — long-poll the worker and wake immediately when you reply (do NOT sleep on a fixed timer between checks).
  • TG_RESPONSE_TIMEOUT_MIN (default 30): minutes before a pending question reports timed_out.

Tools exposed to the agent

| Tool | Purpose | | --- | --- | | notify_human_task_complete(summary) | Fire-and-forget "task done" message. | | ask_human_for_guidance(question) | Send a question, return a questionId right away. | | ask_human_and_wait(question, timeoutMin?) | Send a question and block until you answer or it times out. | | check_human_response(questionId, waitMs?) | Poll for your reply: answered / pending / timed_out. Long-polls by default when waitMs is omitted; pass waitMs=0 for an instant check. |

The rule .cursor/rules/telegram-hitl.mdc tells the agent to send a completion message when it finishes and to mirror any question it would ask in chat to Telegram.

Command mode (drive work from your phone)

When a Cursor API key is configured (setup step 3, or CURSOR_API_KEY), the worker treats any message that is not answering an open question as a task:

  1. You text the bot, e.g. add a healthcheck endpoint and a test.
  2. A read-only headless Cursor agent investigates and replies with a numbered plan (Plan (C-1) ...). No files are changed yet.
  3. You reply YES to execute (or NO to cancel). On YES, a second agent carries out the plan and texts back a summary.

You can also use /ask <question> (read-only Q&A) and /plan <task> explicitly, send /status to see what's running, /reset (or /new) to start a fresh conversation, and /help for the full command list. To drive multiple repos and agent threads from one chat (#project, $agent, tappable choosers), see Multiple projects & agents. Command mode needs the Cursor CLI (cursor-agent) installed:

  • macOS / Linux: curl https://cursor.com/install -fsS | bash
  • Windows (PowerShell): irm 'https://cursor.com/install?win32=true' | iex

The headless agent runs locally against TG_AGENT_CWD (default: the directory the worker started in). Every task is gated: nothing changes code until you approve the plan.

Rolling chat (knowledge carries across messages)

By default (TG_ROLLING=true) command mode keeps ONE long-lived Cursor agent and sends every turn — plan, execute, and /ask — to it. That means:

  • The executor remembers the plan it just made, and the next prompt remembers the whole conversation, so you can keep building from your phone without re-explaining context.
  • The agent id is persisted to TG_SESSION_PATH (default <configDir>/rolling-session.json), so the thread survives worker restarts (including the self-update restart) and resumes where you left off.
  • Send /reset (or /new) to drop the memory and start a fresh thread.

Set TG_ROLLING=false to go back to a stateless agent per message.

See the same chat on your computer

Every turn is also appended to a Markdown transcript at TG_TRANSCRIPT_PATH (default <TG_AGENT_CWD>/remote-chat.md). Open it in Cursor (or any editor) to read the same conversation you are driving from your phone. Because it lives in the repo, git tracks its history — commit it whenever you want a snapshot.

Keeping the worker alive

The worker runs only while your laptop is awake. It auto-starts with the MCP server and stays up across Cursor reloads, so for "laptop on the charger, manage from my phone" you usually need nothing else.

If you want it to survive reboots without opening Cursor, install it as an always-on background service. On macOS this is one command:

cursor-telegram-mcp install     # start now + at every login (launchd)
cursor-telegram-mcp uninstall   # stop and remove it

install writes a per-user launch agent (~/Library/LaunchAgents/com.cursor-telegram.worker.plist) that points at your current Node and the installed CLI — no hardcoded paths — runs the worker under caffeinate so idle sleep never blocks delivery, and restarts it if it crashes (KeepAlive). Logs go to ~/Library/Logs/cursor-telegram-worker.log. Keep the Mac on AC power so a closed lid does not fully sleep.

install also sets up a watchdog (com.cursor-telegram.watchdog, every 120s) that checks the worker's /health and restarts it if it is unreachable or its poll loop has wedged. Combined with the worker's own retry/backoff (every Bot API call has a hard abort timeout, so a stale socket after sleep/wake can't silently hang it), the bot stays online as long as the Mac is on.

To stay online the Mac must not fully sleep. The worker runs under caffeinate so idle sleep is prevented while it's up, but a closed lid on battery still sleeps. For a machine you want always-on:

  • Keep it on AC power.
  • Optionally allow it to run with the lid closed on AC: sudo pmset -c sleep 0 disablesleep 1 (revert with sudo pmset -c disablesleep 0).

On Linux/Windows, run cursor-telegram-mcp worker under your own service manager (systemd / Task Scheduler). (Note: on macOS, launchd agents cannot read files under ~/Desktop/~/Documents/~/Downloads; install the package or project outside those folders.)

Configuration

Values resolve in this order: real environment variables (e.g. set in mcp.json) > the config file written by setup > a local .env (dev) > defaults.

| Variable | Default | Description | | --- | --- | --- | | TELEGRAM_BOT_TOKEN | (required) | Bot token from @BotFather. | | TELEGRAM_CHAT_ID | (required) | Chat to message; replies are matched to it. | | TG_PROJECT | default | Project label prefixed to this client's messages. | | TG_WORKER_URL | http://127.0.0.1:8787 | Worker base URL the MCP calls. | | TG_WORKER_HOST | 127.0.0.1 | Host the worker binds to. | | TG_WORKER_PORT | 8787 | Port the worker listens on. | | TG_WORKER_SECRET | (auto-generated) | Shared secret authenticating local HTTP calls. Generated 0600 on first run; set to override. | | TG_MIN_SEND_GAP_MS | 3000 | Minimum gap between outgoing messages. | | TG_RESPONSE_TIMEOUT_MIN | 30 | Minutes before a pending question reports timed_out. | | CURSOR_API_KEY | (unset) | Enables command mode. Cursor -> Integrations. | | TG_AGENT_CWD | worker cwd | Working dir for the default sandbox command-mode project. | | TG_PROJECTS_ROOT | (unset) | Folder auto-scanned for git repos to register as projects. | | TG_AGENT_MODEL | composer-2.5 | Model id for the headless agent. | | TG_AGENT_LOAD_SETTINGS | false | true to load TG_AGENT_CWD's .cursor rules/MCP during runs. | | TG_ROLLING | true | Keep one rolling agent thread so knowledge carries across messages. | | TG_TRANSCRIPT_PATH | <cwd>/remote-chat.md | Markdown transcript of the rolling chat. | | TG_SESSION_PATH | <configDir>/rolling-session.json | Where the rolling agent id is persisted. |

CLI

cursor-telegram-mcp [mcp]    Start the MCP server (default; Cursor runs this)
cursor-telegram-mcp setup    First-time setup: create/link your bot
cursor-telegram-mcp login    Print and save your Telegram chat id
cursor-telegram-mcp worker   Run the background worker in the foreground
cursor-telegram-mcp install  Install the always-on worker + watchdog (macOS launchd)
cursor-telegram-mcp uninstall Remove the always-on worker + watchdog
cursor-telegram-mcp watchdog One-shot health check; restarts the worker if down
cursor-telegram-mcp doctor   Diagnose configuration and connectivity

As a Cursor plugin

This repo is also packaged as a Cursor plugin (manifest in .cursor-plugin/plugin.json, server config in mcp.json, behavior rule in .cursor/rules/telegram-hitl.mdc). Installing it as a plugin makes the server show up under "Plugin MCP Servers" and bundles the human-in-the-loop rule automatically.

Try it locally (no publishing required):

# make the `npx -y cursor-telegram-mcp` command resolve locally
npm run build && npm pack && npm i -g ./cursor-telegram-mcp-*.tgz

# load the plugin from this checkout, then reload Cursor
ln -s "$(pwd)" ~/.cursor/plugins/local/cursor-telegram-mcp

Then "Developer: Reload Window" in Cursor — the telegram server appears under Settings → Tools & MCP → "Plugin MCP Servers". To list it in the in-app marketplace for one-click discovery, publish the repo (public, open source) at cursor.com/marketplace/publish.

Multiple projects & agents (command mode)

One worker can drive command-mode work across many repos, each with multiple agent threads, all addressable from your phone. Switch the active target with a single character prefix and the rest of the line becomes the task:

#altus fix the linear issues       # switch to the "altus" project and run a task
$research summarize the docs       # switch/create the "research" agent thread
/ask is it live?                   # ask the active agent (read-only)
/plan add a healthcheck endpoint   # plan on the active agent (approve to run)

Listing & management (the /# and /$ lists reply with tappable buttons):

| Command | Does | | --- | --- | | /help | List every command with a short description. | | /# | List projects as tappable buttons (tap to switch). | | /# add <name> <path> | Register a project at a path. | | /# remove <name> | Unregister a project. | | /# scan <root> | Auto-register every git repo directly under <root>. | | /$ | List the project's real Cursor chats (newest first) as tappable buttons, plus New chat. | | /$ new <full name> | Create a named thread (names may contain spaces). | | /$ remove <name> | Remove a named thread. | | /status | Show the active target and what each runner is doing. | | /reset | Start a fresh conversation for the active thread. |

Continuing your real Cursor chats from your phone

Command mode runs through the cursor-agent CLI, so every thread the bot drives is a real Cursor chat: it's written to the same on-disk store the desktop IDE reads, and it's resumable with full context across messages and worker restarts.

  • /$ lists the project's actual chats (the same ones you see in the IDE), newest first, by title. Tap one to continue it from your phone.
  • The first message after you tap a pre-existing IDE chat is seeded with that chat's transcript (a one-time handoff — the CLI can't resume an IDE chat's private history directly, so the bot starts a fresh chat primed with the prior conversation). After that, the thread rolls on its own with full context.
  • Tap New chat (or send $<name>) to start a brand-new thread.
  • $<id-prefix> (e.g. $0f1a8e4f) re-addresses a specific chat by id.

Real-time caveat: a thread you drive from the phone shows up in Cursor's chat history when you reopen/refresh that chat — it does not stream live into a tab you already have open. Cursor exposes no way for an external process to push turns into an open desktop tab.

Notes:

  • Inline #name / $name take a single token (letters, digits, ., -, _). Multi-word thread names are created with /$ new <full name>.
  • Switching a project automatically shows that project's chats, so you can immediately pick which one to continue.
  • Each thread is an independent rolling Cursor chat with its own working directory, session, and queue. Different targets run concurrently; a single target runs its tasks one at a time.
  • Set TG_AGENT_CWD for the default sandbox project, and TG_PROJECTS_ROOT to auto-scan a folder of repos on startup. The worker refuses to register its own repo (a command-mode agent editing it would self-restart).
  • Question routing for IDE agents is unchanged: each project's mcp.json sets a different TG_PROJECT, and questions arrive prefixed and numbered ([billing-api] Q-7). The #/$ scheme governs only where command-mode tasks run.

Replying

Reply with a normal Telegram message. With several questions open, reply to the specific question message to answer it precisely; otherwise the oldest open question is answered first.

Answering from your phone

When the agent needs a decision while you are away from the laptop:

  1. Reply on Telegram. Prefer Telegram Reply on the specific Q-n message so the worker matches your answer to the right question.
  2. Ignore the IDE Questions panel (A/B/C, Skip, Continue) when the agent says the question was also sent to Telegram as Q-n. That panel is separate; Skip there does not read your Telegram reply.
  3. The agent should resume as soon as it sees your answer (ask_human_and_wait wakes immediately on reply; check_human_response long-polls by default when you omit waitMs, or pass waitMs=0 for an instant status check). If it picks a default instead, send a follow-up message in the IDE chat with your choice.

Use Telegram for remote decisions; use the IDE panel only when you are at the desk and not relying on Telegram for that question.

Develop from source

npm install
npm run setup       # or: npm run login (after a token is set)
npm run worker      # foreground worker (tsx)
npm run start       # MCP server (tsx)
npm run typecheck
npm run build       # emit dist/ for publishing

Notes & limitations

  • Local-only: if the laptop sleeps or the worker stops, messaging pauses until it is back. Open questions are persisted to disk and restored on the next worker start, so a restart no longer drops unanswered questions.
  • Per user: each person creates their own bot and runs their own worker (one bot token can only be polled by one process).
  • Command mode requires the cursor-agent CLI and a Cursor API key; without them, notifications and questions still work.

Project layout

src/
  cli.ts        # CLI dispatcher (bin) -> mcp / setup / login / worker / doctor
  index.ts      # thin MCP stdio server; auto-spawns the worker
  worker.ts     # long-running Telegram worker + localhost HTTP API
  config.ts     # config resolution (env > config file > .env > defaults)
  setup.ts      # interactive first-time setup wizard
  login.ts      # chat-id discovery helper
  doctor.ts     # diagnostics
  telegram.ts   # Bot API client: long-poll getUpdates, sendText, media
  agentRunner.ts# command mode: rolling/resumable headless Cursor agent (lazy @cursor/sdk)
  projects.ts   # project + agent registry (projects.json) and active-target state
  runners.ts    # per-(project,agent) runner registry: own cwd, session, queue, transcript
  session.ts    # persist the rolling agent id across worker restarts
  transcript.ts # append-only remote-chat.md transcript of the rolling chat
  store.ts      # pending-question store (persisted to disk) + reply matching
  install.ts    # `install`/`uninstall`: generate per-user launchd worker + watchdog (macOS)
  watchdog.ts   # `watchdog`: one-shot /health check that restarts a wedged worker
  parseInbound.ts / splitMessage.ts / taskQueue.ts / formatTelegram.ts
  answerWaiters.ts  # wake-on-answer for long-polling GET /response/:id
.cursor/
  rules/telegram-hitl.mdc  # agent behavior rule
mcp.client.template.json   # per-project MCP client block to copy