LemonMCP
OfficialLemonMCP is a local stdio MCP server that lets an AI client inspect and control a Lemon-enabled iPhone through its local WebControl API.
Device & embedded web page: start/stop the VPN and open, close, refresh, or navigate back/forward in Lemon's embedded WKWebView.
Scheduled tasks: list, read, create, update, enable/disable, or delete Cron/interval JavaScript tasks and check PacketTunnel scheduler runtime status.
Traffic & logs: search traffic previews, read full captured requests, fetch binary payloads, clear captured traffic, and read or clear the lemoncore.log.
Files & database: fetch non-database App Group files and run raw diagnostic SQL against Lemon's SQLite database.
Target & DNS: get/override the device host and port, and list, upsert, or delete native DNS Host mappings and block rules.
HTTP Replay: list/read/create/update/delete saved replay items and execute saved or one-shot real requests.
Rewrite scripts: validate, upsert, rollback, delete, and inspect ESM rewrite packages and revisions, plus runtime status, debug events, and runtime reload.
Rewrite rules: list, create/update, and delete rewrite policies/MatchGroups, and fetch the exact rule/action schema.
UI Modules: list, inspect, validate, install/update, rollback, toggle, delete, and reload Module workers, with legacy aliases (
inspect_module,install_module,set_module_enabled).Resources: read-only snapshots via
lemonmcp://env/hardware_statusandlemonmcp://database/schema.Consequential actions: VPN changes, traffic/log clearing, raw SQL, DNS writes, Replay execution, and Rewrite/Module publication or deletion can change device state or send real network requests.
Enables inspection and control of a Lemon-enabled iPhone through its local WebControl API, providing tools for device management, embedded web page control, scheduled JavaScript tasks, traffic and log capture, file access, SQLite database queries, DNS host mappings, HTTP replay, rewrite scripts and rules, and UI modules.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@LemonMCP show me the last 10 captured requests"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
LemonMCP
LemonMCP is a local Model Context Protocol server for Lemon for iOS. It lets an AI client such as Cursor, Claude Desktop, Codex, or another MCP consumer inspect and control a Lemon-enabled iPhone through the local WebControl API.
LemonMCP runs on the developer's Mac and communicates over stdio with the AI client. It does not open a public HTTP server on the Mac. It discovers the Lemon device over Bonjour/mDNS and sends authenticated HTTP requests to the device's WebControl service.
Fast installation with an AI assistant
If your AI client has permission to use the local terminal, copy the prompt below. It asks the AI to check the environment, clone or update LemonMCP, build it, and create the MCP configuration for the client it detects.
Install and configure LemonMCP on this computer.
Repository: https://github.com/lemonXGroup/lemon-mcp.git
Default install directory: ~/lemon-mcp
Follow these requirements exactly:
1. Check git and Node.js first. Node.js must be version 20 or newer. If it is
not, tell me which version is needed; do not use sudo or modify the system
Node.js installation.
2. Clone the repository if ~/lemon-mcp does not exist. If it already exists,
check for uncommitted changes. Never overwrite, reset, or force-update a
dirty worktree; report it and wait. Only use git pull --ff-only on a clean
worktree.
3. Run npm ci and npm run build in the project directory. Then run npm test and
report the result.
4. Identify the MCP client I use and its configuration file. Only edit the
clearly matching MCP configuration, make a local backup first, and preserve
every other configured server.
5. Add a stdio server named LemonMCP. Use command node and the absolute entry
point <absolute-project-path>/build/index.js.
6. Do not ask me to send a WebControl token in chat. Never print, upload, or
commit it. If a token is required, put a placeholder in the local config and
tell me to replace it locally:
LEMON_WEB_CONTROL_TOKEN=fill-this-in-locally
7. If Bonjour is unavailable, show optional local settings for
LEMON_TARGET_HOST and LEMON_TARGET_PORT. Do not guess or change the device
address by default.
8. Do not start a long-running LemonMCP process. Do not invoke traffic/log
clearing, DNS writes, Replay, Rewrite, Module, or any other consequential
MCP operation. Tell me which client must be restarted or reloaded.
9. Report the install directory, build result, test result, edited config file,
backup location, and any token or restart steps I must complete locally.An AI assistant cannot grant itself local permissions. If it cannot edit client files, let it run the install and build commands, then copy the generated JSON snippet into the client configuration manually. This flow does not require GitHub Actions, Docker, or a global npm installation.
Related MCP server: Mac MCP
What it provides
The server currently registers 61 tools and 2 resources. Tool schemas exposed to the MCP client are the runtime source of truth; the following list is a capability map for humans and AI agents.
Device and embedded web page
toggle_vpn: request VPN/PacketTunnel start or stop.open_web_page: open an HTTP or HTTPS URL in Lemon's embedded WKWebView.close_web_page,refresh_web_page,go_back_web_page,go_forward_web_page: control the current embedded page.
Scheduled JavaScript tasks
list_scheduled_tasks,get_scheduled_task: inspect locally stored tasks.get_scheduled_task_runtime_status: inspect PacketTunnel scheduler state.create_scheduled_task,update_scheduled_task: create or update Cron or fixed-interval tasks.set_scheduled_task_enabled,delete_scheduled_task: change task state or remove a task.
Tasks support a single ESM file or a validated ESM package. Scheduled packages
must export onSchedule(input) from their manifest entry. Fixed intervals are
limited to 250..86400000 milliseconds by the MCP schema.
Traffic, logs, files, and database
clear_captured_traffic: remove captured HTTP records and body files.fetch_system_logs,clear_system_logs: read or clear the Lemon core log.search_traffic_previews: find request summaries by keyword or host.get_captured_request: read a complete request/response and body metadata.fetch_binary_payload: fetch a referenced request or response body.fetch_device_file: read a non-database App Group file.execute_raw_sql: run a diagnostic query against Lemon's SQLite database.
Use search_traffic_previews for discovery and get_captured_request for
authoritative request details. Binary or unsafe text bodies are returned in a
lossless, bounded representation instead of being decoded as arbitrary text.
Device target and DNS Hosts
set_lemon_target_ip,get_lemon_target_ip: inspect or override the active WebControl host and port.list_host_mappings: list native DNS Host mappings.upsert_host_mapping: create or update a mapping or block rule.delete_host_mapping: remove a mapping by UUID.
HTTP Replay
list_replay_items,get_replay_item: inspect saved requests.create_replay_item,update_replay_item: save or edit a request.delete_replay_item: remove a saved request.execute_replay_item: execute a saved request.execute_replay_request: execute a one-shot request without saving it.
Replay execution sends a real request. Verify the target, credentials, headers, body, and expected side effects before using it.
Rewrite script packages
list_rewrite_scripts,get_rewrite_script_package: inspect active or historical packages.list_rewrite_script_revisions: inspect immutable revisions.validate_rewrite_script_package: validate without persisting.upsert_rewrite_script: create a package or publish a new revision.rollback_rewrite_script: switch the active revision.get_rewrite_runtime_status: inspect JavaScript runtime state and limits.get_rewrite_debug_events,clear_rewrite_debug_events: read or clear structured debug events.reload_rewrite_runtime: request a runtime reload.delete_rewrite_script: remove a package and its revisions.
The complete package form contains a manifest and allowlisted ESM modules.
upsert_rewrite_script also accepts a one-file content shorthand, which is
converted to a restricted main.js package. Use
validate_rewrite_script_package before publishing and verify both persistence
and runtime status afterwards.
Rewrite rules
list_rewrite_rules: list policies, MatchGroups, and actions.upsert_rewrite_rule: create or update a rule usingrule_jsonandgroups_json.delete_rewrite_rule: remove a rule by numeric id.get_rewrite_schema: return the current rule, action, and package schema.
Conditions inside one MatchGroup use AND. Matching groups use OR. The exact
accepted fields and action values are returned by get_rewrite_schema and
should be read before generating a rule.
UI Modules
list_modules,get_module_package: inspect installed modules and package revisions.list_module_revisions: inspect immutable revisions.validate_module_package: validate a package without installing it.upsert_module: install a module or publish a new revision.rollback_module: activate a historical revision.toggle_module: enable or disable a module.delete_module: remove a module and all revisions.get_module_runtime_status: inspect active workers and runtime limits.reload_module_runtime: release one worker or reload all workers.
The following compatibility aliases are retained for early clients:
inspect_module, install_module, and set_module_enabled. New integrations
should use the canonical module tools above.
MCP resources
lemonmcp://env/hardware_status: a point-in-time device, memory, VPN, MITM, and CA certificate status snapshot.lemonmcp://database/schema: the current Lemon SQLite table and column descriptions for accurate diagnostic SQL.
Resources are read-only context. They do not replace a later status check or the detailed response from a tool call.
Requirements
macOS with Node.js 20 or newer.
Lemon for iOS running on a real iPhone with WebControl enabled.
The Mac and iPhone on a reachable local network, or a connection that supports the advertised Bonjour service.
A current WebControl token when the iOS app requires authentication.
Lemon advertises _lemon._tcp through Bonjour. The default fallback target is
stack.local:9999. Set LEMON_TARGET_HOST and LEMON_TARGET_PORT when a
different fallback address is needed. Bonjour discovery still takes priority.
Install and build
npm ci
npm run buildRun the server directly with:
export LEMON_WEB_CONTROL_TOKEN='TOKEN_FROM_LEMON_REMOTE_CONTROLLER'
npm startThe token is read from the environment and sent only as the
X-Lemon-WebControl-Token request header. Do not commit it, put it in an MCP
configuration shared with others, or include it in issue reports.
Configure an MCP client
Use the absolute path to the built entry point. The exact configuration file depends on the MCP client:
{
"mcpServers": {
"LemonMCP": {
"command": "node",
"args": [
"/absolute/path/to/lemonMCP/build/index.js"
],
"env": {
"LEMON_WEB_CONTROL_TOKEN": "TOKEN_FROM_LEMON_REMOTE_CONTROLLER"
}
}
}
}For a non-Bonjour fallback target, add LEMON_TARGET_HOST and
LEMON_TARGET_PORT to the same env object. The MCP process starts its device
discovery only after the stdio handshake completes. Successful WebControl
calls send a session-scoped activity ping, and transport shutdown attempts to
clear that session on the iOS side.
Safety model
LemonMCP can change device state and can send real network requests. Treat the following as explicitly consequential operations: VPN start/stop, traffic or log clearing, raw SQL, DNS writes, Replay execution, Rewrite publication or deletion, and Module installation or deletion.
An AI client should explain the target and expected effect before performing a destructive or external operation, then verify three separate outcomes where applicable:
WebControl accepted the request.
The new state is persisted and can be read back.
The iOS runtime loaded the state or a real request demonstrated the change.
Keep WebControl on a trusted network. Do not expose its port to the public Internet, and do not put credentials, cookies, authorization headers, private data, or production secrets in scripts, Rewrite rules, Replay items, logs, or Markdown examples.
Development
npm ci
npm testThe public project includes deterministic unit tests for the API client, Bonjour target selection, byte handling, captured requests, file formatting, traffic search, and Rewrite package validation. Real-device E2E fixtures are kept in the main Lemon repository because they require a controlled iOS device, a private test backend, and repository-specific cleanup tooling.
Relationship to the Lemon repository
This directory is maintained as a standalone-ready copy of the MCP server. The iOS WebControl contract remains owned by the Lemon app. When that contract changes, update the MCP tool schemas and this README together, then run the public project's unit tests and a real-device compatibility check from the main repository.
Available Tools
61 toolsclear_captured_trafficA
Clears all captured HTTP traffics and body binaries from the device.
Inputs: no named parameters.
clear_rewrite_debug_eventsA
Clears structured rewrite-debug events. Provide trace_id to clear only one request; omit it only when intentionally clearing the whole debug projection.
Inputs: trace_id.
clear_system_logsA
Empties the Lemon core engine root logs (lemoncore.log). Useful to clean up logs before starting a fresh capture to isolate issues.
Inputs: no named parameters.
close_web_pageB
Closes the Lemon iOS embedded WKWebView.
Inputs: no named parameters.
create_replay_itemA
Saves a new HTTP replay item in Lemon's local runtime database. The item can later be executed with execute_replay_item.
Inputs: url (required), name (required), method (required), body, +1 more.
create_scheduled_taskA
Creates a locally stored Cron or millisecond-interval JavaScript task. Use script_type=single with script for one file, or script_type=package with script_package for a validated ESM package. Packages must export onSchedule(input) from their manifest entry. Interval values must be 250..86400000 ms. It is enabled by default unless enabled=false is provided.
Inputs: name (required), script (required), enabled, cron_expr, +4 more.
delete_host_mappingB
Deletes a native DNS custom Host mapping by UUID. The change is applied immediately without a second confirmation.
Inputs: id (required).
delete_moduleB
Deletes an installed UI Module and all of its immutable revisions.
Inputs: module_id (required).
delete_replay_itemB
Deletes one saved HTTP replay item by UUID.
Inputs: id (required).
delete_rewrite_ruleC
Delete a rewrite rule by its numeric ID.
Inputs: id (required).
delete_rewrite_scriptC
Delete a rewrite script by its numeric ID.
Inputs: id (required).
delete_scheduled_taskC
Deletes one locally stored scheduled task by id.
Inputs: id (required).
execute_raw_sqlC
Executes a raw SQL diagnostic query on the Lemon SQLite database (Read-Only queries advised).
Inputs: query (required).
execute_replay_itemB
Executes one saved HTTP replay item through Lemon's native URLSession/runtime path and returns the response preview. Saved execution status is updated.
Inputs: id (required).
execute_replay_requestA
Executes a one-shot HTTP replay without saving it. Use this for a captured request after inspecting it with get_captured_request, or for an ad-hoc request.
Inputs: url (required), method (required), body, headers.
fetch_binary_payloadC
Deep-dives into a specific HTTP payload by fetching its full request/response bodies.
Inputs: path (required).
fetch_device_fileA
Fetches a specific non-database file from the iOS device's AppGroup container. ESM rewrite script packages are stored in runtime.sqlite; use get_rewrite_script_package instead of looking for RewriteScripts/*.js files.
Inputs: path (required).
fetch_system_logsB
Safely reads the tail (end) of the Lemon core engine (lemoncore.log) to analyze system or runtime network errors. Suitable for large log files.
Inputs: bytes.
get_captured_requestB
Reads one complete captured request/response by transaction_id, trace_id, or the legacy database id returned by search_traffic_previews. Body metadata distinguishes missing, empty, text, and binary-file payloads.
Inputs: trace_id (required).
get_lemon_target_ipB
Retrieves the current network URL/IP that the MCP is using to communicate with the iOS device.
Inputs: no named parameters.
get_module_packageA
Fetches the complete manifest and ESM sources for an active or historical Module revision.
Inputs: module_id (required), revision.
get_module_runtime_statusB
Reports active Module workers, leases, and runtime limits.
Inputs: no named parameters.
get_replay_itemB
Reads one saved HTTP replay item by UUID, including its request headers and body.
Inputs: id (required).
get_rewrite_debug_eventsA
Reads the independent structured rewrite-debug event projection. Filter by trace, rewrite phase, or severity instead of scanning generic trace events.
Inputs: level, limit, offset, trace_id, +1 more.
get_rewrite_runtime_statusA
Reports whether rewrite and JavaScript execution are enabled, runtime resource limits, sync state, and script counts.
Inputs: no named parameters.
get_rewrite_schemaA
Returns the exact JSON schema and accepted enum values for creating or updating Rewrite Rules and Actions.
Inputs: no named parameters.
get_rewrite_script_packageB
Fetches the complete manifest and source modules for an active or historical ESM rewrite script revision.
Inputs: id (required), revision.
get_scheduled_taskB
Fetches one locally stored Cron or interval JavaScript task by id.
Inputs: id (required).
get_scheduled_task_runtime_statusB
Returns the current PacketTunnel scheduled-task runtime state without exposing script source.
Inputs: no named parameters.
go_back_web_pageA
Navigates back in the Lemon iOS embedded WKWebView history.
Inputs: no named parameters.
go_forward_web_pageA
Navigates forward in the Lemon iOS embedded WKWebView history.
Inputs: no named parameters.
inspect_moduleB
Fetches the active manifest, UI schema, and ESM sources of one installed Module.
Inputs: module_id (required).
install_moduleC
Compatibility alias for installing or publishing a Module package.
Inputs: package_json (required).
list_host_mappingsB
Lists the native DNS custom Host mappings currently applied by Lemon.
Inputs: no named parameters.
list_module_revisionsB
Lists immutable Module revisions, hashes, and the active revision.
Inputs: module_id (required).
list_modulesB
Lists installed host-side UI Modules, active revisions, and enabled state.
Inputs: no named parameters.
list_replay_itemsB
Lists saved HTTP replay items stored in Lemon's local runtime database.
Inputs: no named parameters.
list_rewrite_rulesB
Fetches all existing rewrite policies and their MatchGroups.
Inputs: no named parameters.
list_rewrite_script_revisionsB
Lists immutable revisions for a rewrite script package, including content hashes, byte sizes, and the active revision.
Inputs: id (required).
list_rewrite_scriptsA
Lists ESM rewrite script packages with their ids, active revisions, and enabled state. Use get_rewrite_script_package to read source modules.
Inputs: no named parameters.
list_scheduled_tasksA
Lists locally stored Cron or millisecond-interval JavaScript tasks, including runtime state and next run time.
Inputs: no named parameters.
open_web_pageA
Opens an HTTP or HTTPS URL inside the Lemon iOS app's embedded WKWebView.
Inputs: url (required).
refresh_web_pageB
Reloads the current page in the Lemon iOS embedded WKWebView.
Inputs: no named parameters.
reload_module_runtimeA
Releases one Module worker or all workers so the next activation loads the active revision.
Inputs: module_id.
reload_rewrite_runtimeA
Requests the active rewrite snapshot to reload from runtime.sqlite. This may fail when the VPN runtime is not running; persisted scripts are unaffected.
Inputs: no named parameters.
rollback_moduleB
Switches a Module to an immutable historical revision; history is retained.
Inputs: revision (required), module_id (required), reload.
rollback_rewrite_scriptA
Makes an existing immutable revision the active revision for a rewrite script package. Historical revisions are retained.
Inputs: id (required), revision (required), reload.
search_traffic_previewsC
Find HTTP traffic targeting specific keywords or hosts across recent logs.
Inputs: keyword (required), limit.
set_lemon_target_ipA
Manually override the target IP address of the iOS Lemon device. Use this if mDNS/Bonjour discovery fails or if the device relies on a different network IP.
Inputs: ip (required), port.
set_module_enabledB
Compatibility alias for enabling or disabling one UI Module.
Inputs: enabled (required), module_id (required).
set_scheduled_task_enabledA
Enables or disables one scheduled task. Enabling scheduled execution requires the configured schedule entitlement.
Inputs: id (required), enabled (required).
toggle_moduleC
Enables or disables one installed UI Module.
Inputs: enabled (required), module_id (required).
toggle_vpnB
Starts or stops the Lemon iOS VPN. Wait for success or error response.
Inputs: action (required).
update_replay_itemC
Updates a saved HTTP replay item without changing its execution history.
Inputs: id (required), url (required), name (required), method (required), +2 more.
update_scheduled_taskA
Updates a locally stored Cron or millisecond-interval JavaScript task. Use script_type=single with script for one file, or script_type=package with script_package for a validated ESM package. Packages must export onSchedule(input) from their manifest entry.
Inputs: id (required), name (required), script (required), enabled (required), +5 more.
upsert_host_mappingA
Creates a native DNS Host mapping, or updates one when an existing mapping id is provided. Writes are applied immediately and do not require a second confirmation.
Inputs: domain (required), id, action, target, +2 more.
upsert_moduleB
Installs a new Module or publishes a new immutable revision. Optionally reloads the host runtime.
Inputs: package_json (required), reload.
upsert_rewrite_ruleB
Add or update a rewrite policy with ordered MatchGroups. To update, ensure the rule object has an 'id'.
Inputs: rule_json (required), groups_json (required).
upsert_rewrite_scriptA
Creates a new ESM rewrite script package or publishes a new immutable revision. Provide manifest/modules for multi-file packages, or content as a one-file shorthand. Set reload=true to request an immediate runtime snapshot reload after persistence.
Inputs: id, name, reload, content, +2 more.
validate_module_packageA
Validates a Module package using the iOS validator without persisting it.
Inputs: package_json (required).
validate_rewrite_script_packageB
Validates an ESM rewrite package with the same iOS-side manifest, module-path, and size rules used before persistence. It does not write anything.
Inputs: modules (required), manifest (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 61 tools
The set has clear domain boundaries overall, but several pairs overlap or act as aliases: install_module vs upsert_module, set_module_enabled vs toggle_module, execute_replay_item vs execute_replay_request, and fetch_binary_payload vs get_captured_request. Descriptions help resolve most cases, but an agent still has to choose carefully among similar-sounding operations.
Nearly all tools follow a consistent snake_case verb_noun convention, such as list_rewrite_rules, get_captured_request, and delete_scheduled_task. Minor variants like go_back_web_page and go_forward_web_page are internally consistent and do not break the pattern.
At 61 tools, the server is far beyond the recommended 3–15 range and exceeds the 50-tool threshold that indicates an extreme surface-size mismatch. Even across multiple subdomains, the count is heavy enough to overwhelm tool selection and includes compatibility aliases that further inflate the surface.
The surface covers full lifecycle operations for rewrite scripts, rewrite rules, modules, scheduled tasks, replay items, host mappings, web view navigation, traffic capture, system logs, and runtime status. CRUD, validation, execution, rollback, enable/disable, and clearing operations are broadly represented, leaving no obvious dead ends for the stated iOS-network-debugging domain.
Maintenance
Related MCP Connectors
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceMCP server and CLI for iOS development — build, test, automate, and diagnose from any AI agent or terminal.2MIT
- AlicenseNot gradedqualityAmaintenanceOpen-source, local macOS MCP server for AI agents. Automate background Safari/Chrome tabs, native apps, files and shell with scoped permissions, optional approvals and delegated coding agents.97MIT
- AlicenseAqualityDmaintenanceAn MCP server that gives AI agents the ability to inspect, observe, and automate WKWebViews on connected iOS devices via Safari Web Inspector.141MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to discover and interact with iOS apps through a local MCP gateway, converting remote Streamable HTTP MCP endpoints into stdio tools. Provides dynamic device discovery, tool schema introspection, and deterministic tool calling for app analysis.-