PocketMCP
Turn your Android phone into an MCP (Model Context Protocol) server. AI agents and desktop scripts can call your phone for live data and actions over LAN
Documentation
PocketMCP
Turn your Android phone into an MCP (Model Context Protocol) server. AI agents and desktop scripts can call your phone for live data and actions over LAN or Tailscale.
Demo
Tab switching, staggered content reveals, log filters, the sliding segmented control, category chips, and dark mode — captured from the live UI:
▶ Watch the full-resolution walkthrough (MP4 · 736×1540 · 18s)
Download (Testing Pre-release)
- Latest debug build:
PocketMCP-debug.apk(v1.0.0-beta.9) — install over USB withadb install -r PocketMCP-debug.apk - In-app updates: after the first manual install, new builds are installed from Settings → App Updates (checks a JSON manifest and hands the APK to the system installer). The MCP server auto-resumes after each update. The update source is fully self-hosted — the app ships with no URL; point it at any manifest you control.
- Previous tagged release: v1.0.0-beta.1
- This build is marked as pre-release and may contain bugs while active development continues.
Screenshots
Light mode — Server · Logs · Tools · Settings
Dark mode — the app follows the system light/dark setting
Open-Source Commitment
PocketMCP is fully open-source and core functionality is free. The project is MIT-licensed and community contributions are welcome.
Why this is useful
High-value use cases for all users:
- Communication Hub: Send WhatsApp, Instagram, Messenger messages and make calls from desktop
- Social Media Automation: Interact with Instagram, YouTube, X/Twitter automatically
- Notification Management: Monitor and respond to all phone notifications in real-time
- Daily readiness check: "What is my battery and where is my phone right now?"
- Contact lookup: "Find Alice's number from my phone contacts."
- App ecosystem control: Launch and manage 309+ installed applications
- Phone diagnostics: Run safe shell checks without unlocking the phone.
Built-in tools
| Tool | Description |
|---|---|
device_info | Battery, model, OS, network, memory |
get_location | Best recent location from device providers (with active-fix fallback) |
accessibility_control | Check/toggle the accessibility service (one-time ADB unlock) |
search_contacts | Search contacts by name |
make_call | Make phone calls to any number |
send_message | Send messages via WhatsApp, Instagram, Messenger, Google Messages |
send_whatsapp_business_message | Dedicated WhatsApp Business contact-safe sender |
whatsapp_automation | Advanced WhatsApp automation with accessibility control |
social_media | Instagram, YouTube, X/Twitter interactions |
app_actions | JSON-preset actions for simpler app automation calls |
notifications | Real-time notification monitoring and management |
shell | Run shell commands with safety filters and timeout |
flashlight | Turn flashlight on/off/toggle and read state |
launch_app | Open an installed app by package or app name |
list_apps | List launchable installed apps (309+ apps detected) |
global_action | Home/back/recents/notifications/quick settings/lock screen |
scroll_screen | Scroll current app via accessibility gesture |
search_screen | Find search input on current screen and type query safely |
tap | Tap by visible text/content description or screen coordinates |
volume_control | Read and change stream volume levels |
phone_alert | Ring and/or vibrate phone to help locate it quickly |
voice_record | Record voice notes from microphone |
transcribe_audio | Speech-to-text from microphone or local audio file path |
transcribe_file | Direct audio-file transcription by path |
transcribe_whatsapp_audio | Transcribe latest WhatsApp/WhatsApp Business voice note |
human_command | Natural-language command router across major tools |
intelligent_action | Experimental humanoid planner/executor with retries and traces |
http_request | Make outbound HTTP requests from phone |
read_file | Read files from allowed storage paths |
🆕 New Features (v.0+)
📞 Phone Calling & Messaging
- Direct Calls: Make phone calls to any number with contact name support
- Multi-Platform Messaging: WhatsApp, Instagram, Messenger, Google Messages
- WhatsApp Business Support: Prioritizes WhatsApp Business when installed
- Deep Link Integration: Opens apps with pre-filled content
🤖 Advanced WhatsApp Automation
- Complete Automation: Send messages with contact selection and typing
- Step-by-Step Control: Select contacts, type messages, press send/cancel
- Accessibility Integration: Full UI automation via accessibility service
- Business & Personal: Supports both WhatsApp variants
🌐 Social Media Interactions
- Instagram: Profile search, post interactions (like, comment, share)
- YouTube: Video search, like/dislike/comment on videos
- X/Twitter: Profile search, post interactions
- Deep Links: Direct navigation to specific content
🔔 Real-Time Notifications
- Live Monitoring: Capture all device notifications in real-time
- Full Data: Title, text, app, time, priority, visibility
- Historical Access: Recent notifications with search and filtering
- Management: Clear history, check status, get counts
App UI & Design
PocketMCP uses a custom-built Jetpack Compose UI with a clean, platform-native design language — neutral surfaces, a single system-blue accent, and real typography.
Design Highlights
- Light & Dark: Follows the system setting; calm neutral surfaces with grouped inset lists (no neon, no glassmorphism)
- System Blue Accent (
#007AFFlight /#0A84FFdark); semantic colors are reserved for status (green = running, orange = attention, red = destructive) - Inter Typeface: Bundled static weights mapped to an Apple-scale type ramp (34 / 22 / 20 / 17 / 15 / 13 / 11 pt)
- Hairline Separators & Grouped Cards: iOS-style inset lists with 12 pt rounded cards and inset hairline dividers
- Consistent Rhythm: 24 / 16 / 8 pt section spacing, 48 pt minimum touch targets, single-line rows with ellipsis — nothing cramped
- Restrained Motion: Staggered section entrances on tab switches, a sliding segmented-control pill, scrolling filter chips, spring tab icons, counting stat numbers, a pulsing status dot, and iOS-style press feedback on rows and buttons; no glows, orbs, or parallax
A static HTML replica of all four screens (with a live light/dark toggle) lives in preview/app-preview.html — open it in any browser to see the design without building the app. The screenshots and demo video in this README are generated from it with node preview/capture.mjs both (headless Chrome + ffmpeg).
Screens
| Screen | Description |
|---|---|
| Server | Status card with start/stop action, session stats, connection details, port/API-key config, one-tap MCP config copy, QR |
| Logs | Runtime terminal, segmented filters (All / Errors / Tools / Requests), color-coded event list |
| Tools | 33-tool searchable library with scrolling category filter chips and per-tool status |
| Settings | Grouped permission toggles, safety filter, developer mode, API key management |
Navigation
- Full-width tab bar with a hairline top border; tab icons are outline when idle and filled when selected, tinted system blue
- Quiet cross-fade page transitions between tabs, with a short per-section entrance cascade (no lateral slide)
- Snackbar feedback for all user actions (replacing legacy Toast)
Security model
- API key authentication on every endpoint (except
GET /andGET /health), including the WebSocket and SSE handshakes. - Clients may send the key as
X-API-Key,Authorization: Bearer <key>, or?key=<key>(query parameter, for WebSocket/SSE clients that cannot set headers). - The API key is stored encrypted on the phone using Android Keystore-backed
EncryptedSharedPreferences. - Repeated failed authentication attempts are throttled per client host (HTTP 429).
- Local network usage by default; use Tailscale for remote access.
- Shell tool blocks high-risk commands and enforces timeout/output limits (best-effort filter, not a sandbox).
- File reads are restricted to app storage and external storage roots.
- Loopback URLs are blocked in
http_request. - The in-app updater ships with no built-in endpoint: it only fetches manifest URLs you configure.
- Accessibility Service: Required for advanced automation features. On OEM builds that block the accessibility toggle (for example Samsung Auto Blocker), run
scripts/setup-wireless-adb.ps1once — it grantsWRITE_SECURE_SETTINGSand enables the service; afterwards the app toggles it itself, with no OEM screen involved. - Notification Access: Required for real-time notification monitoring.
Reliability model
- Android foreground service keeps MCP server alive.
- Start/stop/status lifecycle is explicit (
START,STOP,QUERY_STATUS). - UI reflects actual service state using status broadcasts.
- Enhanced App Discovery: Detects 309+ launchable apps (up from 25).
- Graceful Fallbacks: Manual interaction instructions when automation not possible.
Intelligent Orchestration (Experimental)
PocketMCP now includes a new high-level orchestration tool, intelligent_action, designed for "humanoid" multi-step flows across apps.
What it adds
- Natural command parsing into structured intents and entities
- Task-graph planning (instead of one-shot command execution)
- Step-by-step execution with retry and verification
- Risk gating for sensitive actions (for example report/flag flows)
- Trace logging for continuous reliability improvement
Current architecture
- Tool entrypoint:
app/src/main/java/com/pocketmcp/tools/IntelligentActionTool.kt - Agent core packages:
app/src/main/java/com/pocketmcp/agent/model/intent/step/result modelsnlu/parser and entity resolutionplanner/graph builder and policy gateexecution/orchestrator, executor, verifier, retry behaviorskills/app-specific skill packs (youtube,x)perception/popup/blocker helpersmemory/session context and trace writingdialog/clarification prompts for ambiguous requests
Usage notes
- Use
dry_run=trueto inspect parsed intents and planned steps before execution. - Keep
confirm_risky=truefor safer defaults in production-like usage. - Execution traces are written under app-private files (
agent-traces) for tuning.
Example MCP call payload
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "intelligent_action",
"arguments": {
"command": "open youtube and search psg and bayern",
"dry_run": false,
"confirm_risky": true
}
}
}
Quick start
1) Install app
Option A: install from pre-release APK
- Download
PocketMCP-debug.apkfrom v1.0.0-beta.1 - Install with ADB:
adb install -r PocketMCP-debug.apk
Option B: build from source and install
./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk
2) Start server in app
- Open PocketMCP.
- The Server tab opens by default.
- Set port (default
8080) in the Configuration card. - Generate or paste an API key.
- Tap Start Server — the status orb will pulse green when active.
- Copy the endpoint or full MCP config from the Quick Connect card.
3) Enable Permissions
Required for full functionality:
- Location:
ACCESS_FINE_LOCATION— used byget_location - Contacts:
READ_CONTACTS— used bysearch_contacts - Camera:
CAMERA - Phone:
CALL_PHONEpermission in app settings - Microphone:
RECORD_AUDIOpermission in app settings - SMS:
SEND_SMS,READ_SMSpermissions - Audio/Storage:
READ_MEDIA_AUDIO(Android 13+) orREAD_EXTERNAL_STORAGE— used by audio transcription - Notifications: Settings → Apps → Special Access → Notification Access
- Accessibility: Settings → Apps → Special Access → Accessibility Services
All permission states are visible in the Settings tab with one-tap navigation to system settings.
4) Verify server
# health
curl http://192.0.2.100:8080/health
# list tools
curl -X POST http://192.0.2.100:8080/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Or verify everything in one shot (health, auth, protocol, tool list):
node mcp-bridge/setup.mjs doctor --url http://192.0.2.100:8080/mcp --api-key your-api-key
Enabling accessibility when the OEM settings screen blocks it
Some One UI builds (Samsung Auto Blocker) refuse the accessibility toggle. One-time fix — pair wireless debugging, then run:
powershell -ExecutionPolicy Bypass -File .\scripts\setup-wireless-adb.ps1
The script grants WRITE_SECURE_SETTINGS, enables the accessibility service and the notification listener. Afterwards Settings shows a live toggle, and the accessibility_control MCP tool can enable/disable the service remotely.
Emulator connection (Android Studio AVD)
If PocketMCP runs inside an Android emulator, do not use 10.0.2.15 from your host MCP client config.
Use ADB port forwarding and localhost:
powershell -ExecutionPolicy Bypass -File .\scripts\setup-emulator-mcp.ps1
Then set MCP URL to:
http://127.0.0.1:8080/mcp
Notes:
10.0.2.15is emulator-internal (not host-reachable).10.0.2.2is for emulator -> host, not host -> emulator.
Connect your AI tool
PocketMCP speaks Streamable HTTP natively (no companion process needed) and also ships a zero-dependency stdio bridge for tools that only launch local MCP servers. Both paths expose the same tools — use either, or both.
One command does the whole setup (Node 20+, no npm install):
node mcp-bridge/setup.mjs
It finds your phone on the LAN (mDNS), verifies health + API key + tool discovery, saves the connection to ~/.pocketmcp.json, and writes ready-made configs for the tools you pick:
| Tool | Config location | Direct HTTP | Stdio bridge |
|---|---|---|---|
| OpenCode | ~/.config/opencode/opencode.json | ✅ | ✅ |
| Claude Code | claude mcp add / .mcp.json | ✅ | ✅ |
| Codex CLI | ~/.codex/config.toml | ✅ | ✅ |
| Cursor | ~/.cursor/mcp.json | ✅ | ✅ |
| Claude Desktop | claude_desktop_config.json | (Connectors UI) | ✅ |
| Anything else | node mcp-bridge/setup.mjs print generic | ✅ | ✅ |
Handy commands:
node mcp-bridge/setup.mjs doctor # end-to-end connectivity check
node mcp-bridge/setup.mjs doctor --call device_info # ...and actually run a tool
node mcp-bridge/setup.mjs print opencode # print one config, write nothing
node mcp-bridge/setup.mjs --mode bridge # configure the stdio bridge instead
node mcp-bridge/setup.mjs --mode both # write the HTTP config + print the bridge variant
Full per-tool walkthrough with every snippet: docs/harness-setup.md.
Direct Streamable HTTP endpoint
The phone endpoint is the core of the server and stays available either way — the bridge is just a proxy to it:
POST http://<phone-ip>:8080/mcp # JSON-RPC (JSON or SSE response)
GET http://<phone-ip>:8080/mcp # SSE stream
GET http://<phone-ip>:8080/health # public health check (no key)
WS ws://<phone-ip>:8080/ws # WebSocket transport (pass ?key=<api-key>)
Minimal client config (also in mcp-config.example.json):
{
"mcpServers": {
"pocketmcp": {
"type": "http",
"url": "http://192.0.2.100:8080/mcp",
"headers": {
"X-API-Key": "your-api-key"
}
}
}
}
Claude Code requires
"type": "http"; Cursor ignores the type field; OpenCode usesmcp.serversinstead ofmcpServers—setup.mjs print opencodeemits the right shape.
Stdio bridge (for stdio-only clients)
mcp-bridge/bridge.mjs is a single file with zero dependencies — no npm install:
node mcp-bridge/bridge.mjs --url http://192.0.2.100:8080/mcp --api-key your-api-key
After running the setup wizard once, the bridge auto-resolves your phone from ~/.pocketmcp.json (falling back to LAN discovery), so node mcp-bridge/bridge.mjs alone is enough:
--url/POCKET_MCP_URL: phone MCP URL (ws://URLs auto-convert; default falls back to127.0.0.1:8080for emulators)--api-key/POCKET_MCP_API_KEY: key sent asX-API-Key--timeout-ms/POCKET_MCP_TIMEOUT_MS: per-request timeout (default30000)--tools-ttl-ms/POCKET_MCP_TOOLS_TTL_MS: tool-list cache TTL (default30000)--no-tool-cache/POCKET_MCP_DISABLE_TOOL_CACHE=1: always fetch the live tool list--verbose/POCKET_MCP_VERBOSE=1: detailed logs on stderrPOCKET_MCP_PROFILE: alternate profile path (default~/.pocketmcp.json)
Python Client Example
from pocket_mcp_client import PocketMCPClient
phone = PocketMCPClient("http://192.0.2.100:8080", api_key="your-api-key")
print(phone.device_info())
print(phone.list_apps(limit=25))
print(phone.notifications("list", 10))
print(phone.human_command("vibrate my phone for 5 seconds"))
Python client now includes retries, typed exceptions, stricter argument validation, and a CLI:
# health check (default action)
python3 pocket_mcp_client.py 192.0.2.100:8080 your-api-key
# list tools
python3 pocket_mcp_client.py 192.0.2.100:8080 your-api-key --list-tools
# call one tool with JSON args
python3 pocket_mcp_client.py 192.0.2.100:8080 your-api-key \
--call send_message \
--args '{"app":"whatsapp","phone_number":"+15551234567","message":"hello from desktop"}'
Instant command lane (no LLM)
scripts/pocket.mjs (Node 20+, zero dependencies) routes everyday phrases straight to tool calls — no AI in the loop, one HTTP request, typically a few hundred milliseconds on a warm LAN:
node scripts/pocket.mjs "torch on"
node scripts/pocket.mjs "torch on and open youtube" # chains: "and" / "then" / ";" / ","
node scripts/pocket.mjs "find my phone"
node scripts/pocket.mjs "call alex"
node scripts/pocket.mjs help # full phrase cheat sheet
node scripts/pocket.mjs --dry-run "lock the phone, torch on"
It reads the connection profile written by setup.mjs (~/.pocketmcp.json); anything it doesn't recognize is forwarded to the phone's on-device NLU (human_command) in the same round trip — still no desktop model involved.
Development
Tech Stack
| Layer | Technology |
|---|---|
| UI Framework | Jetpack Compose (Material 3) |
| Language | Kotlin 2.2.10 |
| Build System | Gradle 9.4.1 + AGP 9.2.0 (Kotlin DSL) |
| HTTP Server | Ktor 2.3.7 (Netty engine) |
| Serialization | kotlinx-serialization-json 1.6.0 |
| Target SDK | 34 (Android 14) |
| Min SDK | 26 (Android 8.0) |
| Build JDK | 21 |
Project Structure
app/src/main/java/com/pocketmcp/
├── MainActivity.kt # Compose entry point + business logic
├── accessibility/ # PhoneAccessibilityService
├── server/ # Ktor MCP server + JSON-RPC types
├── service/ # McpServerService (foreground service)
├── tools/ # ~35 MCP tool implementations
└── ui/ # Jetpack Compose UI
├── theme/ # Colors, Typography, Theme
├── components/ # Reusable UI components
│ ├── Cards.kt # Grouped cards, list rows, section headers
│ ├── CodeBlock.kt # Monospace code surface
│ ├── Controls.kt # Buttons, segmented control, search bar
│ └── NavBar.kt # Bottom tab bar
└── screens/ # Screen composables
├── DashboardScreen.kt
├── LogsScreen.kt
├── SettingsScreen.kt
└── ToolsScreen.kt
Adding a New Tool
- Create a new Kotlin file in
app/src/main/java/com/pocketmcp/tools/. - Implement
McpToolHandler. - Register the tool in
McpServer.init { registry.register(YourTool()) }. - Add it to
ToolsScreen.ktfor UI visibility.
Testing
# Unit tests (JVM, no device required)
./gradlew testDebugUnitTest
# Debug build
./gradlew assembleDebug
Unit tests live in app/src/test/java/ and cover the API-key guard and throttling,
JSON-RPC encoding, tool result helpers, the shell safety filter, and the agent
NLU/planning layer. CI (.github/workflows/ci.yml) runs the build and the full test
suite on every push and pull request.
Permissions
Some tools require Android special permissions or services:
- Phone (
CALL_PHONE) - Microphone (
RECORD_AUDIO) - SMS (
SEND_SMS,READ_SMS,RECEIVE_SMS) - Location (
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION) - Contacts (
READ_CONTACTS) - Camera (
CAMERA) - Audio/Storage (
READ_MEDIA_AUDIO/READ_EXTERNAL_STORAGE) - Notifications access (Notification Listener)
- Accessibility service (for UI automation)
Security Model
- API key authentication on all endpoints (via
X-API-Key,Authorization: Bearer, or?key=for WebSocket/SSE handshakes) - Encrypted API-key storage (Android Keystore-backed
EncryptedSharedPreferences) - Brute-force throttling per client host
- Local network first; remote access via private networks like Tailscale
- Shell command restrictions with timeout/output limits
- File-read path restrictions
- Loopback URL blocking for
http_request - No built-in update endpoint — the in-app updater only fetches manifests you configure
Reliability Notes
- Runs as an Android foreground service
- Explicit service lifecycle (
START,STOP,QUERY_STATUS) - Status broadcast updates reflected in UI
Roadmap
- Camera capture tools
- More accessibility-driven automations
- One-tap pairing workflow (QR codes)
- Voice-first command flows
- Release signing and Play Store readiness
License
MIT