@aura-payments/mcp-server 1.0.0 → 1.1.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/dist/bin.js +309 -20
- package/dist/bin.mjs +309 -20
- package/dist/index.d.mts +77 -8
- package/dist/index.d.ts +77 -8
- package/dist/index.js +302 -20
- package/dist/index.mjs +295 -21
- package/package.json +19 -5
- package/dist/bin.js.map +0 -1
- package/dist/bin.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -4,13 +4,55 @@ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mc
|
|
|
4
4
|
import { AuraClient, AuraAuthenticationError, AuraNotFoundError, AuraValidationError, AuraRateLimitError, AuraTimeoutError, AuraAPIError, AuraError } from '@aura-payments/sdk';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
|
+
// src/api-key.ts
|
|
8
|
+
var API_KEY_PREFIXES = [
|
|
9
|
+
"sk_test_",
|
|
10
|
+
"sk_live_",
|
|
11
|
+
"pk_test_",
|
|
12
|
+
"pk_live_"
|
|
13
|
+
];
|
|
14
|
+
function maskApiKey(apiKey) {
|
|
15
|
+
const revealed = Math.min(8, Math.floor(apiKey.length / 2));
|
|
16
|
+
return `${apiKey.slice(0, revealed)}\u2026(${apiKey.length} chars)`;
|
|
17
|
+
}
|
|
18
|
+
function parseApiKey(apiKey) {
|
|
19
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
20
|
+
throw new MissingAuraApiKeyError();
|
|
21
|
+
}
|
|
22
|
+
const prefix = API_KEY_PREFIXES.find((p) => apiKey.startsWith(p));
|
|
23
|
+
if (!prefix) {
|
|
24
|
+
throw new MalformedAuraApiKeyError(apiKey);
|
|
25
|
+
}
|
|
26
|
+
return { prefix, mode: prefix.includes("_test_") ? "test" : "live" };
|
|
27
|
+
}
|
|
28
|
+
function resolveKeyMode(apiKey) {
|
|
29
|
+
try {
|
|
30
|
+
return parseApiKey(apiKey).mode;
|
|
31
|
+
} catch (err) {
|
|
32
|
+
return err instanceof MissingAuraApiKeyError ? "unconfigured" : "invalid";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
var MissingAuraApiKeyError = class extends Error {
|
|
36
|
+
constructor() {
|
|
37
|
+
super(
|
|
38
|
+
'AURA_API_KEY not set. Configure it in your MCP client config \u2014 for example in mcp.json: { "mcpServers": { "aura": { "command": "aura-mcp", "env": { "AURA_API_KEY": "pk_live_..." } } } }. Get a key at https://getaura.sh.'
|
|
39
|
+
);
|
|
40
|
+
this.name = "MissingAuraApiKeyError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var MalformedAuraApiKeyError = class extends Error {
|
|
44
|
+
constructor(apiKey) {
|
|
45
|
+
super(
|
|
46
|
+
`AURA_API_KEY is malformed (got ${maskApiKey(apiKey)}). An Aura API key must start with one of: ${API_KEY_PREFIXES.join(", ")}. Check for a truncated copy/paste, a shell-quoting problem, or a key from a different service. Issue a new key at https://getaura.sh.`
|
|
47
|
+
);
|
|
48
|
+
this.name = "MalformedAuraApiKeyError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
7
51
|
var cached = null;
|
|
8
52
|
function getClient() {
|
|
9
53
|
if (cached) return cached;
|
|
10
54
|
const apiKey = process.env.AURA_API_KEY;
|
|
11
|
-
|
|
12
|
-
throw new MissingAuraApiKeyError();
|
|
13
|
-
}
|
|
55
|
+
parseApiKey(apiKey);
|
|
14
56
|
cached = new AuraClient({
|
|
15
57
|
apiKey,
|
|
16
58
|
baseUrl: process.env.AURA_BASE_URL,
|
|
@@ -19,14 +61,6 @@ function getClient() {
|
|
|
19
61
|
});
|
|
20
62
|
return cached;
|
|
21
63
|
}
|
|
22
|
-
var MissingAuraApiKeyError = class extends Error {
|
|
23
|
-
constructor() {
|
|
24
|
-
super(
|
|
25
|
-
'AURA_API_KEY not set. Configure it in your MCP client config \u2014 for example in mcp.json: { "mcpServers": { "aura": { "command": "aura-mcp", "env": { "AURA_API_KEY": "pk_live_..." } } } }. Get a key at https://getaura.sh.'
|
|
26
|
-
);
|
|
27
|
-
this.name = "MissingAuraApiKeyError";
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
64
|
|
|
31
65
|
// src/resources/agents.ts
|
|
32
66
|
function registerAgentResources(server) {
|
|
@@ -65,6 +99,39 @@ function registerAgentResources(server) {
|
|
|
65
99
|
}
|
|
66
100
|
);
|
|
67
101
|
}
|
|
102
|
+
var COLLECTION_LIMIT = 50;
|
|
103
|
+
function registerEscrowResources(server) {
|
|
104
|
+
server.resource("escrows", "aura://escrows", async (uri) => {
|
|
105
|
+
const client = getClient();
|
|
106
|
+
const page = await client.escrows.list({ limit: COLLECTION_LIMIT });
|
|
107
|
+
return {
|
|
108
|
+
contents: [
|
|
109
|
+
{
|
|
110
|
+
uri: uri.href,
|
|
111
|
+
mimeType: "application/json",
|
|
112
|
+
text: JSON.stringify(page, null, 2)
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
server.resource(
|
|
118
|
+
"escrow",
|
|
119
|
+
new ResourceTemplate("aura://escrows/{id}", { list: void 0 }),
|
|
120
|
+
async (uri, { id }) => {
|
|
121
|
+
const client = getClient();
|
|
122
|
+
const escrow = await client.escrows.get(String(id));
|
|
123
|
+
return {
|
|
124
|
+
contents: [
|
|
125
|
+
{
|
|
126
|
+
uri: uri.href,
|
|
127
|
+
mimeType: "application/json",
|
|
128
|
+
text: JSON.stringify(escrow, null, 2)
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
68
135
|
function registerMandateResources(server) {
|
|
69
136
|
server.resource(
|
|
70
137
|
"mandates-pending",
|
|
@@ -101,6 +168,72 @@ function registerMandateResources(server) {
|
|
|
101
168
|
}
|
|
102
169
|
);
|
|
103
170
|
}
|
|
171
|
+
var COLLECTION_LIMIT2 = 50;
|
|
172
|
+
function registerWalletResources(server) {
|
|
173
|
+
server.resource("wallets", "aura://wallets", async (uri) => {
|
|
174
|
+
const client = getClient();
|
|
175
|
+
const page = await client.wallets.list({ limit: COLLECTION_LIMIT2 });
|
|
176
|
+
return {
|
|
177
|
+
contents: [
|
|
178
|
+
{
|
|
179
|
+
uri: uri.href,
|
|
180
|
+
mimeType: "application/json",
|
|
181
|
+
text: JSON.stringify(page, null, 2)
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
server.resource(
|
|
187
|
+
"wallet",
|
|
188
|
+
new ResourceTemplate("aura://wallets/{id}", { list: void 0 }),
|
|
189
|
+
async (uri, { id }) => {
|
|
190
|
+
const client = getClient();
|
|
191
|
+
const wallet = await client.wallets.get(String(id));
|
|
192
|
+
return {
|
|
193
|
+
contents: [
|
|
194
|
+
{
|
|
195
|
+
uri: uri.href,
|
|
196
|
+
mimeType: "application/json",
|
|
197
|
+
text: JSON.stringify(wallet, null, 2)
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
server.resource(
|
|
204
|
+
"wallet-balance",
|
|
205
|
+
new ResourceTemplate("aura://wallets/{id}/balance", { list: void 0 }),
|
|
206
|
+
async (uri, { id }) => {
|
|
207
|
+
const client = getClient();
|
|
208
|
+
const balance = await client.wallets.getBalance(String(id));
|
|
209
|
+
return {
|
|
210
|
+
contents: [
|
|
211
|
+
{
|
|
212
|
+
uri: uri.href,
|
|
213
|
+
mimeType: "application/json",
|
|
214
|
+
text: JSON.stringify(balance, null, 2)
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/annotations.ts
|
|
223
|
+
function readOnly(title) {
|
|
224
|
+
return { title, readOnlyHint: true };
|
|
225
|
+
}
|
|
226
|
+
function write(title, idempotent = false) {
|
|
227
|
+
return {
|
|
228
|
+
title,
|
|
229
|
+
readOnlyHint: false,
|
|
230
|
+
destructiveHint: false,
|
|
231
|
+
...idempotent ? { idempotentHint: true } : {}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function destructive(title) {
|
|
235
|
+
return { title, readOnlyHint: false, destructiveHint: true };
|
|
236
|
+
}
|
|
104
237
|
async function withToolErrorHandling(body, successFormatter = defaultJsonFormatter) {
|
|
105
238
|
try {
|
|
106
239
|
const result = await body();
|
|
@@ -115,7 +248,7 @@ function defaultJsonFormatter(data) {
|
|
|
115
248
|
return JSON.stringify(data, null, 2);
|
|
116
249
|
}
|
|
117
250
|
function formatError(err) {
|
|
118
|
-
if (err instanceof MissingAuraApiKeyError) {
|
|
251
|
+
if (err instanceof MissingAuraApiKeyError || err instanceof MalformedAuraApiKeyError) {
|
|
119
252
|
return errorResult("CONFIG_ERROR", err.message);
|
|
120
253
|
}
|
|
121
254
|
if (err instanceof AuraAuthenticationError) {
|
|
@@ -203,6 +336,8 @@ function registerAgentTools(server) {
|
|
|
203
336
|
autoApproveBelow: z.string().optional()
|
|
204
337
|
}).optional()
|
|
205
338
|
},
|
|
339
|
+
// Additive: provisions a new agent and its wallet. No funds move.
|
|
340
|
+
write("Create Agent"),
|
|
206
341
|
async (args) => withToolErrorHandling(async () => {
|
|
207
342
|
const client = getClient();
|
|
208
343
|
return client.agents.create(args);
|
|
@@ -217,6 +352,7 @@ function registerAgentTools(server) {
|
|
|
217
352
|
limit: z.number().int().min(1).max(200).optional(),
|
|
218
353
|
offset: z.number().int().min(0).optional()
|
|
219
354
|
},
|
|
355
|
+
readOnly("List Agents"),
|
|
220
356
|
async (args) => withToolErrorHandling(async () => {
|
|
221
357
|
const client = getClient();
|
|
222
358
|
return client.agents.list(args);
|
|
@@ -228,6 +364,7 @@ function registerAgentTools(server) {
|
|
|
228
364
|
{
|
|
229
365
|
agentId: z.string().uuid()
|
|
230
366
|
},
|
|
367
|
+
readOnly("Get Agent"),
|
|
231
368
|
async ({ agentId }) => withToolErrorHandling(async () => {
|
|
232
369
|
const client = getClient();
|
|
233
370
|
return client.agents.get(agentId);
|
|
@@ -239,6 +376,7 @@ function registerAgentTools(server) {
|
|
|
239
376
|
{
|
|
240
377
|
agentId: z.string().uuid()
|
|
241
378
|
},
|
|
379
|
+
readOnly("Get Agent Balance"),
|
|
242
380
|
async ({ agentId }) => withToolErrorHandling(async () => {
|
|
243
381
|
const client = getClient();
|
|
244
382
|
return client.agents.getBalance(agentId);
|
|
@@ -251,6 +389,8 @@ function registerAgentTools(server) {
|
|
|
251
389
|
agentId: z.string().uuid(),
|
|
252
390
|
reason: z.string().max(500).optional().describe("Surfaced in activity event metadata for audit trail")
|
|
253
391
|
},
|
|
392
|
+
// Halts an existing agent AND cascade-rejects its in-flight mandates.
|
|
393
|
+
destructive("Freeze Agent (kill switch)"),
|
|
254
394
|
async (args) => withToolErrorHandling(async () => {
|
|
255
395
|
const client = getClient();
|
|
256
396
|
return client.agents.freeze(args);
|
|
@@ -262,6 +402,8 @@ function registerAgentTools(server) {
|
|
|
262
402
|
{
|
|
263
403
|
agentId: z.string().uuid()
|
|
264
404
|
},
|
|
405
|
+
// Re-enables autonomous spending on an existing agent.
|
|
406
|
+
destructive("Unfreeze Agent (resumes autonomous spending)"),
|
|
265
407
|
async (args) => withToolErrorHandling(async () => {
|
|
266
408
|
const client = getClient();
|
|
267
409
|
return client.agents.unfreeze(args);
|
|
@@ -278,11 +420,24 @@ function registerAgentTools(server) {
|
|
|
278
420
|
reasoning: z.string().optional(),
|
|
279
421
|
metadata: z.record(z.unknown()).optional()
|
|
280
422
|
},
|
|
423
|
+
// NOT read-only despite being a dry run: when the decision requires human
|
|
424
|
+
// approval the engine persists a new mandate row. Additive, never
|
|
425
|
+
// destructive — it cannot execute the transaction it evaluates.
|
|
426
|
+
write("Evaluate Policy (dry run, may create a mandate)"),
|
|
281
427
|
async (args) => withToolErrorHandling(async () => {
|
|
282
428
|
const client = getClient();
|
|
283
429
|
return client.agents.evaluate(args);
|
|
284
430
|
})
|
|
285
431
|
);
|
|
432
|
+
return [
|
|
433
|
+
"aura_create_agent",
|
|
434
|
+
"aura_list_agents",
|
|
435
|
+
"aura_get_agent",
|
|
436
|
+
"aura_get_agent_balance",
|
|
437
|
+
"aura_freeze_agent",
|
|
438
|
+
"aura_unfreeze_agent",
|
|
439
|
+
"aura_evaluate_policy"
|
|
440
|
+
];
|
|
286
441
|
}
|
|
287
442
|
var ChainSchema2 = z.enum(["ARC", "ARB", "BASE", "ETH", "MATIC"]);
|
|
288
443
|
var SplitInputSchema = z.object({
|
|
@@ -319,6 +474,8 @@ function registerEscrowTools(server) {
|
|
|
319
474
|
chain: ChainSchema2.optional().describe("Target chain. Defaults to ARC"),
|
|
320
475
|
splits: z.array(SplitInputSchema).min(1).describe("Payment splits. Percentages must sum to 100.")
|
|
321
476
|
},
|
|
477
|
+
// Additive: creates a new escrow record. No funds move until `fund`.
|
|
478
|
+
write("Create Escrow"),
|
|
322
479
|
async (args) => withToolErrorHandling(async () => {
|
|
323
480
|
const client = getClient();
|
|
324
481
|
return client.escrows.create(args);
|
|
@@ -330,6 +487,7 @@ function registerEscrowTools(server) {
|
|
|
330
487
|
{
|
|
331
488
|
escrowId: z.string().uuid()
|
|
332
489
|
},
|
|
490
|
+
readOnly("Get Escrow"),
|
|
333
491
|
async ({ escrowId }) => withToolErrorHandling(async () => {
|
|
334
492
|
const client = getClient();
|
|
335
493
|
return client.escrows.get(escrowId);
|
|
@@ -354,6 +512,7 @@ function registerEscrowTools(server) {
|
|
|
354
512
|
limit: z.number().int().min(1).max(200).optional(),
|
|
355
513
|
offset: z.number().int().min(0).optional()
|
|
356
514
|
},
|
|
515
|
+
readOnly("List Escrows"),
|
|
357
516
|
async (args) => withToolErrorHandling(async () => {
|
|
358
517
|
const client = getClient();
|
|
359
518
|
return client.escrows.list(args);
|
|
@@ -368,6 +527,8 @@ function registerEscrowTools(server) {
|
|
|
368
527
|
amount: z.string().describe("USDC amount to fund (whole-number string)"),
|
|
369
528
|
correlationId: z.string().optional()
|
|
370
529
|
},
|
|
530
|
+
// Moves USDC out of the buyer wallet.
|
|
531
|
+
destructive("Fund Escrow (moves USDC)"),
|
|
371
532
|
async (args) => withToolErrorHandling(async () => {
|
|
372
533
|
const client = getClient();
|
|
373
534
|
return client.escrows.fund(args);
|
|
@@ -382,6 +543,8 @@ function registerEscrowTools(server) {
|
|
|
382
543
|
reason: z.string().optional(),
|
|
383
544
|
correlationId: z.string().optional()
|
|
384
545
|
},
|
|
546
|
+
// Irreversible payout to the split recipients.
|
|
547
|
+
destructive("Release Escrow (pays out USDC)"),
|
|
385
548
|
async (args) => withToolErrorHandling(async () => {
|
|
386
549
|
const client = getClient();
|
|
387
550
|
return client.escrows.release(args);
|
|
@@ -395,6 +558,8 @@ function registerEscrowTools(server) {
|
|
|
395
558
|
reason: z.string().min(10),
|
|
396
559
|
actorId: z.string().uuid()
|
|
397
560
|
},
|
|
561
|
+
// Irreversible return of funds to the buyer.
|
|
562
|
+
destructive("Refund Escrow (returns USDC to buyer)"),
|
|
398
563
|
async (args) => withToolErrorHandling(async () => {
|
|
399
564
|
const client = getClient();
|
|
400
565
|
return client.escrows.refund(args);
|
|
@@ -414,11 +579,22 @@ function registerEscrowTools(server) {
|
|
|
414
579
|
waitForDeploymentMs: z.number().int().min(0).optional().describe("Max ms to wait for on-chain deployment. Default 60000."),
|
|
415
580
|
waitForFundingMs: z.number().int().min(0).optional().describe("Max ms to wait for funds to settle (funded/locked) before releasing. Default 60000.")
|
|
416
581
|
},
|
|
582
|
+
// Composes create -> fund -> release: money moves and is paid out.
|
|
583
|
+
destructive("Receive and Split (moves and pays out USDC)"),
|
|
417
584
|
async (args) => withToolErrorHandling(async () => {
|
|
418
585
|
const client = getClient();
|
|
419
586
|
return client.escrows.receiveAndSplit(args);
|
|
420
587
|
})
|
|
421
588
|
);
|
|
589
|
+
return [
|
|
590
|
+
"aura_create_escrow",
|
|
591
|
+
"aura_get_escrow",
|
|
592
|
+
"aura_list_escrows",
|
|
593
|
+
"aura_fund_escrow",
|
|
594
|
+
"aura_release_escrow",
|
|
595
|
+
"aura_refund_escrow",
|
|
596
|
+
"aura_receive_and_split"
|
|
597
|
+
];
|
|
422
598
|
}
|
|
423
599
|
function registerMandateTools(server) {
|
|
424
600
|
server.tool(
|
|
@@ -430,6 +606,7 @@ function registerMandateTools(server) {
|
|
|
430
606
|
limit: z.number().int().min(1).max(200).optional(),
|
|
431
607
|
cursor: z.string().uuid().optional().describe("Last mandate id from the previous page")
|
|
432
608
|
},
|
|
609
|
+
readOnly("List Mandates (approval inbox)"),
|
|
433
610
|
async (args) => withToolErrorHandling(async () => {
|
|
434
611
|
const client = getClient();
|
|
435
612
|
return client.mandates.list(args);
|
|
@@ -441,6 +618,7 @@ function registerMandateTools(server) {
|
|
|
441
618
|
{
|
|
442
619
|
mandateId: z.string().uuid()
|
|
443
620
|
},
|
|
621
|
+
readOnly("Get Mandate"),
|
|
444
622
|
async ({ mandateId }) => withToolErrorHandling(async () => {
|
|
445
623
|
const client = getClient();
|
|
446
624
|
return client.mandates.get(mandateId);
|
|
@@ -455,6 +633,8 @@ function registerMandateTools(server) {
|
|
|
455
633
|
decisionSignature: z.string().min(16).describe("HMAC-SHA256 hex digest, computed by the caller"),
|
|
456
634
|
decidedAt: z.string().datetime().optional().describe('ISO-8601 timestamp the signature commits to. Defaults to "now" server-side.')
|
|
457
635
|
},
|
|
636
|
+
// Authorizes the agent's intended payment — the money-moving decision.
|
|
637
|
+
destructive("Approve Mandate (authorizes payment)"),
|
|
458
638
|
async (args) => withToolErrorHandling(async () => {
|
|
459
639
|
const client = getClient();
|
|
460
640
|
return client.mandates.approve(args);
|
|
@@ -470,11 +650,19 @@ function registerMandateTools(server) {
|
|
|
470
650
|
decidedAt: z.string().datetime().optional(),
|
|
471
651
|
reason: z.string().optional().describe("Human-readable reason logged to the activity feed")
|
|
472
652
|
},
|
|
653
|
+
// Terminal decision on an existing mandate — the agent cannot resume it.
|
|
654
|
+
destructive("Reject Mandate"),
|
|
473
655
|
async (args) => withToolErrorHandling(async () => {
|
|
474
656
|
const client = getClient();
|
|
475
657
|
return client.mandates.reject(args);
|
|
476
658
|
})
|
|
477
659
|
);
|
|
660
|
+
return [
|
|
661
|
+
"aura_list_mandates",
|
|
662
|
+
"aura_get_mandate",
|
|
663
|
+
"aura_approve_mandate",
|
|
664
|
+
"aura_reject_mandate"
|
|
665
|
+
];
|
|
478
666
|
}
|
|
479
667
|
var TestnetChainSchema = z.enum(["ARC", "ARB", "BASE"]);
|
|
480
668
|
function walletCreateEnabled() {
|
|
@@ -488,6 +676,7 @@ function registerWalletTools(server) {
|
|
|
488
676
|
{
|
|
489
677
|
walletId: z.string().uuid()
|
|
490
678
|
},
|
|
679
|
+
readOnly("Get Wallet Balance"),
|
|
491
680
|
async ({ walletId }) => withToolErrorHandling(async () => {
|
|
492
681
|
const client = getClient();
|
|
493
682
|
return client.wallets.getBalance(walletId);
|
|
@@ -511,6 +700,8 @@ function registerWalletTools(server) {
|
|
|
511
700
|
"tax"
|
|
512
701
|
]).optional().describe("Wallet owner type. Defaults to BUSINESS.")
|
|
513
702
|
},
|
|
703
|
+
// Additive and create-or-get: provisions a receive address, moves no money.
|
|
704
|
+
write("Create Wallet (receive address)", true),
|
|
514
705
|
async ({ entityId, chain, type }) => {
|
|
515
706
|
if (!walletCreateEnabled()) {
|
|
516
707
|
return toolError(
|
|
@@ -532,31 +723,131 @@ function registerWalletTools(server) {
|
|
|
532
723
|
token: z.string().optional().describe("Token to drip. Defaults to 'USDC'."),
|
|
533
724
|
chain: TestnetChainSchema.optional().describe("Override the wallet's chain.")
|
|
534
725
|
},
|
|
726
|
+
// Additive: testnet-only drip that adds play funds, destroys nothing.
|
|
727
|
+
write("Request Testnet Funds"),
|
|
535
728
|
async ({ walletId, token, chain }) => withToolErrorHandling(async () => {
|
|
536
729
|
const client = getClient();
|
|
537
730
|
return client.wallets.requestTestnetFunds(walletId, { token, chain });
|
|
538
731
|
})
|
|
539
732
|
);
|
|
733
|
+
return [
|
|
734
|
+
"aura_get_wallet_balance",
|
|
735
|
+
"aura_create_wallet",
|
|
736
|
+
"aura_request_testnet_funds"
|
|
737
|
+
];
|
|
738
|
+
}
|
|
739
|
+
var WebhookEventTypeSchema = z.enum([
|
|
740
|
+
"*",
|
|
741
|
+
"escrow.created",
|
|
742
|
+
"escrow.funded",
|
|
743
|
+
"escrow.locked",
|
|
744
|
+
"escrow.released",
|
|
745
|
+
"escrow.refunded",
|
|
746
|
+
"escrow.disputed",
|
|
747
|
+
"transfer.completed",
|
|
748
|
+
"transfer.failed",
|
|
749
|
+
"withdrawal.created",
|
|
750
|
+
"withdrawal.processing",
|
|
751
|
+
"withdrawal.completed",
|
|
752
|
+
"withdrawal.failed",
|
|
753
|
+
"account.kyc_approved",
|
|
754
|
+
"account.kyc_rejected",
|
|
755
|
+
"account.tier_upgraded",
|
|
756
|
+
"security.api_key_created",
|
|
757
|
+
"security.api_key_revoked"
|
|
758
|
+
]);
|
|
759
|
+
function registerWebhookTools(server) {
|
|
760
|
+
server.tool(
|
|
761
|
+
"aura_get_webhook_config",
|
|
762
|
+
"Get the current webhook configuration for the authenticated account: delivery URL, subscribed event types, and status. The signing secret is never returned by this endpoint.",
|
|
763
|
+
{},
|
|
764
|
+
readOnly("Get Webhook Config"),
|
|
765
|
+
async () => withToolErrorHandling(async () => {
|
|
766
|
+
const client = getClient();
|
|
767
|
+
return client.webhooks.getConfig();
|
|
768
|
+
})
|
|
769
|
+
);
|
|
770
|
+
server.tool(
|
|
771
|
+
"aura_set_webhook_config",
|
|
772
|
+
"Set the webhook delivery endpoint for the account. An account has ONE configuration, so this REPLACES any existing one \u2014 events stop going to the previous URL. Must be an https:// URL you control. Returns the signing secret; store it, it is shown only on initial configuration.",
|
|
773
|
+
{
|
|
774
|
+
url: z.string().url().describe("HTTPS endpoint that will receive event POSTs"),
|
|
775
|
+
events: z.array(WebhookEventTypeSchema).min(1).optional().describe(
|
|
776
|
+
"Event types to subscribe to. Omit to subscribe to all events, or pass ['*'] explicitly."
|
|
777
|
+
),
|
|
778
|
+
description: z.string().optional().describe("Optional human-readable label")
|
|
779
|
+
},
|
|
780
|
+
destructive("Set Webhook Config (replaces existing)"),
|
|
781
|
+
async (args) => withToolErrorHandling(async () => {
|
|
782
|
+
const client = getClient();
|
|
783
|
+
return client.webhooks.configure(args);
|
|
784
|
+
})
|
|
785
|
+
);
|
|
786
|
+
server.tool(
|
|
787
|
+
"aura_delete_webhook_config",
|
|
788
|
+
"Delete the account webhook configuration. Event delivery stops immediately and the signing secret is invalidated \u2014 reconfiguring issues a new secret.",
|
|
789
|
+
{},
|
|
790
|
+
destructive("Delete Webhook Config"),
|
|
791
|
+
async () => withToolErrorHandling(async () => {
|
|
792
|
+
const client = getClient();
|
|
793
|
+
return client.webhooks.delete();
|
|
794
|
+
})
|
|
795
|
+
);
|
|
796
|
+
return [
|
|
797
|
+
"aura_get_webhook_config",
|
|
798
|
+
"aura_set_webhook_config",
|
|
799
|
+
"aura_delete_webhook_config"
|
|
800
|
+
];
|
|
540
801
|
}
|
|
541
802
|
|
|
542
803
|
// src/index.ts
|
|
804
|
+
var SERVER_NAME = "aura-payments";
|
|
805
|
+
var SERVER_VERSION = "1.1.0";
|
|
806
|
+
var toolManifests = /* @__PURE__ */ new WeakMap();
|
|
807
|
+
function getRegisteredToolNames(server) {
|
|
808
|
+
return toolManifests.get(server) ?? [];
|
|
809
|
+
}
|
|
543
810
|
function createServer(options = {}) {
|
|
544
811
|
const server = new McpServer({
|
|
545
|
-
name: options.name ??
|
|
546
|
-
version: options.version ??
|
|
812
|
+
name: options.name ?? SERVER_NAME,
|
|
813
|
+
version: options.version ?? SERVER_VERSION
|
|
547
814
|
});
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
815
|
+
const toolNames = [
|
|
816
|
+
...registerEscrowTools(server),
|
|
817
|
+
...registerAgentTools(server),
|
|
818
|
+
...registerMandateTools(server),
|
|
819
|
+
...registerWalletTools(server),
|
|
820
|
+
...registerWebhookTools(server)
|
|
821
|
+
];
|
|
822
|
+
toolManifests.set(server, Object.freeze(toolNames));
|
|
552
823
|
registerAgentResources(server);
|
|
553
824
|
registerMandateResources(server);
|
|
825
|
+
registerEscrowResources(server);
|
|
826
|
+
registerWalletResources(server);
|
|
554
827
|
return server;
|
|
555
828
|
}
|
|
556
829
|
|
|
557
830
|
// src/bin.ts
|
|
831
|
+
var DEFAULT_BASE_URL = "https://getaura.sh/api";
|
|
832
|
+
function emitBanner(toolCount) {
|
|
833
|
+
const mode = resolveKeyMode(process.env.AURA_API_KEY);
|
|
834
|
+
const baseUrl = process.env.AURA_BASE_URL || DEFAULT_BASE_URL;
|
|
835
|
+
console.error(
|
|
836
|
+
`${SERVER_NAME} v${SERVER_VERSION} | mode=${mode} | baseUrl=${baseUrl} | tools=${toolCount}`
|
|
837
|
+
);
|
|
838
|
+
if (mode === "unconfigured") {
|
|
839
|
+
console.error(
|
|
840
|
+
`${SERVER_NAME}: AURA_API_KEY is not set \u2014 tool calls will fail until you add it to the \`env\` block of your MCP client config.`
|
|
841
|
+
);
|
|
842
|
+
} else if (mode === "invalid") {
|
|
843
|
+
console.error(
|
|
844
|
+
`${SERVER_NAME}: AURA_API_KEY is malformed \u2014 expected an sk_test_ / sk_live_ / pk_test_ / pk_live_ prefix. Tool calls will fail until it is corrected.`
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
558
848
|
async function main() {
|
|
559
849
|
const server = createServer();
|
|
850
|
+
emitBanner(getRegisteredToolNames(server).length);
|
|
560
851
|
const transport = new StdioServerTransport();
|
|
561
852
|
await server.connect(transport);
|
|
562
853
|
}
|
|
@@ -564,5 +855,3 @@ main().catch((err) => {
|
|
|
564
855
|
console.error("aura-mcp: fatal error:", err);
|
|
565
856
|
process.exit(1);
|
|
566
857
|
});
|
|
567
|
-
//# sourceMappingURL=bin.mjs.map
|
|
568
|
-
//# sourceMappingURL=bin.mjs.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { AuraClient } from '@aura-payments/sdk';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* API key parsing and validation for the Aura MCP server.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately dependency-free: this module imports nothing (not even the
|
|
8
|
+
* Aura SDK) so it can be unit-tested in isolation and imported from the
|
|
9
|
+
* startup banner without pulling the whole client graph into scope.
|
|
10
|
+
*
|
|
11
|
+
* SECURITY: no function here ever returns the full key. `maskApiKey` reveals
|
|
12
|
+
* at most half of the key (capped at 8 characters) so a malformed-key error
|
|
13
|
+
* can identify WHICH key is wrong without ever writing the secret into a log,
|
|
14
|
+
* a stderr banner, or an MCP tool result.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Recognized API key prefixes.
|
|
18
|
+
*
|
|
19
|
+
* `sk_` = secret key (server-side), `pk_` = publishable key. The middle
|
|
20
|
+
* segment selects the environment the key is bound to; a key issued for one
|
|
21
|
+
* environment is never valid in the other.
|
|
22
|
+
*/
|
|
23
|
+
declare const API_KEY_PREFIXES: readonly ["sk_test_", "sk_live_", "pk_test_", "pk_live_"];
|
|
24
|
+
type AuraApiKeyPrefix = (typeof API_KEY_PREFIXES)[number];
|
|
25
|
+
/** Which Aura environment a key is bound to. */
|
|
26
|
+
type AuraKeyMode = 'test' | 'live';
|
|
27
|
+
interface ParsedAuraApiKey {
|
|
28
|
+
/** The matched prefix, e.g. `pk_test_`. Safe to log — carries no secret. */
|
|
29
|
+
prefix: AuraApiKeyPrefix;
|
|
30
|
+
/** Resolved environment, derived from the prefix. */
|
|
31
|
+
mode: AuraKeyMode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Redact a key for display.
|
|
35
|
+
*
|
|
36
|
+
* Reveals `min(8, floor(length / 2))` leading characters, so the result can
|
|
37
|
+
* never contain the whole key for any input of length >= 1. The length is
|
|
38
|
+
* appended because "wrong length" is the most common misconfiguration (a
|
|
39
|
+
* truncated paste) and it leaks nothing.
|
|
40
|
+
*/
|
|
41
|
+
declare function maskApiKey(apiKey: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Parse and validate `AURA_API_KEY`.
|
|
44
|
+
*
|
|
45
|
+
* @throws {MissingAuraApiKeyError} when the key is absent or blank.
|
|
46
|
+
* @throws {MalformedAuraApiKeyError} when the key carries no recognized prefix.
|
|
47
|
+
*/
|
|
48
|
+
declare function parseApiKey(apiKey: string | undefined): ParsedAuraApiKey;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the environment for display without throwing.
|
|
51
|
+
*
|
|
52
|
+
* The startup banner must never crash the process — an unusable key still has
|
|
53
|
+
* to produce a running server whose FIRST TOOL CALL returns a clear error, so
|
|
54
|
+
* the MCP host surfaces something actionable instead of a dead subprocess.
|
|
55
|
+
*/
|
|
56
|
+
declare function resolveKeyMode(apiKey: string | undefined): AuraKeyMode | 'unconfigured' | 'invalid';
|
|
57
|
+
declare class MissingAuraApiKeyError extends Error {
|
|
58
|
+
constructor();
|
|
59
|
+
}
|
|
60
|
+
declare class MalformedAuraApiKeyError extends Error {
|
|
61
|
+
constructor(apiKey: string);
|
|
62
|
+
}
|
|
63
|
+
|
|
4
64
|
/**
|
|
5
65
|
* Aura SDK client factory for the MCP server.
|
|
6
66
|
*
|
|
@@ -9,20 +69,22 @@ import { AuraClient } from '@aura-payments/sdk';
|
|
|
9
69
|
* the `env` field in mcp.json). The client is created lazily on first tool
|
|
10
70
|
* invocation so missing env doesn't crash the server during the MCP handshake
|
|
11
71
|
* — instead, the FIRST tool call returns a clear error the LLM can act on.
|
|
72
|
+
*
|
|
73
|
+
* The key is validated for BOTH presence and format before it is ever put on
|
|
74
|
+
* the wire. A malformed key would otherwise fail as an opaque 401 from the
|
|
75
|
+
* platform, which is indistinguishable from a revoked key — the local check
|
|
76
|
+
* turns that into an actionable configuration error.
|
|
12
77
|
*/
|
|
13
78
|
|
|
14
79
|
declare function getClient(): AuraClient;
|
|
15
|
-
declare class MissingAuraApiKeyError extends Error {
|
|
16
|
-
constructor();
|
|
17
|
-
}
|
|
18
80
|
|
|
19
81
|
/**
|
|
20
82
|
* Aura Payments MCP Server — programmatic entry point.
|
|
21
83
|
*
|
|
22
|
-
* The MCP server exposes Aura's escrow, agent, mandate, and
|
|
23
|
-
* as Model Context Protocol tools and resources, so AI agents
|
|
24
|
-
* Cursor, Continue, custom orchestrators) can drive Aura natively
|
|
25
|
-
* stdio without writing HTTP boilerplate.
|
|
84
|
+
* The MCP server exposes Aura's escrow, agent, mandate, wallet, and webhook
|
|
85
|
+
* primitives as Model Context Protocol tools and resources, so AI agents
|
|
86
|
+
* (Claude, Cursor, Continue, custom orchestrators) can drive Aura natively
|
|
87
|
+
* over stdio without writing HTTP boilerplate.
|
|
26
88
|
*
|
|
27
89
|
* This file exports `createServer()` for programmatic use (tests, custom
|
|
28
90
|
* transports, embedding in other MCP hosts). For the standalone binary,
|
|
@@ -33,10 +95,17 @@ declare class MissingAuraApiKeyError extends Error {
|
|
|
33
95
|
* shape, idempotency, retries, and error mapping.
|
|
34
96
|
*/
|
|
35
97
|
|
|
98
|
+
declare const SERVER_NAME = "aura-payments";
|
|
99
|
+
declare const SERVER_VERSION = "1.1.0";
|
|
36
100
|
interface CreateServerOptions {
|
|
37
101
|
name?: string;
|
|
38
102
|
version?: string;
|
|
39
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Names of the tools registered on `server`, in registration order.
|
|
106
|
+
* Returns an empty array for a server this module did not build.
|
|
107
|
+
*/
|
|
108
|
+
declare function getRegisteredToolNames(server: McpServer): readonly string[];
|
|
40
109
|
/**
|
|
41
110
|
* Build a fully-configured MCP server with all Aura tools and resources
|
|
42
111
|
* registered. The caller is responsible for connecting it to a transport
|
|
@@ -44,4 +113,4 @@ interface CreateServerOptions {
|
|
|
44
113
|
*/
|
|
45
114
|
declare function createServer(options?: CreateServerOptions): McpServer;
|
|
46
115
|
|
|
47
|
-
export { type CreateServerOptions, MissingAuraApiKeyError, createServer, getClient };
|
|
116
|
+
export { API_KEY_PREFIXES, type AuraKeyMode, type CreateServerOptions, MalformedAuraApiKeyError, MissingAuraApiKeyError, type ParsedAuraApiKey, SERVER_NAME, SERVER_VERSION, createServer, getClient, getRegisteredToolNames, maskApiKey, parseApiKey, resolveKeyMode };
|