Open Device Cloud MCP¶
openDeviceCloud exposes a built-in Model Context Protocol server at:
http://127.0.0.1:8000/mcp
Unlike the REST API, the MCP endpoint is not mounted under /api.
Transport¶
HTTP
POSTJSON-RPC 2.0 request bodies
optional Server-Sent Events responses when the client sends
Accept: text/event-stream
Initialize A Session¶
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
}
}'
List Available Tools¶
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
The server exposes tools across five categories:
Category |
Tools |
|---|---|
Images |
|
Devices |
|
Apps & files |
|
Interaction |
|
Networking |
|
It also supports MCP resources for screenshot payloads:
resources/list— list screenshot resources captured in the current MCP sessionresources/read— lazily fetch screenshot bytes from a server-owned resource URI
By default, screenshot returns an MCP resource link only, keeping large image blobs out of the tool result.
Pass include_inline_image: true to also embed the image bytes directly in the response.
Call A Tool¶
Example: list devices.
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "device_list",
"arguments": {}
}
}'
Example: read a screenshot resource returned by the screenshot tool.
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-H 'X-OpenDC-MCP-Session: demo-session' \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/read",
"params": {
"uri": "odc-screenshot://example/device/capture"
}
}'
Example: request both the resource link and an inline image preview.
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "screenshot",
"arguments": {
"device_id": "device-id",
"include_inline_image": true
}
}
}'
Example: create a persistent Frida bridge to the default Frida server port on an iOS device.
curl -s http://127.0.0.1:8000/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "bridge_create",
"arguments": {
"device_id": "device-id",
"device_port": 27042,
"persistent": true
}
}
}'
When device_port is 27042, the tool returns a Frida usage hint so clients can connect directly with a local frida CLI over the exposed bridge.
Session Header¶
Requests that need to share state across calls (for example, reading a screenshot resource captured in a previous request) should include a consistent session identifier:
X-OpenDC-MCP-Session: <any-string>
The server scopes screenshot resources to this header value. Without it, resources/list and resources/read will not find resources from prior requests.
Batch Requests¶
The endpoint accepts a JSON array of JSON-RPC 2.0 objects in a single POST. Each item is processed independently and the response is an array of results in the same order. Notifications (messages without an id) are processed but produce no output entry.
Connect Claude Code¶
Add the server to ~/.claude/mcp.json so Claude Code discovers it automatically:
{
"mcpServers": {
"odc": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
}
Claude Code will then have access to all ODC tools directly from within any conversation.
Tool Reference¶
Images¶
image_list — List managed images and Android SDK images.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
no |
Filter by agent |
|
integer |
no |
Page size |
|
string |
no |
Pagination cursor |
|
boolean |
no |
Return full metadata (default: false) |
|
boolean |
no |
Bypass cache (default: false) |
image_update — Rename or re-describe a managed image without changing its ID.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
Image ID or exact name |
|
string |
no |
New name |
|
string |
no |
New description |
|
string |
no |
Agent scope |
image_delete — Delete a managed image.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
Image ID or exact name |
|
string |
no |
Agent scope |
image_create_from_device — Snapshot a stopped device into a new managed image.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
Source device |
|
string |
yes |
Name for the new image |
Devices¶
device_list — List managed devices with status and metadata.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
integer |
no |
Page size |
|
string |
no |
Pagination cursor |
|
boolean |
no |
Bypass cache (default: false) |
device_create — Create a device from an image.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
Image ID or exact name |
|
string |
no |
Device display name |
|
string |
no |
Device model override |
|
string |
no |
OS version override |
device_start / device_stop / device_reboot / device_delete — Lifecycle controls.
Argument |
Type |
Required |
|---|---|---|
|
string |
yes |
device_status — Power state plus SSH and runtime readiness.
Argument |
Type |
Required |
|---|---|---|
|
string |
yes |
device_wait_ready — Block until a device accepts remote connections.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
integer |
no |
Max wait time |
Apps & Files¶
shell_exec — Run a shell command in the device guest environment.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
yes |
Shell command |
|
integer |
no |
|
|
object |
no |
Extra environment variables |
file_write — Write UTF-8 text to a path on the device.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
yes |
Absolute device path |
|
string |
yes |
Text content |
|
string |
no |
File permissions (e.g. |
file_read — Read a file from the device.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
yes |
Absolute device path |
|
string |
no |
|
app_install — Install an IPA from a URL reachable by the agent.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
yes |
Download URL (e.g. presigned S3) |
|
string |
no |
Display name |
ipa_upload — Get presigned upload and install URLs for an IPA. Call this first, upload the bytes yourself, then pass the install URL to app_install.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
IPA filename |
|
string |
no |
MIME type |
app_list — List installed applications on a device.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
integer |
no |
Page size |
|
string |
no |
Pagination cursor |
|
boolean |
no |
Full metadata (default: false) |
app_launch — Launch an installed application by bundle ID.
Argument |
Type |
Required |
|---|---|---|
|
string |
yes |
|
string |
yes |
syslog_get — Fetch recent syslog entries with optional filtering.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
no |
Filter string |
|
integer |
no |
How far back to look |
|
integer |
no |
Result cap |
Interaction¶
screenshot — Capture the device screen with optional crop and resize.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
no |
|
|
object |
no |
|
|
integer |
no |
Scale down to fit |
|
integer |
no |
Scale down to fit |
|
string |
no |
|
|
integer |
no |
JPEG quality (1–100) |
|
boolean |
no |
Also embed bytes in result (default: false) |
ui_dump_hierarchy — Dump the accessibility element tree of the current screen. Returns a paginated flat list with labels, values, and bounding boxes. Use coordinate_width and coordinate_height from the response as coordinate bounds for ui_tap and ui_swipe.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
integer |
no |
Page size |
|
string |
no |
Pagination cursor |
|
boolean |
no |
Full element metadata (default: false) |
ui_tap — Send a tap gesture at the given coordinates.
Argument |
Type |
Required |
|---|---|---|
|
string |
yes |
|
number |
yes |
|
number |
yes |
ui_swipe — Send a swipe gesture between two points.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
number |
yes |
Start point |
|
number |
yes |
End point |
|
integer |
no |
Swipe duration (default: 180) |
button_press — Press a hardware-style device button.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
string |
yes |
|
Networking¶
bridge_create — Forward a TCP port from the agent host to a device port. Use persistent: true for long-lived clients like Frida.
Argument |
Type |
Required |
Description |
|---|---|---|---|
|
string |
yes |
|
|
integer |
yes |
Port inside the device |
|
boolean |
no |
Keep alive after the request (default: false) |
|
integer |
no |
Auto-expire after this many seconds |
|
boolean |
no |
Return connection instructions |
When device_port is 27042, the response includes a Frida usage hint for connecting with the local frida CLI.
bridge_delete — Remove a TCP bridge created by bridge_create.
Argument |
Type |
Required |
|---|---|---|
|
string |
yes |
Authentication¶
The endpoint understands:
Authorization: Basic ...Authorization: Bearer <token>whenOPEN_DEVICE_CLOUD_API_TOKENis configured
If you deploy the backend behind your own auth layer, keep the MCP route aligned with that policy.
When To Use MCP vs REST¶
Use REST for app integration, backend workflows, and explicit resource management.
Use MCP when you want AI tooling or assistant-driven flows to interact with devices through a structured tool catalog.