Skip to main content
Glama

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 using rule_json and groups_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 build

Run the server directly with:

export LEMON_WEB_CONTROL_TOKEN='TOKEN_FROM_LEMON_REMOTE_CONTROLLER'
npm start

The 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:

  1. WebControl accepted the request.

  2. The new state is persisted and can be read back.

  3. 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 test

The 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 tools
clear_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

    B3.2/5.0

    Scored across 61 tools

    Disambiguation3/5

    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.

    Naming Consistency5/5

    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.

    Tool Count1/5

    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.

    Completeness5/5

    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

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      A
      maintenance
      Open-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.
      97
      MIT
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables 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.
      -