npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

electromcp

v2.0.1

Published

Drive any Electron app from your AI. MCP server with 93 tools, 4 recipe packages (Slack/Discord/Notion/Linear), security primitives, and a CLI mirror. The testing surface area Tauri structurally cannot match.

Readme

ElectroMCP

Drive any Electron app from your AI. One install.

ElectroMCP demo

pipeline npm version


What you can do Monday morning

  • Bulk-invite a cohort to Slack and send welcome DMs in 60 seconds — instead of 50 minutes of manual clicking
  • Ship Friday-afternoon Electron features without dread, because tests stop hanging on dialogs you forgot to mock
  • Drive your already-running Slack / Discord / Notion / Linear / VS Code from Claude or Cursor — no API tokens, no OAuth, no code changes to those apps
  • Snapshot every screen of your app with one prompt — instead of 30 manual screenshots
  • Reproduce the IPC bug from yesterday's trace by replaying the recorded sequence

These aren't demos. They're the actual workflows ElectroMCP was built for.

Quick start (5 tools you'll use 80% of the time)

claude mcp add electromcp -- npx electromcp

Then in any AI conversation:

| Tool | What it does | When to use it | |---|---|---| | app_launch { stubMode: 'auto' } | Zero-config launch + auto-stub every native dialog/menu/tray/notification | Start of every test session | | app_attach_by_name { name: "Slack" } | Connect to a running app over CDP | Power-user / consumer-app flows | | app_vision_read | Returns app summary + screenshot + a11y + main-state in one call | "What is my app showing right now?" | | electron_main_state | Full nervous system of your app (windows, IPC, menu, tray) in one call | Debugging or pre-flight | | slack_bulk_invite { csvPath, channels } | Onboard a cohort with welcome DMs | Mondays |

That's the 80%. The other 88 tools are there when you need them.

Magic moments

"I forgot to mock that dialog"

Old way: test hangs forever, you Ctrl-C, dig through stack trace, add mockDialog, re-run. ElectroMCP: app_launch { stubMode: 'auto' } — every native dialog / menu / tray / notification / shell.openExternal is stubbed at boot. Tests never hang again.

"Which workspace am I even in"

Old way: open Slack, scroll the workspace switcher, count. ElectroMCP: prompt Claude with slack_list_workspaces — back in 200ms.

"Is my main process actually ready"

Old way: add console.log, restart app, scroll terminal. ElectroMCP: electron_main_state returns BrowserWindows + ipcMain handlers + menu tree + Tray instances + locale + theme in one call.

"What did the AI just do to my Slack"

Old way: scroll Slack manually, hope nothing weird happened. ElectroMCP: every recipe call writes to ~/.electromcp/audit.log with timestamp, tool, args, return summary. Receipts.

Three things in one MCP server

  1. Automate any Electron app you didn't write

    • app_attach_by_name finds running Electron processes via ps (Slack, Discord, Cursor, Notion, Linear, …) and attaches over CDP
    • Multi-window, multi-instance, multi-session aware
    • BrowserView shim that Playwright structurally cannot match
  2. Pre-built recipes for popular Electron apps

    • @electromcp/recipes-slack, -discord, -notion, -linear (TradingView lands in v1.1; VS Code + Cursor in v1.2)
    • Security model every recipe inherits: auth_scope allowlist (default empty), PII redaction default, append-only audit log, readonly-by-default, token-leak regression test in CI
  3. Deep dev tooling for your own Electron app

    • electron_main_state — full nervous system in one call
    • Native shell auto-stub at one toggle
    • IPC observability (listen, mock, replay, assert)
    • Auto-update simulation, deep-link harness, perf gating, per-OS visual regression

    The testing surface area Tauri structurally cannot match.

Why now

  • MCP just hit critical mass — Claude Desktop, Cursor, Codex, Gemini, Copilot all speak it
  • Tauri is taking marketing oxygen from Electron — the testability moat needs a flagship demonstration
  • The recipe pattern is unclaimed — first mover wins the convention

Install

claude mcp add electromcp -- npx electromcp

For Claude Desktop / Cursor / Windsurf / Copilot / Gemini configs, the command is the same (npx electromcp); only the config file path differs per AI tool.


Feature matrix

| Capability | ElectroMCP v2.0 | Tauri | WDIO Electron | Spectron | kanishka MCP | halilural MCP | |---|---|---|---|---|---|---| | Zero-config launch (6 archetypes) | ✓ | — | partial (Forge/builder only) | — | — | — | | Native shell auto-stub (one toggle) | ✓ | — | — (per-call manual) | — | — | — | | Mock substrate (vitest-spy ergonomics) | ✓ | — | ✓ | — | — | — | | electron_main_state (one-call snapshot) | ✓ | — | — | partial | — | — | | IPC live observability (listen/traffic/replay) | ✓ | — | mock only | — | — | — | | Auto-update simulation (fake server + scenarios) | ✓ | — | — | — | — | — | | Deep-link harness (warm + cold start) | ✓ | — | — | — | — | — | | Perf gating + assertions | ✓ | — | — | — | — | — | | Visual regression (per-OS baselines + auto-mask) | ✓ | partial | — | — | — | partial | | Multi-session / partition introspection | ✓ | — | — | — | — | — | | BrowserView shim (raw CDP) | ✓ | n/a | — | — | — | — | | Process-name attach (Slack, Discord) | ✓ | — | — | — | — | — | | Recipe packages (Slack/Discord/Notion/Linear) | ✓ | — | — | — | — | — | | Security primitives (auth_scope + PII + audit + readonly) — recipes only [^sec] | ✓ | — | — | — | — | partial | | macOS testing | ✓ | broken (no WKWebView WebDriver) | ✓ | ✓ (archived) | ✓ | ✓ | | Codegen export | ✓ | — | — | — | ✓ | — |

[^sec]: Core tools do not auto-enforce auth_scope / PII redaction / audit log / readonly mode. These primitives are exposed via the electromcp/security subpath export and are wired automatically into every recipe via @electromcp/recipes-template. To apply them to core tool outputs, redact in your AI prompt or call redactObject in user-side post-processing.


Why not Tauri?

Tauri is a great choice for some apps. But the testing story is structurally broken in ways ElectroMCP exposes:

  1. No WKWebView WebDriver on macOS. tauri-driver works on Windows and Linux. macOS testing is third-party hacks against Apple's closed-source webview. ElectroMCP runs the same way on every platform.
  2. No main-process introspection. Tauri's webview-only architecture means there is no equivalent to electron_main_state — no live BrowserWindow registry, no ipcMain handler list, no menu tree, no Tray instance dump. Your testing tool can only see what's inside the webview.
  3. No native shell stub surface. Tauri's native dialogs/menus/notifications are Rust-side. There's no construction-site interception model like ElectroMCP's electron_stub_*. Every native call hangs your test or hits the real OS.

If you stay on Electron, you keep the moat. ElectroMCP is the moat.


Tools

App lifecycle (5)

| Tool | Purpose | |---|---| | app_launch | Launch with zero-config archetype detection. Optional stubMode: 'auto', preset, instanceId. | | app_connect | Attach to a running app on port or full url. | | app_disconnect | Disconnect without killing the app. | | app_stop | Shut down and disconnect. | | app_health | Ping; auto-reconnect if the page is dead. |

Visual + interaction (12)

| Tool | Purpose | |---|---| | ui_screenshot | Full screenshot of the active window. | | ui_accessibility_snapshot | Full a11y tree — cheaper than a screenshot. | | ui_get_dom | Raw HTML of the page or an element. | | ui_observe | Visual state with context for AI reasoning. | | ui_click | Click by selector or visible text. | | ui_click_text | a11y-role+name first, text fallback — the semantic locator. | | ui_fill | Set an input value instantly. | | ui_type | Type character-by-character. | | ui_press | Press a keyboard chord. | | ui_hover | Hover (tooltips, hover states). | | ui_scroll | Scroll page or element in any direction. | | ui_wait_for | Wait for selector to appear / disappear / become visible. | | ui_get_element | Attributes, text, bbox, visibility, enabled state. | | ui_act | Returns a screenshot so the AI picks the next action. | | ui_screenshot_match | Per-OS visual baseline diff. Auto-masks titlebar / traffic lights. | | app_screenshot_match_docker | Optional Docker-normalized baseline (cross-platform-stable). |

Windows (3)

| Tool | Purpose | |---|---| | window_list | Every open window: title, URL, dimensions, focus. | | window_switch | Switch by title substring or index. | | window_get_by_title | First window matching a title substring. |

Debug (5)

| Tool | Purpose | |---|---| | app_console_logs | Renderer console output since launch. | | app_evaluate_renderer | Run JS in the renderer; get the return. | | app_evaluate_main | Run JS in main. Gated by ALLOW_MAIN_EVAL=1 (or allowMainEval: true settings). | | app_crash_status | Renderer crash check. | | app_crash_reset | Clear the crash flag. |

Test runner (4)

| Tool | Purpose | |---|---| | test_run | Shell out to any test command, parse pass/fail. | | test_run_file | Run a single test file. | | test_run_grep | Run tests matching a name pattern. | | test_get_results | Parsed results from the last run. |

Recording + planning (5)

| Tool | Purpose | |---|---| | batch_run | Plan a multi-step sequence; AI executes one tool at a time. | | app_record_har | Start HAR network recording. | | app_stop_har | Flush + save HAR. | | app_record_video | Start .webm video recording. | | app_stop_video | Flush + save video. |

Electron sugar (10)

| Tool | Purpose | |---|---| | electron_ipc_send | Fire-and-forget IPC from renderer (contextBridge or nodeIntegration fallback). | | electron_ipc_invoke_main | Invoke an ipcMain.handle handler from MCP and capture the return. | | electron_ipc_invoke_renderer | Drive ipcRenderer.invoke and capture the return. | | electron_main_state | One-call structured snapshot: BrowserWindows, ipcMain handlers, menu tree, Tray instances, app event log, locale, theme, isReady. | | electron_app_get_path | app.getPath(name) — userData, logs, downloads, etc. | | electron_app_get_metrics | getAppMetrics() + getProcessMemoryInfo() per process. | | electron_clipboard_read | Read system clipboard. | | electron_clipboard_write | Write system clipboard. | | electron_shell_open_external | shell.openExternal with stub: 'capture' \| 'noop' \| 'real'. | | electron_on_crash | Wait for renderer crash or timeout. |

Native shell auto-stub (8)

| Tool | Purpose | |---|---| | electron_stub_dialog | Stub native OS dialogs by type and matchers (title/buttons). | | electron_stub_menu | Capture Menu.setApplicationMenu / buildFromTemplate template tree. | | menu_click | Walk captured menu tree and synthesize a click on "File > Save". | | electron_stub_tray | Capture every new Tray() instance + listeners. | | tray_click | Synthesize click / right-click / double-click on a captured Tray. | | electron_stub_notification | Intercept new Notification(); capture title/body/silent/icon. | | notification_assert | Assert against the captured notification registry. | | electron_stub_shell_open_external | Capture shell.openExternal URLs without spawning a browser. |

app_launch({ stubMode: 'auto' }) toggles all of the above with sane defaults at boot.

IPC observability (7)

| Tool | Purpose | |---|---| | electron_ipc_listen | Start recording all ipcMain.handle / ipcRenderer.send traffic. | | electron_ipc_traffic | Return recorded events with timestamps + serialization diagnostics. | | electron_ipc_mock | Vitest-style handler mock — override ipcMain.handle returns. | | electron_ipc_assert | Pass/fail matcher: { channel, calledWith?, calledTimes? }. | | electron_ipc_replay | Replay a recorded trace to reproduce a bug from prod. |

Auto-update harness (5)

| Tool | Purpose | |---|---| | app_update_server_start | Fake update server: serves latest.yml (electron-updater) and RELEASES (Squirrel.Windows). | | app_update_server_stop | Stop the fake server. | | app_update_set_scenario | Pre-arm: available / downloading / downloaded / corrupt / signature_mismatch / partial_download / rollback. | | app_update_simulate | Fire the armed scenario into the running app's electron-updater listeners. | | app_update_assert_called | Assert the updater hit your fake server with expected url/headers/channel/times. | | app_squirrel_simulate | Relaunch with --squirrel-firstrun / install / update / uninstall argv. |

Deep-link harness (5)

| Tool | Purpose | |---|---| | app_deeplink_register | Work around setAsDefaultProtocolClient dev-mode broken-ness on macOS/Linux/Win. | | app_deeplink_unregister | Reverse the registration. | | app_deeplink_fire | Warm-start: inject via app.emit('open-url') / 'second-instance'. | | app_deeplink_simulate_cold_start | Cold-start: relaunch with URL prepended to argv. | | app_deeplink_assert | Assert scheme/path/params were observed by the app. |

Perf (4)

| Tool | Purpose | |---|---| | app_perf_snapshot | Startup time + per-process metrics + RSS/heap + recent FPS sample. | | app_perf_trace_start | Wraps contentTracing.startRecording with named scenarios. | | app_perf_trace_stop | Stop and return the trace JSON path. | | app_perf_assert | expect(startup).toBeUnder(1500)-style matcher with stable-baseline hashing. |

Multi-session (4)

| Tool | Purpose | |---|---| | app_partitions | List named sessions with metadata. | | partition_snapshot | Cookies + localStorage + IndexedDB + serviceWorker registrations. | | partition_assert_isolated | Assert zero key overlap between two partitions. | | partition_clear | Bulk reset a partition. |

BrowserView + process attach (4)

| Tool | Purpose | |---|---| | browserview_list | List BrowserViews via raw CDP (Playwright doesn't support them). | | browserview_evaluate | Run JS inside a BrowserView. | | browserview_screenshot | Screenshot a BrowserView. | | app_attach_by_name | Find a running Electron process via ps (Slack, Discord, …) and attach over CDP. |

Environment overrides (4)

| Tool | Purpose | |---|---| | app_set_geolocation | Override geolocation. | | app_set_locale | Override locale. | | app_set_timezone | Override timezone. | | app_set_color_scheme | Override prefers-color-scheme. | | app_network_emulate | CDP Network.emulateNetworkConditions: offline / slow-3g / fast-3g / custom. |

Codegen export (3)

| Tool | Purpose | |---|---| | app_codegen_start | Begin recording every tool call with its args. | | app_codegen_stop | Stop recording. | | app_codegen_export | Output as runnable Playwright .spec.ts or replayable MCP transcript. |


Recipes

ElectroMCP ships four recipe packages — each one attaches to your real installed Electron app and exposes a small, scoped, secure tool surface:

  • @electromcp/recipes-slackslack_read_channel, slack_send_message, slack_search, slack_react
  • @electromcp/recipes-discorddiscord_read_channel, discord_send, discord_dm
  • @electromcp/recipes-notionnotion_search, notion_create_page, notion_update_db_row, notion_export_db
  • @electromcp/recipes-linearlinear_create_issue, linear_comment, linear_move_issue, linear_triage_inbox

Security model (every recipe inherits)

  • auth_scope allowlist — explicit list of channels / workspaces / accounts the agent may touch. Default empty → no access until granted.
  • PII redaction by default — email / phone / credit-card patterns are scrubbed from returned text unless pii: 'allow' is set per-call.
  • Append-only audit log at ~/.electromcp/audit.log — every recipe call writes { timestamp, tool, redacted args, return summary }. You can review what the agent saw and sent.
  • Read-only by defaultmode: 'readonly' ships on every recipe. Write actions (*_send_*, *_post_*, *_create_*) require explicit mode: 'write'.
  • Token-leak assertion — the test suite asserts no recipe tool ever returns a cookie / bearer / OAuth token. CI fails on regression.

Selectors are pinned per app version via @electromcp/selector-tools (capture, pin, validate). When the target app upgrades, the recipe loads the closest matching selector file and warns on fallback. Auto-PR'd selector regen is aspirational; manual capture is the v2.0 path.


Migration


Recommended flow

1. app_health                 confirm connection
2. ui_accessibility_snapshot  cheap structure
3. ui_screenshot              only if visuals matter
4. ui_click / ui_fill / ...   interact
5. electron_main_state        verify main-side state

For debugging:

1. app_console_logs           renderer output
2. app_evaluate_renderer      live DOM / variables
3. electron_ipc_traffic       what crossed the bridge

Environment variables

| Variable | Default | Description | |---|---|---| | ALLOW_MAIN_EVAL | unset | Set to 1 to enable app_evaluate_main AND electron_ipc_mock's implementation parameter (both compile user-supplied JS into the Electron main process). |


Limitations

Surfaced honestly so you know what you're buying. Several of these are tracked for v2.1.

  • PII redaction is recipe-side only. Core tools (ui_accessibility_snapshot, electron_main_state, electron_ipc_traffic, etc.) return raw text and state. If your app's accessibility tree, IPC traffic, or main-state contains emails / phone numbers / tokens / credit-card patterns, those will surface unredacted in tool returns. Recipe packages (@electromcp/recipes-*) auto-redact via the recipe template. For core tools, redact in your AI prompt or call redactObject from electromcp/security in user-side post-processing.
  • electron_ipc_send sends from the renderer. If your app uses contextIsolation: true without a contextBridge-exposed ipcRenderer and without nodeIntegration: true, the call fails with a clear error.
  • electron_ipc_listen is not "everything that crosses the bridge". Renderer → main ipcRenderer.send traffic is only observable when the app actually registered an ipcMain.on handler for that channel; sends to channels with no handler are silently dropped by Electron itself and we cannot see them. Main → renderer webContents.send is not observed at all in v2.0 — Electron offers no public hook in the main process to intercept outgoing sends without monkey-patching every webContents instance. Tracked for v2.1.
  • app_update_assert_called blockmap is not real electron-builder wire format. The fake update server emits an uncompressed JSON description of block hashes, not the actual .blockmap binary format. Strict real electron-updater clients will reject it. The harness is sufficient for testing your app's update event handlers; it is not a full blockmap fuzzer. Tracked for v2.1.
  • app_deeplink_assert requires fixture cooperation. It reads from globalThis.__deeplink__.events which the target app must populate (typically via a small instrumentation snippet at boot). The cold-start variant is fully turnkey; warm-start assertions need the snippet. Tracked for v2.1.
  • app_screenshot_match_docker does not run Electron in Docker. It screenshots an HTTP URL inside a pinned Playwright Chromium container so baselines don't drift across host OS / GPU / fonts. Useful for comparing renderer output against a normalized reference; does not exercise main-process or native-shell behavior. The host-Electron path (ui_screenshot_match) is what you want for full-app regression. Tracked for v2.1 (Electron-in-Docker is non-trivial because Electron needs root + display + sandbox bypass).
  • partition_snapshot is partial. Partitions not bound to an open BrowserWindow are invisible (Electron has no public partition-enum API). localStorage is only walked for partitions with at least one open window. IndexedDB returns aggregate usage, not per-DB enumeration. serviceWorkers is [] on Electron <28. The exported helpers' JSDoc spells this out per-method.
  • HAR / video recording require launch mode (cannot be added to an existing CDP session).
  • app_evaluate_main is launch mode only. It requires either ALLOW_MAIN_EVAL=1 in the environment OR a preset that grants it (preset: 'permissive' | 'dev', or settings: { allowMainEval: true } on launch).
  • electron_ipc_mock's implementation parameter compiles arbitrary JS into the main process and is gated by the same ALLOW_MAIN_EVAL / allowMainEval primitive as app_evaluate_main. The static response parameter remains unrestricted. Set the env or preset before passing implementation strings, otherwise the call rejects with eval_blocked.
  • Recipe selectors rot. The 4 recipe packages pin selectors per app version. When the target app upgrades past your pinned version, loadSelectors warns at >30 days stale and escalates to "deprecated" at >90 days. The recipe packages' CONTRIBUTING.md documents the regen flow. CI auto-PR'd selector capture is aspirational for v2.0 — manual capture is the v2.0 path.
  • Headless is not officially supported by Electron. On Linux CI: xvfb-run npm test (ElectroMCP auto-detects + auto-launches xvfb when DISPLAY is unset).

Development

git clone https://gitlab.com/therealseandonahoe/electromcp
cd electromcp
npm install
npm run build    # tsc -> build/
npm run dev      # tsx src/index.ts
npm test         # full suite

Contributing

Recipe selectors break weekly. PRs against packages/recipes-*/selectors.<version>.json auto-merge if CI is green. Each recipe has a CONTRIBUTING.md with the selector-regen flow.

License

MIT