Skip to main content
Glama

dsh-adb-phone

English | 简体中文

An MCP 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.

Related MCP server: scrcpy-mcp

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

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:

- 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 (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

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to control, inspect, and automate Android devices, Waydroid containers, and AVD emulators over ADB. Provides tools for screenshots, UI-hierarchy text-based tapping, gestures, key presses, text input, app management, and raw shell commands.
    12
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to visually perceive and directly control Android devices via ADB and screen-control tooling, including screenshots, taps, swipes, typing, app management, UI inspection, file transfer, shell commands, and audio/video streaming.
    374 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to see and control Android devices through ADB and screen mirroring, supporting screen capture, touch input, app management, UI element finding, file transfer, shell commands, clipboard access, and audio/video streaming.
    374 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to see and control Android devices through ADB and scrcpy, including screenshots, taps, swipes, typing, app management, UI inspection, file transfer, shell commands, audio/video streaming, and clipboard access.
    374 npm
    MIT