MCP server

Tools and resources that `optics mcp` gives your AI agent.

optics mcp runs a Model Context Protocol (MCP) server, a standard way for AI agents such as Claude, Cursor or VS Code to call outside tools. Your agent can start a session on a device or browser, look at the screen, and run Optics keywords one at a time.

For a guided walkthrough, see Build tests with an AI agent.

Install#

The server needs the mcp extra. optics setup can't install it, and the all bundle doesn't include it.

$ pip install "optics-framework[mcp]"

You also need the extras for your driver, for example appium or playwright. See Engines and extras.

Start the server#

optics mcp [--transport stdio|http] [--host HOST] [--port PORT]
FlagDefaultWhat it does
--transportstdiostdio: your agent starts the server and talks to it directly. http: the server listens at http://<host>:<port>/mcp.
--host127.0.0.1The address to listen on. http only.
--port8090The port to listen on. http only.

We recommend stdio for an agent on your own machine. Use http when the server runs in a container or on another machine.

Connect your agent#

Most agents read a JSON file that lists MCP servers. For Claude Desktop it's claude_desktop_config.json; for Claude Code it's .mcp.json in your project. Other agents use the same shape.

.mcp.json
{
  "mcpServers": {
    "optics": {
      "command": "optics",
      "args": ["mcp"]
    }
  }
}

If your agent can't find optics, use the full path to it, for example /Users/ana/.optics/bin/optics.

For the http transport, point the agent at the URL instead:

.mcp.json
{
  "mcpServers": {
    "optics": {
      "url": "http://127.0.0.1:8090/mcp"
    }
  }
}

When the server runs in Docker and Appium runs on your machine, pass url: "http://host.docker.internal:4723" to start_session.

Session tools#

start_session#

Starts a session and launches the app. Returns {"session_id", "driver_id"}. Keep the session_id: every other tool needs it.

ParameterDefaultWhat it does
driverappiumappium, selenium, playwright or ble.
urlAppium: http://127.0.0.1:4723The driver's server URL.
capabilitiesNoneThe driver's capabilities, as in config.yaml.
elements_sourcesThe driver's three sourcesFor example ["appium_find_element", "appium_page_source", "appium_screenshot"]. Passing [] makes the session fail to start.
text_detectionNoneOCR engines, for example ["easyocr"].
image_detectionNoneImage engines, for example ["templatematch"].
project_pathNoneA project folder. Optics loads its image templates. It doesn't load elements or test cases.
ai_self_healOPTICS_AI_SELF_HEAL, else offTurns on AI self-heal.
llm_providerOPTICS_LLM_PROVIDER, else geminiThe LLM provider for self-heal.
llm_modelOPTICS_LLM_MODEL, else gemini-2.5-flashThe model for self-heal.
strict_element_matchOffAccepts only exact text matches.

The first session against a remote device farm can take 30 to 60 seconds to start.

terminate_session#

Closes the app and ends the session. Takes session_id. Returns {"session_id", "status": "terminated"}.

screenshot#

Returns the current screen as a PNG image. Takes session_id.

Keyword tools#

Every app, action and verification keyword is a tool named after the keyword in snake_case. Each takes session_id plus the keyword's parameters. All parameter values are strings. Leave out a parameter to use its default.

aoi_* stands for aoi_x, aoi_y, aoi_width and aoi_height, an area of the screen in percent (0–100). See Area of interest.

ToolParameters (defaults)
launch_appapp_identifier, app_activity, event_name
launch_other_appapp_name, event_name
close_and_terminate_appnone
force_terminate_appapp_name, event_name
get_app_versionapp_package
get_driver_session_idnone
start_appium_sessionevent_name
initialise_setupnone
ToolParameters (defaults)
press_elementelement, repeat (1), offset_x (0), offset_y (0), index (0), aoi_*, event_name
detect_and_presselement, timeout (30), event_name
select_dropdown_optionelement, option, timeout (30), event_name
enter_textelement, text, aoi_*, event_name, index (0)
enter_text_directtext, event_name
enter_text_using_keyboardtext_input, event_name
enter_numberelement, number, aoi_*, event_name, index (0)
clear_element_textelement, aoi_*, event_name, index (0)
get_textelement, index (0), aoi_*
press_keycodekeycode, event_name
swipecoor_x, coor_y, direction (right), swipe_length (50), event_name
swipe_by_percentagepercent_x, percent_y, direction (right), swipe_length (50), event_name
swipe_from_elementelement, direction, swipe_length, aoi_*, event_name, index (0)
swipe_until_element_appearselement, direction, timeout, event_name
scrolldirection, event_name
scroll_from_elementelement, direction, scroll_length, aoi_*, event_name, index (0)
scroll_until_element_appearselement, direction, timeout, event_name
sleepduration
execute_scriptscript_or_json, event_name
press_checkbox, press_radio_button, swipe_seekbar_to_right_androidDeprecated. Use press_element and swipe_from_element.
ToolParameters (defaults)
validate_elementelement, timeout (10), rule (all), event_name
is_elementelement, element_state, timeout, event_name
assert_presenceelements, timeout_str (30), rule (any), event_name, fail (True)
assert_visibilityelements, timeout_str (30), rule (any), event_name, fail (True)
assert_equalityoutput, expression, event_name
validate_screenelements, timeout (30), rule (any), event_name
get_interactive_elementsfilter_config, compact (False)

Separate several elements with |, for example elements: "text=Trail Runner 2|text=Pace Knit". Each tool's description in your agent comes from the keyword's own documentation. See Keywords for what each parameter does.

A tool returns the keyword's result. When self-heal recovers a step, it returns {"result", "healed": true, "heal_summary", "suggested_steps"} instead, so your agent can write the extra steps into the test.

Hidden coordinate taps#

press_by_coordinates and press_by_percentage are hidden by default, because agents that guess coordinates write fragile tests. To expose them, set OPTICS_MCP_ALLOW_COORDINATE_TAPS=1 before you start the server.

ToolParameters (defaults)
press_by_coordinatescoor_x, coor_y, repeat (1), event_name
press_by_percentagepercent_x, percent_y, repeat (1), event_name

Resources#

Resources are read-only data your agent can fetch by URI.

URITypeWhat it returns
optics://keywordsJSONEvery keyword, including flow control, with its description and parameters.
optics://project-formatMarkdownHow to write a CSV project: the files, columns, ${name} variables and flow-control keywords.
optics://session/{session_id}/screenshotPNGThe current screen.
optics://session/{session_id}/sourceJSON{"page_source", "timestamp"}: the UI tree or HTML.
optics://session/{session_id}/elementsJSONA compact list of interactive elements on screen. Appium and Playwright only.
optics://session/{session_id}/screen_elementsJSON{"screenshot", "elements"}: a base64 PNG and the elements in the same frame.

Capture Screenshot, Capture Pagesource and Get Screen Elements aren't tools; use these resources instead. There are no MCP prompts.

Environment variables#

Set these in the environment that starts optics mcp. In a JSON client config, add an env object next to command.

VariableWhat it does
OPTICS_AI_SELF_HEAL1, true, yes or on turns self-heal on for every session unless start_session says otherwise.
OPTICS_LLM_PROVIDERThe default LLM provider. Only gemini is supported.
OPTICS_LLM_MODELThe default model.
OPTICS_MCP_ALLOW_COORDINATE_TAPS1, true, yes or on exposes the coordinate tap tools.
GEMINI_API_KEY, GOOGLE_API_KEY and the Vertex AI variablesGemini credentials. They never travel in a tool call.

Typical agent loop#

  1. Start a session#

    Call start_session with the driver, URL and capabilities, for example driver: "appium", capabilities: {"platformName": "Android", "appPackage": "com.birch.shop", ...}. Keep the session_id.

  2. Look at the screen#

    Call screenshot, then read optics://session/{session_id}/elements (or call get_interactive_elements) for labels and positions. Read /source when you need XPaths.

  3. Act#

    Call keyword tools with a locator: press_element with element: "text=Sign in", enter_text with an XPath, or detect_and_press with a visible label. Look again after each action.

  4. Save the run as a test#

    Read optics://project-format, then write the steps you ran into CSV files with a config.yaml. Run them with optics execute <folder>.

  5. End the session#

    Call terminate_session.

Limits#

  • No flow control. Run Loop, Condition, Evaluate, Read Data, Invoke API and the other flow-control keywords aren't tools. Your agent can still write them into CSV modules for optics execute.
  • No recording or saving. There are no tools to record, save, replay, find devices or run doctor. The agent writes project files itself.
  • Coordinate taps are hidden unless you set OPTICS_MCP_ALLOW_COORDINATE_TAPS. Self-heal can still tap by percentage when it recovers a step.
  • Sessions aren't shared. Sessions live in the server's memory. optics serve and optics live can't see them, and restarting the server ends them.
  • Images come from a project. There's no upload tool. Pass project_path to use template images.
  • Selenium has no interactive element list. The elements resource and get_interactive_elements fail on Selenium; use /source instead.

Errors#

A failing tool returns an error message. When Optics raises a coded error, the message starts with the code in brackets, for example [Code.E0106] Driver session is no longer active .... The code can carry a Code. prefix; it's the same code. A step that fails after trying every element value arrives as Execution failed: All fallback attempts failed for keyword ..., with the code inside the text. See Error codes.