pi-session-mcp 0.6.4 → 0.7.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/.pi-session-mcp-cli/config.js +11 -1
- package/.pi-session-mcp-cli/doctor.js +22 -1
- package/.pi-session-mcp-cli/execution-profile.js +1 -0
- package/.pi-session-mcp-cli/extension-spec.js +21 -0
- package/.pi-session-mcp-cli/pi-extensions.js +67 -0
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +2 -2
- package/SECURITY.md +1 -1
- package/dist/capabilities.d.ts +1 -0
- package/dist/capabilities.js +2 -1
- package/dist/client-adapters/mcp-verifier.js +5 -2
- package/dist/config.d.ts +1 -0
- package/dist/config.js +11 -1
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +22 -1
- package/dist/execution-profile.d.ts +3 -0
- package/dist/execution-profile.js +1 -0
- package/dist/extension-spec.d.ts +15 -0
- package/dist/extension-spec.js +21 -0
- package/dist/main.js +6 -2
- package/dist/pi-adapter.d.ts +1 -1
- package/dist/pi-adapter.js +4 -0
- package/dist/pi-extensions.d.ts +17 -0
- package/dist/pi-extensions.js +67 -0
- package/dist/sdk-pi-adapter.d.ts +24 -6
- package/dist/sdk-pi-adapter.js +253 -86
- package/dist/server.js +1 -0
- package/dist/session-tools.d.ts +9 -0
- package/dist/session-tools.js +25 -0
- package/dist/setup-command-guardian.js +29 -73
- package/dist/setup-main.js +2 -1
- package/dist/setup-ownership.js +18 -28
- package/dist/setup-platform.d.ts +57 -0
- package/dist/setup-platform.js +195 -0
- package/dist/setup-process.d.ts +6 -3
- package/dist/setup-process.js +85 -93
- package/dist/setup.js +2 -1
- package/dist/stdout-guard-install.d.ts +5 -0
- package/dist/stdout-guard-install.js +6 -0
- package/dist/stdout-guard.d.ts +20 -0
- package/dist/stdout-guard.js +72 -0
- package/docs/acceptance.md +216 -0
- package/docs/adr/0005-macos-setup-platform.md +84 -0
- package/docs/adr/0006-pi-extension-allowlist.md +58 -0
- package/docs/architecture.md +1 -1
- package/docs/client-setup-design.md +21 -9
- package/docs/client-setup.md +25 -10
- package/docs/doctor-design.md +7 -2
- package/docs/installation.md +122 -4
- package/docs/macos-setup-design.md +386 -0
- package/docs/pi-extensions-design.md +421 -0
- package/docs/releasing.md +1 -1
- package/docs/superpowers/plans/2026-10-10-macos-setup.md +1725 -0
- package/docs/superpowers/plans/2026-10-11-pi-extensions.md +2450 -0
- package/docs/threat-model.md +54 -18
- package/docs/tool-contracts.md +8 -3
- package/package.json +1 -1
package/docs/threat-model.md
CHANGED
|
@@ -30,23 +30,36 @@ Pi Session MCP trusts the local process that launches and speaks MCP over inheri
|
|
|
30
30
|
equality with a bounded direct MCP initialize, `tools/list`, and
|
|
31
31
|
`pi_capabilities_get({})` call. It never starts a session or invokes
|
|
32
32
|
a provider; the verifier cleans up its process.
|
|
33
|
-
- **Concurrent setup corruption:**
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
33
|
+
- **Concurrent setup corruption:** Durable ownership transactions hold a
|
|
34
|
+
stable, never-renamed regular file through a kernel lock on an explicitly
|
|
35
|
+
supported local filesystem:
|
|
36
|
+
- on Linux, through the trusted util-linux `flock`, on ext2/3/4, XFS, Btrfs,
|
|
37
|
+
tmpfs, overlayfs, ZFS, F2FS, UBIFS, or bcachefs;
|
|
38
|
+
- on macOS, through `O_EXLOCK` at open, on the APFS volume type of `/`.
|
|
39
|
+
|
|
40
|
+
There is no clock-based stale recovery. A transaction guardian inherits that
|
|
41
|
+
locked file description, launches each mutating client command in its own
|
|
42
|
+
process group, and retains the fence across parent death until a determinate
|
|
43
|
+
process-table scan confirms that no non-zombie group member remains. The
|
|
44
|
+
scan reads `/proc` on Linux and the trusted system `/bin/ps` on macOS; a
|
|
45
|
+
`ps` sample that fails, has an unexpected line or does not list the scanning
|
|
46
|
+
process is indeterminate. On macOS the proof rests on `/bin/ps` on the
|
|
47
|
+
sealed, SIP-protected system volume, together with the uid and mode check
|
|
48
|
+
that also guards `flock`. The macOS lock relies on the documented `O_EXLOCK`
|
|
49
|
+
behavior of open(2): flock(2) semantics on the open file description, and
|
|
50
|
+
`EOPNOTSUPP` on a filesystem without locking, which fails closed.
|
|
51
|
+
Indeterminate cleanup retains the fence and fails closed. A missing or
|
|
52
|
+
untrusted `flock` or `ps`, unsupported filesystems, symlinks, inode
|
|
53
|
+
mismatch, and raw lock errors are reduced to stable codes. Directory
|
|
54
|
+
creation and atomic state replacement are fsynced through their parent
|
|
55
|
+
directory before success. A mutation already accepted by an external CLI or
|
|
56
|
+
configuration backend cannot be rolled back automatically and remains
|
|
57
|
+
`pending` for reconciliation.
|
|
58
|
+
- **Unsupported process-group guarantees:** Setup runs on Linux and macOS
|
|
59
|
+
only. Every other platform fails closed before client spawn because no
|
|
60
|
+
tested kernel fence and process-group proof exist for it. On both supported
|
|
61
|
+
platforms, the fence does not cover descendants that leave the process
|
|
62
|
+
group, and it does not promise PID reaping.
|
|
50
63
|
|
|
51
64
|
- **Workspace escape:** callers can request configured workspace aliases only; validated configuration maps aliases to resolved paths. There is no arbitrary `cwd` input.
|
|
52
65
|
- **Execution-selection escalation:** callers cannot supply raw provider, model, thinking level, permission profile, or credentials. A configured execution-profile alias binds all of those values; exactly one configured default is `read-only`. The legacy `profile` input is rejected rather than silently reinterpreted.
|
|
@@ -55,12 +68,19 @@ Pi Session MCP trusts the local process that launches and speaks MCP over inheri
|
|
|
55
68
|
- **Thinking-level clamping:** SDK capability handling can alter a requested level. The adapter compares the effective `session.thinkingLevel` after creation and disposes on a mismatch.
|
|
56
69
|
- **Orphaned SDK session:** a post-creation mismatch or later registry failure could otherwise leave a live Pi handle. The adapter holds it locally until all postconditions pass, best-effort disposes on each later failure, and the registry admits only verified handles.
|
|
57
70
|
- **Excess capability:** the execution profile selects a permission-derived tool allowlist. Read-only permits only `read`, `grep`, `find`, and `ls`; coding remains high impact.
|
|
58
|
-
- **Project resource code execution:** Pi resource loading disables
|
|
71
|
+
- **Project resource code execution:** Pi resource loading disables extension discovery, skills, prompts, and themes; only a profile's allowlisted extensions load (see below). Non-executable `AGENTS.md` context remains untrusted instruction content, never authorization.
|
|
59
72
|
- **Concurrent state corruption:** a per-session queue serializes prompt admission and close; concurrent abort callers share one attempt for the active turn. Closing is terminal, settles an active turn, and disposes once.
|
|
60
73
|
- **Secret/prompt disclosure:** stdout is protocol-only. Stderr diagnostics use stable code and safe context only. Public metadata is whitelisted and omits auth objects/sources, credential paths, headers, base URLs, complete model objects, SDK IDs, raw provider errors, prompts, transcripts, and tool data. Completed `assistantText` can still repeat model-visible data and is potentially sensitive.
|
|
61
74
|
- **Capability-enumeration disclosure:** the trusted local MCP peer can read configured workspace aliases and execution-profile provider/model intent. Discovery omits workspace paths, authentication state, SDK state, sessions, turns, prompts, transcripts, and tool data. Operators must choose aliases that are suitable for this trusted-peer boundary.
|
|
62
75
|
- **Stale capability assumptions:** discovery reads configuration only. It makes no provider, authentication, filesystem, or network probe and cannot prove that a configured provider/model is available. Session creation keeps the existing exact runtime checks.
|
|
63
76
|
- **Availability:** input length is bounded; profile-specific authentication/catalog work and session creation have 5,000 ms and 10,000 ms deadlines. Preflight, abort, close cleanup, registry shutdown, and process shutdown (signal or stdin EOF) have 5,000 ms, 5,000 ms, 5,000 ms, 12,000 ms, and 15,000 ms server-side deadlines. Active sessions retain 20 turns and 64 KiB UTF-8 of final text per turn. The registry rejects starts after shutdown begins and disposes a late-created handle. The process shutdown path explicitly exits the process after its cleanup deadline, but cannot prove graceful termination of a blocked provider operation.
|
|
77
|
+
- **Allowlisted Pi extensions:** a profile's `extensions` load operator-trusted code into the server process with the user's full rights; it may start processes, use the network and write files (for example `pi-cursor-sdk` below `~/.pi/agent`, `~/.cursor/projects/` and `<workspace>/.pi/`). Mitigations:
|
|
78
|
+
- Only exact `npm:<name>@<version>` specs from the operator's configuration load; the MCP client cannot name an extension.
|
|
79
|
+
- Resolution never installs, and a different installed version fails closed. Only Pi's own user install (`<Pi agent dir>/npm/node_modules/<name>`, normally below `~/.pi/agent`) counts; a package installed elsewhere, for example with `npm i -g`, is reported as not installed.
|
|
80
|
+
- `read-only` profiles never activate extension tools. At session start, after load and again after binding, no extension tool may shadow a built-in or granted tool; later registrations are covered in the residual risks.
|
|
81
|
+
- Client prompts never dispatch extension commands, but extension input hooks can still see, rewrite or consume a prompt.
|
|
82
|
+
- Each extension session gets its own model runtime, and close emits `session_shutdown`.
|
|
83
|
+
- **stdout corruption:** every write through `process.stdout` or `console.log`, `console.info` and `console.debug` other than the MCP transport's is dropped. The stdout guard intercepts `process.stdout.write`, `process.stdout.end` and `console.log`, `console.info` and `console.debug`, which covers output from extensions and the SDK in the server process. stderr gets only `foreign_stdout_suppressed` with byte and write counts, never the content. Anything that writes file descriptor 1 directly is not covered; see the residual risks.
|
|
64
84
|
- **Misleading annotations:** annotations are client hints only and never grant access.
|
|
65
85
|
- **Shutdown orphaning:** `SIGINT`, `SIGTERM`, and stdin EOF invoke the same bounded registry cleanup and transport close, so a client that only closes stdin does not leave sessions or their MCP children running. Handles are disposed at most once; late promises are ignored after removal. Explicit process exit prevents local shutdown from hanging indefinitely, but SDK limitations can leave external work unconfirmed or abruptly cut off.
|
|
66
86
|
|
|
@@ -87,3 +107,19 @@ change public terminal errors; cancellation and close still take precedence.
|
|
|
87
107
|
Aliases and profile definitions are trusted administrator configuration, not a filesystem or provider-security sandbox. A locally available model may later be unreachable; no live provider request is made during selection. Symlinks and Pi tools can reach resources permitted to the OS identity. `AGENTS.md` can influence model behavior. The number of active sessions and the duration of an already accepted turn remain unbounded. Stdio peer authentication, quotas, persistent recovery, provider hard-kill capability, dependency integrity policy, and OS/filesystem isolation remain outside the verified boundary. Coding-profile acceptance checks behavior in a selected fixture; it does not prove OS-level isolation.
|
|
88
108
|
The trusted same-UID operator can unlink or replace the setup lock path between
|
|
89
109
|
checks and must not mutate the ownership directory during a transaction.
|
|
110
|
+
|
|
111
|
+
An allowlisted extension is trusted code; pinning its version does not detect
|
|
112
|
+
modification of the installed package directory. `read-only` limits the
|
|
113
|
+
model's tools, not extension code or hooks. Anything that writes file
|
|
114
|
+
descriptor 1 directly reaches the MCP stream, because Node.js cannot intercept
|
|
115
|
+
it: in-process writes such as `fs.writeSync(1, …)` or native code, and child
|
|
116
|
+
processes that an extension starts with inherited stdio. The Cursor runtime
|
|
117
|
+
behind `pi-cursor-sdk` starts processes of its own during turns (observed with
|
|
118
|
+
`pi-cursor-sdk@0.5.3`: `git`, `ssh`, `gh` and the MCP servers configured for
|
|
119
|
+
Cursor, in a `read-only` profile too); none inherited the server's stdout in
|
|
120
|
+
that run. Extensions may persist their own state outside Pi
|
|
121
|
+
Session MCP's in-memory boundary. Extension tool names are checked for
|
|
122
|
+
conflicts after loading and again after binding; a tool that an extension
|
|
123
|
+
registers later, during a turn, is not re-checked and may replace a built-in
|
|
124
|
+
tool, `read` included, because allowlisted extensions are trusted code. An extension may deactivate built-in or granted
|
|
125
|
+
tools for its own session.
|
package/docs/tool-contracts.md
CHANGED
|
@@ -22,7 +22,7 @@ There are exactly eight tools. No `pi_turn_wait` tool or live provider/model inv
|
|
|
22
22
|
```json
|
|
23
23
|
{
|
|
24
24
|
"ok": true,
|
|
25
|
-
"server": { "name": "pi-session-mcp", "version": "0.
|
|
25
|
+
"server": { "name": "pi-session-mcp", "version": "0.7.0" },
|
|
26
26
|
"configuration": {
|
|
27
27
|
"fingerprint": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
28
28
|
"reloadPolicy": "restart-required"
|
|
@@ -34,12 +34,13 @@ There are exactly eight tools. No `pi_turn_wait` tool or live provider/model inv
|
|
|
34
34
|
"permissionProfile": "read-only",
|
|
35
35
|
"provider": "configured-provider",
|
|
36
36
|
"model": "configured-model",
|
|
37
|
-
"thinkingLevel": "medium"
|
|
37
|
+
"thinkingLevel": "medium",
|
|
38
|
+
"extensions": []
|
|
38
39
|
}]
|
|
39
40
|
}
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
The server sorts both arrays by alias with a deterministic code-point comparison. It copies only loaded configuration fingerprint/reload policy, configured aliases, and the
|
|
43
|
+
The server sorts both arrays by alias with a deterministic code-point comparison. It copies only loaded configuration fingerprint/reload policy, configured aliases, and the seven documented profile fields. `extensions` lists the configured extension specs (`npm:<name>@<version>`), empty when a profile loads none; it makes no claim that the package is installed. It never copies the configuration path or contents, workspace paths, authentication state, SDK data, session/turn data, prompts, transcripts, or tool arguments/results. The handler reads the in-memory loaded snapshot only and does not call the registry, Pi adapter, provider, filesystem, or network. The fingerprint identifies the exact loaded bytes, not current-file freshness; provider/model fields describe configured intent and make no availability claim.
|
|
43
44
|
|
|
44
45
|
Annotations are `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, and `openWorldHint: false`. Clients may use them for presentation, but the strict input schema and server-owned projection enforce the contract.
|
|
45
46
|
|
|
@@ -67,6 +68,10 @@ Public MCP errors are stable and sanitized. Their messages do not include inputs
|
|
|
67
68
|
| `external_mcp_no_tools` | Complete valid discovery returned no tools while explicit grants were required. |
|
|
68
69
|
| `external_mcp_grant_tool_missing` | Complete valid nonempty discovery omitted an explicitly granted remote tool. |
|
|
69
70
|
| `external_mcp_activation_mismatch` | Pi did not activate exactly the expected post-discovery tool set. |
|
|
71
|
+
| `extension_not_installed` | Pi has no installed package for a configured extension. |
|
|
72
|
+
| `extension_version_mismatch` | Pi's installed extension package has another version than the configured one. |
|
|
73
|
+
| `extension_load_failed` | A configured extension has an invalid manifest, failed to load or failed to bind. |
|
|
74
|
+
| `extension_tool_conflict` | An extension tool name collides with a built-in, MCP or other extension tool. |
|
|
70
75
|
| `pi_session_creation_failed` | Pi session construction failed without a more specific safe classification. |
|
|
71
76
|
| `server_stopping` | Shutdown has begun, so a new session cannot be admitted. |
|
|
72
77
|
|