@prismnetwork/mcp 0.1.2 → 0.3.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 +21 -1
- package/package.json +26 -8
- package/server.mjs +66 -12
package/README.md
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
# @prismnetwork/mcp
|
|
2
2
|
|
|
3
|
-
An MCP server that lets Claude (or any MCP client)
|
|
3
|
+
An MCP server that lets Claude (or any MCP client) see and lease real GPUs through [Prism Network](https://prismnetwork.tech). Give it a wallet and it handles auth, onchain payment, provisioning, and SSH.
|
|
4
|
+
|
|
5
|
+
## Try it without a wallet
|
|
6
|
+
|
|
7
|
+
Looking costs nothing and needs no configuration:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
claude mcp add prism -- npx -y @prismnetwork/mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then ask what you can rent. `prism_list_gpus` answers from live capacity with
|
|
14
|
+
real prices. Leasing spends money, so those tools ask for a wallet and say so.
|
|
4
15
|
|
|
5
16
|
## Tools
|
|
6
17
|
|
|
18
|
+
| Tool | Wallet |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| `prism_list_gpus` | no |
|
|
21
|
+
| `prism_wallet` | yes |
|
|
22
|
+
| `prism_lease_and_run` | yes |
|
|
23
|
+
| `prism_lease` | yes |
|
|
24
|
+
| `prism_run` | yes |
|
|
25
|
+
| `prism_end_lease` | yes |
|
|
26
|
+
|
|
7
27
|
- `prism_wallet`: the agent's address and USDG/ETH balances.
|
|
8
28
|
- `prism_list_gpus`: GPUs available to lease, with price per second and per hour.
|
|
9
29
|
- `prism_lease_and_run`: lease a GPU, run a command, return the output (one shot).
|
package/package.json
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prismnetwork/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server for leasing and running on Prism Network GPUs.",
|
|
5
5
|
"mcpName": "io.github.prismnetwork-tech/mcp",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"bin": {
|
|
8
|
+
"prism-mcp": "server.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"server.mjs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
},
|
|
10
17
|
"dependencies": {
|
|
11
18
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
12
|
-
"@prismnetwork/agent-sdk": "^0.
|
|
19
|
+
"@prismnetwork/agent-sdk": "^0.2.0",
|
|
13
20
|
"viem": "^2"
|
|
14
21
|
},
|
|
15
|
-
"keywords": [
|
|
22
|
+
"keywords": [
|
|
23
|
+
"prism",
|
|
24
|
+
"mcp",
|
|
25
|
+
"gpu",
|
|
26
|
+
"agent",
|
|
27
|
+
"claude",
|
|
28
|
+
"compute"
|
|
29
|
+
],
|
|
16
30
|
"homepage": "https://prismnetwork.tech",
|
|
17
31
|
"repository": {
|
|
18
32
|
"type": "git",
|
|
19
33
|
"url": "git+https://github.com/prismnetwork-tech/prism.git",
|
|
20
34
|
"directory": "mcp"
|
|
21
35
|
},
|
|
22
|
-
"bugs": {
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/prismnetwork-tech/prism/issues"
|
|
38
|
+
},
|
|
23
39
|
"license": "Apache-2.0",
|
|
24
|
-
"publishConfig": {
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
25
43
|
}
|
package/server.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Prism Network MCP server: lets an MCP client (Claude, agents)
|
|
3
|
-
// real GPUs.
|
|
2
|
+
// Prism Network MCP server: lets an MCP client (Claude, agents) see and lease
|
|
3
|
+
// real GPUs. Looking is free and needs no configuration. Leasing spends money,
|
|
4
|
+
// so it needs a wallet: PRISM_AGENT_KEY, PRISM_ESCROW.
|
|
4
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
7
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
-
import { DEFAULT_IMAGE, PrismAgent } from "@prismnetwork/agent-sdk";
|
|
8
|
+
import { DEFAULT_IMAGE, PrismAgent, TRUST_CLASSES } from "@prismnetwork/agent-sdk";
|
|
8
9
|
|
|
9
10
|
const IMAGE = process.env.PRISM_DEFAULT_IMAGE ?? DEFAULT_IMAGE;
|
|
10
11
|
|
|
@@ -14,7 +15,12 @@ function requireEnv(name) {
|
|
|
14
15
|
return value;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
const PUBLIC_API = process.env.PRISM_PUBLIC_API ?? "https://api.prismnetwork.tech";
|
|
19
|
+
|
|
20
|
+
// Refusing to start without a wallet meant nobody could ask what a GPU costs
|
|
21
|
+
// without first producing a private key, which is a strange thing to demand of
|
|
22
|
+
// someone deciding whether to use you at all.
|
|
23
|
+
let agent = null;
|
|
18
24
|
try {
|
|
19
25
|
agent = new PrismAgent({
|
|
20
26
|
privateKey: requireEnv("PRISM_AGENT_KEY"),
|
|
@@ -22,9 +28,28 @@ try {
|
|
|
22
28
|
apiBase: process.env.PRISM_API_BASE ?? "https://prismnetwork.tech",
|
|
23
29
|
rpcUrl: process.env.PRISM_RPC_URL,
|
|
24
30
|
});
|
|
25
|
-
} catch
|
|
26
|
-
console.error(
|
|
27
|
-
|
|
31
|
+
} catch {
|
|
32
|
+
console.error(
|
|
33
|
+
"prism mcp: no wallet configured, so capacity and pricing are readable and leasing is not. " +
|
|
34
|
+
"Set PRISM_AGENT_KEY and PRISM_ESCROW to lease.",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function requireWallet(tool) {
|
|
39
|
+
if (!agent) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`${tool} spends money, so it needs a wallet. Set PRISM_AGENT_KEY and PRISM_ESCROW in this server's environment and restart it.`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return agent;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function publicOffers(minTrust) {
|
|
48
|
+
const url = new URL("/v1/offers", PUBLIC_API);
|
|
49
|
+
if (minTrust) url.searchParams.set("min_trust", minTrust);
|
|
50
|
+
const response = await fetch(url, { headers: { accept: "application/json" } });
|
|
51
|
+
if (!response.ok) throw new Error(`prism offers unavailable (${response.status})`);
|
|
52
|
+
return response.json();
|
|
28
53
|
}
|
|
29
54
|
|
|
30
55
|
const leases = new Map();
|
|
@@ -55,8 +80,17 @@ const TOOLS = [
|
|
|
55
80
|
},
|
|
56
81
|
{
|
|
57
82
|
name: "prism_list_gpus",
|
|
58
|
-
description: "List GPUs currently available to lease on Prism Network, with model, VRAM,
|
|
59
|
-
inputSchema: {
|
|
83
|
+
description: "List GPUs currently available to lease on Prism Network, with model, VRAM, price per second in USDG, and trust class. Trust class runs open < isolated < attested < confidential; on an 'open' supplier the host operator can read anything the workload touches, so never send secrets, credentials or private model weights to one.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
min_trust: {
|
|
88
|
+
type: "string",
|
|
89
|
+
enum: TRUST_CLASSES,
|
|
90
|
+
description: "Only list suppliers at or above this trust class (default 'open').",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
60
94
|
},
|
|
61
95
|
{
|
|
62
96
|
name: "prism_lease_and_run",
|
|
@@ -67,6 +101,11 @@ const TOOLS = [
|
|
|
67
101
|
command: { type: "string", description: "Shell command to run on the GPU (e.g. 'nvidia-smi')." },
|
|
68
102
|
duration_seconds: { type: "integer", description: "Lease length in seconds (default 900, max 21600)." },
|
|
69
103
|
min_vram_mib: { type: "integer", description: "Minimum GPU memory in MiB (default 16000)." },
|
|
104
|
+
min_trust_class: {
|
|
105
|
+
type: "string",
|
|
106
|
+
enum: TRUST_CLASSES,
|
|
107
|
+
description: "Refuse suppliers below this trust class (default 'open'). Raise it for anything the host operator must not read.",
|
|
108
|
+
},
|
|
70
109
|
},
|
|
71
110
|
required: ["command"],
|
|
72
111
|
},
|
|
@@ -79,6 +118,11 @@ const TOOLS = [
|
|
|
79
118
|
properties: {
|
|
80
119
|
duration_seconds: { type: "integer", description: "Lease length in seconds (default 900, max 21600)." },
|
|
81
120
|
min_vram_mib: { type: "integer", description: "Minimum GPU memory in MiB (default 16000)." },
|
|
121
|
+
min_trust_class: {
|
|
122
|
+
type: "string",
|
|
123
|
+
enum: TRUST_CLASSES,
|
|
124
|
+
description: "Refuse suppliers below this trust class (default 'open'). Raise it for anything the host operator must not read.",
|
|
125
|
+
},
|
|
82
126
|
},
|
|
83
127
|
},
|
|
84
128
|
},
|
|
@@ -108,12 +152,18 @@ const TOOLS = [
|
|
|
108
152
|
|
|
109
153
|
async function handle(name, args) {
|
|
110
154
|
if (name === "prism_wallet") {
|
|
111
|
-
const b = await
|
|
155
|
+
const b = await requireWallet("prism_wallet").balances();
|
|
112
156
|
return { address: b.address, usdg: usdg(b.usdg), eth_wei: b.eth };
|
|
113
157
|
}
|
|
114
158
|
if (name === "prism_list_gpus") {
|
|
115
|
-
|
|
116
|
-
|
|
159
|
+
const minTrust = args.min_trust ?? "open";
|
|
160
|
+
let offers;
|
|
161
|
+
if (agent) {
|
|
162
|
+
await ensureAuth();
|
|
163
|
+
offers = await agent.offers({ minTrust });
|
|
164
|
+
} else {
|
|
165
|
+
offers = await publicOffers(minTrust);
|
|
166
|
+
}
|
|
117
167
|
return {
|
|
118
168
|
available: offers.length,
|
|
119
169
|
gpus: offers.map((o) => ({
|
|
@@ -121,22 +171,26 @@ async function handle(name, args) {
|
|
|
121
171
|
vram_mib: o.gpu.vram_mib,
|
|
122
172
|
price_per_second: usdg(o.rate_per_second),
|
|
123
173
|
price_per_hour: usdg(o.rate_per_second * 3600),
|
|
174
|
+
trust: o.trust_class,
|
|
124
175
|
})),
|
|
125
176
|
};
|
|
126
177
|
}
|
|
127
178
|
if (name === "prism_lease_and_run" || name === "prism_lease") {
|
|
128
179
|
if (name === "prism_lease_and_run" && !args.command) throw new Error("command is required");
|
|
180
|
+
requireWallet(name);
|
|
129
181
|
await ensureAuth();
|
|
130
182
|
sweepExpiredLeases();
|
|
131
183
|
const lease = await agent.lease({
|
|
132
184
|
image: IMAGE,
|
|
133
185
|
durationSeconds: args.duration_seconds ?? 900,
|
|
134
186
|
minVramMib: args.min_vram_mib ?? 16000,
|
|
187
|
+
minTrustClass: args.min_trust_class ?? "open",
|
|
135
188
|
});
|
|
136
189
|
leases.set(lease.leaseId, lease);
|
|
137
190
|
const summary = {
|
|
138
191
|
lease_id: lease.leaseId,
|
|
139
192
|
ssh: { host: lease.access.ssh_host, port: lease.access.ssh_port, user: lease.access.ssh_user },
|
|
193
|
+
trust: lease.quote?.trust_class ?? "open",
|
|
140
194
|
expires_at: lease.access.expires_at,
|
|
141
195
|
};
|
|
142
196
|
if (name === "prism_lease") return summary;
|