Skip to content
stixezPublic

About

Android SDK and MCP server: 157 tools for calendar, contacts, SMS, files, camera, sensors, notifications and UI automation, for on-device LLMs and MCP clients such as Claude Code and Cursor.

Topics

Resources

Security policy

Stars

40 stars

Watchers

0 watching

Forks

Latest commit

 

History

161 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

droid-mcp

An Android SDK and MCP server that lets an LLM use the phone.
160 tools for calendar, contacts, SMS, files, camera, sensors, notifications and UI automation, for on-device models and any MCP client, such as Claude or Cursor.

CI JitPack API docs Min SDK 28 License Buy Me a Coffee


droid-mcp turns Android phone capabilities into tools a language model can call, using the Model Context Protocol. Use it in two ways:

  • On-device: your app runs a local model and calls the tools directly. No server involved.
  • Over MCP: your app runs a small HTTP server on the phone, and Claude Code, Cursor or any other MCP client that speaks Streamable HTTP connects over Wi-Fi.

With the matching modules, a model can for example:

  • summarize today's calendar and unread messages, then reply to one of them
  • find a photo from last weekend and read the text in it
  • open an app and tap through its screens with the accessibility tools
  • check battery, storage and connectivity, and turn on Do Not Disturb

Highlights:

  • Pick only what you need. 53 independent modules. Each adds only its own permissions to your manifest.
  • Safe by default. Bearer auth, Origin and session checks, an SSRF guard, sandboxed file access, read-only mode, per-tool gating, and optional user confirmation for risky calls.
  • Current MCP. Protocol 2025-11-25: typed results (outputSchema) on every tool, resources, prompts with argument completion, live list_changed updates, image content, progress, elicitation and cancellation.
  • Your permission UX. The library never asks for permissions. Your app decides when and how.

Quick start

Add JitPack and the modules you want:

// settings.gradle.kts
dependencyResolutionManagement {
    repositories { maven { url = uri("https://jitpack.io") } }
}

// build.gradle.kts
dependencies {
    implementation("com.github.stixez.droid-mcp:droid-mcp-core:0.13.0")
    implementation("com.github.stixez.droid-mcp:droid-mcp-calendar:0.13.0")
    implementation("com.github.stixez.droid-mcp:droid-mcp-contacts:0.13.0")
    // or everything except the opt-in modules:
    // implementation("com.github.stixez.droid-mcp:droid-mcp-all:0.13.0")
}

Build it and call a tool:

val mcp = DroidMcp.builder()
    .addTools(CalendarTools.all(context))
    .addTools(ContactsTools.all(context))
    .build()

val result = mcp.callTool("read_calendar", mapOf("start_date" to "2026-10-01"))
if (result.isSuccess) println(result.data)   // {events=[...], count=3}
else println(result.errorMessage)
Packaging error about duplicate META-INF files?

Netty and BouncyCastle ship the same license files in several jars. Exclude them:

android {
    packaging {
        resources {
            excludes += setOf(
                "META-INF/INDEX.LIST",
                "META-INF/io.netty.versions.properties",
                "META-INF/LICENSE.md",
                "META-INF/NOTICE.md",
                "META-INF/license/**",
                "META-INF/versions/9/OSGI-INF/MANIFEST.MF", // droid-mcp-tls only
            )
        }
    }
}

Use it with an on-device model

Give the model the tool catalogue, then run whatever it picks:

val toolsJson = mcp.listToolsJson()           // names, descriptions, JSON Schemas

val result = mcp.callTool("send_message", mapOf("to" to "+15551234567", "body" to "On my way"))

Tool calls run on Dispatchers.IO with a timeout (5 minutes by default, Builder.toolTimeout()), so calling from the main thread is fine. Long tools can report progress: mcp.callTool(name, params) { update -> … }.

Use it from a desktop MCP client

Start the server on the phone:

val mcp = DroidMcp.builder()
    .addTools(DeviceTools.all(context))
    .addTools(CalendarTools.all(context))
    .enableHttpServer(context = context)      // port 8080, token auto-generated
    .build()

mcp.startServer()
val token = mcp.serverToken                   // show it, or put it in a pairing QR

Then add the phone to your client, for example Claude Code (~/.claude/settings.json):

{
  "mcpServers": {
    "phone": {
      "type": "http",
      "url": "http://<phone-ip>:8080/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

The phone advertises itself over mDNS (_mcp._tcp). Useful enableHttpServer options:

  • readOnly = true: only tools that change nothing.
  • allowedOrigins: browser-based clients such as MCP Inspector.
  • Builder.enableTls(...): HTTPS with a pinned self-signed certificate.

Pairing, sessions and TLS are covered in docs/PAIRING.md.

Resources and prompts

Give clients device data to attach, and ready-made prompts:

DroidMcp.builder()
    .addTools(MediaTools.all(context))
    .addResourceProvider(MediaTools.resources(context))    // recent photos and videos
    .addResourceProvider(CalendarTools.resources(context)) // droidmcp://calendar/today
    .addBuiltInPrompts()                                    // message_contact, device_health_check, …

A prompt is listed only while the tools it uses are registered. Tools added later with mcp.registerTools(...), for example after the user grants a permission, reach connected clients through notifications/tools/list_changed. Details are in docs/TOOLS.md.

Confirm risky calls

Ask the user before a destructive tool runs, on either transport:

DroidMcp.builder()
    .addTools(SmsTools.all(context))
    .confirmToolCalls { request ->            // every destructiveHint tool, by default
        withContext(Dispatchers.Main) { askUser(request.toolName, request.arguments) }
    }

If the user declines or doesn't answer in time, the result is tool_call_declined and the tool never runs. ToolCallConfirmer.viaClientElicitation() asks the desktop client's user instead.

Modules

Every module depends only on core. The full list of tools, parameters and permissions is in docs/TOOLS.md.

Area Modules
Personal data calendar contacts sms calllog media files downloads clipboard
Device device screen settings sensors health biometric keyguard flashlight vibration audio usb wallpaper ringtone dnd
Connectivity network wifi bluetooth telephony nfc location web
Camera & vision camera screenshot qr mlkit
Apps & intents apps alarms intent print tts playback
Notifications notifications notifications-reply notification-watch
UI automation accessibility ime overlay
Shell / root admin (opt-in) shizuku root: install and uninstall apps, grant permissions, write settings, run allowlisted commands. See docs/SHELL.md.
Hardening (opt-in) audit (Room-backed call log), tls (self-signed HTTPS), server-service (foreground service that keeps the server alive)

droid-mcp-all bundles everything except the opt-in modules, which pull extra dependencies (Shizuku, libsu, Room, BouncyCastle).

Permissions

Your app requests runtime permissions itself. Check each provider first:

if (CalendarTools.hasPermissions(context)) builder.addTools(CalendarTools.all(context))
else requestPermissions(CalendarTools.requiredPermissions())

Some providers only register tools whose permission is granted, for example create_event needs WRITE_CALENDAR, so rebuild after a grant. A few modules need a grant in system Settings instead:

Module Needs Granted in
playback, notifications-reply, notification-watch Notification access. Your service extends McpNotificationListenerServiceBase. Settings › Apps › Special access › Notification access
accessibility Your service extends DroidMcpAccessibilityService Settings › Accessibility
ime Your service extends DroidMcpInputMethodService, enabled and selected Settings › System › Keyboard
overlay Display over other apps Settings › Apps › Special access
screenshot MediaProjection consent, handed to MediaProjectionHolder from a mediaProjection foreground service Consent dialog
dnd Do Not Disturb access (set_dnd_mode) Settings › Apps › Special access
settings, ringtone Modify system settings (set_brightness, set_ringtone) Settings › Apps › Special access
network, apps Usage access (get_data_usage, get_app_usage; to drop the permission, see docs/TOOLS.md) Settings › Apps › Special access
shizuku, root Shizuku running, or a rooted device See docs/SHELL.md

Note

Android 10+ blocks activity launches from the background. Tools that open another app (launch_app, alarms, intents, toggle_wifi) need your app in the foreground or holding the overlay permission. Otherwise they return an error.

Security

The HTTP server:

  • requires a bearer token
  • rejects foreign Origin headers, non-JSON bodies, bodies over 4 MB and unknown protocol versions
  • ties every request to a session

Tools are also constrained: file tools and file resources are sandboxed to external storage (the file write tools are opt-in), web tools refuse private and loopback addresses, and intents use an action and URI-scheme allowlist. The server listens on every network the phone joins, so use it on networks you trust or enable TLS. The threat model is in docs/SECURITY.md.

droid-mcp itself sends no analytics. Google ML Kit, used by mlkit and qr, reports usage to Google under its own terms.

Requirements

  • Android 9 (API 28) or newer at runtime
  • compileSdk 36+, AGP 8.9.1+ and Kotlin 2.3+ in your app

Sample app

sample-app registers every module, the four resource providers and the built-in prompts, and has four tabs:

  • Tools: a test button per tool, plus shortcuts to grant special permissions.
  • Gating: switch tools on and off on the live server.
  • Activity: recent calls.
  • Audit: the persisted call log, with JSON export.

Start the server there and pair a desktop client with the QR code.

Documentation

Tools Every tool, its parameters and permissions
Pairing Connecting clients: tokens, sessions, mDNS, QR, TLS
Security Threat model and trust boundaries
Shell tools Shizuku and root setup, safety policy
Versioning Compatibility promise and how CI enforces it
API reference KDoc for every module
Releases Release notes

Contributing

Contributions are welcome. For anything non-trivial, please open an issue first.

License

Apache License 2.0. See LICENSE.

About

Android SDK and MCP server: 157 tools for calendar, contacts, SMS, files, camera, sensors, notifications and UI automation, for on-device LLMs and MCP clients such as Claude Code and Cursor.

Topics

Resources

Security policy

Stars

40 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages