Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ host as an argument.
| `packages/runtimes` | Pinned Node runtimes bundled into the server (agent-device, serve-emu). |
| `packages/skills` | Agent skills for the shared tools; each host's package step includes the ones its host supports. |
| `apps/codex-plugin` | Codex: manifest, launcher, assets, and its own server (`server/`, the self-updater) and panel (`ui/`, the update banner). |
| `apps/claude` | Claude: the Claude Desktop extension (`manifest.json`, MCPB) and the Claude Code plugin (`.claude-plugin/plugin.json`). Both run Claude's server (`server/`): the shared server with the panel, which Claude Code shows in a browser, and agent-device's commands, with its skill in `skills/` and the shared agent-device skill. The packages leave out the panel's native parts and download them on first use. |
| `apps/claude` | Claude: the Claude Desktop extension (`manifest.json`, MCPB) and the Claude Code plugin (`.claude-plugin/plugin.json`). Both run Claude's server (`server/`): the shared server with the native MCP Apps panel and agent-device's commands. They ship the shared Mobile Dev and agent-device skills and Claude's setup skill in `skills/`. The packages leave out the panel's native parts and download them on first use. |
| `apps/cursor` | Cursor: the Cursor plugin manifest (`.cursor-plugin/plugin.json`). It runs the shared server and panel unchanged. |
| `apps/mac` | The Mac app: a SwiftUI shell (`Sources/`), the page it hosts (`web/`) and its server (`server/`). |
| `packages/test-support` | Fixtures shared by tests across packages and apps. |
Expand Down Expand Up @@ -313,7 +313,8 @@ This writes `release/mobile-dev-<version>-claude-desktop-darwin-arm64.mcpb`, the
Claude plugin folder `release/claude-plugin/mobile-dev` with its ZIP, and a local
`mobile-dev-local` marketplace in `release/claude-plugin`. Both packages run
Claude's server (`apps/claude/server`), with the panel and agent-device's commands as
`device_*` tools, the skill in `apps/claude/skills` and the shared agent-device skill.
`device_*` tools, the shared Mobile Dev and agent-device skills, and Claude's setup
skill in `apps/claude/skills`.
Packaging fails if a file exceeds the Claude plugin directory's 5 MiB limit, so the
packages leave out the panel's native parts (`PANEL_PARTS` in
`tooling/host-runtime.mjs`: Baguette, serve-emu, the iOS mirror addon and its
Expand Down Expand Up @@ -352,26 +353,36 @@ Local builds retain the `development` telemetry environment. Public releases use

### Claude Code local development

Claude's server shows Mobile Dev in a browser beside the chat; in the Claude desktop
app's Code tab that is its built-in browser pane. The terminal advertises no MCP Apps
support, but the Code tab does (Claude Code runs there with `CLAUDE_CODE_MCP_APPS_HOST=1`)
and would render the panel inline. So Claude's server passes `createPanel({ inline: false })`,
whose opening tools carry no `ui.resourceUri` for a host to render and name their page under
`mobile-dev/panel` instead, and `browserPanel({ always: true })`, which links the page for
every host. Opening a recording in the workspace is left out there; recordings stay chat
cards. Build, then load the Claude plugin folder from this checkout:
Claude's server registers the same native MCP Apps panel and device tools as Codex,
without Codex's updater. The resource content sets
`_meta.ui.preferredDisplayMode: "fullscreen"` for Claude, alongside the existing
OpenAI display-mode metadata. Claude uses this preference to open the side panel
where available; it can keep the view inline when the rollout, window size, or
conversation does not allow the side panel. The shared UI also offers an expand
control. See [Claude's display-mode guide](https://claude.com/docs/connectors/building/mcp-apps/display-modes).

Build, then load the Claude plugin folder from this checkout:

```sh
npm run build
npm run package:claude
claude --plugin-dir ./release/claude-plugin/mobile-dev
```

Ask **“Open Mobile Dev.”** The agent opens the returned loopback link in its
browser. The server cannot choose how the host shows that browser: the result asks
the agent to open the page in the foreground, but the host may still show it as a
card in the chat with an **Open** button. Rebuild, repackage and restart the
session after code changes.
Ask **"Open Mobile Dev"** in Claude Desktop. The native panel includes device
streams and controls, logs, storage, App Intelligence, recordings with per-thread
detail, comparisons, and TraceSift's explorer. Its chat actions use the capabilities
Claude advertises. A terminal without MCP Apps can use the tools directly.
Claude's package has no browser page, HTTP panel bridge, or
`mobile_read_panel_context` tool. Rebuild, repackage, and restart the session after
code changes.

The shared Mobile Dev skill keeps Claude's device workflows in step with Codex.
Claude ships its own setup skill and Node recovery reference. Its pinned helper
download and server splitting still meet the directory's 5 MiB file limit.
[Global entry points](https://claude.com/docs/connectors/building/mcp-apps/entry-points)
in Claude currently require a remote connector and access to the unified Claude
experience. They are not an install route for this local plugin.

### Browser panels and Synara

Expand All @@ -381,8 +392,8 @@ Node.js 22.19 or later. For local development, `npm run build` and
`npm run claude:config` generate a standard MCP JSON entry in
`.local-dev/claude-desktop-config.json` with absolute command and argument paths.
Use those paths in the selected provider's MCP configuration, then start a fresh
Synara provider session. The Claude Code and Cursor packages include this same
server and `dist/browser-panel.html`. The native Codex plugin runs its own entry;
Synara provider session. The Cursor package includes this same server and `dist/browser-panel.html`.
Claude and Codex run their own native panel entries;
use the shared server entry for a Synara browser panel.

Ask the agent to open Mobile Dev. When the MCP client advertises no MCP Apps
Expand Down Expand Up @@ -492,8 +503,8 @@ claude plugin install mobile-dev@mobile-dev-local

Set `MOBILE_DEV_PANEL=browser` on T3 Code's Codex instance, as the
[installation steps](README.md#t3-code) describe. The Codex manifest forwards that
variable to the server, which then serves the panel as a browser page like Claude's
server does: `mobile_open_simulator` has no `ui.resourceUri`, so T3 Code renders no
variable to the server, which then serves the panel as a browser page:
`mobile_open_simulator` has no `ui.resourceUri`, so T3 Code renders no
inline app, and its result carries the `browserPanel` link that the agent opens with
`preview_open`. The shared server in `dist/server.mjs` reads the variable too. An
unknown value logs a warning to the server's stderr and keeps the default placement.
Expand Down
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,17 @@ To install the prebuilt plugin from this repository instead, see

### Claude Code and Claude Desktop

In Claude Code, ask to see a device and Claude opens Mobile Dev's device panel in its
browser beside the chat, such as the Claude desktop app's built-in browser pane. The
first open downloads the panel's runtime (Baguette, Android streaming and iPhone
mirroring) once from this repository's GitHub release, checked against the checksum
the plugin pins. Claude reads the devices you select in the panel and anything you add
to chat from it. Mobile Dev also adds device control through the bundled
[agent-device](https://agent-device.dev/) runtime, native
and Metro logs, app control and storage, interactive CPU, memory and FPS charts in
chat, and TraceSift findings.
In Claude Desktop, ask to see a device and Claude opens Mobile Dev's native MCP Apps
panel. It requests the side panel where available and includes the same device
workspace as Codex, with logs, storage, App Intelligence, performance recordings,
comparisons, and TraceSift's explorer. The panel shares selected devices, logs,
screenshots, and notes with Claude, and its Ask and Investigate actions use Claude's
chat bridge. Claude controls side-panel availability; use its expand control when
needed. Terminal sessions can use the tools directly.

The first device-panel open downloads the pinned runtime helpers from this
repository's GitHub release and checks their size and checksum. The other tools
work without that download.

On an Apple Silicon Mac with Node.js 22.19 or later, install the Claude Code plugin
from this repository's `release/claude` branch. It finds Node on `PATH` or where
Expand Down
45 changes: 32 additions & 13 deletions apps/claude/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Mobile Dev for Claude

Build, run, and debug iOS and Android apps without leaving Claude. Mobile Dev streams
your simulators, emulators, and devices into a panel that Claude Code opens in its
browser beside the chat, and gives Claude the tools to control them, read their logs,
inspect your app, and measure its performance. It works with Expo, React Native,
your simulators, emulators, and devices into a native MCP Apps panel inside Claude,
and gives Claude the tools to control them, read their logs, inspect your app,
and measure its performance. It works with Expo, React Native,
SwiftUI, and other native mobile projects.

- **Device panel:** a live, interactive iOS simulator, Android emulator, or connected
Expand All @@ -24,7 +24,11 @@ SwiftUI, and other native mobile projects.
chat, which Claude can analyze and compare.
- **App storage:** read what your app saved, such as UserDefaults, SharedPreferences,
AsyncStorage, MMKV, and SQLite, without adding code to it.
- **Profile analysis:** TraceSift findings for local CPU and React profiles.
- **Profile analysis:** TraceSift findings and the full explorer for local CPU and React
profiles, with investigation actions that send their evidence to Claude.
- **App Intelligence:** an app map of Expo Router and React Navigation screens and
their source dependencies.
- **Device resource saving:** saved resource limits for simulators and emulators.

## Install

Expand All @@ -35,8 +39,25 @@ claude plugin marketplace add https://github.com/callstackincubator/mobile-dev.g
claude plugin install mobile-dev@mobile-dev
```

Start a new session and ask Claude to open your app on a simulator. Approve the tool
calls when prompted. Run `claude plugin marketplace update mobile-dev` to update.
Start a new session in Claude Desktop and ask Claude to open your app on a simulator.
Approve the tool calls when prompted. Mobile Dev requests Claude's side panel and
uses the same device workspace, tools, recordings, storage views, and TraceSift
explorer as the Codex plugin. Claude controls whether the view opens beside the
conversation, inline, or full screen; side-panel access is still rolling out. Use
Claude's expand control when needed.

In a terminal, the device, log, storage, and performance tools work without a panel.
The plugin does not open a browser. Run
`claude plugin marketplace update mobile-dev` to update.

For the Claude Desktop extension, install the `.mcpb` asset from the
[latest release](https://github.com/callstackincubator/mobile-dev/releases/latest),
then restart Claude. The local plugin needs Claude Desktop on the Mac with your
devices. Claude's web connector and Artifacts entry-point features require a remote
server and do not turn this local plugin into a web service.

See the [Claude MCP Apps audit](../../docs/claude-mcp-apps.md) for each supported
feature and the features Claude limits to remote connectors.

## Requirements

Expand All @@ -62,15 +83,13 @@ its Node.js server, it runs:
`github.com/callstackincubator/codex-mobile-dev-plugin/releases`). The plugin pins
the archive's size and SHA-256 checksum and refuses any other file. It holds
[Baguette](https://github.com/tddworks/baguette), which streams and controls iOS
simulators, serve-emu with scrcpy for Android streaming, and the physical iPhone
mirroring addon and its service, built from the source and versions this
repository pins. It is unpacked into Claude Code's data folder for the plugin
simulators, serve-emu with scrcpy for Android streaming, the physical iPhone
mirroring addon and its service, and device resource-saving helpers. The archive
uses the source and versions this repository pins. It is unpacked into Claude Code's data folder for the plugin
(`~/.claude/plugins/data/`), or `~/Library/Caches/mobile-dev` elsewhere, and kept
across sessions; an update downloads its own version and removes older ones.
Nothing is downloaded until you open the panel, and the other tools work without it.
- **A loopback page for the panel:** while the panel is open, the server serves it on
`127.0.0.1` at a random port behind a private link, and answers only that page.

The server downloads these helpers when a tool first needs them. The other tools
work without them.
- **A Node.js launcher and a session check:** `scripts/launch-node.sh` finds Node.js
in the locations above and starts the server; at the start of each session it
checks that one is available.
Expand Down
2 changes: 1 addition & 1 deletion apps/claude/plugin-host.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"panelRuntime": "download",
"build": "tooling/build.mjs",
"skills": ["skills/mobile-dev", "../../packages/skills/agent-device"],
"skills": ["../../packages/skills/mobile-dev", "skills/mobile-dev-setup", "../../packages/skills/agent-device"],
"folders": ["scripts", "hooks"],
"readme": "README.md",
"maxFileBytes": 5242880
Expand Down
14 changes: 5 additions & 9 deletions apps/claude/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ import { readFile } from "node:fs/promises";
import { runStdioServer } from "@mobile-dev/core/stdio-server.ts";
import { agentDeviceTools, readAgentDeviceCatalog } from "@mobile-dev/core/agent-device-tools.ts";
import { createPanel } from "@mobile-dev/core/panel-tools.ts";
import { browserPanel } from "@mobile-dev/core/browser-panel.ts";
import { downloadedPanelRuntime, panelRuntimeReleaseSchema, usePanelRuntime } from "@mobile-dev/core/panel-runtime.ts";

// Claude's server: the shared server with agent-device's commands and Mobile Dev's panel,
// which Claude Code shows in a browser beside the chat. The panel never renders inline,
// even in the desktop app's Code tab, which renders MCP Apps: every host gets the
// browser link, so the device stays beside the chat. The plugin directory's file limit
// leaves the panel's native parts out of the package; it pins their release archive in
// panel-runtime.json, which the server downloads on first use. Without that file, as in
// host tests, the parts sit beside the server.
// Claude's server uses the shared native MCP Apps panel and agent-device tools.
// The plugin directory's file limit leaves the panel's native parts out of the
// package. It pins their release archive in panel-runtime.json for download on
// first use. Without that file, as in host tests, the parts sit beside the server.
const pinned = await readFile(new URL("./panel-runtime.json", import.meta.url), "utf8").catch(() => undefined);
if (pinned !== undefined) usePanelRuntime(downloadedPanelRuntime(panelRuntimeReleaseSchema.parse(JSON.parse(pinned))));
await runStdioServer({ panel: createPanel({ inline: false }), features: [agentDeviceTools(readAgentDeviceCatalog()), browserPanel({ always: true })] });
await runStdioServer({ panel: createPanel(), features: [agentDeviceTools(readAgentDeviceCatalog())] });
37 changes: 37 additions & 0 deletions apps/claude/skills/mobile-dev-setup/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: mobile-dev-setup
description: Set up Mobile Dev in Claude, check its local iOS and Android tools, and recover missing plugin tools.
---

# Set up Mobile Dev in Claude

Resolve Mobile Dev's tools through tool discovery before device work. If
`mobile_open_simulator` or the device-list tools are missing, tell the user:
"Mobile Dev could not start. I'll check its setup." Follow
[missing-tools recovery](references/missing-tools.md) and explain the actual failure.
Source edits and compilation can continue without device tools.

The installed plugin includes the server, MCP Apps panel, agent-device, and native
log and performance helpers. The first device-panel open downloads the pinned
Baguette, serve-emu, physical iOS mirroring, and resource-saving helpers. The server
checks the archive's size and SHA-256 and caches it across sessions. Do not install
separate backends or ask the user to start them. No account or hosted service is
needed.

1. Check for an Apple Silicon Mac, Node.js 22.19 or later, and the toolchain for the
requested platform. iOS simulators need Xcode 26 or later. Physical iPhone logs
need Xcode 27 or later. Android needs SDK platform-tools and emulator, plus an
installed AVD or an authorized device.
2. Call `mobile_open_simulator` to show the native panel, or reuse an open panel.
Use `mobile_open_workspace` for the workspace with logs and performance tools.
In a terminal without MCP Apps, use the tools directly. Do not open a browser.
3. Read any startup error and fix its cause. Confirm device discovery with
`mobile_list_simulators` or `mobile_list_android_devices`. Setup alone does not
need to boot a device. Do not download Xcode runtimes without the user's request.
4. Follow the shared Mobile Dev and agent-device skills for device work. The
bundled agent-device runtime starts on its first command and builds its iOS
XCTest runner with the local Xcode. Use `device_doctor` for a reported runtime
failure. Do not install a global agent-device CLI.

Claude controls whether the native view opens beside the conversation or inline.
If the side panel is unavailable, use its expand control where offered.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Use this when the installed plugin's tools are unavailable. Diagnose and explain
setup problem in chat from the actual startup failure.

Find the installed plugin root from the absolute path of the loaded `SKILL.md`: the
skill is under `<plugin-root>/skills/mobile-dev/SKILL.md`. Inspect its
skill is under `<plugin-root>/skills/<skill-name>/SKILL.md`. Inspect its
`.claude-plugin/plugin.json` and whether the plugin is enabled. Use that installed
copy rather than a source checkout or a guessed cache version. In Claude Code,
`claude mcp list` and `/mcp` show the `mobile-dev` server's status.
Expand Down
Loading
Loading