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

sealnet-mcp

v0.4.0

Published

Model Context Protocol server for SEAL: handoff mode puts the link on the user's clipboard or in a 0600 file, never in the chat; explicit opt-in to forward mode with strict TTL/recipient policy.

Downloads

711

Readme

sealnet-mcp

SEAL is how agents and people hand each other large files and secrets without the content passing through the chat, the model or the SEAL server.

Model Context Protocol (MCP) server for SEAL.

Design principle: the model never holds capability by default

When an MCP-connected AI agent (Claude Desktop, Cursor, Cline, etc.) creates a SEAL via this server:

  • handoff mode (default): the share link (the key is in its fragment, there is no password) is delivered to the human user via system clipboard (primary) or 0o600 local file (fallback when clipboard is unavailable — headless, SSH, WSL without display). The tool_result returned to the model contains only an opaque handle and a human-readable receipt. The link is never written into the conversation; on the file channel the receipt names the file, and an agent that can read files on that machine can read it.
  • forward mode (explicit opt-in): model receives { handle, share_url, expires_at, max_reads, mode, delivered } in tool_result; the link opens only with the recipient's X25519 key and also lands in the recipient's inbox (seal_inbox). Requires short TTL (≤30m), max_reads=1, mandatory to (recipient address). Every forward is audit-logged in the encrypted state file.

Tool surface

| Tool | Purpose | |------|---------| | seal_share(path, mode='handoff'\|'forward', expire?, max_reads?, tier?) / seal_share(payment) | Create a SEAL from a local file or folder (sent as one ZIP), streamed from disk. Default: handoff; without expire, 5m, or 1d for a handoff over 100 MB. Over 1 GB the user pays once by card (smallest tier that fits, or tier): the payment page goes through URL-mode elicitation, or comes back as payment_url and a second call with payment finishes the upload into the same seal | | seal_request(what, kind='any'\|'secret'\|'file', where_url?, wait=true) / seal_request(request) | Ask the user for a file or a secret without it passing through the chat. On the user's computer the seal CLI draws the system dialog (seal request --local --json); otherwise the user answers at seal.net/i/<id>, sealed to this server's key, shown with three emoji of that key. Returns the path of a 0600 file, never the value | | seal_open(url\|item, mode='metadata'\|'file'\|'inline', dir?) | Read metadata (default — no download, no counter consumption), save to disk (file: streamed, verified before it gets its name, 0600, returns paths) or inline parse (whitelisted MIMEs only, ≤100 KB, refuses secrets, HTML and binary). item is an inbox handle instead of a link | | seal_inbox(wait?) | Seals other agents or people sent to this server's key (its address): handles, the sender's three emoji and name, never a link. seal_share mode=forward to=<address> puts a link there; wait (0 to 300 s) waits for something new | | seal_list() | List SEALs created by this MCP server only (scope: state.json; never reveals user's CLI seals) | | seal_revoke(handle) | Revoke by opaque handle (model never learns raw seal_id) |

With SEAL Pro workload credentials (sealpro agent enroll, or SEALPRO_WORKLOAD_ID, SEALPRO_WORKLOAD_SEED and SEALPRO_BASE_URL) three tools appear: seal_pro_secret_use(secret, version?) saves a secret your organisation granted to this agent to a 0600 file and returns its path, never the value; seal_pro_secret_request(secret, reason, ttl_seconds?) asks a person for one, for a while, and waits for the decision; seal_pro_file_get(seal, file?, dir?) saves the files of a room whose key a person granted this agent, 0600 and digest-checked, and returns their paths.

Large transfers report notifications/progress when the host sends a progressToken. Where the host supports URL-mode elicitation, seal_request shows the page link through it and waits in one call; otherwise it returns the link and a second call with request waits.

The agent's key and state

The agent has one key: a 32-byte X25519 secret whose public half is its address (sealnet-mcp pubkey). It comes from, in order:

  1. SEAL_SEED — how a container or a cloud session gets the same address as at home (sealnet-mcp seed --force prints the key to put there);
  2. the OS keychain — @napi-rs/keyring (optional dependency): Secret Service on Linux, macOS Keychain, Windows Credential Manager;
  3. seed, a 0600 file in the state directory, where there is no keychain.

The first start makes the key (keychain, else the file); there is no setup step. State lives in ${XDG_CONFIG_HOME}/seal-mcp/state.json (mode 0o600), encrypted with a passphrase derived from the key (HKDF-SHA256 → Argon2id → AES-256-GCM). It holds:

  • identity — the key itself, for incoming targeted seals
  • handles[] — opaque handle → { seal_id, owner_token, mode, created_at }. Each owner_token is full owner-capability for that seal; encrypting only identity and leaving tokens plain would be a security illusion.
  • audit[] — historical tool invocations (timestamps, handles, modes). Side-channel relevant.

Several MCP hosts on one machine (Claude Desktop, Claude Code, Cursor) share the key and the state: each write re-reads the file under a lock. serve --ephemeral (or SEAL_MCP_EPHEMERAL=1) keeps nothing on disk and makes a new key each start; handles then last until restart, and seal expiry does not depend on it. A state from version 0.2 moves under the key on the first start, once.

Install + configure

No setup step: the first start creates the agent's key and state.

Add to ~/.cursor/mcp.json (or claude_desktop_config.json):

{
  "seal": {
    "command": "npx",
    "args": ["-y", "sealnet-mcp"]
  }
}

Production defaults are baked in (backend https://api.seal.net, share URLs on https://seal.net) — no env needed. Self-hosted deployments set both URL knobs; they are independent origins and are never derived from each other:

{
  "seal": {
    "command": "npx",
    "args": ["-y", "sealnet-mcp"],
    "env": {
      "SEAL_MCP_BACKEND_URL": "https://api.example.com",
      "SEAL_MCP_PUBLIC_HOST": "https://example.com"
    }
  }
}

Environment variables consumed by the CLI:

| Variable | Used by | Purpose | |---|---|---| | SEAL_SEED | every subcommand | The agent's key (43 base64url characters); the same address wherever it is set | | SEAL_MCP_EPHEMERAL=1 | serve | As --ephemeral: a new key each start, nothing on disk | | SEAL_MCP_CONFIG_DIR | every subcommand | Override default state directory (mirrors Rust seal-cli's SEAL_CONFIG_DIR) | | SEAL_MCP_PASSPHRASE | serve | Read once, to move a state of version 0.2 | | SEAL_MCP_BACKEND_URL | serve, doctor | SEAL backend base URL (default https://api.seal.net) | | SEAL_MCP_PUBLIC_HOST | serve, doctor | Public origin for minted share URLs (default https://seal.net) | | SEAL_MCP_DEBUG=1 | all | Include stack traces in fatal-error output (otherwise plain error: <msg>) |

Available subcommands:

sealnet-mcp serve         # default — start the stdio MCP server (used by MCP hosts); --ephemeral keeps nothing on disk
sealnet-mcp init          # optional: make the key and state without starting the server
sealnet-mcp pubkey        # print the agent's address, its X25519 public key (for senders)
sealnet-mcp seed --force  # print the agent's key, to set SEAL_SEED elsewhere
sealnet-mcp doctor        # diagnose key source / keychain / file perms / backend reachability
sealnet-mcp reset --force # wipe state.json and the key: the address is lost for good

Development

pnpm install
pnpm build
pnpm test

Source of truth

  • docs/security/seal_phase1_plan.md §"Phase 3 — MCP-оболочка"
  • shared/contracts/seal_mcp.v1.json (tool input/output schemas)
  • All cryptographic primitives are bundled into dist/ from internal workspace packages — no algorithm code is duplicated and no external @-scoped dependencies are pulled at install time.