# core [Health: Active]

**Category:** 🖥️ OS Automation  
**Repository:** https://github.com/electron-stagewright/electron-stagewright  
**GitHub Stars:** 12  
**npm Downloads (last month):** 32780896  
**Views:** 3  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/core

## Description
Agent-native MCP server for driving, inspecting, and asserting on real Electron desktop apps.

## Tools
Capabilities this server exposes over MCP:

- **electron_assert_pattern** — Validate, in a single check (no polling), that an element's text or a named attribute matches a pattern. Target by ref or selector. With `attribute` set, reads that attribute; otherwise reads the element's trimmed text. Provide exactly one of: equals, contains, matches_regex. Optional flags (any of i, m, s, u) apply to matches_regex; g and y are rejected as stateful. Returns: { ok, session_id, matched, actual }. Errors: EXPECTATION_FAILED (element found but its value did not match the pattern — details carry expected + actual; a missing attribute reads as actual: null), SELECTOR_NO_MATCH (no element matched — this is one-shot, so a missing element is a precondition failure, not a retry; carries similar_refs), REF_NOT_FOUND (stale ref), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (no/multiple predicates, invalid regex or flags, or ref+selector both/neither).
- **electron_attach** — Attach to an already-running Electron app exposing a CDP debug endpoint (use electron_discover_running to find one, or start the app with --remote-debugging-port). Provide port (+ optional loopback host) or a loopback cdpUrl; pid alone is not attachable over CDP but, when supplied alongside, lets stop escalate to SIGKILL. The CDP transport supports eval/read/observe and core interaction surfaces against the attached app. The selected CDP page is also the default snapshot/find surface; explicit iframe/webview surface targeting remains unavailable. Returns: { ok, session_id, transport, windows, capabilities }. Errors: TRANSPORT_UNSUPPORTED (no attach-capable transport), CDP_DISCONNECTED (endpoint unreachable or dropped; retryable), CDP_TIMEOUT (handshake/method timeout; retryable), BAD_ARGUMENT (missing target selector or non-loopback endpoint).
- **electron_check** — Check the checkbox/radio identified by ref or selector (no-op if already checked). Options: force, timeoutMs. Returns: { ok, session_id, target, checked: true }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_clear_input** — Clear the value of the input/textarea identified by ref or selector (sets it to empty). Options: force, timeoutMs. Returns: { ok, session_id, target, cleared }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_click** — Click the element identified by ref (from a snapshot) or selector. Options: button (left|right|middle, default left), clickCount (2 = double-click), force (bypass actionability), timeoutMs. Returns: { ok, session_id, target }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (no such element — re-snapshot; not retryable, carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED (not retryable), NOT_RUNNING, BAD_ARGUMENT (ref+selector both/neither).
- **electron_console_logs** — Read the captured renderer console output for the session, newest-relevant entries last. Filters (all optional, ANDed): type (one or more of log/info/warning/error/debug/...), match (a regular expression the text must match), since (epoch ms — only entries at/after it), limit (max entries, default 200, max 1000 — the most recent are kept). Returns: { ok, session_id, entries: [{ type, text, timestamp, windowId?, location? }], count, overflowed }. overflowed is the number of older entries the buffer dropped. Errors: NOT_RUNNING, BAD_ARGUMENT (invalid regex, or multiple sessions).
- **electron_detach** — Disconnect from an attached or injected app without stopping it. A launch-owned session cannot detach because its transport owns the process; this includes Playwright development launches and packaged CDP launches. Use electron_stop for that case. Returns: { ok, session_id, detached: true }. Errors: TRANSPORT_UNSUPPORTED (launch-owned session; not retryable), NOT_RUNNING (no such session), BAD_ARGUMENT (multiple sessions).
- **electron_dialog_handler** — Arm the auto-responder for native JS dialogs (alert/confirm/prompt/beforeunload) and read which dialogs fired. Dialogs block the renderer, so the policy is applied automatically the instant one appears. Arming args (all optional): action (accept|dismiss — the default for every dialog), perType (per-kind overrides, e.g. {"confirm":"accept","beforeunload":"dismiss"}, falls back to action), promptText (text submitted to prompt() when it is accepted), oneShot (apply to exactly the next dialog, then revert to dismiss). With NO arming args the call is inspect-only and leaves the policy unchanged. Read args (all optional): type (one or more kinds to include), since (epoch ms), limit (max events, default 50, max 200 — most recent kept), clear (flush the whole buffer after reading). Until armed, the default policy is dismiss, so dialogs never hang the app. Returns: { ok, session_id, policy, entries: [{ type, message, action, defaultValue?, promptText?, timestamp, windowId? }], count, overflowed }. overflowed counts dropped events across the whole buffer, not just the returned (type/since/limit-filtered) subset. Errors: NOT_RUNNING, BAD_ARGUMENT (promptText without an accepting prompt policy, or oneShot without a policy to arm).
- **electron_discover_running** — Scan the conventional CDP debug ports (9222-9225 by default) for already-running, debuggable Electron apps on loopback only. No session required. Returns: { ok, targets, count, scanned } where each target is { targetId, port, appName, pid } and scanned reports { host, ports, elapsed_ms } so an empty result is unambiguous. Errors: BAD_ARGUMENT (non-loopback host, invalid port list, or timeout outside bounds). A failed probe is simply "no target on that port".
- **electron_doctor** — Run non-mutating preflight checks without starting an Electron session: Node version, Playwright, Electron, Linux display, configured app root and screenshot directory, eval policy, and project Electron runtime alignment. Returns: { ok, doctor_ok, checks, runtime }, where runtime includes server and, with --app-root, target Electron/Node/V8/ABI facts plus a bounded native-addon inventory. Inspect failed checks and warnings before electron_launch. Errors: none.
- **electron_drag** — Drag the source element (ref or selector) onto the target element (targetRef or targetSelector), using the real mouse API. Options: force, timeoutMs. Returns: { ok, session_id, source, target }. Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), NOT_RUNNING, BAD_ARGUMENT (a side missing or both ref+selector given).
- **electron_drop_file** — Simulate dropping OS files onto the element identified by ref or selector. Web DataTransfer mode: reads each path on the host running the server, rebuilds the files in the renderer, and dispatches dragenter/dragover/drop with a real DataTransfer — engaging standard web drop handlers. Paths must be ABSOLUTE (max 10 files, 5242880 bytes each). default_prevented reports whether a drop handler engaged (called preventDefault); false usually means the target has no web drop handler. Apps that resolve dropped files to native OS paths need an app-specific IPC convention this tool does not simulate. Options: mimeType, timeoutMs. Returns: { ok, session_id, target, files, default_prevented }. Errors: ABSOLUTE_PATH_REQUIRED, FILE_NOT_FOUND, BAD_ARGUMENT (too many/large files, or ref+selector both), SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), NOT_RUNNING.
- **electron_elements_list** — Return every element matching a CSS selector as { ref, role, name, bbox }, capped at `limit` (default 50, max 200). When more matched than returned,  `truncated` is the number dropped and `count` is the true total. Returns: { ok, session_id, matches, count, truncated }. Errors: TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, limit, or multiple sessions).
- **electron_exists** — Return whether the element identified by ref or selector is present in the DOM. A no-match is a normal result (exists: false), NOT an error — so an agent can poll for appearance/disappearance. Returns: { ok, session_id, exists }. Errors: TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector or ref+selector both/neither).
- **electron_expect_count** — Assert how many elements match, polling until the count satisfies the predicate or timeoutMs elapses. Target EITHER by selector (counts querySelectorAll; visible:true counts visible only, visible:false counts hidden only) OR by accessibility role/name filters (role, name_contains, name_exact, visible, enabled, interactive). Provide at least one of equals, min, max. Returns: { ok, session_id, matched, actual }. Errors: EXPECTATION_FAILED (count predicate not met within timeoutMs — details carry expected + actual; retryable), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (no count predicate, or selector mixed with role filters).
- **electron_expect_state** — Assert the element identified by ref or selector matches the given state flags (any of visible, enabled, disabled, checked, selected, expanded, pressed, focused, readonly, required, invalid, busy), evaluated atomically and polled until they hold or timeoutMs elapses. Returns: { ok, session_id, matched, state }. Errors: EXPECTATION_FAILED (state not reached within timeoutMs — details carry expected + the last observed actual state; retryable), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, no state flags, or ref+selector both/neither).
- **electron_expect_text** — Assert the text of the element identified by ref or selector matches a predicate, polling until it holds or timeoutMs elapses. Provide exactly one of: equals, contains, regex, not_equals, not_contains. Optional flags (any of i, m, s, u) apply to regex; g and y are rejected as stateful. Returns: { ok, session_id, matched, actual }. Errors: EXPECTATION_FAILED (predicate not met within timeoutMs — details carry expected + actual; retryable), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (no/multiple predicates, invalid regex or flags, or ref+selector both/neither).
- **electron_expect_url** — Assert the active window's URL (location.href) satisfies a predicate, polling until it does or timeoutMs elapses. Provide exactly one of: contains (substring) or matches (JavaScript regex). Optional flags (any of i, m, s, u) apply to matches; g and y are rejected as stateful. Returns: { ok, session_id, matched, actual }. Errors: EXPECTATION_FAILED (URL did not match within timeoutMs — details carry expected + actual; retryable), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (no/both predicates, or invalid regex or flags).
- **electron_expect_value** — Assert the value of the element identified by ref or selector matches a predicate, polling until it holds or timeoutMs elapses. Provide exactly one of: equals, contains, regex, not_equals, not_contains. Optional flags (any of i, m, s, u) apply to regex; g and y are rejected as stateful. Returns: { ok, session_id, matched, actual }. Errors: EXPECTATION_FAILED (predicate not met within timeoutMs — details carry expected + actual; retryable), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (no/multiple predicates, invalid regex or flags, or ref+selector both/neither).
- **electron_expect_visible** — Assert the element identified by ref or selector is visible, polling until it is or timeoutMs elapses. Visible means attached, laid out, and not visibility:hidden. Returns: { ok, session_id, matched }. Errors: EXPECTATION_FAILED (not visible within timeoutMs; retryable), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, or ref+selector both/neither).
- **electron_find** — Find elements in the renderer by accessibility role + name + state — no CSS selectors. Filters: role (exact), name_contains, name_exact, visible, enabled, interactive; limit caps the matches returned (count still reports the true total). Returns: { ok, surface_id, matches: [{ ref, role, name, bbox }], count, truncated, renderer_reloaded }. A ref may be null for non-interactive landmarks. Errors: NOT_RUNNING (no session — call electron_launch first; not retryable), BAD_ARGUMENT (multiple sessions live — pass sessionId).
- **electron_focused_element** — Return the element that currently has focus as { ref, role, name }, or focused: null when nothing (or only the body) is focused. Useful after a Tab press or to confirm focus moved. Returns: { ok, session_id, focused }. Errors: TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (multiple sessions).
- **electron_force_kill** — Forcefully kill a session (SIGKILL) and release it — the escape hatch when stop hangs. Pass sessionId to target a specific session. Returns: { ok, session_id, killed: true }. Errors: NOT_RUNNING (no such session; not retryable), BAD_ARGUMENT (multiple sessions live — pass sessionId).
- **electron_get_attribute** — Return the value of attribute `name` on the element identified by ref or selector (null when the attribute is absent — that is not an error). Returns: { ok, session_id, value }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_get_bbox** — Return the bounding box (CSS pixels) of the element identified by ref or selector. Returns: { ok, session_id, bbox: { x, y, w, h } }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_get_computed_style** — Return the computed value of each requested CSS property (kebab-case, e.g. "background-color") for the element identified by ref or selector (max 50 properties). Only the requested properties are returned, never the full declaration. Returns: { ok, session_id, style: { <prop>: <value> } }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_get_state** — Return the full state envelope of the element identified by ref or selector: { visible, enabled, disabled, checked, selected, expanded, pressed, focused, readonly, required, invalid, busy } plus its role and name. One call answers "is this clickable / checked / focused". Returns: { ok, session_id, ref, role, name, state }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector or ref+selector both/neither).
- **electron_get_text** — Return the text of the element identified by ref or selector: its trimmed textContent, or — when that is empty — the accessible label that electron_find matches on (aria-labelledby/aria-label, native labels, alt, title, placeholder), so a find-by-name then get_text chain works on labelled controls. Returns: { ok, session_id, text }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (no such element; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector or ref+selector both/neither).
- **electron_get_value** — Return the .value of the input/textarea/select identified by ref or selector (null if the element has no value). Returns: { ok, session_id, value }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_hover** — Hover the element identified by ref or selector (e.g. to reveal a tooltip or menu). Options: force, timeoutMs. Returns: { ok, session_id, target }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), NOT_RUNNING, BAD_ARGUMENT.
- **electron_info** — Report the running Electron app environment: runtime versions (electron/node/chrome/v8), app name/version/paths, packaged flag, code-signature status (verified for packaged macOS apps; "unknown" for unpackaged/dev apps, "unsupported" off macOS), the active transport, and its capability matrix. Pass sessionId to target a specific session when several are running. Returns: { ok, session_id, transport, versions, app, signature, capabilities }. Errors: NOT_RUNNING (no session — call electron_launch first; not retryable), BAD_ARGUMENT (multiple sessions live — pass sessionId; not retryable).
- **electron_inject** — Attach to a running Electron process that was NOT started with a debug flag, by injecting the Node inspector. Provide pid. Returns: { ok, session_id, transport, windows, capabilities }. Errors: INJECT_FAILED (handshake failed or inspector belongs to another process; retryable — try electron_attach when the app already exposes a debug endpoint), TRANSPORT_UNSUPPORTED, BAD_ARGUMENT.
- **electron_key** — Press a key or chord (e.g. 'Enter', 'Control+A', 'ArrowDown'). Focuses ref/selector first when given; otherwise presses against the active element. For editors, click the visible content area first; reserve force:true for offscreen inputs that truly accept focus. Options: force, timeoutMs. Returns: { ok, session_id, key }. Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), NOT_RUNNING, BAD_ARGUMENT (ref+selector both).
- **electron_keyboard_type** — Type text as real per-character keystrokes (fires keydown/keypress/input/keyup per char), unlike electron_type which sets the value directly. Focuses ref/selector first when given; otherwise types into the active element. For a code editor (Monaco / EditContext), the reliable path is electron_type_into_editor (it clicks the editor content area, e.g. '.monaco-editor .view-lines', then types into the focused editor) — do NOT target the hidden textarea, which modern editors ignore. force:true focuses an offscreen/aria-hidden input but a swallowed keystroke returns TYPE_NO_EFFECT. Options: force, timeoutMs. Returns: { ok, session_id, typed }. Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), TYPE_NO_EFFECT (typing changed nothing — use electron_type_into_editor), NOT_RUNNING, BAD_ARGUMENT.
- **electron_launch** — Launch an Electron app and start a driving session. Provide main (absolute path to the main-process entry) or executablePath. Set runtime:"project" to resolve Electron only from the operator-configured --app-root (requires main when resolving that runtime); explicit executablePath takes precedence. Executable-only launches are treated as packaged apps and use a transport-owned, loopback CDP endpoint; main-based development launches use Playwright. A server started with --demo supplies its packaged demo entry when both are omitted. Returns: { ok, session_id, transport, windows, renderer_ready, runtime_source, launch_mode, capabilities }. Packaged launches default credentialStore to "testing": macOS receives --use-mock-keychain and Linux receives --password-store=basic so OS credential prompts cannot wedge automation. Use credentialStore:"system" when assertions must verify genuine safeStorage sealing. Waits (up to readyTimeoutMs, default 5000) for the renderer DOM to finish its initial render, so a snapshot/find right after launch sees a populated app; renderer_ready:false means it was not confirmed in time (the session is still usable — retry the read, or wait_for_selector on an expected element). By default refuses a second launch while a session is live (pass allowMultiple: true to override). Errors: ALREADY_RUNNING (a session is live, or the concurrent-session cap is reached — stop one or pass allowMultiple; not retryable), ABSOLUTE_PATH_REQUIRED / FILE_NOT_FOUND (preflight; not retryable), BAD_ARGUMENT (neither main nor executablePath given; runtime:"project" without main when no executablePath is given, or without --app-root when resolving that runtime; a runtime-altering env var like NODE_OPTIONS; instrumentNative without main; or, when the server set --app-root, a main/executablePath/cwd outside that root), FUSES_BLOCK_LAUNCH (a main-based development launch selected a binary that disables the Node CLI inspect channel Playwright requires; not retryable — use executablePath without main for packaged CDP launch, attach over CDP, or use a compatible development build), SINGLE_INSTANCE_LOCK (another app instance holds the lock; not retryable), LAUNCH_FAILED (the packaged app could not start or exited before a driveable renderer; not retryable), LAUNCH_TIMEOUT (first window did not appear; retryable), TRANSPORT_UNSUPPORTED (no launch-capable transport).
- **electron_press_sequence** — Press each key in `keys`, in order (e.g. ['Control+A', 'Delete', 'Enter']). Focuses ref/selector first when given. For editors, click the visible content area first; reserve force:true for offscreen inputs that truly accept focus. Options: force, timeoutMs. Returns: { ok, session_id, keys }. Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), NOT_RUNNING, BAD_ARGUMENT (empty keys or ref+selector both).
- **electron_screenshot** — Capture a screenshot to an image file and return its path (the image is written on the server host; the bytes are NOT returned inline). With ref/selector, captures just that element; otherwise the targeted window (windowId > windowTitle > windowIndex, default the active window) with optional fullPage or clip. Options: format (png|jpeg), quality (jpeg), path (absolute file) or dir (absolute directory, generated filename). With neither, writes to the server --screenshot-dir if configured, else the OS temp dir — pass dir or set --screenshot-dir for a stable, retrievable artifact location. Returns: { ok, session_id, path, bytes, format, width?, height? } (path is the absolute file written). Errors: ABSOLUTE_PATH_REQUIRED (relative path), REF_NOT_FOUND (no such window), SELECTOR_NO_MATCH (element not found), SURFACE_UNSUPPORTED (iframe element crops are not window-relative), NOT_RUNNING, BAD_ARGUMENT (invalid selector/options).
- **electron_scroll** — Scroll: with ref/selector, centre that element into view; otherwise dispatch a wheel delta (dx/dy). Options: timeoutMs. Returns: { ok, session_id, target } (into-view) or { ok, session_id, dx, dy } (wheel). Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (no element matched the selector; carries similar_refs), NOT_RUNNING, BAD_ARGUMENT (ref+selector both).
- **electron_scroll_into_view** — Centre the element identified by ref or selector into the viewport. Options: timeoutMs. Returns: { ok, session_id, target }. Errors: SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), NOT_RUNNING, BAD_ARGUMENT (ref+selector both/neither).
- **electron_select_option** — Select option(s) by value in the <select> identified by ref or selector. Options: force, timeoutMs. Returns: { ok, session_id, target, selected } (selected = the values actually chosen). Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_set_files** — Set the files of the <input type=file> identified by ref or selector. Paths must be ABSOLUTE and exist on the host running the server (max 20 files, 52428800 bytes each). Options: timeoutMs. Returns: { ok, session_id, target, files }. Errors: ABSOLUTE_PATH_REQUIRED (relative path; not retryable), FILE_NOT_FOUND (missing path), BAD_ARGUMENT (too many/large files, or ref+selector both), SELECTOR_NO_MATCH / REF_NOT_FOUND (carries similar_refs), NOT_RUNNING.
- **electron_snapshot** — Capture the selected renderer surface accessibility tree: interactive elements (and landmarks) with role, name, state, bbox, and a stable ref. Pass since:"last" for only what changed since the previous snapshot (added/removed/changed + ref_map), interactiveOnly to drop landmarks, maxEntries to cap. format:"text" returns a compact one-line-per-entry rendering instead of JSON (5-10x fewer tokens): `[ref] role "name" value=… flags`, ~ marks recently-changed, [-] marks landmarks. Diffs default to a compact encoding (changed fields only; diffFormat:"full" restores complete prev/curr entries) and accept budgetTokens for server-side truncation that keeps interactive entries first. Each response carries renderer_reloaded so stale refs are detectable (P10). Refs are tagged on the DOM (data-sw-ref) so later interaction tools can act by ref. Closed shadow roots are opaque unless the app opts in: push each root onto window.__stagewright_closedShadowRoots at attachShadow time (or implement window.__stagewright_inspectShadow); their entries carry state.shadow_closed: true. Returns: { ok, surface_id, kind: "full" | "diff", snapshot?, diff?, snapshot_text?, diff_text?, diff_format?, renderer_reloaded, truncated }. Errors: NOT_RUNNING (no session — call electron_launch first; not retryable), BAD_ARGUMENT (multiple sessions live — pass sessionId).
- **electron_status** — Return compact orientation for this server: version, start time, uptime, the last stable failure not tied to a live session, active-session count, and each live session's transport, renderer readiness, selected surface, last stable error code, and non-default dialog policy. It never returns arguments, paths, window arrays, logs, stack traces, dialog entries, prompt text, or plugin payloads. Use electron_windows_list, electron_surfaces_list, or the relevant plugin tool for detailed state. Returns: { ok, server: { version, started_at, uptime_ms, last_error? }, active_sessions, sessions }. Errors: none.
- **electron_stop** — Gracefully stop a session and release it. If the app ignores the close within timeoutMs (default 10s) the stop auto-escalates to SIGKILL, so the process is always reaped and never left orphaned; the response reports escalated: true when that happened. Pass sessionId to target a specific session. Returns: { ok, session_id, stopped: true, escalated }. Errors: NOT_RUNNING (no such session; not retryable), BAD_ARGUMENT (multiple sessions live — pass sessionId).
- **electron_surfaces_list** — List the session renderer surfaces in parent-first order: BrowserWindow roots, WebContentsViews, webview guests, and iframe children. Each opaque id is stable only while its surface stays live; select it with electron_switch_surface before snapshot/find/renderer interactions. Returns: { ok, session_id, surfaces, active_surface_id, count }. Existing window tools remain compatible for window-only flows. Errors: TRANSPORT_UNSUPPORTED (surface targeting is unavailable on this transport; not retryable), NOT_RUNNING, BAD_ARGUMENT (multiple sessions).
- **electron_switch_surface** — Select a live renderer surface by the opaque id returned by electron_surfaces_list. Following snapshot, find, renderer reads/eval, waits, expectations, and interactions target that surface; a ref from a different surface is rejected rather than reused. Returns: { ok, session_id, active, active_surface_id }. Errors: SURFACE_NOT_FOUND (the id was never observed in this session), SURFACE_CLOSED (it detached or closed), SURFACE_UNSUPPORTED (the live surface cannot be driven), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_switch_window** — Select the active window by precedence targetId > windowTitle > index > default. The selection changes Stagewright's renderer target; it does not promise native OS foreground focus. Returns: { ok, session_id, active, active_window_id } on success. Errors: REF_NOT_FOUND (no window matched; not retryable), TRANSPORT_UNSUPPORTED (transport has no renderer window target; not retryable), NOT_RUNNING, BAD_ARGUMENT (multiple sessions).
- **electron_type** — Set the value of the input/textarea identified by ref or selector (fires an input event). For a code editor (Monaco / EditContext, CodeMirror) use electron_type_into_editor — setting .value on an editor host does not update its model. Options: force, timeoutMs. Returns: { ok, session_id, target }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED, TYPE_NO_EFFECT (value did not change — wrong target), NOT_RUNNING, BAD_ARGUMENT.
- **electron_type_into_editor** — Type into a code editor (Monaco / EditContext, CodeMirror, contenteditable) the reliable way: click the editor's content area identified by ref or selector (e.g. '.monaco-editor .view-lines'), then type the text into the now-focused editor as real keystrokes. Use this instead of typing into an editor's hidden textarea, which modern EditContext editors ignore (returns TYPE_NO_EFFECT). Pass replace:true to REPLACE the editor contents: after the focusing click it selects all (Meta/Control+A, platform-aware) and types over the selection — no second click that would collapse the selection; with empty text it clears the editor (select-all + Delete). Editor auto-pairing caveat: real keystrokes trigger auto-closing of quotes/brackets, so typed source can gain debris like a trailing }') — type pairing-safe fragments, or use replace:true and include the full intended contents. Returns: { ok, session_id, target, typed, replaced }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), TYPE_NO_EFFECT, NOT_RUNNING, BAD_ARGUMENT.
- **electron_uncheck** — Uncheck the checkbox identified by ref or selector (no-op if already unchecked). Options: force, timeoutMs. Returns: { ok, session_id, target, checked: false }. Errors: REF_NOT_FOUND / SELECTOR_NO_MATCH (carries similar_refs), ELEMENT_NOT_VISIBLE (retryable), ELEMENT_DISABLED, NOT_RUNNING, BAD_ARGUMENT.
- **electron_wait** — Pause for ms milliseconds (clamped to 60000). Prefer electron_wait_for_state or electron_wait_for_selector — a fixed wait is slower and more brittle than waiting on a condition. Returns: { ok, session_id, waited_ms }. Errors: NOT_RUNNING (no session), BAD_ARGUMENT (multiple sessions).
- **electron_wait_for_event** — Wait until a named DOM event (e.g. "transitionend", "load", a custom event) fires on the element identified by ref or selector — or on document when neither is given. Returns: { ok, session_id, fired, event }. Errors: WAIT_TIMEOUT (event did not fire within timeoutMs; retryable), SELECTOR_NO_MATCH (target element not present), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, or ref+selector both).
- **electron_wait_for_selector** — Wait until the element identified by ref or selector reaches state: attached (in the DOM), visible (laid out + not visibility:hidden), hidden (absent or not visible), or detached (removed). Default state: visible. For an intentionally offscreen / aria-hidden element (e.g. a code editor's hidden textarea like Monaco), wait for state:'attached' — state:'visible' will time out because the element is never laid out. Returns: { ok, session_id, matched, state }. Errors: WAIT_TIMEOUT (condition not met within timeoutMs; retryable — for offscreen editor inputs use state:'attached'), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, or ref+selector both/neither).
- **electron_wait_for_state** — Wait until the element identified by ref or selector matches the given state flags (any of visible, enabled, disabled, checked, selected, expanded, pressed, focused, readonly, required, invalid, busy), evaluated atomically. Returns: { ok, session_id, matched, state }. Errors: WAIT_TIMEOUT (state not reached within timeoutMs — details.last_state shows the last observed state; retryable), REF_NOT_FOUND (stale ref; carries similar_refs), TRANSPORT_UNSUPPORTED, NOT_RUNNING, BAD_ARGUMENT (invalid selector, no state flags, or ref+selector both/neither).
- **electron_windows_list** — List the app windows with their id, index, title, url, and visibility. Pass sessionId to target a specific session. Returns: { ok, session_id, windows, active_window_id, count }. Errors: NOT_RUNNING (no such session; not retryable), BAD_ARGUMENT (multiple sessions — pass sessionId).

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "core": {
    "command": "npx",
    "args": ["-y","--package","@electron-stagewright/core@0.5.0","--package","playwright@1.61.1","--package","electron@42.3.0","electron-stagewright"]
  }
}
```

## Documentation

## What the core MCP server does

The core MCP server gives MCP-compatible agents a way to operate real Electron applications rather than only browser pages. It can start an application, connect to an existing development process, or inject into a running main process through the Node Inspector handshake. This makes it suitable for testing renderer interfaces alongside Electron-specific behavior such as multiple windows, native menus, dialogs, packaged runtimes, and release artifacts.

UI inspection is based on accessibility roles and ARIA information. Agents can work with stable element references instead of CSS selectors or XPath, and can query for elements by role, partial name, and visibility. Snapshot results can include visibility, enabled state, focus, checked state, expansion, busy state, and validation state. Snapshots can also report changed elements and renderer reloads that may invalidate earlier references.

## How it works

The server communicates with an MCP host over its default local launch transport. The documented setup uses the published core package together with pinned Playwright and Electron packages. An agent starts or connects to an application, reads a snapshot, interacts with returned references, waits for state changes, and asserts expected results before stopping the session.

Composite state predicates are evaluated by the server in one wait operation. Expectation tools combine checking and retry behavior, reducing the need for repeated read-and-compare calls. Snapshot output can be requested as compact text when a one-line-per-element representation is more useful than the full JSON state. Session traces record tool calls, arguments, results, timings, and token estimates, and can be replayed against a fresh app instance with per-tool budgets.

## Setup and configuration

For a published installation, prime the package cache before starting an MCP stdio session. The documented command pins `@electron-stagewright/core` 0.5.0, Playwright 1.61.1, and Electron 42.3.0, then runs `electron-stagewright doctor --json`. This avoids first-run Electron download output interfering with the MCP session.

Claude Code can be configured with an `npx` command using those same packages. A local development setup instead runs `pnpm install`, `pnpm build`, and points the host at `packages/core/dist/cli.js`. The server can launch an app with a main-process path and environment values, or connect to an application that exposes the required loopback debugging endpoint. A separate demo package is available for verifying a host configuration without supplying an application path.

## Tools and capabilities

The core MCP server includes capabilities for:

- Launching, attaching to, injecting into, and stopping Electron sessions.
- Inspecting accessibility snapshots, snapshot deltas, compact text output, and renderer reload status.
- Finding elements semantically by role, name text, and visibility.
- Clicking and otherwise interacting with elements through stable references.
- Waiting for composite conditions such as visible, enabled, or focused.
- Asserting text and other UI expectations with retrying operations.
- Capturing screenshots, console output, dialogs, and session traces.
- Inspecting plugins, their enabled tools, and safe configuration.
- Supporting validation workflows for signed and notarized `.app` bundles, including code signing, Gatekeeper assessment, updater feeds, URL schemes, and crash reporting machinery.

The documented fixtures cover vanilla, React, Vue, and Angular renderers, while the broader renderer matrix is still expanding. The server also returns token-cost information with responses, which helps an agent account for inspection overhead.

## Limitations and notes

The server is designed for Electron applications and does not replace a general browser automation service. The default workflow depends on Playwright and an Electron runtime, and the release-tested package versions should be pinned for the documented setup. Attaching requires an exposed loopback CDP endpoint; injection is intended for cases where a debug flag was not configured in advance.

References are tied to the inspected UI state. After a renderer reload, agents should refresh their snapshot before using older references. The accessibility-based approach avoids framework internals, but coverage beyond the currently documented fixture frameworks is still developing. The full tool inventory and parameters are maintained in the repository's generated tool reference.

_Full upstream README: https://allmcps.com/mcp/core/readme_

