@prismnetwork/mcp 0.8.0 → 0.8.2
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 +38 -2
- package/budget.mjs +5 -8
- package/package.json +1 -1
- package/server.mjs +20 -9
package/README.md
CHANGED
|
@@ -13,10 +13,14 @@ claude mcp add prism -- npx -y @prismnetwork/mcp
|
|
|
13
13
|
Then ask what you can rent. `prism_list_gpus` answers from live capacity with
|
|
14
14
|
real prices. Leasing spends money, so those tools ask for a wallet and say so.
|
|
15
15
|
|
|
16
|
+
Packaged for Claude Code and Codex as the [Prism plugin](https://plugins.prismnetwork.tech),
|
|
17
|
+
which wires this server up and prompts for the wallet at install time.
|
|
18
|
+
|
|
16
19
|
## Tools
|
|
17
20
|
|
|
18
21
|
| Tool | Wallet |
|
|
19
22
|
| --- | --- |
|
|
23
|
+
| `prism_budget` | no |
|
|
20
24
|
| `prism_list_gpus` | no |
|
|
21
25
|
| `prism_price_index` | no |
|
|
22
26
|
| `prism_receipts` | no |
|
|
@@ -34,6 +38,8 @@ real prices. Leasing spends money, so those tools ask for a wallet and say so.
|
|
|
34
38
|
| `prism_vault_delete` | yes |
|
|
35
39
|
| `prism_vault_release` | yes |
|
|
36
40
|
|
|
41
|
+
- `prism_budget`: the spending limits in force and what has already been spent
|
|
42
|
+
today, with the recent charges.
|
|
37
43
|
- `prism_wallet`: the agent's address and USDG/ETH balances.
|
|
38
44
|
- `prism_list_gpus`: GPUs available to lease, with price per second and per hour.
|
|
39
45
|
- `prism_price_index`: sourced and settled pricing per GPU model, for cost estimates.
|
|
@@ -57,6 +63,29 @@ real prices. Leasing spends money, so those tools ask for a wallet and say so.
|
|
|
57
63
|
- `prism_vault_delete`: permanently delete an item.
|
|
58
64
|
- `prism_vault_release`: authorize an item into a lease that clears its trust floor.
|
|
59
65
|
|
|
66
|
+
## Spending limits
|
|
67
|
+
|
|
68
|
+
Two ceilings bound what this server can spend, and a refusal quotes both.
|
|
69
|
+
|
|
70
|
+
| Variable | Default | What it bounds |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| `PRISM_MAX_USDG` | 1 | Any single lease or generation. `max_usdg` on a call may lower it, never raise it past this. |
|
|
73
|
+
| `PRISM_DAILY_BUDGET_USDG` | 5 | Everything in a rolling 24 hours. `0` removes the ceiling. |
|
|
74
|
+
| `PRISM_LEDGER_PATH` | `~/.prism/spend.json` | Where the spend is recorded. |
|
|
75
|
+
|
|
76
|
+
Spend is written before the money moves, so a crash between funding an escrow
|
|
77
|
+
and answering is counted rather than forgiven, and a restart does not hand back
|
|
78
|
+
a fresh day's allowance. Only an attempt that provably never reached the chain
|
|
79
|
+
is reverted. Two clients pointed at one wallet share one ceiling, because they
|
|
80
|
+
share the ledger file.
|
|
81
|
+
|
|
82
|
+
None of this is the real limit. Fund a dedicated wallet with what you are
|
|
83
|
+
willing to lose: that balance is what survives a bug in everything above.
|
|
84
|
+
|
|
85
|
+
Tools that spend are annotated `destructiveHint` and carry
|
|
86
|
+
`anthropic/requiresUserInteraction`, so Claude Code asks before every one of
|
|
87
|
+
them even in modes that otherwise approve tools automatically.
|
|
88
|
+
|
|
60
89
|
## Vault
|
|
61
90
|
|
|
62
91
|
An agent that handles a card, an identity document or a credential should not
|
|
@@ -82,7 +111,8 @@ Point your MCP client (Claude Desktop / Code) at the published server:
|
|
|
82
111
|
"args": ["-y", "@prismnetwork/mcp"],
|
|
83
112
|
"env": {
|
|
84
113
|
"PRISM_AGENT_KEY": "0x<agent wallet private key>",
|
|
85
|
-
"
|
|
114
|
+
"PRISM_MAX_USDG": "1",
|
|
115
|
+
"PRISM_DAILY_BUDGET_USDG": "5"
|
|
86
116
|
}
|
|
87
117
|
}
|
|
88
118
|
}
|
|
@@ -95,11 +125,17 @@ Or add it to Claude Code in one line:
|
|
|
95
125
|
|
|
96
126
|
```sh
|
|
97
127
|
claude mcp add prism \
|
|
98
|
-
--env PRISM_ESCROW=0x62C042265991bEa17B07229322A01850974626dA \
|
|
99
128
|
--env PRISM_AGENT_KEY=0x<agent wallet private key> \
|
|
129
|
+
--env PRISM_DAILY_BUDGET_USDG=5 \
|
|
100
130
|
-- npx -y @prismnetwork/mcp
|
|
101
131
|
```
|
|
102
132
|
|
|
133
|
+
Codex takes the same server:
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
codex mcp add prism --env PRISM_AGENT_KEY=0x<agent wallet private key> -- npx -y @prismnetwork/mcp
|
|
137
|
+
```
|
|
138
|
+
|
|
103
139
|
## Timing
|
|
104
140
|
|
|
105
141
|
`prism_lease` and `prism_lease_and_run` block while a GPU provisions (usually one to four minutes, occasionally longer on a slow host). Configure your MCP client to allow long tool calls.
|
package/budget.mjs
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
// What stands between a model deciding to rent a GPU and a wallet paying for it.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// alone never was one. `max_usdg` bounds a single lease at 1 USDG by default and
|
|
7
|
-
// says nothing about the fortieth lease in a row, which is the failure an
|
|
8
|
-
// unattended agent actually produces.
|
|
2
|
+
// The real ceiling is the balance; fund the agent wallet with what you are
|
|
3
|
+
// willing to lose. This is the second line, and it exists because `max_usdg`
|
|
4
|
+
// never was one: it bounds a single lease and says nothing about the fortieth in
|
|
5
|
+
// a row, which is what an unattended agent actually does.
|
|
9
6
|
//
|
|
10
7
|
// Spend is written before the money moves and reverted only when the attempt
|
|
11
8
|
// provably cost nothing, so a crash between funding and reply is counted rather
|
|
12
9
|
// than forgiven. The file is shared across clients on purpose: one wallet gets
|
|
13
|
-
// one daily ceiling
|
|
10
|
+
// one daily ceiling whoever is holding it.
|
|
14
11
|
import { mkdirSync, readFileSync, renameSync, writeFileSync, openSync, closeSync, unlinkSync, statSync } from "node:fs";
|
|
15
12
|
import { homedir } from "node:os";
|
|
16
13
|
import { dirname, join } from "node:path";
|
package/package.json
CHANGED
package/server.mjs
CHANGED
|
@@ -67,7 +67,7 @@ function requireWallet(tool, reason = "spends money") {
|
|
|
67
67
|
|
|
68
68
|
function requireLedger(tool) {
|
|
69
69
|
if (!ledger) {
|
|
70
|
-
throw new Error(`${tool}
|
|
70
|
+
throw new Error(`${tool} needs the spend limits, and they are unusable: ${budgetProblem}`);
|
|
71
71
|
}
|
|
72
72
|
return ledger;
|
|
73
73
|
}
|
|
@@ -79,14 +79,25 @@ function requireLedger(tool) {
|
|
|
79
79
|
async function spending(tool, micros, run) {
|
|
80
80
|
const book = requireLedger(tool);
|
|
81
81
|
const id = book.commit({ tool, micros });
|
|
82
|
+
// Reconciling is bookkeeping and must never be the reason a caller loses a
|
|
83
|
+
// machine it paid for, or the reason a failure is reported as the wrong
|
|
84
|
+
// failure. A ledger that cannot be written says so on stderr and the
|
|
85
|
+
// committed figure stands, which errs towards counting the spend.
|
|
86
|
+
const reconcile = (action, ...args) => {
|
|
87
|
+
try {
|
|
88
|
+
book[action](id, ...args);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(`prism mcp: could not ${action} the ledger entry for ${tool}: ${err?.message ?? err}`);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
82
93
|
try {
|
|
83
94
|
const { value, settledMicros, reference } = await run();
|
|
84
|
-
|
|
95
|
+
reconcile("settle", { micros: settledMicros, reference });
|
|
85
96
|
return value;
|
|
86
97
|
} catch (err) {
|
|
87
98
|
const funded = err?.body?.funding_hash;
|
|
88
|
-
if (funded)
|
|
89
|
-
else
|
|
99
|
+
if (funded) reconcile("settle", { reference: funded });
|
|
100
|
+
else reconcile("revert");
|
|
90
101
|
throw err;
|
|
91
102
|
}
|
|
92
103
|
}
|
|
@@ -104,8 +115,8 @@ function requireCommand(value) {
|
|
|
104
115
|
// The per-call ceiling is the operator's, not the model's: an omitted max_usdg
|
|
105
116
|
// takes the configured cap rather than a hardcoded one, and a stated max_usdg
|
|
106
117
|
// above it is refused when the ledger checks the commit.
|
|
107
|
-
function maxDeposit(args) {
|
|
108
|
-
if (args.max_usdg === undefined) return requireLedger(
|
|
118
|
+
function maxDeposit(tool, args) {
|
|
119
|
+
if (args.max_usdg === undefined) return requireLedger(tool).maxPerCallMicros;
|
|
109
120
|
const cap = args.max_usdg;
|
|
110
121
|
if (typeof cap !== "number" || !Number.isFinite(cap) || cap <= 0) {
|
|
111
122
|
throw new Error("max_usdg must be a positive number of USDG.");
|
|
@@ -473,7 +484,7 @@ async function handle(name, args) {
|
|
|
473
484
|
if (name === "prism_batch_run") {
|
|
474
485
|
requireCommand(args.command);
|
|
475
486
|
requireWallet(name);
|
|
476
|
-
const cap = maxDeposit(args);
|
|
487
|
+
const cap = maxDeposit(name, args);
|
|
477
488
|
return spending(name, cap, async () => {
|
|
478
489
|
const batch = await agent.lease({
|
|
479
490
|
image: IMAGE,
|
|
@@ -571,7 +582,7 @@ async function handle(name, args) {
|
|
|
571
582
|
if (name === "prism_lease_and_run" || name === "prism_lease") {
|
|
572
583
|
if (name === "prism_lease_and_run") requireCommand(args.command);
|
|
573
584
|
requireWallet(name);
|
|
574
|
-
const cap = maxDeposit(args);
|
|
585
|
+
const cap = maxDeposit(name, args);
|
|
575
586
|
sweepExpiredLeases();
|
|
576
587
|
const lease = await spending(name, cap, async () => {
|
|
577
588
|
const funded = await agent.lease({
|
|
@@ -679,7 +690,7 @@ async function handleVault(name, args) {
|
|
|
679
690
|
throw new Error(`unknown tool ${name}`);
|
|
680
691
|
}
|
|
681
692
|
|
|
682
|
-
const server = new Server({ name: "prism", version: "0.8.
|
|
693
|
+
const server = new Server({ name: "prism", version: "0.8.2" }, { capabilities: { tools: {} } });
|
|
683
694
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
684
695
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
685
696
|
try {
|