@magpieloans/magpie-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.
- package/README.md +27 -4
- package/dist/envelope.js +84 -0
- package/dist/index.js +202 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
**MCP server exposing the Magpie Capital x402 API as native tools for Claude Desktop, Cursor, Windsurf, ChatGPT desktop, and any other MCP-aware agent host.**
|
|
4
4
|
|
|
5
|
-
Drop one config block into your host and your agent can query Magpie's protocol state, simulate borrows, fetch credit scores, build deposit/withdraw transactions,
|
|
5
|
+
Drop one config block into your host and your agent can query Magpie's protocol state, simulate borrows, fetch credit scores, build deposit/withdraw transactions, post conditional borrow intents, and arm self-owned in-vault take-profit / stop-loss exits on its own loans — all as first-class tool calls. No bespoke client code, no API keys.
|
|
6
|
+
|
|
7
|
+
> A share of Magpie protocol fees accrues to a **$MAGPIE** holder-rewards pool, paid pro-rata in SOL (no staking, no lockup). 70% is the governance-ratified (MGP-001) target allocation; distributions run on a governance cadence. x402 call fees feed the same holder-rewards economics — agent adoption grows the fees that reward holders.
|
|
6
8
|
|
|
7
9
|
## What it exposes
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
26 tools wrapping the x402 endpoints:
|
|
10
12
|
|
|
11
13
|
**Free reads (work out of the box):**
|
|
12
14
|
- `magpie_pool_state` — live LendingPool account
|
|
@@ -20,20 +22,41 @@ Drop one config block into your host and your agent can query Magpie's protocol
|
|
|
20
22
|
- `magpie_liquidatable` — loans currently liquidatable
|
|
21
23
|
- `magpie_credit_leaderboard` — top wallets by credit score
|
|
22
24
|
- `magpie_lp_state` — depositor position + pool context
|
|
25
|
+
- `magpie_loan_by_pda` — single loan by on-chain loan PDA
|
|
26
|
+
- `magpie_pools` — Magpie lending pools (program-version lanes + context)
|
|
27
|
+
- `magpie_list_exits` — armed in-vault exit orders for a wallet
|
|
28
|
+
- `magpie_modify_exit` — change an armed exit's trigger / params
|
|
29
|
+
- `magpie_cancel_exit` — cancel an armed exit (loan stays Active)
|
|
23
30
|
|
|
24
31
|
**Paid (require a configured Solana keypair):**
|
|
25
32
|
- `magpie_credit_score` — 0.001 SOL
|
|
26
33
|
- `magpie_token_risk` — 0.001 SOL (per-token risk profile)
|
|
27
|
-
- `magpie_build_borrow` — 0.005 SOL
|
|
34
|
+
- `magpie_build_borrow` — 0.005 SOL (pass `has_exit_arming: true` to route into the V4 in-vault-exit lane)
|
|
28
35
|
- `magpie_build_repay` — 0.002 SOL
|
|
29
36
|
- `magpie_build_deposit` — 0.002 SOL
|
|
30
37
|
- `magpie_build_withdraw` — 0.002 SOL
|
|
31
38
|
- `magpie_build_liquidate` — 0.003 SOL (liquidate a past-due loan, receive keeper bounty)
|
|
32
39
|
- `magpie_create_intent` — 0.01 SOL (conditional borrow)
|
|
33
40
|
- `magpie_get_intent` — 0.0005 SOL (poll)
|
|
41
|
+
- `magpie_arm_exit` — 0.001 SOL (arm a self-owned in-vault TP / SL / trailing exit)
|
|
34
42
|
|
|
35
43
|
When a paid tool fires, the server signs an x402 payment tx locally with your configured keypair and forwards the signature to magpie-x402. The keypair never leaves your machine.
|
|
36
44
|
|
|
45
|
+
## Self-owned in-vault exits (V4)
|
|
46
|
+
|
|
47
|
+
Magpie's V4 lane lets an agent arm **its own** take-profit, stop-loss, and trailing exits on **its own** active loan — and the sell happens **in-vault**: when a trigger fires, the collateral is auto-sold and the proceeds (SOL by default, or USDC) accumulate inside that loan's per-loan proceeds vault while the loan stays **Active**. Proceeds only ever reach your wallet through your own borrower-signed repay. There's no fire-and-close, and nothing the protocol can do to move your funds out.
|
|
48
|
+
|
|
49
|
+
- `magpie_arm_exit` (**0.001 SOL**) — arm a TP / SL / trailing exit on a V4 loan you own. Set `direction` (`above` = take-profit, the default; `below` = stop-loss) and exactly one trigger: `target` (e.g. `"2x"` / `"0.7x"`), `price_usd`, `mc_usd` (e.g. `"5M"`, `"1.2B"`), or `trailing_bps` (stop-loss only). Optional `slippage_bps`, `dest` (`sol` | `usdc`), and `slice` for laddered exits.
|
|
50
|
+
- `magpie_modify_exit` (**free**) — retune an armed order's trigger or params in place.
|
|
51
|
+
- `magpie_cancel_exit` (**free**) — remove an armed order; the loan is untouched.
|
|
52
|
+
- `magpie_list_exits` (**free**) — audit a wallet's armed orders, each with its distance-to-trigger.
|
|
53
|
+
|
|
54
|
+
Every exit call is authenticated with a dependency-free Ed25519 **signed envelope** built locally from your configured keypair. For `magpie_arm_exit` the envelope is signed by the **same** keypair that pays the 0.001 SOL x402 challenge, so the bot's `payer == signer` invariant holds and only the owner of a loan can arm exits on it. The bot enforces a 5-minute freshness window and nonce-uniqueness on every envelope.
|
|
55
|
+
|
|
56
|
+
To start a borrow that supports these exits, call `magpie_build_borrow` with `has_exit_arming: true` (routes into V4); leave it `false` for a plain memecoin (V1) borrow.
|
|
57
|
+
|
|
58
|
+
> RWA / xStock collateral runs on the separate V3 lane, which is launch-gated — on the V3 launch, the same exit tooling will extend to RWA loans.
|
|
59
|
+
|
|
37
60
|
## Install
|
|
38
61
|
|
|
39
62
|
Two paths. Both end at the same place.
|
|
@@ -116,7 +139,7 @@ Use the same shape — point the host at `node /ABS/PATH/.../mcp/dist/index.js`,
|
|
|
116
139
|
|
|
117
140
|
## Free-only mode (no keypair)
|
|
118
141
|
|
|
119
|
-
Omit `MAGPIE_MCP_PAYER_KEYPAIR` and
|
|
142
|
+
Omit `MAGPIE_MCP_PAYER_KEYPAIR` and the read-only free tools still work. Paid tools — and the envelope-signed exit tools (`magpie_arm_exit`, `magpie_modify_exit`, `magpie_cancel_exit`, which need the keypair to sign the envelope even though modify/cancel cost nothing) — return a clear error explaining that no payer is configured. Useful for read-only research agents or as a no-friction first install.
|
|
120
143
|
|
|
121
144
|
## Environment variables
|
|
122
145
|
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ed25519 signed-envelope builder for Magpie's self-owned exit orders.
|
|
3
|
+
*
|
|
4
|
+
* The bot's /api/v1/site/limit-close/* surface authenticates with a signed
|
|
5
|
+
* "Header: value" text envelope (NOT a session). This module builds + signs
|
|
6
|
+
* that envelope so an agent can arm / modify / cancel exits on its OWN loan
|
|
7
|
+
* with one call. The signature is produced with Node's built-in crypto
|
|
8
|
+
* (Ed25519) and a tiny inline base58 encoder — ZERO extra dependencies.
|
|
9
|
+
*
|
|
10
|
+
* The signed text is exactly what the bot re-parses and verifies, e.g.:
|
|
11
|
+
*
|
|
12
|
+
* magpie: limit-close-arm/v1
|
|
13
|
+
* From: <signer pubkey>
|
|
14
|
+
* LoanId: 12345
|
|
15
|
+
* Direction: above
|
|
16
|
+
* Target: 2x
|
|
17
|
+
* Slippage: 100
|
|
18
|
+
* Dest: sol
|
|
19
|
+
* Nonce: <uuid>
|
|
20
|
+
* IssuedAt: 2026-06-20T00:00:00.000Z
|
|
21
|
+
*/
|
|
22
|
+
import { createPrivateKey, sign as nodeSign, randomUUID } from "node:crypto";
|
|
23
|
+
// PKCS8 DER prefix for an Ed25519 private key (RFC 8410). The 32-byte seed
|
|
24
|
+
// follows, giving a 48-byte DER we can hand to Node's createPrivateKey.
|
|
25
|
+
const PKCS8_ED25519_PREFIX = Buffer.from("302e020100300506032b657004220420", "hex");
|
|
26
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
27
|
+
/** Standard (Bitcoin/Solana) base58 encode. */
|
|
28
|
+
function base58Encode(bytes) {
|
|
29
|
+
const digits = [0];
|
|
30
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
31
|
+
let carry = bytes[i];
|
|
32
|
+
for (let j = 0; j < digits.length; j++) {
|
|
33
|
+
carry += digits[j] << 8;
|
|
34
|
+
digits[j] = carry % 58;
|
|
35
|
+
carry = (carry / 58) | 0;
|
|
36
|
+
}
|
|
37
|
+
while (carry > 0) {
|
|
38
|
+
digits.push(carry % 58);
|
|
39
|
+
carry = (carry / 58) | 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let zeros = 0;
|
|
43
|
+
while (zeros < bytes.length && bytes[zeros] === 0)
|
|
44
|
+
zeros++;
|
|
45
|
+
let out = "1".repeat(zeros);
|
|
46
|
+
for (let k = digits.length - 1; k >= 0; k--)
|
|
47
|
+
out += BASE58_ALPHABET[digits[k]];
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function signEd25519(message, keypair) {
|
|
51
|
+
// Solana secretKey is [32-byte seed || 32-byte pubkey]; Ed25519 PKCS8
|
|
52
|
+
// needs only the seed.
|
|
53
|
+
const seed = Buffer.from(keypair.secretKey.slice(0, 32));
|
|
54
|
+
const der = Buffer.concat([PKCS8_ED25519_PREFIX, seed]);
|
|
55
|
+
const key = createPrivateKey({ key: der, format: "der", type: "pkcs8" });
|
|
56
|
+
return nodeSign(null, Buffer.from(message), key);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build + sign an envelope. `From`, `Nonce`, and `IssuedAt` are added
|
|
60
|
+
* automatically (unless you override them) — the bot requires all three and
|
|
61
|
+
* enforces a 5-minute freshness window on IssuedAt + nonce-uniqueness.
|
|
62
|
+
*/
|
|
63
|
+
export function buildSignedEnvelope(keypair, magpieHeader, fields) {
|
|
64
|
+
const signer = keypair.publicKey.toBase58();
|
|
65
|
+
const merged = {
|
|
66
|
+
Nonce: randomUUID(),
|
|
67
|
+
IssuedAt: new Date().toISOString(),
|
|
68
|
+
...fields,
|
|
69
|
+
};
|
|
70
|
+
const lines = [`magpie: ${magpieHeader}`, `From: ${signer}`];
|
|
71
|
+
for (const [k, v] of Object.entries(merged)) {
|
|
72
|
+
if (v === undefined || v === null || v === "")
|
|
73
|
+
continue;
|
|
74
|
+
lines.push(`${k}: ${v}`);
|
|
75
|
+
}
|
|
76
|
+
const text = lines.join("\n");
|
|
77
|
+
const messageBytes = new TextEncoder().encode(text);
|
|
78
|
+
const sig = signEd25519(messageBytes, keypair);
|
|
79
|
+
return {
|
|
80
|
+
signedMessageBase64: Buffer.from(messageBytes).toString("base64"),
|
|
81
|
+
signatureBase58: base58Encode(sig),
|
|
82
|
+
signerPubkey: signer,
|
|
83
|
+
};
|
|
84
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -29,10 +29,20 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
29
29
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
30
30
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
31
31
|
import { call, loadKeypairFromEnv } from "./x402-client.js";
|
|
32
|
+
import { buildSignedEnvelope } from "./envelope.js";
|
|
32
33
|
const baseUrl = process.env.MAGPIE_X402_BASE_URL ?? "https://x402.magpie.capital";
|
|
33
34
|
const rpcUrl = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";
|
|
34
35
|
const payer = loadKeypairFromEnv();
|
|
35
36
|
const ctx = { baseUrl, rpcUrl, payer };
|
|
37
|
+
// The self-owned exit surface signs an Ed25519 envelope with the payer
|
|
38
|
+
// keypair. Both the signature AND (for arm) the x402 payment come from this
|
|
39
|
+
// one keypair, guaranteeing the bot's payer==signer invariant.
|
|
40
|
+
function requirePayer() {
|
|
41
|
+
if (!payer) {
|
|
42
|
+
throw new Error("this tool signs an exit envelope (and arm also pays an x402 challenge) but no payer keypair was configured. Set MAGPIE_MCP_PAYER_KEYPAIR.");
|
|
43
|
+
}
|
|
44
|
+
return payer;
|
|
45
|
+
}
|
|
36
46
|
// Schema-only tool registry. Each entry maps to a thin handler below
|
|
37
47
|
// that turns the args into a magpie-x402 HTTP call. Keeping the tool
|
|
38
48
|
// list in one declarative block makes ListTools cheap + always in sync
|
|
@@ -161,7 +171,7 @@ const TOOLS = [
|
|
|
161
171
|
},
|
|
162
172
|
{
|
|
163
173
|
name: "magpie_build_borrow",
|
|
164
|
-
description: "Build an UNSIGNED borrow transaction. Server runs the full anti-exploit gate eval (ban registry, TWAP, pool floor, cross-source price, RWA-only guard, etc.) and returns a partial-signed tx. Agent signs locally and submits to magpie.capital/api/v1/cosign-borrow. Paid: 0.005 SOL.",
|
|
174
|
+
description: "Build an UNSIGNED borrow transaction. Server runs the full anti-exploit gate eval (ban registry, TWAP, pool floor, cross-source price, RWA-only guard, etc.) and returns a partial-signed tx. Agent signs locally and submits to magpie.capital/api/v1/cosign-borrow. Set has_exit_arming=true to route the loan into the V4 in-vault exit pool so you can later arm self-owned TP/SL exits on it (via magpie_arm_exit); leave false for a plain memecoin (V1) borrow. Paid: 0.005 SOL.",
|
|
165
175
|
inputSchema: {
|
|
166
176
|
type: "object",
|
|
167
177
|
properties: {
|
|
@@ -169,6 +179,11 @@ const TOOLS = [
|
|
|
169
179
|
collateral_mint: { type: "string" },
|
|
170
180
|
collateral_amount: { type: "string", pattern: "^[0-9]+$" },
|
|
171
181
|
tier: { type: "integer", enum: [0, 1, 2] },
|
|
182
|
+
has_exit_arming: {
|
|
183
|
+
type: "boolean",
|
|
184
|
+
default: false,
|
|
185
|
+
description: "When true, routes the borrow into the V4 program so the loan supports in-vault auto-sell exits (TP/SL/trailing). When false, a standard V1 borrow with no exit arming.",
|
|
186
|
+
},
|
|
172
187
|
},
|
|
173
188
|
required: ["borrower_wallet", "collateral_mint", "collateral_amount", "tier"],
|
|
174
189
|
},
|
|
@@ -262,6 +277,136 @@ const TOOLS = [
|
|
|
262
277
|
required: ["id"],
|
|
263
278
|
},
|
|
264
279
|
},
|
|
280
|
+
// ── V4 in-vault exit orders (self-owned TP / SL / trailing) ─────────
|
|
281
|
+
{
|
|
282
|
+
name: "magpie_arm_exit",
|
|
283
|
+
description: "Arm a self-owned in-vault exit (take-profit / stop-loss / trailing) on YOUR OWN active V4 loan. When the trigger fires, the collateral is auto-sold IN-VAULT: SOL (or USDC) accumulates inside the loan's per-loan proceeds vault and the loan stays Active — the proceeds only leave to your wallet via your own borrower-signed repay. Pick exactly one trigger: target (e.g. '2x' TP / '0.7x' SL), price_usd, mc_usd (e.g. '5M','1.2B'), or trailing_bps (SL only). direction defaults to 'above' (TP); use 'below' for a stop-loss. The envelope is signed with the configured payer keypair, and the x402 payment pays from that SAME keypair, so payer==signer holds (the bot rejects any mismatch). Only works on V4 loans you own. Paid: 0.001 SOL.",
|
|
284
|
+
inputSchema: {
|
|
285
|
+
type: "object",
|
|
286
|
+
properties: {
|
|
287
|
+
loan_id: {
|
|
288
|
+
type: "string",
|
|
289
|
+
description: "The u64 loan ID of your active V4 loan to arm the exit on.",
|
|
290
|
+
},
|
|
291
|
+
direction: {
|
|
292
|
+
type: "string",
|
|
293
|
+
enum: ["above", "below"],
|
|
294
|
+
description: "above = take-profit (default), below = stop-loss.",
|
|
295
|
+
},
|
|
296
|
+
target: {
|
|
297
|
+
type: "string",
|
|
298
|
+
description: "Multiplier trigger, e.g. '2x' for a 2x take-profit or '0.7x' for a stop-loss. One trigger only.",
|
|
299
|
+
},
|
|
300
|
+
price_usd: {
|
|
301
|
+
type: "string",
|
|
302
|
+
description: "Absolute USD price-per-token trigger. One trigger only.",
|
|
303
|
+
},
|
|
304
|
+
mc_usd: {
|
|
305
|
+
type: "string",
|
|
306
|
+
description: "Market-cap trigger, e.g. '5M' or '1.2B'. One trigger only.",
|
|
307
|
+
},
|
|
308
|
+
trailing_bps: {
|
|
309
|
+
type: "integer",
|
|
310
|
+
minimum: 1,
|
|
311
|
+
description: "Trailing stop distance in basis points (stop-loss / direction=below only). One trigger only.",
|
|
312
|
+
},
|
|
313
|
+
slippage_bps: {
|
|
314
|
+
type: "integer",
|
|
315
|
+
minimum: 0,
|
|
316
|
+
description: "Max slippage tolerance for the in-vault sell, in basis points.",
|
|
317
|
+
},
|
|
318
|
+
dest: {
|
|
319
|
+
type: "string",
|
|
320
|
+
enum: ["sol", "usdc"],
|
|
321
|
+
description: "Proceeds asset accumulated in the vault. Defaults to sol.",
|
|
322
|
+
},
|
|
323
|
+
slice: {
|
|
324
|
+
type: "string",
|
|
325
|
+
description: "Optional fraction/size of the position to sell at this trigger (for laddered exits). Omit to sell the full position.",
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
required: ["loan_id"],
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: "magpie_modify_exit",
|
|
333
|
+
description: "Modify an existing armed in-vault exit order on your own V4 loan — change its trigger or execution params without cancelling and re-arming. Signed with the configured payer keypair (payer==signer). FREE.",
|
|
334
|
+
inputSchema: {
|
|
335
|
+
type: "object",
|
|
336
|
+
properties: {
|
|
337
|
+
order_id: {
|
|
338
|
+
type: "string",
|
|
339
|
+
description: "The ID of the armed exit order to modify.",
|
|
340
|
+
},
|
|
341
|
+
price_usd: { type: "string", description: "New absolute USD price trigger." },
|
|
342
|
+
mc_usd: { type: "string", description: "New market-cap trigger, e.g. '5M'." },
|
|
343
|
+
target: { type: "string", description: "New multiplier trigger, e.g. '2x' / '0.7x'." },
|
|
344
|
+
trailing_bps: {
|
|
345
|
+
type: "integer",
|
|
346
|
+
minimum: 1,
|
|
347
|
+
description: "New trailing stop distance in basis points (SL only).",
|
|
348
|
+
},
|
|
349
|
+
slippage_bps: {
|
|
350
|
+
type: "integer",
|
|
351
|
+
minimum: 0,
|
|
352
|
+
description: "New max slippage tolerance in basis points.",
|
|
353
|
+
},
|
|
354
|
+
dest: {
|
|
355
|
+
type: "string",
|
|
356
|
+
enum: ["sol", "usdc"],
|
|
357
|
+
description: "New proceeds asset for the in-vault sell.",
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
required: ["order_id"],
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "magpie_cancel_exit",
|
|
365
|
+
description: "Cancel an armed in-vault exit order on your own V4 loan. The loan stays Active and unaffected; only the pending auto-sell is removed. Signed with the configured payer keypair (payer==signer). FREE.",
|
|
366
|
+
inputSchema: {
|
|
367
|
+
type: "object",
|
|
368
|
+
properties: {
|
|
369
|
+
order_id: {
|
|
370
|
+
type: "string",
|
|
371
|
+
description: "The ID of the armed exit order to cancel.",
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
required: ["order_id"],
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
name: "magpie_list_exits",
|
|
379
|
+
description: "List the armed in-vault exit orders for a wallet — each order's loan, direction, trigger, distance-to-trigger, and status. Use to audit what's armed before modifying or cancelling. FREE.",
|
|
380
|
+
inputSchema: {
|
|
381
|
+
type: "object",
|
|
382
|
+
properties: {
|
|
383
|
+
wallet: {
|
|
384
|
+
type: "string",
|
|
385
|
+
description: "The wallet whose armed exit orders to list.",
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
required: ["wallet"],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "magpie_loan_by_pda",
|
|
393
|
+
description: "Fetch a single Magpie loan by its on-chain loan PDA (account address). Returns the loan's program version, status, collateral, due timestamp, and (for V4) proceeds-vault context. FREE.",
|
|
394
|
+
inputSchema: {
|
|
395
|
+
type: "object",
|
|
396
|
+
properties: {
|
|
397
|
+
loan_pda: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "The on-chain loan PDA / account address.",
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
required: ["loan_pda"],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
name: "magpie_pools",
|
|
407
|
+
description: "List the Magpie lending pools (program versions and their pool context) — V1 memecoin and V4 in-vault-exit lanes. FREE.",
|
|
408
|
+
inputSchema: { type: "object", properties: {} },
|
|
409
|
+
},
|
|
265
410
|
];
|
|
266
411
|
// ── Server wiring ─────────────────────────────────────────────────
|
|
267
412
|
const server = new Server({
|
|
@@ -369,6 +514,62 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
369
514
|
query: { id: String(a.id) },
|
|
370
515
|
});
|
|
371
516
|
break;
|
|
517
|
+
// ── V4 in-vault exit orders ──────────────────────────────────
|
|
518
|
+
case "magpie_arm_exit": {
|
|
519
|
+
// PAID. The envelope MUST be signed by the SAME keypair that pays
|
|
520
|
+
// the x402 challenge, so the bot's payer==signer guard holds.
|
|
521
|
+
const kp = requirePayer();
|
|
522
|
+
const fields = {
|
|
523
|
+
LoanId: String(a.loan_id),
|
|
524
|
+
Direction: a.direction !== undefined ? String(a.direction) : undefined,
|
|
525
|
+
Target: a.target !== undefined ? String(a.target) : undefined,
|
|
526
|
+
Price: a.price_usd !== undefined ? String(a.price_usd) : undefined,
|
|
527
|
+
MC: a.mc_usd !== undefined ? String(a.mc_usd) : undefined,
|
|
528
|
+
Trailing: a.trailing_bps !== undefined ? String(a.trailing_bps) : undefined,
|
|
529
|
+
Slippage: a.slippage_bps !== undefined ? String(a.slippage_bps) : undefined,
|
|
530
|
+
Slice: a.slice !== undefined ? String(a.slice) : undefined,
|
|
531
|
+
Dest: a.dest !== undefined ? String(a.dest) : undefined,
|
|
532
|
+
};
|
|
533
|
+
const env = buildSignedEnvelope(kp, "limit-close-arm/v1", fields);
|
|
534
|
+
result = await call(ctx, "POST", "/api/v1/agent/self-limit-close/arm", { body: env });
|
|
535
|
+
break;
|
|
536
|
+
}
|
|
537
|
+
case "magpie_modify_exit": {
|
|
538
|
+
// FREE — still envelope-signed by the payer keypair (payer==signer).
|
|
539
|
+
const kp = requirePayer();
|
|
540
|
+
const fields = {
|
|
541
|
+
OrderId: String(a.order_id),
|
|
542
|
+
Price: a.price_usd !== undefined ? String(a.price_usd) : undefined,
|
|
543
|
+
MC: a.mc_usd !== undefined ? String(a.mc_usd) : undefined,
|
|
544
|
+
Target: a.target !== undefined ? String(a.target) : undefined,
|
|
545
|
+
Trailing: a.trailing_bps !== undefined ? String(a.trailing_bps) : undefined,
|
|
546
|
+
Slippage: a.slippage_bps !== undefined ? String(a.slippage_bps) : undefined,
|
|
547
|
+
Dest: a.dest !== undefined ? String(a.dest) : undefined,
|
|
548
|
+
};
|
|
549
|
+
const env = buildSignedEnvelope(kp, "limit-close-modify/v1", fields);
|
|
550
|
+
result = await call(ctx, "POST", "/api/v1/agent/self-limit-close/modify", { body: env });
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case "magpie_cancel_exit": {
|
|
554
|
+
// FREE — envelope-signed by the payer keypair (payer==signer).
|
|
555
|
+
const kp = requirePayer();
|
|
556
|
+
const env = buildSignedEnvelope(kp, "limit-close-cancel/v1", {
|
|
557
|
+
OrderId: String(a.order_id),
|
|
558
|
+
});
|
|
559
|
+
result = await call(ctx, "POST", "/api/v1/agent/self-limit-close/cancel", { body: env });
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
case "magpie_list_exits":
|
|
563
|
+
result = await call(ctx, "GET", "/api/v1/agent/self-limit-close/list", {
|
|
564
|
+
query: { wallet: String(a.wallet) },
|
|
565
|
+
});
|
|
566
|
+
break;
|
|
567
|
+
case "magpie_loan_by_pda":
|
|
568
|
+
result = await call(ctx, "GET", `/api/v1/loan/by-pda/${encodeURIComponent(String(a.loan_pda))}`);
|
|
569
|
+
break;
|
|
570
|
+
case "magpie_pools":
|
|
571
|
+
result = await call(ctx, "GET", "/api/v1/pools");
|
|
572
|
+
break;
|
|
372
573
|
default:
|
|
373
574
|
return {
|
|
374
575
|
isError: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magpieloans/magpie-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"mcpName": "io.github.magpiecapital/magpie-mcp",
|
|
4
5
|
"description": "MCP server exposing Magpie Capital's x402 API as native tools for Claude Desktop, Cursor, Windsurf, ChatGPT desktop, and any MCP-aware agent host.",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"bin": {
|