mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 19:35:13 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip runs across the CLI, server, adapters, plugins, CI, and container images. > - These surfaces declared different Node.js versions from 20 through 24. > - A newer `@types/node` major can expose APIs that the supported runtime does not provide. > - Node.js 20 is no longer a suitable project baseline, and Node.js 24 is the current LTS line. > - This pull request sets Node.js 24.11.0 as one repository-wide baseline, adds a drift check, and gives users actionable startup guidance when their runtime is too old. > - The benefit is one clear runtime contract for development, release, installation, and published packages. ## Linked Issues or Issue Description Refs #2734 Refs #11727 Refs #739 ## What Changed - Require Node.js 24.11.0 or newer in all 42 package manifests and runtime checks. - Use Node.js 24 in GitHub Actions, Docker images, smoke images, sandbox setup, portable installs, and esbuild targets. - Align every direct `@types/node` declaration on `^24.0.0`. - Prevent Dependabot from opening major `@types/node` upgrades without a matching runtime decision. - Add `.nvmrc` and a CI policy check for Node version drift. - Update ACP version gates, tests, and user documentation for the new minimum. - Print a non-blocking warning on CLI and server startup when Node is unsupported, with remediation through a version manager or the documented downloaded `install.sh` workflow. - Deduplicate that warning when `paperclipai run` boots the CLI and server in the same process. ## Verification - `node scripts/check-node-version-policy.mjs` - `node --check scripts/check-node-version-policy.mjs` - `node --check cli/esbuild.config.mjs` - `node --check scripts/generate-npm-package-json.mjs` - `bash -n scripts/install.sh scripts/test-install-sh-docker.sh scripts/e2e-install-lifecycle.sh` - Parsed all 42 package manifests and confirmed `engines.node` is `>=24.11.0`. - `git diff --check` - `vitest run packages/adapter-utils/src/sandbox-install-command.test.ts` passed with 3 tests. - `vitest run cli/src/node-version.test.ts` passed with 4 tests. - Directly exercised the shared warning helper for unsupported-version messaging and same-process deduplication. - The focused exe.dev suite could not resolve the locally unbuilt plugin SDK from this isolated worktree. A full offline workspace install was also blocked because the package-manager signature verifier requires registry access. The full suite was not run locally; draft CI performs a clean install and evaluates the wider impact. ## Risks - This is a breaking runtime change for users, plugins, and deployments that still use Node.js 20 or 22. - Published workspace packages will now produce an engine warning or failure in strict package managers on older Node.js releases. - Node.js 24 can reveal dependency, native module, Playwright, or agent CLI compatibility issues in CI. - The bootstrap installer now installs Node.js 24 when the current runtime is older than 24.11.0. - The portable sandbox fallback is pinned to Node.js 24.11.0 and depends on that upstream tarball remaining available. - Unsupported runtimes continue booting after a warning, so a later incompatibility can still fail at its point of use. - The CLI and server share the warning policy through the published `@paperclipai/shared` package; packaging checks must keep that subpath export available. - This PR does not commit `pnpm-lock.yaml` because repository policy assigns lockfile generation to CI. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex based on GPT-5. The exact deployment ID and context window are not exposed in this session. Reasoning, repository tools, shell execution, and GitHub tools were enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
208 lines
8.7 KiB
Markdown
208 lines
8.7 KiB
Markdown
# KV Demo MCP Server
|
|
|
|
A standalone, self-contained MCP server for demos. One process exposes four
|
|
key/value MCP tools **and** a tiny web UI that renders the values those tools
|
|
mutate — so you can call a tool from a Paperclip agent and watch the value
|
|
appear in a browser tab.
|
|
|
|
The shared in-memory store is the whole point: the same `Map<string, string>`
|
|
backs every tool call and every UI render. There is no database, no file, no
|
|
persistence. Restart the process and the store is empty again. That makes this
|
|
the right fixture for showing what Paperclip stores versus what the demo
|
|
package stores — the package stores the values, Paperclip stores the
|
|
connection, the profile/policy decisions, and the audit log.
|
|
|
|
This package pairs with the operator guide in
|
|
[doc/MCP-ACCESS-GOVERNANCE.md](../../doc/MCP-ACCESS-GOVERNANCE.md) and the
|
|
recorded walkthrough in [doc/MCP-DEMO-SCRIPT.md](../../doc/MCP-DEMO-SCRIPT.md).
|
|
|
|
## What you get
|
|
|
|
- Four MCP tools (over the Streamable HTTP transport):
|
|
- `kv_list` (read) — list every key/value, optionally filtered by `prefix`.
|
|
- `kv_get` (read) — read one key.
|
|
- `kv_set` (write) — set one key to a string value.
|
|
- `kv_delete` (destructive) — delete a key. Carries `destructiveHint: true`
|
|
so Paperclip's catalog quarantines it on first sight.
|
|
- A Values UI at `/` — an auto-refreshing HTML table over the same store.
|
|
- A JSON state route at `/api/state` — what the UI polls.
|
|
|
|
## Local startup
|
|
|
|
From the repo root:
|
|
|
|
```sh
|
|
pnpm --filter @paperclipai/kv-demo-mcp-server build
|
|
pnpm --filter @paperclipai/kv-demo-mcp-server start
|
|
```
|
|
|
|
Or run the source directly during development:
|
|
|
|
```sh
|
|
cd packages/kv-demo-mcp-server
|
|
node --experimental-strip-types src/main.ts # Node 24+
|
|
```
|
|
|
|
By default it listens on `http://127.0.0.1:8848` and prints three URLs to
|
|
stderr on startup:
|
|
|
|
- **MCP endpoint** — `POST http://127.0.0.1:8848/mcp` (Streamable HTTP)
|
|
- **Values UI** — `GET http://127.0.0.1:8848/` (auto-refreshes every 2s)
|
|
- **JSON state** — `GET http://127.0.0.1:8848/api/state`
|
|
|
|
Open the Values UI in a browser tab and keep it visible. Every successful
|
|
`kv_set` / `kv_delete` lands in that table within ~2 seconds.
|
|
|
|
### Configuration
|
|
|
|
All configuration is via environment variables:
|
|
|
|
| Variable | Default | Purpose |
|
|
| --- | --- | --- |
|
|
| `PORT` (or `KV_DEMO_PORT`) | `8848` | Listen port. Use `0` for a random free port. |
|
|
| `KV_DEMO_HOST` | `127.0.0.1` | Bind host. Use `0.0.0.0` to accept connections from another machine on the LAN. |
|
|
| `KV_DEMO_TOKEN` | unset | Optional shared secret. When set, data and MCP routes require it. |
|
|
|
|
When `KV_DEMO_TOKEN` is set, present it as `Authorization: Bearer <token>`.
|
|
For the browser UI, open `http://127.0.0.1:8848/#token=<token>`; the fragment is
|
|
not sent to the server and the page removes it from the address bar before
|
|
polling `/api/state` with the bearer header. The token is a convenience guard
|
|
for local demos, not a hardened auth scheme; do not expose this server to
|
|
untrusted networks.
|
|
|
|
## Connecting from Paperclip
|
|
|
|
The KV demo is meant for the `remote_http` connection path. The server speaks
|
|
Streamable HTTP at `/mcp`, runs in a single process so the Values UI and the
|
|
MCP tools share state, and listens on a fixed loopback port. Paperclip's
|
|
remote-HTTP gateway proxies every call through policy and audit while leaving
|
|
process supervision to you (just `Ctrl+C` the server when you are done).
|
|
|
|
### Via the Connect-an-app wizard (recommended)
|
|
|
|
1. Open the company's Tools UI at `/<prefix>/companies/<companyId>/tools`.
|
|
2. Go to **Connect an app** and pick **Connect with a link**.
|
|
3. Paste `http://127.0.0.1:8848/mcp` and give it a name (e.g. "KV demo").
|
|
4. If you launched the server with `KV_DEMO_TOKEN`, paste the token in the
|
|
**App key** field. The wizard stores it as an `Authorization: Bearer …`
|
|
header secret.
|
|
5. Pick the profile defaults (read/write/destructive) and finish. Paperclip
|
|
imports the four tools and quarantines `kv_delete`.
|
|
|
|
The wizard hits this API under the hood:
|
|
|
|
```sh
|
|
curl -fsS -X POST \
|
|
-H "Authorization: Bearer $BOARD_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
"$PAPERCLIP_URL/api/companies/$COMPANY_ID/tools/apps/connect" \
|
|
-d '{
|
|
"link": "http://127.0.0.1:8848/mcp",
|
|
"name": "KV demo"
|
|
}'
|
|
```
|
|
|
|
If a token is set, add the `credentialValues` block:
|
|
|
|
```json
|
|
{
|
|
"link": "http://127.0.0.1:8848/mcp",
|
|
"name": "KV demo",
|
|
"credentialValues": {
|
|
"credentials.authorization": "my-demo-secret"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Transport tradeoffs
|
|
|
|
- **`remote_http` (recommended for this demo)** — required if you want the
|
|
Values UI to reflect what the agent just did. The KV demo intentionally
|
|
holds state in one process and exposes both the MCP endpoint and the UI
|
|
from that process. Paperclip's `remote_http` gateway forwards every call to
|
|
the same loopback URL, so the UI always sees the same store the tools
|
|
mutated.
|
|
- **`local_stdio` (not used here)** — runs MCP servers as supervised child
|
|
processes inside Paperclip's runtime slots. Reserved for *trusted local
|
|
deployments* (developer laptop, `local_trusted` or
|
|
`authenticated/private` with `PAPERCLIP_TRUSTED_MCP_RUNTIME_HOST` set on a
|
|
single trusted worker). Each runtime slot has its own process, which would
|
|
give each slot its own in-memory store — you would lose the shared-state
|
|
property that makes this demo work. Use the approved stdio templates that
|
|
ship in the Paperclip build when you need stdio; do not try to shoehorn
|
|
this server into a local-stdio template.
|
|
|
|
For the full transport policy across deployment modes, see
|
|
[MCP-ACCESS-GOVERNANCE.md → Local trusted deployment](../../doc/MCP-ACCESS-GOVERNANCE.md#local-trusted-deployment).
|
|
|
|
## What you should see in Paperclip
|
|
|
|
After the wizard finishes, expect:
|
|
|
|
- **Catalog** — four tools imported from this connection. `kv_list` and
|
|
`kv_get` are tagged `read`; `kv_set` is tagged `write`; `kv_delete` is
|
|
tagged `destructive` and starts in `quarantined` status.
|
|
- **Tools panel** on an agent — `kv_list`, `kv_get`, and (with the default
|
|
ask-first policy) `kv_set`. `kv_delete` is not listed until you take it
|
|
out of quarantine.
|
|
- **Audit feed** — one row per call. Reads show
|
|
`tool_gateway.call_completed` with `decision: allow`. Writes that hit the
|
|
default ask-first policy show `tool_gateway.approval_requested` followed
|
|
by `tool_gateway.call_allowed` and `tool_gateway.call_completed` once you
|
|
approve. Calls to `kv_delete` show `tool_gateway.call_denied` with
|
|
`reasonCode: quarantined_catalog_entry`.
|
|
|
|
The recorded walkthrough in [doc/MCP-DEMO-SCRIPT.md](../../doc/MCP-DEMO-SCRIPT.md)
|
|
runs all three cases end-to-end against this package and matches the audit
|
|
rows above.
|
|
|
|
## What lives where
|
|
|
|
| Concern | Stored in this package | Stored in Paperclip |
|
|
| --- | --- | --- |
|
|
| Key/value entries (`kv_*` data) | In-memory `Map`, lost on restart. | Not stored. Paperclip never sees the values directly; the gateway only sees the MCP request/response envelope and the redacted-by-policy view the audit log keeps. |
|
|
| Connection record (URL, token, transport) | Not stored. | Persisted in `tool_connections`. The optional token becomes a secret. |
|
|
| Profile / policy / binding decisions | Not stored. | Persisted under `tool_profiles`, `tool_policies`, and `tool_profile_bindings`. |
|
|
| Approval action requests | Not stored. | Persisted under `tool_action_requests`, linked to issue-thread interactions. |
|
|
| Audit rows for each call | Not stored. | Persisted under `tool_call_events`. Append-only. |
|
|
|
|
## Cleanup and reset
|
|
|
|
Resetting the demo state usually means resetting this process; Paperclip's
|
|
records stay intact unless you also archive the connection.
|
|
|
|
- **Empty the KV store** — `Ctrl+C` (or `kill`) the server and start it
|
|
again. The new process starts with zero keys and revision `0`. There is no
|
|
in-process reset endpoint by design; restart is the single supported
|
|
reset.
|
|
- **Free the port** — if startup logs `EADDRINUSE`, another `kv-demo`
|
|
process is still bound to `8848`. Find and kill it:
|
|
|
|
```sh
|
|
lsof -nP -iTCP:8848 -sTCP:LISTEN
|
|
kill <pid>
|
|
```
|
|
- **Quiesce the Paperclip side** — disable the connection so the gateway
|
|
stops trying to reach the now-stopped server:
|
|
|
|
```sh
|
|
curl -fsS -X PATCH \
|
|
-H "Authorization: Bearer $BOARD_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
"$PAPERCLIP_URL/api/tool-connections/$CONNECTION_ID" \
|
|
-d '{ "enabled": false, "status": "disabled" }'
|
|
```
|
|
- **Archive the application** when you are fully done. Audit history is
|
|
retained, but no new calls can land:
|
|
|
|
```sh
|
|
curl -fsS -X PATCH \
|
|
-H "Authorization: Bearer $BOARD_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
"$PAPERCLIP_URL/api/tool-applications/$APPLICATION_ID" \
|
|
-d '{ "status": "archived" }'
|
|
```
|
|
|
|
The KV demo is a fixture, not a piece of infrastructure. Treat each session
|
|
as disposable: start it, run the demo, kill it.
|