neutron-mcp 1.0.1 → 1.0.3

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
@@ -42,8 +42,8 @@ Add to your config file:
42
42
  "command": "npx",
43
43
  "args": ["-y", "neutron-mcp"],
44
44
  "env": {
45
- "NEUTRON_ACCESS_KEY": "your_access_key",
46
- "NEUTRON_SECRET_KEY": "your_secret_key"
45
+ "NEUTRON_API_KEY": "your_api_key",
46
+ "NEUTRON_API_SECRET": "your_api_secret"
47
47
  }
48
48
  }
49
49
  }
@@ -63,8 +63,8 @@ Add to `~/.claude.json` or your project's `.mcp.json`:
63
63
  "command": "npx",
64
64
  "args": ["-y", "neutron-mcp"],
65
65
  "env": {
66
- "NEUTRON_ACCESS_KEY": "your_access_key",
67
- "NEUTRON_SECRET_KEY": "your_secret_key"
66
+ "NEUTRON_API_KEY": "your_api_key",
67
+ "NEUTRON_API_SECRET": "your_api_secret"
68
68
  }
69
69
  }
70
70
  }
@@ -84,8 +84,8 @@ Add to `.cursor/mcp.json` in your project or global config:
84
84
  "command": "npx",
85
85
  "args": ["-y", "neutron-mcp"],
86
86
  "env": {
87
- "NEUTRON_ACCESS_KEY": "your_access_key",
88
- "NEUTRON_SECRET_KEY": "your_secret_key"
87
+ "NEUTRON_API_KEY": "your_api_key",
88
+ "NEUTRON_API_SECRET": "your_api_secret"
89
89
  }
90
90
  }
91
91
  }
@@ -105,8 +105,8 @@ Add to your Windsurf MCP configuration:
105
105
  "command": "npx",
106
106
  "args": ["-y", "neutron-mcp"],
107
107
  "env": {
108
- "NEUTRON_ACCESS_KEY": "your_access_key",
109
- "NEUTRON_SECRET_KEY": "your_secret_key"
108
+ "NEUTRON_API_KEY": "your_api_key",
109
+ "NEUTRON_API_SECRET": "your_api_secret"
110
110
  }
111
111
  }
112
112
  }
@@ -126,8 +126,8 @@ Add to your Cline MCP settings:
126
126
  "command": "npx",
127
127
  "args": ["-y", "neutron-mcp"],
128
128
  "env": {
129
- "NEUTRON_ACCESS_KEY": "your_access_key",
130
- "NEUTRON_SECRET_KEY": "your_secret_key"
129
+ "NEUTRON_API_KEY": "your_api_key",
130
+ "NEUTRON_API_SECRET": "your_api_secret"
131
131
  }
132
132
  }
133
133
  }
@@ -164,7 +164,7 @@ Once configured, just ask your AI assistant naturally:
164
164
 
165
165
  > "Set up a webhook for transaction notifications"
166
166
 
167
- > "What banks are supported for payouts in Nigeria?"
167
+ > "What banks are supported for payouts in Vietnam?"
168
168
 
169
169
  ---
170
170
 
@@ -189,7 +189,7 @@ Once configured, just ask your AI assistant naturally:
189
189
  | `neutron_create_transaction` | Create payment (Lightning, on-chain, USDT, fiat) |
190
190
  | `neutron_list_transactions` | List transactions with filters |
191
191
  | `neutron_get_transaction` | Get transaction status |
192
- | `neutron_confirm_transaction` | Confirm pending transaction |
192
+ | `neutron_confirm_transaction` | Confirm quoted transaction |
193
193
  | `neutron_cancel_transaction` | Cancel pending transaction |
194
194
 
195
195
  ### Webhooks
@@ -214,7 +214,7 @@ Once configured, just ask your AI assistant naturally:
214
214
  | **Bitcoin Lightning** | Bolt11 invoices, LNURL, Lightning Address |
215
215
  | **Bitcoin On-chain** | Standard BTC transactions |
216
216
  | **Stablecoins** | USDT on Ethereum (ERC20) and Tron (TRC20) |
217
- | **Fiat Payouts** | Bank transfers, Mobile money |
217
+ | **Fiat Payouts** | Bank transfers, Mobile money (VN, NG, KE, GH, etc.) |
218
218
 
219
219
  ---
220
220
 
@@ -227,7 +227,7 @@ Once configured, just ask your AI assistant naturally:
227
227
  > "Create a payment flow where users can pay $10/month in Bitcoin. Generate a Lightning invoice and set up a webhook to activate their account when paid."
228
228
 
229
229
  ### Payout System
230
- > "Build a function to pay out earnings to users. They can choose Lightning address, on-chain Bitcoin, or bank transfer in supported countries."
230
+ > "Build a function to pay out earnings to users in Vietnam. Send VND to their bank account from our BTC balance."
231
231
 
232
232
  ### Treasury Management
233
233
  > "Show me all my wallet balances and recent transactions. Then help me consolidate funds by transferring USDT to my main wallet."
@@ -238,9 +238,9 @@ Once configured, just ask your AI assistant naturally:
238
238
 
239
239
  | Variable | Required | Description |
240
240
  |----------|----------|-------------|
241
- | `NEUTRON_ACCESS_KEY` | Yes | Your Neutron API access key |
242
- | `NEUTRON_SECRET_KEY` | Yes | Your Neutron API secret key |
243
- | `NEUTRON_API_URL` | No | API URL (defaults to `https://api.neutron.me/v2`) |
241
+ | `NEUTRON_API_KEY` | Yes | Your Neutron API key |
242
+ | `NEUTRON_API_SECRET` | Yes | Your Neutron API secret |
243
+ | `NEUTRON_API_URL` | No | API URL (defaults to `https://enapi.npay.dev`) |
244
244
 
245
245
  ---
246
246
 
package/dist/index.js CHANGED
@@ -6,63 +6,26 @@ import { z } from "zod";
6
6
  import { NeutronClient } from "./neutron-client.js";
7
7
  // Validation schemas
8
8
  const CreateTransactionSchema = z.object({
9
- sourceMethod: z.enum([
10
- "lightning",
11
- "lightning_address",
12
- "lnurl",
13
- "bolt11",
14
- "on_chain",
15
- "eth",
16
- "tron",
17
- "bank",
18
- "mobile_money",
19
- "internal",
20
- ]),
9
+ extRefId: z.string().optional(),
21
10
  sourceCurrency: z.string(),
22
- sourceAmount: z.string().optional(),
23
- sourceWalletId: z.string().optional(),
24
- destMethod: z.enum([
25
- "lightning",
26
- "lightning_address",
27
- "lnurl",
28
- "bolt11",
29
- "on_chain",
30
- "eth",
31
- "tron",
32
- "bank",
33
- "mobile_money",
34
- "internal",
35
- ]),
11
+ sourceAmount: z.number().optional(),
12
+ sourceMethod: z.string(),
13
+ sourceNotes: z.string().optional(),
36
14
  destCurrency: z.string(),
37
- destAmount: z.string().optional(),
38
- destAddress: z.string().optional(),
39
- destLightningAddress: z.string().optional(),
40
- destBolt11: z.string().optional(),
41
- destAccountNumber: z.string().optional(),
42
- destBankCode: z.string().optional(),
43
- destPhoneNumber: z.string().optional(),
15
+ destAmount: z.number().optional(),
16
+ destMethod: z.string(),
17
+ destBankAcctNum: z.string().optional(),
18
+ destInstitutionCode: z.string().optional(),
44
19
  destRecipientName: z.string().optional(),
45
- destCountry: z.string().optional(),
46
- reference: z.string().optional(),
20
+ destCountryCode: z.string().optional(),
21
+ destAddress: z.string().optional(),
22
+ kycType: z.enum(["individual", "business"]).optional(),
47
23
  });
48
24
  const ListTransactionsSchema = z.object({
49
25
  status: z
50
- .enum(["pending", "processing", "completed", "failed", "cancelled"])
51
- .optional(),
52
- method: z
53
- .enum([
54
- "lightning",
55
- "lightning_address",
56
- "lnurl",
57
- "bolt11",
58
- "on_chain",
59
- "eth",
60
- "tron",
61
- "bank",
62
- "mobile_money",
63
- "internal",
64
- ])
26
+ .enum(["quoted", "pending", "processing", "completed", "failed", "cancelled"])
65
27
  .optional(),
28
+ method: z.string().optional(),
66
29
  currency: z.string().optional(),
67
30
  fromDate: z.string().optional(),
68
31
  toDate: z.string().optional(),
@@ -97,18 +60,18 @@ const UpdateWebhookSchema = z.object({
97
60
  });
98
61
  // Initialize Neutron client
99
62
  function createClient() {
100
- const apiUrl = process.env.NEUTRON_API_URL || "https://api.neutron.me/v2";
101
- const accessKey = process.env.NEUTRON_ACCESS_KEY;
102
- const secretKey = process.env.NEUTRON_SECRET_KEY;
103
- if (!accessKey || !secretKey) {
104
- throw new Error("NEUTRON_ACCESS_KEY and NEUTRON_SECRET_KEY environment variables are required");
63
+ const apiUrl = process.env.NEUTRON_API_URL || "https://enapi.npay.dev";
64
+ const apiKey = process.env.NEUTRON_API_KEY;
65
+ const apiSecret = process.env.NEUTRON_API_SECRET;
66
+ if (!apiKey || !apiSecret) {
67
+ throw new Error("NEUTRON_API_KEY and NEUTRON_API_SECRET environment variables are required");
105
68
  }
106
- return new NeutronClient({ apiUrl, accessKey, secretKey });
69
+ return new NeutronClient({ apiUrl, apiKey, apiSecret });
107
70
  }
108
71
  // Create MCP server
109
72
  const server = new Server({
110
73
  name: "neutron-mcp-server",
111
- version: "1.0.0",
74
+ version: "1.0.3",
112
75
  }, {
113
76
  capabilities: {
114
77
  tools: {},
@@ -118,7 +81,7 @@ const server = new Server({
118
81
  const tools = [
119
82
  {
120
83
  name: "neutron_get_account",
121
- description: "Get Neutron account information including name, email, and status",
84
+ description: "Get Neutron account information including display name, status, country, and timezone",
122
85
  inputSchema: {
123
86
  type: "object",
124
87
  properties: {},
@@ -167,7 +130,6 @@ const tools = [
167
130
  type: "string",
168
131
  enum: ["eth", "tron"],
169
132
  description: "Network for USDT address (eth for ERC20, tron for TRC20)",
170
- default: "tron",
171
133
  },
172
134
  },
173
135
  required: [],
@@ -175,106 +137,75 @@ const tools = [
175
137
  },
176
138
  {
177
139
  name: "neutron_create_transaction",
178
- description: `Create a new transaction. Supports Lightning payments (bolt11, LNURL, Lightning Address), Bitcoin on-chain, USDT (ERC20/TRC20), and fiat payouts (bank, mobile money).
140
+ description: `Create a new transaction. Supports Lightning payments, Bitcoin on-chain, USDT, and fiat payouts.
179
141
 
180
- Examples:
181
- - Lightning payment: sourceMethod="internal", destMethod="lightning_address", destLightningAddress="user@wallet.me"
182
- - Bitcoin withdrawal: sourceMethod="internal", destMethod="on_chain", destAddress="bc1q..."
183
- - USDT transfer: sourceMethod="internal", destMethod="tron", destAddress="T..."
184
- - Bank payout: sourceMethod="internal", destMethod="bank", destAccountNumber="...", destBankCode="...", destRecipientName="..."`,
142
+ Example for VND bank payout:
143
+ - sourceCurrency: "BTC", sourceMethod: "lightning", sourceAmount: 0.001
144
+ - destCurrency: "VND", destMethod: "vnd-instant", destAmount: 300000
145
+ - destBankAcctNum: "0123456789", destInstitutionCode: "970422"
146
+ - destRecipientName: "NGUYEN VAN A", destCountryCode: "VN"`,
185
147
  inputSchema: {
186
148
  type: "object",
187
149
  properties: {
188
- sourceMethod: {
150
+ extRefId: {
189
151
  type: "string",
190
- enum: [
191
- "lightning",
192
- "lightning_address",
193
- "lnurl",
194
- "bolt11",
195
- "on_chain",
196
- "eth",
197
- "tron",
198
- "bank",
199
- "mobile_money",
200
- "internal",
201
- ],
202
- description: "Source funding method",
152
+ description: "Your external reference ID for tracking",
203
153
  },
204
154
  sourceCurrency: {
205
155
  type: "string",
206
- description: "Source currency (BTC, USDT, USD, etc.)",
156
+ description: "Source currency (BTC, USDT, etc.)",
207
157
  },
208
158
  sourceAmount: {
209
- type: "string",
210
- description: "Amount to send from source (optional if destAmount specified)",
159
+ type: "number",
160
+ description: "Amount from source",
211
161
  },
212
- sourceWalletId: {
162
+ sourceMethod: {
213
163
  type: "string",
214
- description: "Specific wallet ID to fund from (optional)",
164
+ description: "Source method (lightning, on_chain, internal, etc.)",
215
165
  },
216
- destMethod: {
166
+ sourceNotes: {
217
167
  type: "string",
218
- enum: [
219
- "lightning",
220
- "lightning_address",
221
- "lnurl",
222
- "bolt11",
223
- "on_chain",
224
- "eth",
225
- "tron",
226
- "bank",
227
- "mobile_money",
228
- "internal",
229
- ],
230
- description: "Destination payout method",
168
+ description: "Notes for the source transaction",
231
169
  },
232
170
  destCurrency: {
233
171
  type: "string",
234
- description: "Destination currency",
172
+ description: "Destination currency (VND, USD, BTC, etc.)",
235
173
  },
236
174
  destAmount: {
237
- type: "string",
238
- description: "Amount to receive at destination (optional if sourceAmount specified)",
239
- },
240
- destAddress: {
241
- type: "string",
242
- description: "Destination address (for on_chain, eth, tron)",
243
- },
244
- destLightningAddress: {
245
- type: "string",
246
- description: "Lightning address (e.g., user@wallet.me)",
175
+ type: "number",
176
+ description: "Amount to destination",
247
177
  },
248
- destBolt11: {
178
+ destMethod: {
249
179
  type: "string",
250
- description: "Bolt11 Lightning invoice to pay",
180
+ description: "Destination method (vnd-instant, lightning, on_chain, tron, etc.)",
251
181
  },
252
- destAccountNumber: {
182
+ destBankAcctNum: {
253
183
  type: "string",
254
184
  description: "Bank account number (for bank payouts)",
255
185
  },
256
- destBankCode: {
186
+ destInstitutionCode: {
257
187
  type: "string",
258
- description: "Bank code/routing number",
188
+ description: "Bank/institution code",
259
189
  },
260
- destPhoneNumber: {
190
+ destRecipientName: {
261
191
  type: "string",
262
- description: "Phone number (for mobile money)",
192
+ description: "Recipient full legal name (for fiat payouts)",
263
193
  },
264
- destRecipientName: {
194
+ destCountryCode: {
265
195
  type: "string",
266
- description: "Recipient name for fiat payouts",
196
+ description: "Destination country code (VN, NG, etc.)",
267
197
  },
268
- destCountry: {
198
+ destAddress: {
269
199
  type: "string",
270
- description: "Destination country code (ISO 3166-1 alpha-2)",
200
+ description: "Crypto address (for on_chain, tron, eth)",
271
201
  },
272
- reference: {
202
+ kycType: {
273
203
  type: "string",
274
- description: "Custom reference ID for the transaction",
204
+ enum: ["individual", "business"],
205
+ description: "KYC type for recipient",
275
206
  },
276
207
  },
277
- required: ["sourceMethod", "sourceCurrency", "destMethod", "destCurrency"],
208
+ required: ["sourceCurrency", "sourceMethod", "destCurrency", "destMethod"],
278
209
  },
279
210
  },
280
211
  {
@@ -285,23 +216,18 @@ Examples:
285
216
  properties: {
286
217
  status: {
287
218
  type: "string",
288
- enum: ["pending", "processing", "completed", "failed", "cancelled"],
219
+ enum: [
220
+ "quoted",
221
+ "pending",
222
+ "processing",
223
+ "completed",
224
+ "failed",
225
+ "cancelled",
226
+ ],
289
227
  description: "Filter by transaction status",
290
228
  },
291
229
  method: {
292
230
  type: "string",
293
- enum: [
294
- "lightning",
295
- "lightning_address",
296
- "lnurl",
297
- "bolt11",
298
- "on_chain",
299
- "eth",
300
- "tron",
301
- "bank",
302
- "mobile_money",
303
- "internal",
304
- ],
305
231
  description: "Filter by transaction method",
306
232
  },
307
233
  currency: {
@@ -318,7 +244,7 @@ Examples:
318
244
  },
319
245
  limit: {
320
246
  type: "number",
321
- description: "Number of results to return (default 20)",
247
+ description: "Number of results to return",
322
248
  },
323
249
  offset: {
324
250
  type: "number",
@@ -336,7 +262,7 @@ Examples:
336
262
  properties: {
337
263
  transactionId: {
338
264
  type: "string",
339
- description: "The transaction ID to check",
265
+ description: "The transaction ID (txnId) to check",
340
266
  },
341
267
  },
342
268
  required: ["transactionId"],
@@ -344,7 +270,7 @@ Examples:
344
270
  },
345
271
  {
346
272
  name: "neutron_confirm_transaction",
347
- description: "Confirm a pending transaction to proceed with execution",
273
+ description: "Confirm a quoted transaction to proceed with execution",
348
274
  inputSchema: {
349
275
  type: "object",
350
276
  properties: {
@@ -358,7 +284,7 @@ Examples:
358
284
  },
359
285
  {
360
286
  name: "neutron_cancel_transaction",
361
- description: "Cancel a pending transaction",
287
+ description: "Cancel a pending or quoted transaction",
362
288
  inputSchema: {
363
289
  type: "object",
364
290
  properties: {
@@ -468,7 +394,7 @@ Examples:
468
394
  properties: {
469
395
  country: {
470
396
  type: "string",
471
- description: "Country code (ISO 3166-1 alpha-2, e.g., NG, KE, GH)",
397
+ description: "Country code (ISO 3166-1 alpha-2, e.g., VN, NG, KE, GH)",
472
398
  },
473
399
  },
474
400
  required: ["country"],
@@ -519,30 +445,42 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
519
445
  }
520
446
  case "neutron_create_transaction": {
521
447
  const validated = CreateTransactionSchema.parse(args);
448
+ const reqDetails = {};
449
+ if (validated.destBankAcctNum)
450
+ reqDetails.bankAcctNum = validated.destBankAcctNum;
451
+ if (validated.destInstitutionCode)
452
+ reqDetails.institutionCode = validated.destInstitutionCode;
453
+ if (validated.destAddress)
454
+ reqDetails.address = validated.destAddress;
522
455
  const transaction = await client.createTransaction({
456
+ extRefId: validated.extRefId,
523
457
  sourceReq: {
458
+ ccy: validated.sourceCurrency,
459
+ amtRequested: validated.sourceAmount,
524
460
  method: validated.sourceMethod,
525
- currency: validated.sourceCurrency,
526
- amount: validated.sourceAmount,
527
- walletId: validated.sourceWalletId,
461
+ notes: validated.sourceNotes,
462
+ reqDetails: {},
528
463
  },
529
464
  destReq: {
465
+ ccy: validated.destCurrency,
466
+ amtRequested: validated.destAmount,
530
467
  method: validated.destMethod,
531
- currency: validated.destCurrency,
532
- amount: validated.destAmount,
533
- address: validated.destAddress,
534
- lightningAddress: validated.destLightningAddress,
535
- bolt11: validated.destBolt11,
536
- accountNumber: validated.destAccountNumber,
537
- bankCode: validated.destBankCode,
538
- phoneNumber: validated.destPhoneNumber,
539
- recipientName: validated.destRecipientName,
540
- country: validated.destCountry,
468
+ reqDetails,
469
+ kyc: validated.kycType
470
+ ? {
471
+ type: validated.kycType,
472
+ details: {
473
+ legalFullName: validated.destRecipientName,
474
+ countryCode: validated.destCountryCode,
475
+ },
476
+ }
477
+ : undefined,
541
478
  },
542
- reference: validated.reference,
543
479
  });
544
480
  return {
545
- content: [{ type: "text", text: JSON.stringify(transaction, null, 2) }],
481
+ content: [
482
+ { type: "text", text: JSON.stringify(transaction, null, 2) },
483
+ ],
546
484
  };
547
485
  }
548
486
  case "neutron_list_transactions": {
@@ -557,28 +495,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
557
495
  offset: validated.offset,
558
496
  });
559
497
  return {
560
- content: [{ type: "text", text: JSON.stringify(transactions, null, 2) }],
498
+ content: [
499
+ { type: "text", text: JSON.stringify(transactions, null, 2) },
500
+ ],
561
501
  };
562
502
  }
563
503
  case "neutron_get_transaction": {
564
504
  const { transactionId } = args;
565
- const transaction = await client.getTransactionStatus(transactionId);
505
+ const transaction = await client.getTransaction(transactionId);
566
506
  return {
567
- content: [{ type: "text", text: JSON.stringify(transaction, null, 2) }],
507
+ content: [
508
+ { type: "text", text: JSON.stringify(transaction, null, 2) },
509
+ ],
568
510
  };
569
511
  }
570
512
  case "neutron_confirm_transaction": {
571
513
  const { transactionId } = args;
572
514
  const transaction = await client.confirmTransaction(transactionId);
573
515
  return {
574
- content: [{ type: "text", text: JSON.stringify(transaction, null, 2) }],
516
+ content: [
517
+ { type: "text", text: JSON.stringify(transaction, null, 2) },
518
+ ],
575
519
  };
576
520
  }
577
521
  case "neutron_cancel_transaction": {
578
522
  const { transactionId } = args;
579
523
  const transaction = await client.cancelTransaction(transactionId);
580
524
  return {
581
- content: [{ type: "text", text: JSON.stringify(transaction, null, 2) }],
525
+ content: [
526
+ { type: "text", text: JSON.stringify(transaction, null, 2) },
527
+ ],
582
528
  };
583
529
  }
584
530
  case "neutron_create_webhook": {
@@ -612,14 +558,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
612
558
  const { webhookId } = args;
613
559
  await client.deleteWebhook(webhookId);
614
560
  return {
615
- content: [{ type: "text", text: `Webhook ${webhookId} deleted successfully` }],
561
+ content: [
562
+ { type: "text", text: `Webhook ${webhookId} deleted successfully` },
563
+ ],
616
564
  };
617
565
  }
618
566
  case "neutron_get_fiat_institutions": {
619
567
  const { country } = args;
620
568
  const institutions = await client.getFiatInstitutions(country);
621
569
  return {
622
- content: [{ type: "text", text: JSON.stringify(institutions, null, 2) }],
570
+ content: [
571
+ { type: "text", text: JSON.stringify(institutions, null, 2) },
572
+ ],
623
573
  };
624
574
  }
625
575
  default:
@@ -1,12 +1,13 @@
1
1
  import type { NeutronConfig, Account, Wallet, ReceiveAddress, Transaction, CreateTransactionRequest, TransactionListParams, TransactionListResponse, Webhook, CreateWebhookRequest, UpdateWebhookRequest, FiatInstitution } from "./types.js";
2
2
  export declare class NeutronClient {
3
3
  private config;
4
- private token;
4
+ private accountId;
5
+ private accessToken;
5
6
  private tokenExpiry;
6
7
  constructor(config: NeutronConfig);
7
8
  private generateSignature;
9
+ private ensureAuthenticated;
8
10
  private request;
9
- authenticate(): Promise<void>;
10
11
  getAccount(): Promise<Account>;
11
12
  getWallets(): Promise<Wallet[]>;
12
13
  getWallet(walletId: string): Promise<Wallet>;
@@ -14,7 +15,7 @@ export declare class NeutronClient {
14
15
  getUsdtAddress(network?: "eth" | "tron"): Promise<ReceiveAddress>;
15
16
  createTransaction(request: CreateTransactionRequest): Promise<Transaction>;
16
17
  getTransactions(params?: TransactionListParams): Promise<TransactionListResponse>;
17
- getTransactionStatus(transactionId: string): Promise<Transaction>;
18
+ getTransaction(transactionId: string): Promise<Transaction>;
18
19
  confirmTransaction(transactionId: string): Promise<Transaction>;
19
20
  cancelTransaction(transactionId: string): Promise<Transaction>;
20
21
  createWebhook(request: CreateWebhookRequest): Promise<Webhook>;
@@ -1,75 +1,96 @@
1
1
  import crypto from "crypto";
2
2
  export class NeutronClient {
3
3
  config;
4
- token = null;
4
+ accountId = null;
5
+ accessToken = null;
5
6
  tokenExpiry = 0;
6
7
  constructor(config) {
7
8
  this.config = config;
8
9
  }
9
- generateSignature(method, path, timestamp, body) {
10
- const payload = `${method}${path}${timestamp}${body || ""}`;
10
+ generateSignature(payload) {
11
+ // HMAC-SHA256 signature: {apiKey}&payload={payload}
12
+ const stringToSign = `${this.config.apiKey}&payload=${payload}`;
11
13
  return crypto
12
- .createHmac("sha256", this.config.secretKey)
13
- .update(payload)
14
+ .createHmac("sha256", this.config.apiSecret)
15
+ .update(stringToSign)
14
16
  .digest("hex");
15
17
  }
18
+ async ensureAuthenticated() {
19
+ // Check if we have a valid token
20
+ if (this.accessToken && this.accountId && Date.now() < this.tokenExpiry) {
21
+ return;
22
+ }
23
+ // Authenticate to get accountId and accessToken
24
+ const payload = JSON.stringify({ test: "auth" });
25
+ const signature = this.generateSignature(payload);
26
+ const response = await fetch(`${this.config.apiUrl}/api/v2/authentication/token-signature`, {
27
+ method: "POST",
28
+ headers: {
29
+ "Content-Type": "application/json",
30
+ "X-Api-Key": this.config.apiKey,
31
+ "X-Api-Signature": signature,
32
+ },
33
+ body: payload,
34
+ });
35
+ if (!response.ok) {
36
+ const error = await response.json().catch(() => ({}));
37
+ throw new Error(`Authentication failed: ${response.status} - ${error.message || response.statusText}`);
38
+ }
39
+ const authResult = (await response.json());
40
+ this.accountId = authResult.accountId;
41
+ this.accessToken = authResult.accessToken;
42
+ // Set expiry (parse the expiredAt or default to 1 hour)
43
+ this.tokenExpiry = authResult.expiredAt
44
+ ? new Date(authResult.expiredAt).getTime()
45
+ : Date.now() + 3600000;
46
+ }
16
47
  async request(method, path, body) {
17
- const timestamp = Date.now().toString();
18
- const bodyString = body ? JSON.stringify(body) : undefined;
19
- const signature = this.generateSignature(method, path, timestamp, bodyString);
48
+ await this.ensureAuthenticated();
20
49
  const headers = {
21
50
  "Content-Type": "application/json",
22
- "X-Access-Key": this.config.accessKey,
23
- "X-Timestamp": timestamp,
24
- "X-Signature": signature,
51
+ Authorization: `Bearer ${this.accessToken}`,
25
52
  };
26
- // Add bearer token if authenticated
27
- if (this.token && Date.now() < this.tokenExpiry) {
28
- headers["Authorization"] = `Bearer ${this.token}`;
29
- }
30
- const response = await fetch(`${this.config.apiUrl}${path}`, {
53
+ const url = `${this.config.apiUrl}${path}`;
54
+ const response = await fetch(url, {
31
55
  method,
32
56
  headers,
33
- body: bodyString,
57
+ body: body ? JSON.stringify(body) : undefined,
34
58
  });
35
59
  if (!response.ok) {
36
60
  const error = await response.json().catch(() => ({}));
37
61
  throw new Error(`API Error: ${response.status} - ${error.message || response.statusText}`);
38
62
  }
39
- const result = (await response.json());
40
- if (!result.success && result.error) {
41
- throw new Error(`${result.error.code}: ${result.error.message}`);
42
- }
43
- return result.data;
44
- }
45
- // Authentication
46
- async authenticate() {
47
- const result = await this.request("POST", "/authenticate");
48
- this.token = result.token;
49
- this.tokenExpiry = Date.now() + result.expiresIn * 1000;
63
+ return (await response.json());
50
64
  }
51
65
  // Account Management
52
66
  async getAccount() {
53
- return this.request("GET", "/account");
67
+ await this.ensureAuthenticated();
68
+ return this.request("GET", `/api/v2/account/${this.accountId}`);
54
69
  }
55
70
  async getWallets() {
56
- return this.request("GET", "/account/wallets");
71
+ await this.ensureAuthenticated();
72
+ return this.request("GET", `/api/v2/account/${this.accountId}/wallets`);
57
73
  }
58
74
  async getWallet(walletId) {
59
- return this.request("GET", `/wallet/${walletId}`);
75
+ await this.ensureAuthenticated();
76
+ return this.request("GET", `/api/v2/account/${this.accountId}/wallet/${walletId}`);
60
77
  }
61
78
  // Receive Addresses
62
79
  async getBitcoinAddress() {
63
- return this.request("GET", "/bitcoin/receive-address");
80
+ await this.ensureAuthenticated();
81
+ return this.request("GET", `/api/v2/account/${this.accountId}/bitcoin/receive-address`);
64
82
  }
65
83
  async getUsdtAddress(network = "tron") {
66
- return this.request("GET", `/usdt/receive-address?network=${network}`);
84
+ await this.ensureAuthenticated();
85
+ return this.request("GET", `/api/v2/account/${this.accountId}/usdt/receive-address?network=${network}`);
67
86
  }
68
87
  // Transactions
69
88
  async createTransaction(request) {
70
- return this.request("POST", "/transaction", request);
89
+ await this.ensureAuthenticated();
90
+ return this.request("POST", `/api/v2/account/${this.accountId}/transaction`, request);
71
91
  }
72
92
  async getTransactions(params) {
93
+ await this.ensureAuthenticated();
73
94
  const queryParams = new URLSearchParams();
74
95
  if (params) {
75
96
  Object.entries(params).forEach(([key, value]) => {
@@ -79,32 +100,40 @@ export class NeutronClient {
79
100
  });
80
101
  }
81
102
  const query = queryParams.toString();
82
- return this.request("GET", `/transactions${query ? `?${query}` : ""}`);
103
+ return this.request("GET", `/api/v2/account/${this.accountId}/transactions${query ? `?${query}` : ""}`);
83
104
  }
84
- async getTransactionStatus(transactionId) {
85
- return this.request("GET", `/transaction/${transactionId}/status`);
105
+ async getTransaction(transactionId) {
106
+ await this.ensureAuthenticated();
107
+ return this.request("GET", `/api/v2/account/${this.accountId}/transaction/${transactionId}`);
86
108
  }
87
109
  async confirmTransaction(transactionId) {
88
- return this.request("PUT", `/transaction/${transactionId}/confirm`);
110
+ await this.ensureAuthenticated();
111
+ return this.request("PUT", `/api/v2/account/${this.accountId}/transaction/${transactionId}/confirm`);
89
112
  }
90
113
  async cancelTransaction(transactionId) {
91
- return this.request("PATCH", `/transaction/${transactionId}`);
114
+ await this.ensureAuthenticated();
115
+ return this.request("DELETE", `/api/v2/account/${this.accountId}/transaction/${transactionId}`);
92
116
  }
93
117
  // Webhooks
94
118
  async createWebhook(request) {
95
- return this.request("POST", "/webhook", request);
119
+ await this.ensureAuthenticated();
120
+ return this.request("POST", `/api/v2/account/${this.accountId}/webhook`, request);
96
121
  }
97
122
  async getWebhooks() {
98
- return this.request("GET", "/webhooks");
123
+ await this.ensureAuthenticated();
124
+ return this.request("GET", `/api/v2/account/${this.accountId}/webhooks`);
99
125
  }
100
126
  async updateWebhook(webhookId, request) {
101
- return this.request("PUT", `/webhook/${webhookId}`, request);
127
+ await this.ensureAuthenticated();
128
+ return this.request("PUT", `/api/v2/account/${this.accountId}/webhook/${webhookId}`, request);
102
129
  }
103
130
  async deleteWebhook(webhookId) {
104
- await this.request("DELETE", `/webhook/${webhookId}`);
131
+ await this.ensureAuthenticated();
132
+ await this.request("DELETE", `/api/v2/account/${this.accountId}/webhook/${webhookId}`);
105
133
  }
106
134
  // Reference Data
107
135
  async getFiatInstitutions(country) {
108
- return this.request("GET", `/fiat-institutions/${country}`);
136
+ await this.ensureAuthenticated();
137
+ return this.request("GET", `/api/v2/reference/fiat-institutions/${country}`);
109
138
  }
110
139
  }
package/dist/types.d.ts CHANGED
@@ -1,14 +1,24 @@
1
1
  export interface NeutronConfig {
2
2
  apiUrl: string;
3
- accessKey: string;
4
- secretKey: string;
3
+ apiKey: string;
4
+ apiSecret: string;
5
+ }
6
+ export interface AuthResponse {
7
+ accountId: string;
8
+ accessToken: string;
9
+ refreshToken: string;
10
+ expiredAt: string;
11
+ scope: string;
5
12
  }
6
13
  export interface Account {
7
14
  id: string;
8
- name: string;
9
- email: string;
10
- status: string;
15
+ parentId?: string;
16
+ displayName: string;
17
+ accountStatus: string;
18
+ countryCode: string;
19
+ timezone: string;
11
20
  createdAt: string;
21
+ updatedAt: string;
12
22
  }
13
23
  export interface Wallet {
14
24
  id: string;
@@ -23,62 +33,49 @@ export interface ReceiveAddress {
23
33
  network?: string;
24
34
  expiresAt?: string;
25
35
  }
26
- export type TransactionMethod = "lightning" | "lightning_address" | "lnurl" | "bolt11" | "on_chain" | "eth" | "tron" | "bank" | "mobile_money" | "internal";
27
- export type TransactionStatus = "pending" | "processing" | "completed" | "failed" | "cancelled";
28
- export interface TransactionSource {
29
- method: TransactionMethod;
30
- currency: string;
31
- amount?: string;
32
- walletId?: string;
36
+ export type TransactionMethod = "lightning" | "lightning_address" | "lnurl" | "bolt11" | "on_chain" | "eth" | "tron" | "bank" | "mobile_money" | "vnd-instant" | "internal";
37
+ export type TransactionState = "quoted" | "pending" | "processing" | "completed" | "failed" | "cancelled";
38
+ export interface TransactionSourceReq {
39
+ ccy: string;
40
+ amtRequested?: number;
41
+ method: string;
42
+ notes?: string;
43
+ reqDetails?: Record<string, unknown>;
33
44
  }
34
- export interface TransactionDestination {
35
- method: TransactionMethod;
36
- currency: string;
37
- amount?: string;
38
- address?: string;
39
- lightningAddress?: string;
40
- bolt11?: string;
41
- accountNumber?: string;
42
- bankCode?: string;
43
- phoneNumber?: string;
44
- recipientName?: string;
45
- country?: string;
45
+ export interface TransactionDestReq {
46
+ ccy: string;
47
+ amtRequested?: number;
48
+ method: string;
49
+ reqDetails?: Record<string, unknown>;
50
+ kyc?: {
51
+ type: "individual" | "business";
52
+ details: Record<string, unknown>;
53
+ };
46
54
  }
47
55
  export interface CreateTransactionRequest {
48
- sourceReq: TransactionSource;
49
- destReq: TransactionDestination;
50
- reference?: string;
51
- metadata?: Record<string, unknown>;
56
+ extRefId?: string;
57
+ sourceReq: TransactionSourceReq;
58
+ destReq: TransactionDestReq;
59
+ sourceOfFunds?: {
60
+ purpose?: number;
61
+ source?: number;
62
+ relationship?: number;
63
+ };
52
64
  }
53
65
  export interface Transaction {
54
- id: string;
55
- reference: string;
56
- status: TransactionStatus;
57
- source: {
58
- method: TransactionMethod;
59
- currency: string;
60
- amount: string;
61
- };
62
- destination: {
63
- method: TransactionMethod;
64
- currency: string;
65
- amount: string;
66
- address?: string;
67
- };
68
- fees: {
69
- amount: string;
70
- currency: string;
71
- };
72
- exchangeRate?: string;
73
- paymentRequest?: string;
74
- createdAt: string;
75
- updatedAt: string;
66
+ txnId: string;
67
+ extRefId?: string;
68
+ txnState: TransactionState;
69
+ fxRate?: number;
70
+ sourceReq: TransactionSourceReq;
71
+ destReq: TransactionDestReq;
72
+ createdAt?: string;
73
+ updatedAt?: string;
76
74
  completedAt?: string;
77
- metadata?: Record<string, unknown>;
78
75
  }
79
76
  export interface TransactionListParams {
80
- status?: TransactionStatus;
81
- method?: TransactionMethod;
77
+ status?: TransactionState;
78
+ method?: string;
82
79
  currency?: string;
83
80
  fromDate?: string;
84
81
  toDate?: string;
@@ -96,7 +93,7 @@ export interface Webhook {
96
93
  id: string;
97
94
  url: string;
98
95
  events: WebhookEvent[];
99
- secret: string;
96
+ secret?: string;
100
97
  status: "active" | "inactive";
101
98
  createdAt: string;
102
99
  }
@@ -116,11 +113,3 @@ export interface FiatInstitution {
116
113
  type: "bank" | "mobile_money";
117
114
  supportedCurrencies: string[];
118
115
  }
119
- export interface ApiResponse<T> {
120
- success: boolean;
121
- data?: T;
122
- error?: {
123
- code: string;
124
- message: string;
125
- };
126
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neutron-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "MCP server for Neutron - Lightning payments, Bitcoin, USDT, and fiat transactions for AI-powered applications",
5
5
  "main": "dist/index.js",
6
6
  "bin": {