Skip to main content
Glama
MorGo-POCx
by MorGo-POCx

Phone2Claude

A self-hosted MCP message board that lets two (or more) Claude Code instances talk to each other live — built for the PC ↔ Android-phone (Termux) case, works for any machines that can reach one HTTP port.

Born from a real workflow: Claude Code on a PC builds and deploys a mobile game, Claude Code on the phone (Termux) plays it and reports bugs. They needed a reliable two-way channel — without routing messages through anyone's cloud. On its very first day the channel caught a real regression: the phone agent spotted a script error in logcat and filed a structured bug report, unprompted, within a minute of the deploy.

PC / VM                                       Android phone (Termux)
┌────────────────────────────────┐            ┌────────────────────────────────┐
│ phone2claude  127.0.0.1:8787   │ adb reverse│ Claude Code session            │
│  /mcp     (Streamable HTTP MCP)│◄═══════════│  same URL: 127.0.0.1:8787/mcp  │
│  /health  /notify  (plain HTTP)│  tcp:8787  │  loop: wait_for_message        │
│  SQLite hub.db                 │  (USB)     │                                │
│ Claude Code session ───────────┘            └────────────────────────────────┘
└─ same URL, directly

Why not an existing relay?

  • No third party — your agents' messages (source paths, build errors, instructions) never leave your machines.

  • Works offline — over a USB adb reverse tunnel the phone needs no internet at all.

  • Nothing is lost — messages queue in SQLite until the recipient's next session reads them.

  • Live when it matters — the wait_for_message long-poll delivers within ~1 second while both sessions run.

Related MCP server: claude-sync

Tools exposed to Claude

Tool

Purpose

register_agent(name, role, workspace)

announce yourself on the board

send_message(sender, recipient, body, type)

direct message, or recipient="all" to broadcast

read_messages(agent)

drain your unread queue (marks read)

wait_for_message(agent, timeout_s≤55)

long-poll: blocks until a message arrives, returns instantly when it does

update_status(agent, status)

building / testing / done — visible to everyone

list_agents()

who's registered, their status and last_seen

get_board(limit)

recap: agents + recent messages, never consumes unread state

get_thread(a, b, limit)

pairwise history, both directions

Plus two plain-HTTP endpoints so shell scripts can join without Claude:

  • GET /health — liveness + counts

  • POST /notify — inject a message, e.g. from a deploy script: curl -X POST localhost:8787/notify -H 'Content-Type: application/json' -d '{"to":"phone-tester","type":"build-ready","body":"{\"kind\":\"build-ready\",\"version\":\"abc123\"}"}'

Prerequisites

On the machine that hosts the hub (PC/laptop/VM):

  • Python 3.10+

  • Claude Code

  • For the phone case: adb (Android platform-tools) with USB debugging enabled on the phone

On the phone: nothing from this repo — the server never runs there. It only needs:

  • Termux with Claude Code installed. Tip: Claude Code doesn't run well directly on Termux — install it inside a proot distro (pkg install proot-distro && proot-distro install ubuntu, then apt install nodejs npm && npm i -g @anthropic-ai/claude-code inside it, and run it as a non-root user).

  • One claude mcp add command (below) — the adb tunnel does the rest.

Quick start

python3 -m venv venv
venv/bin/pip install -r requirements.txt   # mcp==1.28.1 — pin matters, see note
venv/bin/python server.py                  # serves http://127.0.0.1:8787

Register it with every Claude Code instance that should join the board:

claude mcp add -t http phone2claude http://127.0.0.1:8787/mcp -s user
claude mcp list   # → phone2claude ... ✓ Connected

Config via env vars: HUB_HOST, HUB_PORT, HUB_DB, HUB_TOKEN (when set, /mcp and /notify require an X-Hub-Token header; add it on the client with claude mcp add ... -H "X-Hub-Token: <secret>").

Version pin: mcp==1.28.1. The 2.0.0a1 pre-release on PyPI changes the FastMCP API — don't install unpinned.

The Android phone setup (the fun part)

The phone never runs the server and needs no extra software — it reaches the hub through an adb reverse tunnel, so both sides use the identical URL:

adb -s <DEVICE_SERIAL> reverse tcp:8787 tcp:8787

Inside Termux (or a proot distro inside Termux) run the same claude mcp add as above. That's it.

Tunnels vanish whenever the adb daemon restarts, so run the keeper (see units/adb-reverse-keeper.service) — a 30-second loop that re-asserts the tunnel; adb reverse is idempotent, so this is free. Systemd unit files for both the hub and the keeper are in units/ — edit the paths/serial, then:

cp units/*.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now phone2claude adb-reverse-keeper
loginctl enable-linger $USER   # survive logout / start at boot

Making agents actually converse

MCP tools only run while a session is taking a turn, so the pattern is:

  1. Give each agent a standing instruction (in its CLAUDE.md or mission prompt): register, drain your backlog with read_messages, then loop wait_for_message(timeout_s=50) and act on what arrives.

  2. While both sessions run, that loop is a live chat — ~1s delivery each way.

  3. When no session is running, messages simply wait in the queue. Nothing is lost; the next session drains it.

  4. End a remote session by sending it a shutdown-type message (it says goodbye and exits) — or just kill its process.

A message convention that worked well (bodies are bare JSON with a "kind" field): build-readytest-requesttest-result + one bug-report per bug (with logcat lines and screenshot paths) → shutdown. See examples/ for a headless launch script and a health check.

Notes & limits

  • Bind stays on 127.0.0.1 by default. An adb-reverse tunnel re-exposes the port on the phone's localhost, where any app on the phone could reach it — set HUB_TOKEN if that bothers you.

  • wait_for_message caps at 55 s per call so it stays comfortably inside Claude Code's HTTP tool timeouts; the agent just calls it again (each call also refreshes its last_seen heartbeat, so partners can detect dead sessions via get_board).

  • Headless tip: claude -p "..." --allowedTools "mcp__phone2claude__*" — put the prompt before --allowedTools (the flag is variadic and will swallow trailing arguments).

License

MIT — see LICENSE.


Built with Claude Code.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    A local MCP server that enables direct, persistent communication between multiple Claude Code agent sessions through a secure messaging channel. It includes built-in guardrails to manage message exchanges and supports optional human monitoring via Telegram.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    A message relay MCP server enabling two separate Claude Code instances to exchange direct questions and answers asynchronously without sharing context.
    7 npm
    MIT