Cursor on your phone: open-source remote control for agent mode

I kept running into the same problem: I’d start a Cursor agent on some refactor, go make coffee or step out for lunch, and come back to find it had been sitting there waiting for my approval for 20+ minutes. Sound notifications didn’t help because I wasn’t at my desk. Remote desktop from my phone was technically possible but pretty painful for just clicking “accept.” I looked for some way to control cursor from my phone but nothing really existed.

So I built CursorRemote, basically a remote control for your local Cursor IDE that you can use from your phone. It’s a VS Code extension that connects to your running Cursor instance via Chrome DevTools Protocol and streams the full agent conversation to a mobile web UI. You can approve or reject tool calls, send new prompts, switch modes and models, and monitor multiple windows at once. All from your phone browser.

There’s also a Telegram integration if you prefer that. Each agent conversation gets its own forum topic with inline approve/reject buttons, so you can manage everything from a cursor telegram bot without opening a browser.

I’ll be honest, most of it was vibecoded. The core idea is straightforward, connect via CDP, poll the DOM, stream over websocket. But getting it to actually work reliably across different Cursor versions, handling multi-window state, keeping the mobile UI responsive, dealing with all the edge cases in the Telegram bot… that part was way trickier than expected. Burned through a lot of tokens polishing it into something that doesn’t feel janky.

How it works technically

You launch Cursor with --remote-debugging-port=9222, the extension starts a local relay server that polls the DOM via CDP, and streams state changes over WebSocket to any connected client. Latency is under 100ms. Everything runs on your machine, nothing goes to any cloud or third party server. No telemetry, no analytics, no phone-home. The license validation itself is offline.

Setup is pretty quick

  1. Install the extension (from the marketplace or download the .vsix from GitHub)

  2. Add --remote-debugging-port=9222 to your Cursor launch command

  3. Open the web UI on your phone (local network or Tailscale for remote access)

Takes about 3 minutes.

It’s open source, cross-platform (Windows, macOS, Linux including WSL2), and works as a Cursor IDE mobile companion without needing a cloud VM or remote desktop. The license key is $7.99 one-time, not a subscription.

I’d love feedback from anyone who tries it, especially around the CDP connection reliability across different Cursor versions. Happy to answer questions.

GitHub: https://github.com/len5ky/CursorRemote Website: https://www.cursor-remote.com

5 Likes

This is honestly super cool — exactly the kind of thing you only realize you need once you run into it
Love how practical it is, especially the Telegram part.

1 Like

Basically started building the same project:

But right now it is just GUI for ssh connecting to cursor agent ACP

Very cool. Took it for a spin and set it up but it failed to load the conversations. The Socket.IO client JS isn’t being served in the bundle.

Opus 4.6 fixed it up for me: and it seems to be working now that I’ve got it serving the Socket.io client.

I've found the root cause. Here's what's happening:

The chain of failure:

The relay server is bundled into a single file (dist/server/bundle.mjs)

The bundle sets __dirname to dist/server/ (from import.meta.url)

Socket.IO is created with default serveClient: true, so it tries to serve /socket.io/socket.io.js by looking for its client-dist/ folder relative to __dirname

There are no node_modules and no client-dist/ directory in the extension package - the file doesn't exist

The file read fails silently, the response is never sent -> ERR_EMPTY_RESPONSE

Without the Socket.IO client library, io is undefined -> ReferenceError -> web app never initializes

This is a packaging bug in the extension - the server code is bundled but the Socket.IO client library it depends on at runtime is missing.

Let me fix it by downloading the Socket.IO client library and placing it in the static files directory that Express already serves.

Thanks for the detailed write-up. You’re right: this is an extension packaging bug on our side.

The web app currently expects the Socket.IO browser client at /socket.io/socket.io.js, but the packaged extension build does not reliably include the runtime asset needed to serve that file. In some local/dev environments this was masked by an already-running server, cached assets, or a non-clean setup, which is why we didn’t catch it before release.

We’re preparing a proper fix now and expect to ship it within the next few hours. In the meantime, the standalone repo flow should still work: cloning the repo and running npm install uses the normal local dependency layout, so it avoids this packaged-extension issue.

After the fix is out, we’ll follow up directly to make sure it works correctly on your machine and confirm the packaged extension path is behaving in a clean install.

Really appreciate the report and the root-cause analysis.

1 Like

Should be resolved in latest release: v0.1.41

Looks good! Working for me!
Thanks

1 Like

Why not provide a trial key that expires in 7 days?

Good question. The goal from the start was to keep the whole thing completely independent from my servers or any third party. It’s fully self-hosted, no phone-home, no analytics, no server-side license validation. I didn’t want to introduce any DRM bloat.

The license mechanism is already pretty easy to crack, and that’s by design. I’d rather keep the code open and simple than add layers of protection that annoy paying users.

The problem with a 7-day trial is I don’t see a clean way to do it without adding a server connection. Anything purely local wouldn’t survive a reinstall, and anything server-side could be bypassed by just requesting a new key with a new email. Both options add complexity and move away from the self-hosted philosophy.

What I could do instead is introduce a no-questions-asked refund policy. If you try it and it’s not for you, you get your money back. Would that make you feel safer about committing to the $7.99?

1 Like

Thanks a lot. After 1st try. I am using Telegram bot. 2 issues :

  • Models list has some fix items. Not providing same models as I have selected in Cursor.
  • Approval flow never work. I am not getting diffs/ or request to approve it. I see only file name and number of lines edit in output.

So how long till this is backdoor’d by Russian, North Korean, and or Chinese hackers?

Thanks for the detailed report.

Models: The model list mismatch should be fixed in the latest release (0.1.43). After you update, if anything still doesn’t match what you see in Cursor, say which surface (web vs Telegram) and your Cursor version.

Approvals / diffs: Full diffs and the full approve flow are in the web app right now. Telegram is intentionally lighter: you get the summary (file, line counts, etc.) and inline approve/reject, but not the full diff inline. We know that gap is annoying if you live in Telegram; improving Telegram parity is on the list.

If something still fails to approve from Telegram even when the agent is clearly waiting, that’s a bug worth chasing. A screenshot of one stuck thread + Cursor version helps us reproduce.

We’re still a few tens of thousands of GitHub stars short of the threshold where the Russian / North Korean / Chinese hacker backdoor program kicks in. Until then you’re stuck reading the source like the rest of us.

More seriously: it’s source-available, runs on your machine only, no phone-home. Audit away.

This is really cool. Well worth $7.
Works great. Thanks for sharing and keeping it open source.

NGL, built it local and tried it first, but you deserve the $ for this. Good stuff~