@arcnow/mcp 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/README.md +92 -83
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,14 +1,3 @@
1
- > **This repository is a published mirror.** Every release of the arcnow.io MCP
2
- > server lands here as one commit, tagged `vX.Y.Z`, with the `npm pack` tarball
3
- > under [Releases](https://github.com/arcnow-io/arcnow-io-mcp/releases). Issues and pull requests are welcome
4
- > here. The maintainers' tooling (the pin gate against the SDK's history, the
5
- > fork proof against the contracts) is not part of the mirror, so `scripts/`
6
- > referred to below is absent; `@arcnow/sdk` is a path dependency, so clone
7
- > [arcnow-io/arcnow-io-sdk](https://github.com/arcnow-io/arcnow-io-sdk) as a
8
- > sibling directory named `sdk` and build `sdk/typescript` first.
9
- > Site: [www.arcnow.io](https://www.arcnow.io) - docs:
10
- > [docs.arcnow.io](https://docs.arcnow.io).
11
-
12
1
  # `@arcnow/mcp`
13
2
 
14
3
  An [MCP](https://modelcontextprotocol.io) server that lets an AI assistant use
@@ -19,14 +8,42 @@ graduating, and, **only if the operator explicitly turns it on**, launch, buy,
19
8
  sell and rescue a stranded migration.
20
9
 
21
10
  Every chain interaction goes through
22
- [`@arcnow/sdk`](https://github.com/arcnow-io/arcnow-io-sdk), pinned to a commit in
23
- [`pins.json`](pins.json). Nothing here encodes a call or computes a curve.
11
+ [`@arcnow/sdk`](https://www.npmjs.com/package/@arcnow/sdk), pinned to an exact
12
+ published version in [`pins.json`](pins.json). Nothing here encodes a call or
13
+ computes a curve.
14
+
15
+ ## Install and run
24
16
 
17
+ The server is on npm as [`@arcnow/mcp`](https://www.npmjs.com/package/@arcnow/mcp)
18
+ (Node 22.12 or newer). Run it straight from the registry:
19
+
20
+ ```sh
21
+ npx -y @arcnow/mcp # read-only. The default, and the useful part.
22
+ npx -y @arcnow/mcp --allow-writes # can spend, if ARCNOW_PRIVATE_KEY is in the environment.
25
23
  ```
26
- node dist/index.js # read-only. The default, and the useful part.
27
- node dist/index.js --allow-writes # can spend, if ARCNOW_PRIVATE_KEY is in the environment.
24
+
25
+ Or tell an MCP client to. Claude Desktop, Cursor, Claude Code and the like all
26
+ take this shape in their MCP server configuration:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "arcnow": {
32
+ "command": "npx",
33
+ "args": ["-y", "@arcnow/mcp"],
34
+ "env": { "ARCNOW_MCP_NETWORK": "arc-testnet" }
35
+ }
36
+ }
37
+ }
28
38
  ```
29
39
 
40
+ A writes-enabled client adds `"--allow-writes"` to `args` and puts the key
41
+ **in a file**, never in the config: see [`examples/`](examples) for both shapes
42
+ and [Configuration](#configuration) for every variable. To run from source
43
+ instead, clone
44
+ [arcnow-io/arcnow-io-mcp](https://github.com/arcnow-io/arcnow-io-mcp), then
45
+ `npm ci && npm run build && node dist/index.js`; the SDK comes from npm.
46
+
30
47
  ---
31
48
 
32
49
  ## The two rules this server is built around
@@ -373,72 +390,62 @@ token. Gas is always native USDC, whatever a token's quote.
373
390
 
374
391
  ## The SDK, and how the pin works
375
392
 
376
- `@arcnow/sdk` **is not published to npm.** `package.json` depends on it by
377
- path — `file:../sdk/typescript` so a checkout of
378
- [`arcnow-io/sdk`](https://github.com/arcnow-io/arcnow-io-sdk) has to sit beside this one:
393
+ `@arcnow/sdk` is published to npm from
394
+ [arcnow-io/arcnow-io-sdk](https://github.com/arcnow-io/arcnow-io-sdk), one tagged
395
+ release per version, and this server depends on it at an **exact version** —
396
+ `"@arcnow/sdk": "0.1.3"`, never `^0.1.3`. The tool descriptions promise what one
397
+ known SDK does; a range would let `npm install` move the code under them with no
398
+ commit here saying so. Moving the pin is a pull request.
379
399
 
380
- ```
381
- project/
382
- sdk/ git clone https://github.com/arcnow-io/arcnow-io-sdk.git sdk
383
- mcp/ this repository
400
+ [`pins.json`](pins.json) records it:
401
+
402
+ ```json
403
+ "sdk": {
404
+ "package": "@arcnow/sdk",
405
+ "version": "0.1.3",
406
+ "integrity": "sha512-…",
407
+ "public_repo": "arcnow-io/arcnow-io-sdk",
408
+ "tag": "v0.1.3",
409
+ "why": ["what this server uses from that SDK, in prose"]
410
+ }
384
411
  ```
385
412
 
386
- npm **links** that directory into `node_modules`, which means "which SDK am I
387
- running" is answered by whatever somebody happens to have checked out — a
388
- branch, a rebase, an edit made five minutes ago. None of that fails loudly. The
389
- server still compiles, the tool descriptions still promise what they promised,
390
- and the call that reaches the chain is encoded by code this repository has never
391
- seen.
413
+ `integrity` is the sha512 of that version's tarball, as npm records it in
414
+ `package-lock.json` and serves it as `dist.integrity`. **The tarball is the
415
+ surface**: every module, the generated ABIs that encode every call, the
416
+ `networks.json` every address comes from one hash. (Until the SDK was
417
+ published this file hashed its sources file by file and the gate recompiled its
418
+ `dist/`; the integrity replaces all of that.)
392
419
 
393
- So the SDK is pinned the way `arcnow-io/sdk` pins `arcnow-io/contracts`, and
394
420
  `scripts/check-pins.sh` (run straight after the install by `scripts/preflight.sh`)
395
- enforces five things:
396
-
397
- 0. `sdk.commit` is a **full 40-hex commit**, never a ref that resolves to
398
- whatever it names today.
399
- 1. `package.json` still depends on the SDK **by path**. A `file:` specifier that
400
- became a version range would resolve through the public registry, under a
401
- name nobody in this project has claimed.
402
- 2. `node_modules/@arcnow/sdk` really is that sibling directory — linked, not
403
- copied carries the pinned version, and its `dist/` is **exactly what its
404
- sources compile to**. The gate compiles the SDK again, with the SDK's own
405
- TypeScript, into a temporary directory and compares every emitted file. This
406
- server imports `dist/`, not `src/`, so a `dist/` left over from an older
407
- checkout runs old code under new hashes which is the state the sibling
408
- checkout was found in when the pin moved off `ac52eaa`, with no `dist/pool.js`
409
- at all, and the old gate passed it.
410
- 3. The sibling's **working tree** hashes to `surface_sha256`, with **no surface
411
- file unpinned**. The linked directory *is* the working tree, so an
412
- uncommitted edit or an uncommitted new module — is code this server runs
413
- under no git ref at all.
414
- 4. The sibling repository has `sdk.commit`, **it is on `sdk.branch`**, and it
415
- carries exactly the pinned files with the pinned bytes — the only check that
416
- can see that the recorded hashes belong to the commit named. It also
417
- **reports, without failing**, when the SDK has moved past the pin and whether
418
- the surface changed on the way. A pin is supposed to lag.
419
-
420
- Together: `dist/` is the compilation of the working tree, the working tree is the
421
- pinned bytes, and the pinned bytes are the commit on the branch.
422
-
423
- **What is pinned is a rule, not a list:** `networks.json`,
424
- `typescript/package.json`, and every file under `typescript/src` except
425
- `typescript/src/errors/`. A module the SDK adds is surface the moment it exists.
426
- The generated ABIs are inside the rule because they encode every call, and the
427
- generated `networks.json` because it is the copy the SDK compiles its
428
- **addresses** from. `errors/` is outside it: message prose behind a surface
429
- `index.ts` already pins, where pinning would make every improved error message
430
- a false alarm. `test/unit/check-pins.test.ts` builds real repositories and
431
- breaks each link on purpose — a stale build, an unpinned module, an uncommitted
432
- edit, a ref for a commit, a commit off the branch.
433
-
434
- Moving the pin is a commit of its own: check the SDK out at the commit and build
435
- it, run `scripts/check-pins.sh --record` — which records `sdk.commit` and every
436
- surface hash from `HEAD`, and refuses an edit no commit carries — update
437
- `sdk.why`, run preflight, and say what changed in the SDK surface and what it
438
- meant for the tools. A tool description that still promises what an older SDK
439
- did is a model quoting a wrong price.
440
-
441
- Point the gate at a checkout somewhere else with `ARCNOW_SDK_DIR`.
421
+ enforces four things:
422
+
423
+ 1. `package.json` depends on the SDK at **exactly** `sdk.version`. A range, a
424
+ `file:` path or another number fails, by name.
425
+ 2. `package-lock.json`'s entry for it carries that version, resolves to the npm
426
+ registry, and its `integrity` **is** `sdk.integrity` the link between the
427
+ version and the bytes; npm refuses to install a tarball that does not hash to
428
+ it.
429
+ 3. `node_modules/@arcnow/sdk/package.json` is that version what the server
430
+ actually compiles against and imports.
431
+ 4. The registry has that version and serves it with that `dist.integrity`, so
432
+ the pinned bytes are the published bytes. This needs the network: unreachable
433
+ is a **warning** (a laptop on a train is not a broken pin) unless
434
+ `ARCNOW_REQUIRE_REGISTRY=1`, which CI sets; a 404 is always a failure.
435
+
436
+ Together: the manifest asks for one version, the lockfile binds it to one
437
+ tarball, `node_modules` holds it, and the registry says those are the bytes it
438
+ serves under that number. `test/unit/check-pins.test.ts` builds real roots with
439
+ a fake `npm` on `PATH` and breaks each link on purpose — a range, a path, a
440
+ foreign tarball, a stale install, a version the registry never had, a registry
441
+ that cannot be reached.
442
+
443
+ Moving the pin is a commit of its own: `npm install @arcnow/sdk@X.Y.Z
444
+ --save-exact`, `npm ci`, `scripts/check-pins.sh --record` which records the
445
+ version, the lockfile's integrity and the tag, and refuses a range or a version
446
+ the registry does not have update `sdk.why`, run preflight, and say what
447
+ changed in the SDK surface and what it meant for the tools. A tool description
448
+ that still promises what an older SDK did is a model quoting a wrong price.
442
449
 
443
450
  ---
444
451
 
@@ -458,16 +465,18 @@ repository in this org has made. **`scripts/preflight.sh` is the gate**; the
458
465
  workflow is a transcription of it, kept because a clean-checkout run is the one
459
466
  thing a local run cannot prove.
460
467
 
461
- The fork proof starts one container, an anvil fork of Arc testnet from the
462
- Foundry image `pins.json` pins, labelled `io.arcnow.mcp.test`, and deploys
463
- arcnow.io's 3.x multi-quote contracts onto it with the pinned SDK's
464
- `scripts/fork-deploy-stack.sh`. Arc testnet now runs a 3.x stack of its own,
468
+ Everything but the fork proof needs nothing beyond `npm ci`: the SDK comes from
469
+ npm. The fork proof is the maintainers' **private infrastructure**: it starts one
470
+ container, an anvil fork of Arc testnet from the Foundry image `pins.json` pins,
471
+ labelled `io.arcnow.mcp.test`, and deploys arcnow.io's 3.x multi-quote contracts
472
+ onto it with the private `arcnow-io/sdk` checkout's `scripts/fork-deploy-stack.sh`
473
+ (`ARCNOW_SDK_DIR`, default `../sdk`). Arc testnet now runs a 3.x stack of its own,
465
474
  deployed on 2026-09-15, but the fork is taken at a pinned, already-cached block
466
475
  from before that, where the live contracts are the 2.x ones the SDK refuses — and
467
476
  a proof that deploys its own stack does not depend on what happens to be live
468
- anyway. That needs `ARCNOW_CONTRACTS_DIR`, a checkout
469
- of arcnow-io/contracts at the commit the SDK's `pins.json` names, and forge at
470
- the release it names. Its harness —
477
+ anyway. That also needs `ARCNOW_CONTRACTS_DIR`, a checkout
478
+ of arcnow-io/contracts at the commit that SDK checkout's `pins.json` names, and
479
+ forge at the release it names. Its harness —
471
480
  copied from `arcnow-io/sdk`'s, not imported, because that repository's tests are
472
481
  not part of the pinned surface — removes it on every exit path, sweeps only its
473
482
  own label, and touches nothing else on a shared daemon.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcnow/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "An MCP server for arcnow.io on Arc: read the curves, quote a trade, and — only when the operator opts in — launch, buy and sell.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "start": "node dist/index.js"
31
31
  },
32
32
  "dependencies": {
33
- "@arcnow/sdk": "^0.1.0",
33
+ "@arcnow/sdk": "0.1.3",
34
34
  "@modelcontextprotocol/sdk": "1.30.0",
35
35
  "viem": "^2.56.3",
36
36
  "zod": "^4.6.2"