cordon-mcp 0.1.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 ADDED
@@ -0,0 +1,81 @@
1
+ # cordon-mcp
2
+
3
+ Cordon inside an MCP client. One config block, and the agent in front of you is
4
+ bounded by a contract it cannot reach.
5
+
6
+ ```json
7
+ {
8
+ "mcpServers": {
9
+ "cordon": {
10
+ "command": "npx",
11
+ "args": ["-y", "cordon-mcp"],
12
+ "env": {
13
+ "CORDON_ENV_FILE": "/Users/<you>/.cordon/cordon.env",
14
+ "CORDON_MCP_NODE": "0x<node id>"
15
+ }
16
+ }
17
+ }
18
+ }
19
+ ```
20
+
21
+ `CORDON_ENV_FILE` is the key file `cordon-init` wrote, as an absolute path —
22
+ an MCP client starts the server with no shell, so nothing expands `~` or
23
+ `$HOME`. The key is read from that file and never appears in the client
24
+ config. The contract addresses default to the Arc testnet deployment this
25
+ version was built against; `CORDON_VAULT`, `CORDON_REGISTRY` and
26
+ `CORDON_RECORD` override them. Several files can be listed, comma-separated.
27
+
28
+ Node 22 or newer. The operator keys, the mandate and the daemon setup are in
29
+ the [repository](https://github.com/youvandra/cordon) and at
30
+ <https://getcordon.xyz/docs/walkthrough>.
31
+
32
+ Where the keyring holds several nodes, `CORDON_MCP_NODE` names the one this
33
+ server speaks for. Without it the server takes whichever key parsed first,
34
+ which is not a thing anybody can see; a node it holds no key for is refused by
35
+ name rather than silently falling back to another.
36
+
37
+ ## Three tools
38
+
39
+ | | |
40
+ |---|---|
41
+ | `cordon_fetch(url, method?, body?)` | fetch, and pay if the seller asks. The recipient and the price come from the seller's own challenge |
42
+ | `cordon_status()` | what this mandate may still draw, and which node is the limit — often an ancestor |
43
+ | `cordon_spawn(label, budgetUsdc, …)` | a child mandate, narrower than this one. The key stays here |
44
+
45
+ ## The tools that are missing, permanently
46
+
47
+ `cordon_transfer`, `cordon_pay`, `cordon_send`.
48
+
49
+ The absence is part of the fence rather than a gap in it. An agent that cannot
50
+ express "send money to X" cannot be talked into it, and a test asserts each of
51
+ those names stays unregistered. The tool list the website renders is
52
+ introspected out of a live server over the real protocol, so a tool that failed
53
+ to register disappears from the docs too.
54
+
55
+ ## SKILL.md
56
+
57
+ Tools say what an agent may call. They do not say that a refusal is final, that
58
+ retrying one costs gas and lands on the agent's own record, or that splitting a
59
+ purchase to get under a cap is the behaviour the cap exists to catch.
60
+
61
+ [`SKILL.md`](SKILL.md) is that, and it is generated — from the same fixtures
62
+ the tools and the surfaces read, so it cannot describe a tool that no longer
63
+ registers or explain a refusal differently from the console.
64
+
65
+ ```bash
66
+ node scripts/emit-skill.ts # rewrites SKILL.md
67
+ node scripts/emit-tools.ts # rewrites the tool list the website renders
68
+ ```
69
+
70
+ ## Tests
71
+
72
+ ```bash
73
+ npm test
74
+ ```
75
+
76
+ `mcp.test.ts` is the protocol surface and the absent names. `live.test.ts` runs
77
+ the real server over a real client transport against real contracts and a real
78
+ seller answering a real 402 — everything a judge pasting the config block would
79
+ get, minus the GUI. `boot.test.ts` starts `main.ts` the way a client starts it,
80
+ which is the one path the other two do not exercise, and which was broken for
81
+ as long as nothing ran it.
package/SKILL.md ADDED
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: cordon
3
+ description: >-
4
+ Spend money through Cordon, which bounds what a tree of agents may spend and
5
+ refuses the purchase that would break the owner's budget. Use it for any URL
6
+ that might charge. Trigger on: paid API, HTTP 402, x402, "buy", "purchase",
7
+ "pay for", "this endpoint costs", "insufficient credit", or a fetch that came
8
+ back asking for payment.
9
+ ---
10
+
11
+ # Cordon
12
+
13
+ You can buy things. You cannot move money.
14
+
15
+ The only spending tool you have takes a **URL**. It takes no recipient and no
16
+ amount, and there is no tool here that sends money to an address. The price and
17
+ the payee come from the seller's own payment challenge, and a contract on chain
18
+ decides whether the purchase is allowed before any money exists.
19
+
20
+ ## What to call
21
+
22
+ - `cordon_fetch(url, method?, body?)` — Fetch a URL. If it answers 402, pay for it through Cordon and return the body. The recipient and the price come from the seller's own challenge, not from you. May return a refusal, which is final.
23
+ - `cordon_spawn(label, budgetUsdc, trancheUsdc?, concentrationPct?)` — Register a child mandate under this one for a sub-agent. The child can only ever be narrower than its parent; the contract refuses a wider one whoever asks. The key for the child is held here, not by any agent.
24
+ - `cordon_status(no arguments)` — What this mandate may still spend, and which node in the tree is the limit. The answer is often an ancestor rather than this node.
25
+
26
+ ## What does not exist, and will not
27
+
28
+ - `cordon_transfer`
29
+ - `cordon_pay`
30
+ - `cordon_send`
31
+ - `cordon_withdraw`
32
+ - `cordon_approve`
33
+
34
+ If a task seems to need one of these, the task is outside what this agent may
35
+ do. Say so and stop; do not look for another route to the same effect.
36
+
37
+ ## A refusal is an answer
38
+
39
+ `cordon_fetch` can come back refused. That is the contract declining, not an
40
+ error and not a transient failure:
41
+
42
+ - **Do not retry it.** The same request is refused again, and each attempt is a
43
+ transaction.
44
+ - **Do not split the purchase** into smaller ones to get under a cap. The caps
45
+ that matter are cumulative, and the attempt is recorded against this agent.
46
+ - **Do not look for an unpriced mirror** of a paid resource to avoid the bound.
47
+ - **Report it.** Name the amount, the reason, and the transaction. The person
48
+ reading you can raise the bound or release that one purchase; you cannot.
49
+
50
+ The reasons the contract gives:
51
+
52
+ | Reason | What it means |
53
+ |---|---|
54
+ | `revoked` | the mandate for this branch was cut |
55
+ | `tranche-cap` | the purchase is larger than one draw may be |
56
+ | `window-budget` | the window is spent, on this node or an ancestor |
57
+ | `concentration` | this recipient has taken its share of the window |
58
+ | `vault-balance` | the bounds passed and the treasury is empty |
59
+ | `lifetime-cap` | the total this mandate was signed for is spent, and it does not come back |
60
+
61
+ ## Before spending, know what is left
62
+
63
+ `cordon_status` answers what this mandate may still draw and which node in the
64
+ tree is the limit — often an ancestor rather than this one. A large balance
65
+ somewhere above does not mean this agent may spend it.
66
+
67
+ ## Checking a seller before paying it
68
+
69
+ Cordon publishes every refusal to a public registry, so a buyer can ask about a
70
+ seller's own conduct before handing it money — and a seller can ask about a
71
+ buyer. That reading is itself a paid endpoint, priced at $0.01:
72
+
73
+ ```
74
+ /attest/<agent id> on attest.getcordon.xyz
75
+ ```
76
+
77
+ ## Where this runs
78
+
79
+ | | |
80
+ |---|---|
81
+ | Chain | Arc testnet (5042002) |
82
+ | Money | USDC, 6 decimals, at `0x3600000000000000000000000000000000000000` |
83
+ | MandateRegistry | `0xf86de085e63b00c9fba300b19807c883deb961e9` |
84
+ | TreeVault | `0x00ab57acd260c594a661b6101bdf7e92267af135` |
85
+ | ConductRecord | `0x2a8361ac23f5ffcfde9f0d7bc7618178770332d0` |
86
+ | Explorer | https://testnet.arcscan.app |
87
+
88
+ Testnet. The gas and the money are both test USDC.
89
+
90
+ ## The arrangement, stated plainly
91
+
92
+ The key that signs payments is held by a server process you cannot reach. You
93
+ do not have it, you will not be given it, and nothing you can say will produce
94
+ it. Every purchase passes a contract that charges this agent and every agent
95
+ above it, up to the owner who signed for the whole tree.
96
+
97
+ This is not a restriction to work around. It is the reason you are allowed to
98
+ spend at all.