Skip to content

feat(cursor): package mobile dev as a cursor plugin - #40

Open
grabbou wants to merge 1 commit into
feat/devices-cardfrom
feat/cursor
Open

grabbou wants to merge 1 commit into
feat/devices-cardfrom
feat/cursor

Conversation

@grabbou

@grabbou grabbou commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Stacked on #39 (feat/devices-card), which is stacked on #34.

What Cursor supports

From the Cursor MCP docs, plugins and plugin reference:

  • Config: mcpServers in .cursor/mcp.json (project) or ~/.cursor/mcp.json (global). Transports are stdio, SSE and Streamable HTTP. Supports ${userHome}, ${workspaceFolder} and ${env:…} interpolation.
  • MCP features: tools, prompts, resources, roots, elicitation, image content, and MCP Apps (since 2.6). MCP Apps is rolling out per account, and Cursor falls back to the plain tool response. The docs list no tool-count or description-size limits.
  • Plugins: .cursor-plugin/plugin.json (only name is required), with skills/ discovered automatically and mcpServers inline or in mcp.json. ${CURSOR_PLUGIN_ROOT} expands in command, args, env and cwd. Install locally at ~/.cursor/plugins/local/<name>; the marketplace takes reviewed, open-source Git repositories.
  • Deeplinks: cursor://anysphere.cursor-deeplink/mcp/install?name=…&config=<base64>. Not used here: a stdio config would need absolute paths on each machine, since nothing is published to npm.

What changed

  • .cursor-plugin/plugin.json: same metadata as the Claude plugin. It starts node ${CURSOR_PLUGIN_ROOT}/dist/server.mjs from PATH.
  • npm run package:cursor (scripts/package-cursor.mjs): reuses scripts/package.mjs and writes release/cursor-plugin/mobile-dev with dist, assets, skills and the docs. It leaves out .mcp.json, .codex-plugin and the launcher.
  • npm run cursor:config (scripts/cursor-config.mjs): writes .local-dev/cursor-mcp.json with absolute paths, for merging into the global ~/.cursor/mcp.json when running from a checkout.
  • npm run test:cursor (scripts/smoke-cursor-package.mjs): copies the plugin folder to a path with spaces and runs the server with a minimal PATH and a fresh HOME, in both development and release environments. With no client capabilities, it checks the manifest, the payload, that Codex-only files are absent, the tools, the UI resource, the chat fallback for mobile_show_devices with a selectionMode, and the disabled updater.
  • README install section, CONTRIBUTING local development, and a note in docs/releases.md.

No server or UI code changes and no Cursor-specific branches. Behavior still follows advertised client capabilities. If Cursor advertises io.modelcontextprotocol/ui, the device card and workspace render. If not, mobile_show_devices returns the device list as text, and choice requests tell the agent to ask in chat.

Telemetry

Coverage is preserved unchanged. The server, UI and native helpers are the same, so existing surfaces, metrics (including device_picker.*) and error capture apply in Cursor too. The development/release environments come from the same build (package:cursor -- --release for public builds), and the smoke test checks the packaged environment meta in both. No new identity sources or attributes, and telemetry opt-out is honored (the smoke test runs with MOBILE_DEV_TELEMETRY=off).

Testing

  • npm run build && npm run package:cursor && npm run test:cursor: passes in both environments.
  • npm run package:claude && npm run test:claude: passes (no regression).
  • npm run cursor:config: generates the snippet.
  • npm test: 808 of 811 tests pass. Two failed: tests/http-runtime.test.ts "server startup prevents socket QoS crashes…" (a known, unrelated failure) and the Baguette relocation test, which passed when rerun alone and looks flaky under full-suite load.
  • Not tested in the Cursor app itself (Cursor isn't installed on the test machine), so MCP Apps rendering in Cursor is unverified.

🤖 Generated with Claude Code

Add a Cursor plugin manifest that starts the server with Node from PATH
via ${CURSOR_PLUGIN_ROOT}. package:cursor writes
release/cursor-plugin/mobile-dev without Codex-only files, and
test:cursor starts the server from that folder with no client
capabilities to check the chat fallback and disabled updater.
cursor:config writes an mcp.json snippet for ~/.cursor/mcp.json when
running from a checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant