SkillAgentSearch skills...

sallyport

A security-first bridge between Claude Code (MCP) and Chrome — HMAC pairing, domain allowlist, per-domain evaluate opt-in.

Install / Use

claude mcp add ginkida -- npx -y github:ginkida/sallyport

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

75/100

Category

Security

Supported Platforms

Claude Code
Claude Desktop

Our assessment of sallyport

sallyport scores 75/100 on our quality scale, 1040th of 1,119 Security skills we index.

Its MCP Server is 39 KB long, well organised into 39 sections with 17 code examples: long enough that it reads more like full documentation than a focused instruction file, which agents can find harder to follow.

It has 10 GitHub stars, so there is little community track record yet; judge it on its content.

Substance
21/30
Structure
20/20
Description
15/15
Adoption
4/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 15 days ago, so sallyport is actively maintained.
  • Our last check on 2026-09-25 found the source still online.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 97/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.

AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.

sallyport compared with similar skills

All 4 of these similar skills score higher than sallyport; compare them before choosing.

SkillScoreStarsUpdatedFormat
sallyport (this skill)by ginkida751015d agoMCP Server
Agent-Reachby Panniantong100100.2ktodayCLAUDE.md
headroomby headroomlabs-ai10076.7ktodayCLAUDE.md
CowAgentby zhayujie10047.5ktodayCLAUDE.md
Scraplingby D4Vinci10088.8k1d agoMCP Server

Frequently asked questions

How do I install sallyport?
Run claude mcp add ginkida -- npx -y github:ginkida/sallyport. The install tabs above show the steps for each supported agent.
Which AI agents does sallyport work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is sallyport safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It is MIT-licensed and scores 97/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is sallyport still maintained?
The repository was last updated 15 days ago, so sallyport is actively maintained.

Sallyport

CI CodeQL License: MIT Release

A secure browser-automation bridge between Claude Code (or any MCP client) and your Chrome. An alternative to Kimi WebBridge with explicit security boundaries instead of implicit ones.

Claude Code ── MCP/stdio ──▶ daemon ── WS+HMAC ──▶ extension ── CDP ──▶ Chrome

| Status | Number | |---|---| | Daemon tests (pytest) | 538 | | Extension tests (vitest) | 1069 | | Lint / typecheck (ruff, mypy, eslint, prettier, tsc) | all green |

What's in the box

| Path | What it is | |---|---| | extension/ | MV3 Chrome extension (TypeScript, esbuild, vitest). Loads as an unpacked extension. | | daemon/ | Python MCP server. Speaks MCP on stdio to Claude Code, hosts a WS server on 127.0.0.1:10086 for the extension. | | fixtures/ | Cross-language canonical-JSON / HMAC vectors shared by both test suites. | | .pre-commit-config.yaml | Fast lint/format checks before commit. | | .github/workflows/ci.yml | Same checks plus full tests on push/PR. |

Security model

A deeper threat model + known limitations lives in SECURITY.md. The short version: the original Kimi extension trusts any process that can reach 127.0.0.1:10086, which on a shared/compromised machine means everything. Sallyport changes the default in five places:

  1. HMAC-SHA256 on every frame. A 32-byte random secret lives in ~/.config/sallyport/secret (chmod 600) and is generated on first run. Both sides sign every WS frame and verify timestamp drift (≤ 30 s) and nonce freshness (rolling cache of 4096 nonces — replay-protected and persisted across extension service-worker eviction). A cross-language test pin in pytest + vitest guarantees the canonical-JSON and MAC bytes stay byte-for-byte compatible.
  2. Domain allowlist enforced in the extension. Tools refuse to run on any URL whose host isn't in chrome.storage.local.sallyport_allowlist. Patterns are example.com, *.example.com, or https://x.com/path/*. Bare * is rejected by the validator.
  3. evaluate is opt-in per domain. Even on an allow-listed domain, arbitrary JS is refused unless that entry has allowEvaluate: true. Other tools (click, fill, read_text, …) use structured CDP calls only.
  4. Defense-in-depth on inputs. fill refuses <input type=password> unless allowPassword=true. The daemon refuses to bind to anything that isn't a loopback address. WS frames over 16 MiB are dropped (1009).
  5. Operational visibility. Every tool call (and its outcome — ok or error) is appended to chrome.storage.local.sallyport_audit (last 500 entries), browsable and JSON-exportable from the popup. One-click Pause in the popup stops the WS connection and rejects all tool calls.

Other deliberate choices:

  • No content-script injection, no <all_urls> content scripts. Permissions are only what the debugger API (and a popup-pin context-menu entry) need (tabs, debugger, storage, alarms, contextMenus).
  • Per-tab accessibility refs (@e1, @e2). Snapshotting tab A cannot invalidate refs for tab B, and a ref scoped to A cannot resolve to a node in B.
  • MCP-side tool calls are serialised per client, with up to 8 clients running concurrently. The extension also serialises calls per tab to protect shared browser state.
  • The daemon shuts down cleanly on stdin EOF (Claude Code closing) or SIGINT/SIGTERM: pending calls fail with ExtensionNotConnected, the client gets a 1001 close, no orphan tasks.

What the extension still trusts: anyone with read access to ~/.config/sallyport/secret. The browser debugger is, ultimately, the browser debugger — this bridge limits which domains it operates on and who can drive it.

Setup

1. Build the extension

The extension is not on PyPI — pip install sallyport (step 2) gives you only the daemon. The extension lives in this repo's extension/ directory, so you need a checkout to build it:

git clone https://github.com/ginkida/sallyport
cd sallyport/extension
npm install
npm run build

The output lands in extension/dist/. Load it as an unpacked extension:

  1. chrome://extensions
  2. Enable Developer mode
  3. Load unpacked → pick extension/dist

Pin the toolbar icon.

2. Install the daemon

Sallyport needs Python ≥ 3.10 (it uses match statements and X | Y type syntax). Check with python --version first.

pip install --user sallyport

Or from source (for development): cd daemon && pip install --user -e .

This installs the sallyport-daemon command on your PATH. Verify it landed there:

which sallyport-daemon   # should print a path; if not, add your Python
                      # user-scripts dir (e.g. ~/.local/bin) to PATH

The first time something runs it, the daemon will:

  • Generate a 32-byte secret in ~/.config/sallyport/secret (chmod 600).
  • Print the base64 secret to stderr — paste it into the extension popup.
  • Start listening on 127.0.0.1:10086 and speak MCP on stdio.

Then run the built-in setup check, which validates the install and prints the exact block to paste into the popup:

sallyport-daemon doctor

It checks your Python version, the secret file and its permissions, and that the port is free — then prints the pairing secret and the remaining steps. Run it any time a connection won't come up. To just re-print the secret:

sallyport-daemon --show-secret

3. Register with Claude Code

Add an MCP server entry — either edit ~/.claude/mcp.json directly, or:

# Use the ABSOLUTE path. A GUI-launched Claude Code often doesn't inherit your
# shell PATH, so a bare "sallyport-daemon" command silently fails to spawn.
claude mcp add sallyport "$(which sallyport-daemon)"

sallyport-daemon doctor prints this exact line with the path already resolved (and falls back to python -m sallyport_daemon if the console script isn't on PATH) — copy it from there if you're unsure. The result:

{
  "mcpServers": {
    "sallyport": {
      "command": "/Users/you/.local/bin/sallyport-daemon",
      "args": []
    }
  }
}

Restart Claude Code. The tools appear as mcp__sallyport__navigate, mcp__sallyport__click, etc.

4. Pair the extension

  1. Open the popup. It will show a one-card Pair onboarding view.
  2. Get the secret. Run sallyport-daemon doctor (or --show-secret) in a terminal and copy the printed block. Note: when Claude Code spawns the daemon for you (step 3), the first-run banner goes to the daemon's stderr, which Claude Code does not display — so doctor/--show-secret is the reliable way to see it.
  3. Paste into the popup textarea — you can paste the whole banner; the popup auto-extracts the base64 secret and shows "✓ secret detected (32 bytes)".
  4. Click Pair. Status flips to connected with a pulsing green indicator and an at-a-glance summary of allowed sites / recent calls.

5. Add the first domain to the allowlist

The allowlist starts empty — every tool rejects every URL by default. In the popup's Allowlist tab, add an entry like example.com or *.github.com. Tick allow evaluate() only if you actually need arbitrary JS on that host.

Several sessions, one browser (automatic)

Sallyport is built for the case where you are using Chrome while one or more Claude Code sessions drive tabs in it. That works out of the box: the first sallyport-daemon starts a small broker in the background and attaches to it, and every session after that attaches to the same one. Register Sallyport as in step 3 from as many project folders as you like — nothing else to set up.

# Nothing. Just start a second Claude Code session.

Under the hood the broker owns the extension connection and the port; each session relays its MCP over a 0600 Unix-domain socket next to the secret (broker-10086.sock). Before this, the second session simply failed to start — the first one held the port — and had no browser tools at all.

What you get:

  • Sessions don't block each other. Calls from different sessions run concurrently (a session's own calls stay in order, and a tab is only ever touched by one call at a time). One agent's 30-second wait no longer freezes everyone else's next click.
  • Each agent stays in its own tabs. An agent can only see and act on tabs it created (navigate with no tab opens a fresh one); it cannot touch — or even list — your tabs or another agent's. list_tabs shows a session only its own.
  • It won't steal your focus. Each session's tabs live in its own un-focused, muted window, and the window you were using is re-focused if Chrome tries to raise the new one. Screenshots work there too, without foregrounding anything.
  • You can see who did what. The popup's Audit tab tags every row with the session (its folder name by default), and its Agent tabs section lists what each session left open, with a one-click sweep.
  • You're logged in. These are ordinary tabs in your real Chrome profile, so agents operate on the sites you're already signed into — scoped, as always, to the allowlist. There is no incognito or separate profile involved: the separation is about who may drive which tab, not about identity.

Useful knobs:

sallyport-daemon --no-broker            # single session, own the port directly
                                        # (or SALLYPORT_NO_BROKER=1)
sallyport-daemon --session-label review # name this session in the audit log
sallyport-daemon broker --idle-exit 3600  # start one explicitly, exit when idle
sallyport-daemon doctor --stop-broker   # stop it (needed after an upgrade:
                                        # a broker outlives `pip install -U`
                                        # and serves its build to everyone)

The broker is long-lived by design, so doctor treats it as the intended setup rather than a stale daemon: the port check reports OK, and doctor --kill-stale leaves it running.

This is a software partition of one shared profile, not an OS-level sandbox: the security floor is still "any process running as you" (it can read the secret and drive the browser within the allowlist). See SECURITY.md for the full model, including the tab-ownership and MCP-client-auth invariants.

Tools

| Name | Notes | |---|---| | list_tabs | No allowlist check — listing is free. | | navigate | Checks the destination URL against allowlist. waitFor={selector?,text?,absent?,timeoutMs?} polls after the load until the page is actually usable (SPAs render long after "loaded"). | | reload | Hard reload via bypassCache=true. Allowlist-gated; refs invalidate. | | history_go | Back/forward through the tab's session history — return to the previous page without knowing its URL. direction='back'\|'forward', steps hops several entries in one jump (intermediate pages never load). The landing entry is allowlist-checked before anything moves (Page.getNavigationHistory → Page.navigateToHistoryEntry, no evaluate); too far → no_history with how far it does reach — neither error names the blocked page's host, to avoid an oracle over non-allowlisted browsing history. On a timeout, don't assume it failed: the hop can land before the load watchdog fires, so check with read_text/snapshot rather than blindly retrying. Conversely, if a beforeunload prompt cancels t

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars10
CategorySecurity
Updated15d ago
Forks1

Languages

TypeScript

Trust signals

97/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 info
sallyport — MCP Server: Install & Safety Check | SkillAgent