twzrd-mcp-server 0.2.4 → 0.2.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 CHANGED
@@ -1,10 +1,11 @@
1
1
  # twzrd-mcp-server - auto-pay MCP for the TWZRD Trust API
2
2
 
3
+ <!-- mcp-name: xyz.twzrd/twzrd-mcp -->
4
+
3
5
  > Payment mechanism is mainnet-verified via the official x402 SDK (Python path,
4
- > $0.001 moved 2026-06-26 - see Status). As of v0.2.0 the bundled TypeScript path
5
- > uses the official x402 JS SDK (`@x402/core` + `@x402/svm` + `@x402/fetch`) and
6
- > is construct-verified against the live mainnet challenge; one real on-chain
7
- > settle remains before npm publish.
6
+ > $0.001 moved 2026-06-26 - see Status). The Node package is published on npm as
7
+ > `twzrd-mcp-server`; v0.2.5 source adds the single-shot payment guard required
8
+ > before the next live paid proof.
8
9
 
9
10
  Auto-pay MCP server for TWZRD's Trust API, matching the competitor GTM shape
10
11
  (anchor-x402, Br0ski777, BitBooth all ship one). An agent adds one `mcpServers`
@@ -22,7 +23,8 @@ non-Solana challenge instead of mis-signing.
22
23
  - Cumulative session cap `TWZRD_MAX_USDC_TOTAL` (default 1.00)
23
24
  - Free discovery tools never enter the payment path
24
25
  - No cross-chain fallback — a non-`exact`/non-`solana:` challenge is rejected
25
- - Paid calls run the free preflight first; `decision=block` aborts the pay
26
+ - Paid trust calls buy intel on the target wallet by design; use the free
27
+ `preflight` tool separately to vet a seller before paying it elsewhere.
26
28
 
27
29
  ## Status — payment path VERIFIED on mainnet 2026-06-26
28
30
 
@@ -38,8 +40,8 @@ Two authorized settles from dev wallet `2pHjZLqs…`:
38
40
  a no-data pubkey returned `422 charged:false` — the server's no-charge-on-empty
39
41
  guard works.
40
42
 
41
- **Conclusion: auto-pay works ONLY via the official x402 SDK, not a hand-rolled
42
- header.** Proven client wiring (Python):
43
+ **Conclusion: auto-pay works through the official x402 SDK path.** Proven client
44
+ wiring (Python):
43
45
 
44
46
  ```python
45
47
  from x402.client import x402ClientSync
@@ -52,16 +54,22 @@ session = x402_requests(client)
52
54
  session.get("https://intel.twzrd.xyz/v1/intel/quick/<wallet>") # auto-pays $0.001
53
55
  ```
54
56
 
55
- ### TypeScript path — integrated (v0.2.0)
56
- The hand-rolled `payAndRetry` is replaced with the official x402 JS SDK
57
- (`@x402/core` client + `@x402/svm` ExactSvmScheme + `@x402/fetch`
58
- `wrapFetchWithPayment`). `@x402/svm` reads the challenge `extra.feePayer` and builds
59
- the partially-signed sponsored transfer (verified no-spend against the live mainnet
60
- challenge: 496-byte tx, 2 signature slots), and the SDK encodes the `X-PAYMENT`
61
- header the server validates. Spend caps + preflight gate + free/paid split are
62
- preserved — caps are enforced in the payment selector before any signature.
63
- **Remaining:** one real $0.001 on-chain settle to confirm end-to-end, then npm
64
- publish + MCP-registry listing.
57
+ ### TypeScript path — integrated (v0.2.5)
58
+ The TypeScript path uses the official x402 JS SDK (`@x402/core` client +
59
+ `@x402/svm` ExactSvmScheme). `@x402/svm` reads the challenge
60
+ `extra.feePayer` and builds the partially-signed sponsored transfer, and
61
+ `x402HTTPClient` encodes the `X-PAYMENT` header the server validates. Spend caps +
62
+ free/paid split are preserved caps are enforced in the payment selector before
63
+ any signature.
64
+
65
+ Important: v0.2.5 uses a **single-shot** paid retry. The first SDK-backed E2E found
66
+ that the generic `@x402/fetch` wrapper can re-pay after a transient-looking settle
67
+ response, moving `$0.003` across two `$0.001` calls. This package now performs at
68
+ most one signed retry per logical tool call; any second 402 is surfaced instead of
69
+ silently paying again.
70
+
71
+ **Next verification step:** one operator-authorized `$0.001` `quick_trust` settle
72
+ through v0.2.5, followed by offline receipt verification.
65
73
 
66
74
  ## Install & Config
67
75
 
@@ -86,7 +94,11 @@ The **free** tools (`preflight`, `wallet_lookup`) need no wallet and no flags
86
94
  `TWZRD_MCP_PAYMENTS_ENABLED` unset and they work read-only. Only the paid tools need
87
95
  the keypair + `TWZRD_MCP_PAYMENTS_ENABLED=1`.
88
96
 
89
- ### Node (`npx twzrd-mcp-server`) — v0.2.0, x402 JS SDK
97
+ ### Node (`npx twzrd-mcp-server`) — x402 JS SDK
98
+ ```bash
99
+ npx -y twzrd-mcp-server --help
100
+ ```
101
+
90
102
  ```json
91
103
  { "mcpServers": { "twzrd": {
92
104
  "command": "npx", "args": ["-y", "twzrd-mcp-server"],
@@ -100,9 +112,45 @@ the keypair + `TWZRD_MCP_PAYMENTS_ENABLED=1`.
100
112
  ```
101
113
  Auto-pay is enabled whenever `TWZRD_WALLET_SECRET_KEY` is present (set
102
114
  `TWZRD_MCP_PAYMENTS_ENABLED=0` to force paid tools off). Free tools need no wallet.
103
- Construct-verified against the live mainnet challenge; pending one real settle +
104
- npm publish (until published, `npx twzrd-mcp-server` is not yet resolvable — see
105
- the Python package above for a path that is live on PyPI today).
115
+ The package is published on npm; v0.2.5 is the next source release that includes
116
+ the single-shot double-settle guard.
117
+
118
+ ## One-command Agent Demo
119
+
120
+ The packaged demo starts the MCP server over stdio, lists the tools, and runs a
121
+ live **free** preflight. It is no-spend by default, even if your shell has a
122
+ wallet secret:
123
+
124
+ ```bash
125
+ npm run build
126
+ npm run demo
127
+ ```
128
+
129
+ Turn the same demo into the operator-authorized `$0.001` settle proof by changing
130
+ one env var and setting tight caps:
131
+
132
+ ```bash
133
+ TWZRD_DEMO_PAID=quick \
134
+ TWZRD_WALLET_SECRET_KEY="<base58 Solana secret>" \
135
+ TWZRD_RPC_URL="<mainnet RPC>" \
136
+ TWZRD_MAX_USDC_PER_CALL=0.001 \
137
+ TWZRD_MAX_USDC_TOTAL=0.001 \
138
+ node examples/agent-drop-in.mjs
139
+ ```
140
+
141
+ For the full signed-receipt path, use `TWZRD_DEMO_PAID=full` and set both caps to
142
+ `0.05`; the demo verifies any returned receipt through the MCP `verify_receipt`
143
+ tool. To additionally pipe that receipt into the standalone verifier package:
144
+
145
+ ```bash
146
+ TWZRD_DEMO_PAID=full \
147
+ TWZRD_DEMO_RUN_VERIFIER_SELF_TEST=1 \
148
+ TWZRD_WALLET_SECRET_KEY="<base58 Solana secret>" \
149
+ TWZRD_RPC_URL="<mainnet RPC>" \
150
+ TWZRD_MAX_USDC_PER_CALL=0.05 \
151
+ TWZRD_MAX_USDC_TOTAL=0.05 \
152
+ node examples/agent-drop-in.mjs
153
+ ```
106
154
 
107
155
  ## Tools
108
156
  - `preflight` (free) — allow/warn/block + trust_score before you pay a **seller** you're about to transact with
package/dist/index.js CHANGED
@@ -12,8 +12,8 @@
12
12
  * wallet (the challenge `extra.feePayer`) co-signs + pays the SOL fee server-side.
13
13
  * `@x402/svm`'s ExactSvmScheme reads `extra.feePayer` and builds exactly this
14
14
  * partially-signed transaction; the SDK also encodes the X-PAYMENT header the
15
- * server validates. (An earlier draft hand-rolled both and the server rejected
16
- * it the hand-rolled header never matched the official x402 PaymentPayload.)
15
+ * server validates. This keeps the client payload byte-compatible with the
16
+ * server-side x402 validator instead of inventing a parallel header format.
17
17
  *
18
18
  * SAFETY GUARDRAILS (all enforced in the payment-requirements selector, BEFORE
19
19
  * any signature):
@@ -22,7 +22,8 @@
22
22
  * - Free discovery tools are NEVER routed through the payment path
23
23
  * - No cross-chain fallback: only a Solana "exact" requirement is selectable;
24
24
  * anything else throws (refuse to pay) rather than mis-signing
25
- * - Paid tools run the FREE preflight first; decision=block aborts the pay
25
+ * - Paid tools buy intel on the target wallet by design; use the free
26
+ * `preflight` tool separately to vet a seller before paying it elsewhere.
26
27
  *
27
28
  * STATUS: payment mechanism is SDK-backed and the payload construction is
28
29
  * verified against the live Solana "exact" challenge. The first real on-chain
@@ -40,11 +41,53 @@
40
41
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
41
42
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
42
43
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
43
- import { x402Client } from "@x402/core/client";
44
- import { wrapFetchWithPayment } from "@x402/fetch";
44
+ import { x402Client, x402HTTPClient } from "@x402/core/client";
45
45
  import { ExactSvmScheme, SOLANA_MAINNET_CAIP2 } from "@x402/svm";
46
46
  import { createKeyPairSignerFromBytes } from "@solana/kit";
47
47
  import bs58 from "bs58";
48
+ const VERSION = "0.2.5";
49
+ function printHelp() {
50
+ console.log(`twzrd-mcp-server v${VERSION}
51
+
52
+ TWZRD Trust API MCP server with Solana x402 auto-pay.
53
+
54
+ Usage:
55
+ twzrd-mcp-server Start stdio MCP server
56
+ twzrd-mcp-server --help Show this help
57
+ twzrd-mcp-server --version Print version
58
+
59
+ Free tools work with no wallet:
60
+ preflight, wallet_lookup, verify_receipt
61
+
62
+ Paid tools require:
63
+ TWZRD_WALLET_SECRET_KEY=<base58 Solana secret key>
64
+ TWZRD_RPC_URL=<mainnet Solana RPC>
65
+ TWZRD_MAX_USDC_PER_CALL=0.05
66
+ TWZRD_MAX_USDC_TOTAL=1.00
67
+
68
+ MCP config:
69
+ {
70
+ "mcpServers": {
71
+ "twzrd": {
72
+ "command": "npx",
73
+ "args": ["-y", "twzrd-mcp-server"],
74
+ "env": {
75
+ "TWZRD_RPC_URL": "<mainnet rpc>",
76
+ "TWZRD_WALLET_SECRET_KEY": "<base58 secret>"
77
+ }
78
+ }
79
+ }
80
+ }
81
+ `);
82
+ }
83
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
84
+ printHelp();
85
+ process.exit(0);
86
+ }
87
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
88
+ console.log(VERSION);
89
+ process.exit(0);
90
+ }
48
91
  // ── Config ─────────────────────────────────────────────────────────────────
49
92
  const API_BASE = process.env.TWZRD_API_URL || "https://intel.twzrd.xyz";
50
93
  const RPC_URL = process.env.TWZRD_RPC_URL || "https://api.mainnet-beta.solana.com";
@@ -75,8 +118,11 @@ function selectSolanaExact(_x402Version, accepts) {
75
118
  spentUsdc += amountUsdc;
76
119
  return req;
77
120
  }
78
- // Build the payment-enabled fetch once, if a key is present and payments aren't
79
- // force-disabled. Otherwise paid tools fail closed with a clear message.
121
+ // Build a SINGLE-SHOT payment fetch once, if a key is present and payments
122
+ // aren't force-disabled. We intentionally do not use @x402/fetch's
123
+ // wrapFetchWithPayment here: its recovery branch can create a fresh payload and
124
+ // re-pay after a transient-looking settle response. This wrapper makes exactly
125
+ // one paid retry per logical tool call; any second 402 is surfaced to the caller.
80
126
  let paidFetch = null;
81
127
  let paymentInitError = "";
82
128
  if (SECRET && !PAYMENTS_DISABLED) {
@@ -86,7 +132,30 @@ if (SECRET && !PAYMENTS_DISABLED) {
86
132
  const scheme = new ExactSvmScheme(signer, { rpcUrl: RPC_URL });
87
133
  const client = new x402Client(selectSolanaExact);
88
134
  client.register(SOLANA_MAINNET_CAIP2, scheme);
89
- paidFetch = wrapFetchWithPayment(fetch, client);
135
+ const httpClient = new x402HTTPClient(client);
136
+ paidFetch = (async (input, init) => {
137
+ const first = await fetch(input, init);
138
+ if (first.status !== 402)
139
+ return first;
140
+ let challengeBody;
141
+ try {
142
+ const text = await first.text();
143
+ if (text)
144
+ challengeBody = JSON.parse(text);
145
+ }
146
+ catch {
147
+ // Header-only challenges are valid; the SDK can read those from headers.
148
+ }
149
+ const paymentRequired = httpClient.getPaymentRequiredResponse((name) => first.headers.get(name), challengeBody);
150
+ const payload = await client.createPaymentPayload(paymentRequired);
151
+ const headers = httpClient.encodePaymentSignatureHeader(payload);
152
+ const retry = new Request(input, init);
153
+ for (const [key, value] of Object.entries(headers)) {
154
+ retry.headers.set(key, value);
155
+ }
156
+ retry.headers.set("Access-Control-Expose-Headers", "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE");
157
+ return fetch(retry);
158
+ });
90
159
  console.error(`TWZRD MCP: auto-pay armed (payer ${signer.address}) caps $${MAX_PER_CALL}/call $${MAX_TOTAL}/session`);
91
160
  }
92
161
  catch (e) {
@@ -122,7 +191,7 @@ const TOOLS = [
122
191
  { name: "quick_trust", description: "PAID $0.001 (auto-pay, Solana x402): quick tier+score for a Solana wallet.", inputSchema: { type: "object", properties: { wallet: { type: "string" } }, required: ["wallet"] } },
123
192
  { name: "full_trust", description: "PAID $0.05 (auto-pay, Solana x402): full trust intel + signed V6 receipt.", inputSchema: { type: "object", properties: { wallet: { type: "string" }, seller_wallet: { type: "string" } }, required: ["wallet"] } },
124
193
  ];
125
- const server = new Server({ name: "twzrd-mcp-server", version: "0.2.0" }, { capabilities: { tools: {} } });
194
+ const server = new Server({ name: "twzrd-mcp-server", version: VERSION }, { capabilities: { tools: {} } });
126
195
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
127
196
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
128
197
  const { name, arguments: args } = request.params;
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * TWZRD MCP drop-in demo.
4
+ *
5
+ * Default path is free and read-only:
6
+ * npm run build
7
+ * npm run demo
8
+ *
9
+ * Operator-authorized paid proof (spends exactly one capped x402 call):
10
+ * TWZRD_DEMO_PAID=quick \
11
+ * TWZRD_WALLET_SECRET_KEY=<base58-solana-secret> \
12
+ * TWZRD_RPC_URL=<mainnet-rpc> \
13
+ * TWZRD_MAX_USDC_PER_CALL=0.001 \
14
+ * TWZRD_MAX_USDC_TOTAL=0.001 \
15
+ * node examples/agent-drop-in.mjs
16
+ *
17
+ * Full receipt path (costs 0.05 USDC, verifies receipt if one is returned):
18
+ * TWZRD_DEMO_PAID=full TWZRD_MAX_USDC_PER_CALL=0.05 TWZRD_MAX_USDC_TOTAL=0.05 ...
19
+ */
20
+
21
+ import { spawn, spawnSync } from "node:child_process";
22
+ import path from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
26
+ const serverPath = process.env.TWZRD_MCP_SERVER_PATH || path.resolve(__dirname, "../dist/index.js");
27
+ const demoWallet =
28
+ process.env.TWZRD_DEMO_WALLET || "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
29
+ const paidMode = (process.env.TWZRD_DEMO_PAID || "off").toLowerCase();
30
+
31
+ if (!["off", "quick", "full"].includes(paidMode)) {
32
+ throw new Error("TWZRD_DEMO_PAID must be one of: off, quick, full");
33
+ }
34
+
35
+ const childEnv = { ...process.env };
36
+ if (paidMode === "off" && childEnv.TWZRD_MCP_PAYMENTS_ENABLED === undefined) {
37
+ // Free demo should stay free even if the shell happens to have a wallet secret.
38
+ childEnv.TWZRD_MCP_PAYMENTS_ENABLED = "0";
39
+ }
40
+ if (paidMode !== "off") {
41
+ if (!childEnv.TWZRD_WALLET_SECRET_KEY) {
42
+ throw new Error("Paid demo requires TWZRD_WALLET_SECRET_KEY (base58 Solana secret)");
43
+ }
44
+ childEnv.TWZRD_MAX_USDC_PER_CALL ||= paidMode === "quick" ? "0.001" : "0.05";
45
+ childEnv.TWZRD_MAX_USDC_TOTAL ||= childEnv.TWZRD_MAX_USDC_PER_CALL;
46
+ }
47
+
48
+ const child = spawn(process.execPath, [serverPath], {
49
+ env: childEnv,
50
+ stdio: ["pipe", "pipe", "pipe"],
51
+ });
52
+
53
+ let nextId = 1;
54
+ let stdoutBuffer = "";
55
+ const pending = new Map();
56
+
57
+ child.stderr.on("data", (chunk) => {
58
+ process.stderr.write(`[twzrd-mcp] ${chunk}`);
59
+ });
60
+
61
+ child.stdout.on("data", (chunk) => {
62
+ stdoutBuffer += chunk.toString("utf8");
63
+ parseFrames();
64
+ });
65
+
66
+ child.on("exit", (code, signal) => {
67
+ const err = new Error(`MCP server exited code=${code} signal=${signal}`);
68
+ for (const { reject, timer } of pending.values()) {
69
+ clearTimeout(timer);
70
+ reject(err);
71
+ }
72
+ pending.clear();
73
+ });
74
+
75
+ function parseFrames() {
76
+ for (;;) {
77
+ const lineEnd = stdoutBuffer.indexOf("\n");
78
+ if (lineEnd < 0) return;
79
+
80
+ const line = stdoutBuffer.slice(0, lineEnd).replace(/\r$/, "");
81
+ stdoutBuffer = stdoutBuffer.slice(lineEnd + 1);
82
+ if (!line.trim()) continue;
83
+
84
+ const message = JSON.parse(line);
85
+ if (message.id !== undefined && pending.has(message.id)) {
86
+ const { resolve, reject, timer } = pending.get(message.id);
87
+ pending.delete(message.id);
88
+ clearTimeout(timer);
89
+ if (message.error) reject(new Error(JSON.stringify(message.error)));
90
+ else resolve(message.result);
91
+ }
92
+ }
93
+ }
94
+
95
+ function send(message) {
96
+ const body = JSON.stringify(message);
97
+ child.stdin.write(`${body}\n`);
98
+ }
99
+
100
+ function request(method, params) {
101
+ const id = nextId++;
102
+ send({ jsonrpc: "2.0", id, method, params });
103
+ return new Promise((resolve, reject) => {
104
+ const timer = setTimeout(() => {
105
+ pending.delete(id);
106
+ reject(new Error(`Timed out waiting for ${method}`));
107
+ }, 15000);
108
+ pending.set(id, { resolve, reject, timer });
109
+ });
110
+ }
111
+
112
+ function notify(method, params = {}) {
113
+ send({ jsonrpc: "2.0", method, params });
114
+ }
115
+
116
+ function textFromTool(result) {
117
+ return result?.content?.find((part) => part.type === "text")?.text || "";
118
+ }
119
+
120
+ function parseJsonText(text) {
121
+ try {
122
+ return JSON.parse(text);
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+
128
+ function printSection(title, value) {
129
+ console.log(`\n== ${title} ==`);
130
+ if (typeof value === "string") console.log(value);
131
+ else console.log(JSON.stringify(value, null, 2));
132
+ }
133
+
134
+ async function main() {
135
+ const init = await request("initialize", {
136
+ protocolVersion: "2024-11-05",
137
+ capabilities: {},
138
+ clientInfo: { name: "twzrd-agent-drop-in", version: "0.1.0" },
139
+ });
140
+ notify("notifications/initialized");
141
+ printSection("server", init.serverInfo);
142
+
143
+ const tools = await request("tools/list", {});
144
+ printSection(
145
+ "tools",
146
+ tools.tools.map((tool) => `${tool.name}: ${tool.description}`),
147
+ );
148
+
149
+ const preflight = await request("tools/call", {
150
+ name: "preflight",
151
+ arguments: {
152
+ seller_wallet: demoWallet,
153
+ resource_name: "agent-drop-in-demo",
154
+ price_usdc: paidMode === "quick" ? 0.001 : 0.05,
155
+ },
156
+ });
157
+ printSection("free preflight", parseJsonText(textFromTool(preflight)) || textFromTool(preflight));
158
+
159
+ if (paidMode === "quick") {
160
+ const quick = await request("tools/call", {
161
+ name: "quick_trust",
162
+ arguments: { wallet: demoWallet },
163
+ });
164
+ printSection("paid quick_trust", parseJsonText(textFromTool(quick)) || textFromTool(quick));
165
+ }
166
+
167
+ if (paidMode === "full") {
168
+ const full = await request("tools/call", {
169
+ name: "full_trust",
170
+ arguments: { wallet: demoWallet },
171
+ });
172
+ const body = parseJsonText(textFromTool(full)) || {};
173
+ printSection("paid full_trust", body || textFromTool(full));
174
+
175
+ const receipt = body.twzrd_receipt || body.receipt;
176
+ if (receipt?.leaf) {
177
+ printSection("receipt", {
178
+ leaf: receipt.leaf,
179
+ signature: receipt.signature,
180
+ signing_pubkey: receipt.signing_pubkey,
181
+ settlement_tx: receipt.preimage?.settlement_tx || body.settlement_tx,
182
+ });
183
+ const verified = await request("tools/call", {
184
+ name: "verify_receipt",
185
+ arguments: {
186
+ leaf: receipt.leaf,
187
+ signature: receipt.signature,
188
+ signing_pubkey: receipt.signing_pubkey,
189
+ },
190
+ });
191
+ printSection("receipt verification", parseJsonText(textFromTool(verified)) || textFromTool(verified));
192
+
193
+ if (process.env.TWZRD_DEMO_RUN_VERIFIER_SELF_TEST === "1") {
194
+ console.log("\n== receipt-verifier self-test ==");
195
+ const verifier = spawnSync(
196
+ "npx",
197
+ ["-y", "twzrd-receipt-verifier@1.2.0", "-", "--self-test"],
198
+ { input: JSON.stringify(receipt), stdio: ["pipe", "inherit", "inherit"] },
199
+ );
200
+ if (verifier.status !== 0) {
201
+ throw new Error(`twzrd-receipt-verifier self-test exited ${verifier.status}`);
202
+ }
203
+ }
204
+ } else {
205
+ console.log("\nNo receipt object returned, so receipt verification was skipped.");
206
+ }
207
+ }
208
+
209
+ console.log(`\nDemo complete. paid_mode=${paidMode}`);
210
+ }
211
+
212
+ main()
213
+ .catch((err) => {
214
+ console.error(`\nDemo failed: ${err.message}`);
215
+ process.exitCode = 1;
216
+ })
217
+ .finally(() => {
218
+ child.kill();
219
+ });
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "twzrd-mcp-server",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "TWZRD Trust API MCP server with Solana x402 auto-pay (official @x402 SDK, spend-capped, preflight-gated).",
5
5
  "type": "module",
6
6
  "bin": {
7
- "twzrd-mcp-server": "./dist/index.js"
7
+ "twzrd-mcp-server": "dist/index.js"
8
8
  },
9
9
  "main": "./dist/index.js",
10
10
  "files": [
11
- "dist",
11
+ "dist/index.js",
12
+ "examples/agent-drop-in.mjs",
12
13
  "README.md"
13
14
  ],
14
15
  "engines": {
@@ -31,6 +32,7 @@
31
32
  ],
32
33
  "scripts": {
33
34
  "build": "tsc",
35
+ "demo": "node examples/agent-drop-in.mjs",
34
36
  "typecheck": "tsc --noEmit",
35
37
  "prepublishOnly": "npm run build"
36
38
  },
@@ -38,7 +40,6 @@
38
40
  "@modelcontextprotocol/sdk": "^1.0.0",
39
41
  "@x402/core": "^2.17.0",
40
42
  "@x402/svm": "^2.17.0",
41
- "@x402/fetch": "^2.17.0",
42
43
  "@solana/kit": "^5.1.0",
43
44
  "bs58": "^6.0.0"
44
45
  },