sealnet-mcp 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,17 +10,17 @@ When an MCP-connected AI agent (Claude Desktop, Cursor, Cline, etc.) creates a S
10
10
 
11
11
  - **inbox mode (default once connected)**: after `seal_pair` (or with `SEAL_OWNER` set to the address of the user's inbox) the file lands in the user's SEAL inbox on box.seal.net. Nothing is copied anywhere; the model gets a handle and a receipt. Every seal this server creates, in any mode, also appears there, where the user can manage and revoke it.
12
12
  - **handoff mode (default otherwise)**: 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.
13
- - **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.
13
+ - **forward mode (explicit opt-in)**: model receives `{ handle, share_url, expires_at, max_reads, mode, delivered }` in `tool_result`; the link carries no key: its key is wrapped to the recipient's bundle and kept by the server, so only the agent with that address opens it; it 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.
14
14
 
15
15
  ## Tool surface
16
16
 
17
17
  | Tool | Purpose |
18
18
  |------|---------|
19
- | `seal_share(path, mode='inbox'\|'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: inbox once connected, else handoff; without `expire`, 1d in the inbox, 5m for a handoff, or 1d for one 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 |
20
- | `seal_request(what, kind='any'\|'secret'\|'file', where_url?, wait=true, from?)` / `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 words of that key; once connected the request also waits in the user's inbox (`from=owner`, or `from=anyone` for a plain link). Returns the path of a 0600 file, never the value |
19
+ | `seal_share(path, mode='inbox'\|'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: inbox once connected, else handoff; without `expire`, 1d in the inbox, 5m for a handoff, or 1d for one over 100 MB. Above the free limit 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 |
20
+ | `seal_request(what, kind='any'\|'secret'\|'file', where_url?, wait=true, from?)` / `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 bundle, shown with three words of its address; once connected the request also waits in the user's inbox (`from=owner`, or `from=anyone` for a plain link). Returns the path of a 0600 file, never the value |
21
21
  | `seal_pair(name?, wait=true)` | Connect this agent to the user's SEAL inbox, once: the user opens a page, compares three words and connects; the chat then shows the inbox's three words. After it `seal_share` sends to the inbox by default |
22
22
  | `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 |
23
- | `seal_inbox(wait?)` | Seals other agents or people sent to this server's key (its address): handles, the sender's three words and name, never a link. `seal_share mode=forward to=<address>` puts a link there; `wait` (0 to 300 s) waits for something new |
23
+ | `seal_inbox(wait?)` | Seals other agents or people sent to this server's address: handles, the sender's three words and name, never a link. `seal_share mode=forward to=<address>` puts a link there; `wait` (0 to 300 s) waits for something new |
24
24
  | `seal_run(command, secrets, cwd?, timeout?)` | Run a program with secrets from links or inbox items in its environment, through the `seal` CLI (`seal run --redact`): every value is replaced with `[sealed:NAME]` in the output that comes back, and none enters this server. Needs `seal` on PATH (`run_cli_missing` otherwise). Not a sandbox: a program that prints a value transformed escapes the redaction |
25
25
  | `seal_list()` | List SEALs created by **this MCP server only** (scope: `state.json`; never reveals user's CLI seals) |
26
26
  | `seal_revoke(handle)` | Revoke by opaque handle (model never learns raw `seal_id`) |
@@ -31,7 +31,7 @@ Large transfers report `notifications/progress` when the host sends a `progressT
31
31
 
32
32
  ## The agent's key and state
33
33
 
34
- The agent has one key: a 32-byte X25519 secret whose public half is its address (`sealnet-mcp pubkey`). It comes from, in order:
34
+ The agent has one key: a 32-byte seed. Its bundle comes from the seed, and its address is the bundle's fingerprint (`sealnet-mcp pubkey`). It comes from, in order:
35
35
 
36
36
  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);
37
37
  2. **the OS keychain** — `@napi-rs/keyring` (optional dependency): Secret Service on Linux, macOS Keychain, Windows Credential Manager;
@@ -39,12 +39,12 @@ The agent has one key: a 32-byte X25519 secret whose public half is its address
39
39
 
40
40
  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:
41
41
 
42
- - `identity` — the key itself, for incoming targeted seals
42
+ - `identity` — the seed itself, which opens the links sent to the agent's address
43
43
  - `owner` — the user's inbox this agent is connected to (`seal_pair`): its address and name
44
44
  - `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.
45
45
  - `audit[]` — historical tool invocations (timestamps, handles, modes). Side-channel relevant.
46
46
 
47
- 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.
47
+ 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.
48
48
 
49
49
  ## Install + configure
50
50
 
@@ -84,7 +84,6 @@ Environment variables consumed by the CLI:
84
84
  | `SEAL_OWNER` | `serve` | The address of the user's inbox, instead of `seal_pair`: for a cloud session with nowhere to open the page |
85
85
  | `SEAL_MCP_EPHEMERAL=1` | `serve` | As `--ephemeral`: a new key each start, nothing on disk |
86
86
  | `SEAL_MCP_CONFIG_DIR` | every subcommand | Override default state directory (mirrors Rust `seal-cli`'s `SEAL_CONFIG_DIR`) |
87
- | `SEAL_MCP_PASSPHRASE` | `serve` | Read once, to move a state of version 0.2 |
88
87
  | `SEAL_MCP_BACKEND_URL` | `serve`, `doctor` | SEAL backend base URL (default `https://api.seal.net`) |
89
88
  | `SEAL_MCP_PUBLIC_HOST` | `serve`, `doctor` | Public origin for minted share URLs (default `https://seal.net`) |
90
89
  | `SEAL_MCP_DEBUG=1` | all | Include stack traces in fatal-error output (otherwise plain `error: <msg>`) |
@@ -94,7 +93,7 @@ Available subcommands:
94
93
  ```
95
94
  sealnet-mcp serve # default — start the stdio MCP server (used by MCP hosts); --ephemeral keeps nothing on disk
96
95
  sealnet-mcp init # optional: make the key and state without starting the server
97
- sealnet-mcp pubkey # print the agent's address, its X25519 public key (for senders)
96
+ sealnet-mcp pubkey # print the agent's address and its three words (for senders); publish its bundle
98
97
  sealnet-mcp seed --force # print the agent's key, to set SEAL_SEED elsewhere
99
98
  sealnet-mcp doctor # diagnose key source / keychain / file perms / backend reachability
100
99
  sealnet-mcp reset --force # wipe state.json and the key: the address is lost for good
@@ -110,6 +109,5 @@ pnpm test
110
109
 
111
110
  ## Source of truth
112
111
 
113
- - `docs/security/seal_phase1_plan.md` §"Phase 3 — MCP-оболочка"
114
112
  - `shared/contracts/seal_mcp.v1.json` (tool input/output schemas)
115
113
  - 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.