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

@solarisdk/mcp

v0.6.4

Published

Model Context Protocol server for the Solari cloud browser, sandboxes + desktops — drive them from Claude Desktop/Cowork, Claude Code, Cursor, etc.

Readme

solari-mcp

A Model Context Protocol server that lets AI agents (Claude Desktop incl. Cowork, Claude Code, Cursor, Windsurf, …) use Solari as their browser, sandbox, and desktop:

  • Cloud browser — create stealth/proxied browser sessions, navigate, read pages, screenshot, click/type, session replay (wraps the Solari browser gateway + CDP via puppeteer-core).
  • Sandboxes — headless microVMs: run commands/code, read/write files, expose ports.
  • Desktops — GUI microVMs: screenshot/click/type, launch apps, noVNC stream URL.

MCP tool calls are stateless, so the server keeps an in-memory session registry: *_create tools return a sessionId, and the rest take it.

Use it — hosted connector (no install)

Point any MCP client at the hosted Streamable HTTP endpoint with your API key:

  • Prod: https://mcp.getsolari.com/mcp

Claude Desktop / claude.ai: Settings → Connectors → Add custom connector, URL as above, and send Authorization: Bearer slr_live_…. Or in claude_desktop_config.json / Claude Code:

{
  "mcpServers": {
    "solari": {
      "type": "http",
      "url": "https://mcp.getsolari.com/mcp",
      "headers": { "Authorization": "Bearer slr_live_…" }
    }
  }
}

Each MCP session is bound to the API key that initialized it. The server does not evict idle tenants by default: it frees a tenant's browser sessions after SESSION_IDLE_MS (30 min) of silence only when it runs with TENANT_IDLE_SWEEP=single-replica-only, which is valid for a single replica only, and the hosted server runs more than one. Close browser sessions with solari_browser_close; one left open holds a concurrency slot until the gateway ends it at your plan's maximum session length. Sandboxes and desktops keep their own idle policy (re-attach with solari_connect).

Use it — local stdio (Claude Desktop / Cowork / Cursor / Windsurf)

{
  "mcpServers": {
    "solari": {
      "command": "npx",
      "args": ["-y", "@solarisdk/mcp"],
      "env": { "SOLARI_API_KEY": "slr_live_…" }
    }
  }
}

Use it — single-file bundle (no npm)

// claude_desktop_config.json (Claude Desktop: Developer → Edit Config)
{
  "mcpServers": {
    "solari": {
      "command": "node",
      "args": ["/absolute/path/to/solari-mcp.bundle.cjs"],
      "env": {
        "SOLARI_API_KEY": "slr_live_…"
      }
    }
  }
}

Fully quit and reopen Claude Desktop after editing; the tools then show up in Chat, Code and Cowork alike.

Environment

| Var | Required | Default | Meaning | |---|---|---|---| | SOLARI_API_KEY | ✅ | — | unified slr_live_… key (works on both gateways) | | SOLARI_BASE_URL | | https://api.getsolari.com | sandbox/desktop gateway | | SOLARI_BROWSER_URL | | SOLARI_BASE_URL → prod | cloud-browser gateway. The gateway path-routes browser AND desktop on one host, so this rarely needs setting | | SOLARI_BROWSER_API_KEY | | SOLARI_API_KEY | separate key for the browser gateway, for environments where the browser and desktop key stores are split |

Tools

Browser (Solari cloud browser)

| Tool | What it does | |---|---| | solari_browser_create | Start a browser session (mode, proxy, captcha, recording, profileId) → {sessionId, mode, captcha} | | solari_browser_navigate | Go to a URL → {url, title, status} | | solari_browser_read_page | Page text / links / HTML (30k-char cap) | | solari_browser_screenshot | JPEG screenshot (image content) | | solari_browser_click / solari_browser_type / solari_browser_key | Interact (selector or x/y) | | solari_browser_evaluate | Run a JS expression on the page | | solari_browser_replay_url | rrweb replay URL (needs recording: true) | | solari_browser_login | Ask a HUMAN to sign in — returns a short-lived URL to show them | | solari_browser_await_login | Wait for them to finish, then re-attach the session | | solari_browser_profiles | List saved profiles → {profiles: [{profileId, name, version, populated, lastUsedAt}]}; check here first when a task needs a login | | solari_browser_create_profile | Create a new, empty profile (name) → {profileId, ...}; only when the user has asked for a login to be set up | | solari_browser_delete_profile | Permanently delete a profile and its stored sign-in state; only when the user explicitly asked | | solari_browser_autologin_status | Whether the account can sign in to sites automatically: connected password managers, configured sites, and the setupUrl to show the user | | solari_browser_autologin_site | Say which password-manager credential signs in to a domain (manager, optional item); it never handles the credential itself | | solari_browser_save_profile | Persist the signed-in state to a profile (explicit — see below) | | solari_browser_edit_profile | Open an existing profile for a HUMAN to edit — returns a 30-minute editor link and a handoffId | | solari_browser_finish_profile_edit | Save and close the editor (save: true) or close it without saving (save: false) | | solari_browser_close | Release the session |

Browser mode — stealth by default

solari_browser_create defaults to mode: "stealth" (the anti-bot hardened pool). A bare call with no arguments gets it; the model does not have to ask.

This used to be an optional stealth: true boolean, and in practice models did not opt in — so sessions quietly landed on the fast pool and got blocked by bot detection. The failure looked like "the site is broken" rather than "we chose the wrong pool", which is the worst way for a default to be wrong.

mode: "fast" is the explicit opt-out: lower latency, for sites you already know do not fingerprint or block automation (internal tools, localhost, your own app, plain docs). If a page returns a block/captcha/challenge in fast mode, close the session and retry on stealth.

proxy and captcha are stealth-only upstream and are now rejected in fast mode rather than silently dropped — a quietly unproxied request leaks the origin IP, which is the one thing the caller was trying to avoid. The response echoes the resolved mode, so a later block is actionable.

The deprecated stealth boolean still works in both directions for existing callers (stealth: false still means fast); an explicit mode wins when both are supplied.

Captcha auto-solving is on by default too, for the same reason: an option a model has to opt into does not get used, and the resulting failure ("the page is a challenge screen") reads as a broken site rather than a missing flag. Pass captcha: false to opt out — solving costs money and adds latency, so turn it off for sites you know never challenge.

The default follows the pool rather than being a flat true: captcha is stealth-only upstream, so a flat default would make a plain mode: "fast" call throw on an option the caller never asked for. Stealth ⇒ on, fast ⇒ off, explicit value always wins. Asking for captcha: true together with mode: "fast" is a real contradiction and is refused. The response echoes the resolved captcha alongside mode.

Login handoff — the agent never touches a password

When a session hits a login form or 2FA prompt, the agent calls solari_browser_login and shows the returned URL to the user. They open it, get a live view of the exact page the agent is on, and type their credentials directly into it. The agent then calls solari_browser_await_login and carries on where it left off — same page, now signed in.

The agent is locked out for the duration. The gateway refuses its CDP upgrades and severs the socket it already holds, so it cannot watch the typing even though it is mid-session. That is enforced at the proxy, not here: a check in this layer would be advisory, because the agent speaks raw CDP.

Two consequences worth knowing:

  • Other browser tools on that session fail while a handoff is open. That is the freeze working, not a bug.
  • await_login reconnects on success. The sever kills the stored puppeteer handle, so resuming needs a fresh dial; without it the agent would "resume" into a Target-closed error.

The link lives 5 minutes and is single-use. If it lapses, call solari_browser_login again — the session is untouched.

Saving the login for next time is explicit. solari_browser_save_profile captures the session's cookies + localStorage into a profile, and future runs skip the human entirely via create({profileId}). It is deliberately not automatic: those are live session cookies, which bypass 2FA, so the profile is a credential store and should exist because the user chose it. The tool reports the cookie count and origins it stored, so they can see what was persisted.

Editing an existing profile is explicit too. solari_browser_edit_profile returns a link to show the user; the editor starts when they open it, and the link lasts 30 minutes. Nothing is saved until solari_browser_finish_profile_edit is called: save: true saves and closes, save: false closes and discards. There is no auto-save and no save without closing. If the link has expired or the editor is not open, the finish call says so and you start again with a fresh link.

Sandboxes + desktops

| Tool | What it does | |---|---| | solari_sandbox_create | Create a headless sandbox → sessionId | | solari_desktop_create | Create a GUI desktop → sessionId + streamUrl | | solari_list | List the org's VMs — both sandboxes and desktops, each labelled with its kind (optional kind/state filters) | | solari_kill | Destroy a session | | solari_pause | Pause a session (snapshot RAM+disk, free the slot); its id stays valid | | solari_resume | Resume a paused session and reconnect (other tools also wake it on first use) | | solari_snapshot | Checkpoint a running session → {snapshotId} | | solari_snapshot_list | List snapshots, newest first | | solari_revert | Roll a session back in place to a snapshot | | solari_snapshot_delete | Delete a snapshot | | solari_connect | Re-attach to a session by id across restarts (auto-resumes if paused) | | solari_exec | Run a shell command (via sh -c) → {stdout,stderr,exitCode} | | solari_run_command_bg | Start a background shell command → {cmdId} | | solari_command_status | Output tail + {running, exitCode?} of a background command (optional waitMs ≤ 30000) | | solari_command_kill | Signal a background command (default SIGTERM); reports whether it exited | | solari_run_code | Run code (default Python) → results incl. structured charts | | solari_read_file / solari_write_file / solari_list_files | Guest filesystem | | solari_get_preview_url | Public preview URL for an in-guest port | | solari_screenshot | Capture the desktop as a PNG (image content) | | solari_click / solari_type / solari_key | Desktop mouse/keyboard (solari_click takes optional doubleClick + button: left\|right\|middle) | | solari_drag / solari_mouse_down / solari_mouse_move / solari_mouse_up | Drag-and-drop: one-shot drag, or press-hold → move → release for stepwise drags | | solari_open_app | Launch an app on the desktop |

(The desktop GUI tools require a solari_desktop_create session; they error on a sandbox. The browser tools are independent of both.)

Develop

npm install          # installs @modelcontextprotocol/sdk, puppeteer-core + the local SDK
npm run build        # tsc → dist/
npm test             # mock-client toolset tests (no network)
npm run build:bundle # esbuild → dist/solari-mcp.bundle.cjs (single file, no node_modules)