@priors/mcp 0.1.5 → 0.1.6
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 +3 -3
- package/package.json +1 -1
- package/src/server.mjs +14 -4
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Settings → Developer → Edit Config (`claude_desktop_config.json`), then rest
|
|
|
62
62
|
"mcpServers": {
|
|
63
63
|
"priors": {
|
|
64
64
|
"command": "npx",
|
|
65
|
-
"args": ["-y", "@priors/mcp@0.1.
|
|
65
|
+
"args": ["-y", "@priors/mcp@0.1.6"],
|
|
66
66
|
"env": {
|
|
67
67
|
"PRIORS_KEY": "0xYOUR_AGENT_WALLET_KEY",
|
|
68
68
|
"PRIORS_AGENT_ID": "1234"
|
|
@@ -84,7 +84,7 @@ A project `.mcp.json` that reads the key from your shell's environment, so the f
|
|
|
84
84
|
"mcpServers": {
|
|
85
85
|
"priors": {
|
|
86
86
|
"command": "npx",
|
|
87
|
-
"args": ["-y", "@priors/mcp@0.1.
|
|
87
|
+
"args": ["-y", "@priors/mcp@0.1.6"],
|
|
88
88
|
"env": {
|
|
89
89
|
"PRIORS_KEY": "${PRIORS_KEY}",
|
|
90
90
|
"PRIORS_AGENT_ID": "${PRIORS_AGENT_ID:-}"
|
|
@@ -94,7 +94,7 @@ A project `.mcp.json` that reads the key from your shell's environment, so the f
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
or, for your user only: `claude mcp add priors --scope user -e PRIORS_KEY="$PRIORS_KEY" -- npx -y @priors/mcp@0.1.
|
|
97
|
+
or, for your user only: `claude mcp add priors --scope user -e PRIORS_KEY="$PRIORS_KEY" -- npx -y @priors/mcp@0.1.6`
|
|
98
98
|
(the key is expanded by your shell from the environment; do not paste it on the command line).
|
|
99
99
|
|
|
100
100
|
## Try it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@priors/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "MCP server for Priors on Robinhood Chain: pay x402 URLs in USDG, read balances, credit lines and scores, borrow and repay. Key from PRIORS_KEY only.",
|
|
6
6
|
"type": "module",
|
package/src/server.mjs
CHANGED
|
@@ -151,7 +151,17 @@ export async function createPriorsMcpServer({ env = process.env, fetchImpl = glo
|
|
|
151
151
|
// One money call at a time (pay_url, borrow, repay): MCP clients may send tool calls concurrently, and each check
|
|
152
152
|
// above (an outstanding payment for this URL, the session totals) must see the previous call's result (Codex review).
|
|
153
153
|
let moneyQueue = Promise.resolve();
|
|
154
|
-
|
|
154
|
+
// The time budget counts from the call's arrival, not from its turn: a call queued behind a slow one must still answer
|
|
155
|
+
// before the client gives up (a client timeout hides the "do not retry" answer and invites a retry).
|
|
156
|
+
const serial = (fn) => (args) => {
|
|
157
|
+
const deadline = Date.now() + callBudgetMs;
|
|
158
|
+
const run = moneyQueue.then(() => {
|
|
159
|
+
if (Date.now() >= deadline - Math.min(1000, callBudgetMs / 10)) throw new ToolError("another payment call was still running and this one ran out of time before it could start. Nothing was signed or paid: try again.");
|
|
160
|
+
return fn(args, deadline);
|
|
161
|
+
});
|
|
162
|
+
moneyQueue = run.catch(() => {});
|
|
163
|
+
return run;
|
|
164
|
+
};
|
|
155
165
|
// The real network goes through the rebinding-proof dispatcher; an injected fetchImpl (tests, embedders) is used as given.
|
|
156
166
|
const payFetch = fetchImpl === globalThis.fetch && !allowLocal ? guardedFetch() : fetchImpl;
|
|
157
167
|
|
|
@@ -270,7 +280,7 @@ export async function createPriorsMcpServer({ env = process.env, fetchImpl = glo
|
|
|
270
280
|
max_borrow_usd: z.number().nonnegative().optional().describe("Most to borrow from the Priors line if the wallet is short, in US dollars. Default 0: never borrow."),
|
|
271
281
|
},
|
|
272
282
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
273
|
-
}, serial(async ({ url, method = "GET", body, max_price_usd, max_borrow_usd }) => {
|
|
283
|
+
}, serial(async ({ url, method = "GET", body, max_price_usd, max_borrow_usd }, deadline) => {
|
|
274
284
|
const signer = needWallet("pay_url");
|
|
275
285
|
const u = await checkTarget(url);
|
|
276
286
|
if (method === "GET" && body !== undefined) throw new ToolError("A GET request cannot carry a body: use POST (or another method) with body.");
|
|
@@ -291,7 +301,7 @@ export async function createPriorsMcpServer({ env = process.env, fetchImpl = glo
|
|
|
291
301
|
let r;
|
|
292
302
|
if (prior) {
|
|
293
303
|
// A payment for this purchase is already out and still cashable: send that same one, never a second.
|
|
294
|
-
r = await X.createPayer({ signer, fetchImpl: payFetch, pendingRetries: 2, maxSleepMs: 10_000, timeoutMs: requestTimeoutMs, signal: AbortSignal.timeout(
|
|
304
|
+
r = await X.createPayer({ signer, fetchImpl: payFetch, pendingRetries: 2, maxSleepMs: 10_000, timeoutMs: requestTimeoutMs, signal: AbortSignal.timeout(Math.max(1, deadline - Date.now())), ...(sleep ? { sleep } : {}) }).resend(url, prior.paymentHeaders, init);
|
|
295
305
|
r = { ...r, requirement: prior.requirement, paid: r.response.ok ? prior.price : 0n, borrowed: 0n, signed: prior, resent: true, ...(r.response.ok ? { settlement: settlementOf(r.response) } : {}) };
|
|
296
306
|
lines.push("No new payment was signed: the same signed payment was sent again.");
|
|
297
307
|
} else {
|
|
@@ -299,7 +309,7 @@ export async function createPriorsMcpServer({ env = process.env, fetchImpl = glo
|
|
|
299
309
|
if (maxBorrow > 0n && session.borrowed + maxBorrow > borrowTotalCap) throw new ToolError(`this could bring what is borrowed in this session to ${usd(session.borrowed + maxBorrow)}, above ${usd(borrowTotalCap)} (PRIORS_MAX_BORROW_TOTAL_USD).`);
|
|
300
310
|
let agentId;
|
|
301
311
|
if (maxBorrow > 0n) { agentId = await resolveAgent(); await needController(agentId); }
|
|
302
|
-
const payer = X.createPayer({ signer, maxPrice, maxBorrow, fetchImpl: payFetch, pendingRetries: 2, maxSleepMs: 10_000, timeoutMs: requestTimeoutMs, signal: AbortSignal.timeout(
|
|
312
|
+
const payer = X.createPayer({ signer, maxPrice, maxBorrow, fetchImpl: payFetch, pendingRetries: 2, maxSleepMs: 10_000, timeoutMs: requestTimeoutMs, signal: AbortSignal.timeout(Math.max(1, deadline - Date.now())), ...(sleep ? { sleep } : {}), ...(maxBorrow > 0n ? { pool: addresses.pool, agentId } : {}) });
|
|
303
313
|
try { r = await payer.pay(url, init); } catch (e) {
|
|
304
314
|
if (e?.name === "TimeoutError" || e?.name === "AbortError") throw new ToolError(`${method} ${u.href} did not answer in time. Nothing was signed or paid.`);
|
|
305
315
|
throw e;
|