MCP server for rpcclient targets iOS over stdio transport.
- Python 3.10+
- RPC server reachable
python3 -m venv .venv
source .venv/bin/activate
pip install rpcclient-mcp
which rpcclient-mcprpcclient==6.11.1 is a package dependency, so it installs automatically with this MCP.
If you want to force local rpcclient source instead of PyPI:
export RPCCLIENT_PYTHONPATH=/absolute/path/to/rpc-project/src/rpcclientclaude mcp add --transport stdio rpcclient-mcp -- /absolute/path/to/venv/bin/rpcclient-mcpcodex mcp add rpcclient-mcp -- /absolute/path/to/venv/bin/rpcclient-mcpgemini mcp add --transport stdio rpcclient-mcp /absolute/path/to/venv/bin/rpcclient-mcpAdd to ~/.codex/config.toml (or your active Codex config):
[mcp_servers.rpcclient-mcp]
command = "/absolute/path/to/venv/bin/rpcclient-mcp"
[mcp_servers.rpcclient-mcp.env]
RPCCLIENT_PYTHONPATH = "/absolute/path/to/rpc-project/src/rpcclient" # optionalRestart your client after config changes.
ping()
rpc_connect(host="127.0.0.1", port=5910)
rpc_get_screen_context(session_id="...")
rpc_disconnect(session_id="...")
# health
ping()
# connection lifecycle
rpc_connect(host="127.0.0.1", port=5910, timeout=3.0)
rpc_disconnect(session_id)
rpc_reconnect(session_id)
# session inspection
rpc_list_sessions()
rpc_session_info(session_id)
Use these to establish, inspect, and recover sessions.
rpc_reconnect is the transport recovery path and invalidates old handles.
# discovery
rpc_capabilities(session_id, include_private=False)
rpc_call(session_id, path, args=None, kwargs=None, store_result=True)
# handle lifecycle
rpc_list_handles(session_id)
rpc_release_handle(session_id, handle_id)
rpc_release_all_handles(session_id)
# handle access
rpc_handle_call(session_id, handle_id, method, args=None, kwargs=None, store_result=True)
rpc_handle_get(session_id, handle_id, attr, store_result=True)
Use rpc_call for dot-path execution on the root client object.
When store_result=True, non-JSON return values are materialized as handles.
# app discovery + launch
rpc_list_apps(session_id, query="", limit=30)
rpc_launch_app(session_id, bundle_id=None, app_query=None, kill_existing=True, unlock_device=True, timeout=3.0, wait_foreground_timeout=5.0)
# context + overlay handling
rpc_get_screen_context(session_id, ensure_accessibility=True, wait_primary_bundle=None, wait_timeout=5.0, max_items=300, dedupe=True)
rpc_dismiss_overlays(session_id, timeout=4.0, max_rounds=6)
# interaction: click + type
rpc_click_label(session_id, label, exact=True, index=0, timeout=5.0, auto_scroll=True, draw_frame=False, direction="next", displayed_only=False, dismiss_overlays=True, overlay_timeout=3.0)
rpc_click_by_context(session_id, intent, min_score=0.52, timeout=5.0, auto_scroll=True, draw_frame=False, direction="next", dismiss_overlays=True, overlay_timeout=3.0)
rpc_type_text(session_id, text, target_label=None, intent=None, min_intent_score=0.35, anchor_label=None, anchor_position="before", anchor_offset=1, clear_first=False, timeout=5.0, direction="next", displayed_only=False, dismiss_overlays=True, overlay_timeout=3.0)
# gestures + focused fallback
rpc_scroll(session_id, direction="down", count=1, pause_seconds=0.25, from_x=None, from_y=None, to_x=None, to_y=None)
rpc_tap(session_id, x, y, repeat=1, pause_seconds=0.2)
rpc_type_focused_text(session_id, text, dismiss_overlays=False, overlay_timeout=2.0)
This is the primary automation surface: launch, read context, click, type, and gesture.
Use rpc_tap + rpc_type_focused_text when web fields are visible but not AX-discoverable.
Safari overlay password fields are not always AX-exposed on this target.
Manual password entry may still be required in some runs.
MIT. See LICENSE.