dsh-adb-phone
by BLxieFox
README.md
# dsh-adb-phone
**English** | [简体中文](README.zh-CN.md)
An [MCP](https://modelcontextprotocol.io) server that lets a **DeepSeek Harness (dsh)** agent see and
control a USB-connected Android phone over `adb`.
dsh ships `@deepseek-ai/dsh-mcp-client`, which registers MCP tools as native tools named
`mcp__phone__tap` and friends.
## Why MCP instead of a native Cordis plugin
dsh is built on Cordis, so a native plugin is possible. But the logic here (`src/core.mjs`) is
host-agnostic — JSON Schema plus an `execute` function. Wrapping it as MCP makes it reusable by dsh,
Claude Code, Codex and any other MCP client, while a Cordis plugin would only work inside dsh.
The trade-off is two missing features: there is no `codemode`, and no OpenCode-style `phone`
permission action — approvals are handled by dsh's own policy.
## Requirements
- Android device with **USB debugging** enabled and the host authorised.
- Node.js ≥ 18.
- `adb` reachable through `ANDROID_HOME` / `ANDROID_SDK_ROOT` / `ADB_PATH`, or on `PATH`.
## Install
**From source**
```bash
git clone https://github.com/BLxieFox/dsh-adb-phone.git
cd dsh-adb-phone
npm install
```
There is no package-registry release; clone and run from the checkout.
## Register it in dsh
Edit `~/.dsh/profiles/<profile>/cordis.patch.yml` and append an insert entry:
```yaml
- insert:
- id: mcp-phone
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: phone
transport: stdio
command: node
args: ['C:/Users/you/dsh-adb-phone/bin/mcp.js']
env:
ANDROID_HOME: 'E:/Android/Sdk'
toolCallTimeoutMs: 120000
```
Save the file; `patchReload: live` reloads the profile. The tools then appear as `mcp__phone__*` —
try asking the agent to report the phone status.
## ⚠️ The child environment is scrubbed
MCP clients do **not** pass the full environment to a stdio server. `@modelcontextprotocol/sdk`
keeps only an allowlist (`PATH`, `APPDATA`, `LOCALAPPDATA`, `USERPROFILE`, `TEMP`, `SYSTEMROOT`, … on
Windows).
**`ANDROID_HOME` is not on that list.** Even if you export it in your shell, the MCP server will not
see it and `adb` fails with:
```
spawn adb.exe ENOENT
```
Two fixes, either works:
1. Pass `env.ANDROID_HOME` explicitly in the config (recommended, as above);
2. Make sure `adb` itself is on the `PATH` the child inherits.
## Tools
| Tool (inside dsh) | Description |
| --- | --- |
| `mcp__phone__status` | Devices, model, Android version, ABI, screen size/density, battery, foreground app |
| `mcp__phone__screenshot` | Screen capture, returned as an MCP image block |
| `mcp__phone__snapshot` | UI hierarchy as a labelled tree, optionally with a screenshot |
| `mcp__phone__tap` | Tap by `label` / `text` / coordinates; long press via `duration` |
| `mcp__phone__swipe` | Swipe by direction + distance, or explicit coordinates |
| `mcp__phone__type` | Type text; ASCII via `input text`, Unicode via clipboard; `clear`, `commit` |
| `mcp__phone__key` | Named keys or a raw keycode |
| `mcp__phone__open` | Launch an app, an activity, or a URL |
| `mcp__phone__apps` | List installed packages |
| `mcp__phone__wait` | Poll until text appears or a package becomes foreground |
| `mcp__phone__shell` | Raw `adb shell` |
| `mcp__phone__push` / `mcp__phone__pull` | File transfer |
| `mcp__phone__install` | Install an APK |
## Usage
```
mcp__phone__snapshot first, act on a [label] with mcp__phone__tap,
then snapshot again to verify.
```
With several devices attached, pass `serial` or set `ADB_SERIAL`.
## Differences from the OpenCode version
1. **Timeouts** — dsh allows 60 s per tool call by default; screenshots or app launches may need
`toolCallTimeoutMs: 120000`.
2. **Images** — screenshots come back as MCP `image` blocks (base64). dsh renders them when the
model accepts image input and attachments are enabled.
3. **Permissions** — no `phone` permission action; dsh's own approval policy applies.
## Relationship to opencode-adb-phone
`src/core.mjs` is shared with [opencode-adb-phone](https://github.com/BLxieFox/opencode-adb-phone)
(adb calls, uiautomator parsing, label addressing, text input). Keep the two in sync when changing
behaviour.
Only the entry point differs: an OpenCode plugin (`ctx.tool.transform`) there, an MCP server
(`tools/list` + `tools/call`) here.
## Development
```bash
npm test # real stdio handshake, asserts the 14 tools
ADB_PHONE_SMOKE=1 npm test # also calls status once, needs a device attached
```
## Limitations
- `uiautomator dump` can fail on idle or animating screens; the server retries once.
- WebViews often expose no usable node text — fall back to a screenshot plus coordinates.
- CJK IMEs may leave text in the composing strip; use `commit: true`.
- Not a substitute for instrumentation tests on an app you own.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues