@aura-payments/mcp-server 1.1.0 → 1.2.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 CHANGED
@@ -25,7 +25,7 @@ macOS, `~/.cursor/mcp.json` for Cursor):
25
25
  "aura": {
26
26
  "command": "aura-mcp",
27
27
  "env": {
28
- "AURA_API_KEY": "pk_live_..."
28
+ "AURA_API_KEY": "sk_test_..."
29
29
  }
30
30
  }
31
31
  }
@@ -39,7 +39,7 @@ Get an API key at <https://getaura.sh>.
39
39
  | Variable | Default | Purpose |
40
40
  | ----------------------- | ----------------------------- | ---------------------------------------------------- |
41
41
  | `AURA_API_KEY` | (required) | Your platform API key (`pk_live_*` or `pk_test_*`) |
42
- | `AURA_BASE_URL` | `https://tryaura.xyz/api` | Override for self-hosted or staging deployments |
42
+ | `AURA_BASE_URL` | `https://getaura.sh/api` | Override for self-hosted or staging deployments |
43
43
  | `AURA_AUTO_IDEMPOTENCY` | `true` | Auto-generate idempotency keys for POST/PUT requests |
44
44
 
45
45
  ## Tools
package/dist/bin.js CHANGED
@@ -37,7 +37,7 @@ function resolveKeyMode(apiKey) {
37
37
  var MissingAuraApiKeyError = class extends Error {
38
38
  constructor() {
39
39
  super(
40
- '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.'
40
+ '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": "sk_test_..." } } } }. Get a key at https://getaura.sh.'
41
41
  );
42
42
  this.name = "MissingAuraApiKeyError";
43
43
  }
@@ -134,6 +134,22 @@ function registerEscrowResources(server) {
134
134
  }
135
135
  );
136
136
  }
137
+
138
+ // src/resources/insights.ts
139
+ function registerInsightsResources(server, clientFactory = getClient) {
140
+ server.resource("insights-overview", "aura://insights/overview", async (uri) => {
141
+ const overview = await clientFactory().insights.overview();
142
+ return {
143
+ contents: [
144
+ {
145
+ uri: uri.href,
146
+ mimeType: "application/json",
147
+ text: JSON.stringify(overview, null, 2)
148
+ }
149
+ ]
150
+ };
151
+ });
152
+ }
137
153
  function registerMandateResources(server) {
138
154
  server.resource(
139
155
  "mandates-pending",
@@ -220,6 +236,42 @@ function registerWalletResources(server) {
220
236
  }
221
237
  );
222
238
  }
239
+ var COLLECTION_LIMIT3 = 50;
240
+ var WithdrawalIdSchema = zod.z.string().uuid();
241
+ function registerWithdrawalResources(server, clientFactory = getClient) {
242
+ server.resource("withdrawals", "aura://withdrawals", async (uri) => {
243
+ const page = await clientFactory().withdrawals.list({ limit: COLLECTION_LIMIT3 });
244
+ return {
245
+ contents: [
246
+ {
247
+ uri: uri.href,
248
+ mimeType: "application/json",
249
+ text: JSON.stringify(page, null, 2)
250
+ }
251
+ ]
252
+ };
253
+ });
254
+ server.resource(
255
+ "withdrawal",
256
+ new mcp_js.ResourceTemplate("aura://withdrawals/{id}", { list: void 0 }),
257
+ async (uri, { id }) => {
258
+ const parsed = WithdrawalIdSchema.safeParse(Array.isArray(id) ? id[0] : id);
259
+ if (!parsed.success) {
260
+ throw new Error(`Invalid withdrawal id in ${uri.href}: expected a UUID`);
261
+ }
262
+ const withdrawal = await clientFactory().withdrawals.get(parsed.data);
263
+ return {
264
+ contents: [
265
+ {
266
+ uri: uri.href,
267
+ mimeType: "application/json",
268
+ text: JSON.stringify(withdrawal, null, 2)
269
+ }
270
+ ]
271
+ };
272
+ }
273
+ );
274
+ }
223
275
 
224
276
  // src/annotations.ts
225
277
  function readOnly(title) {
@@ -419,7 +471,7 @@ function registerAgentTools(server) {
419
471
  amount: zod.z.string().describe("USDC amount as decimal string"),
420
472
  destination: zod.z.string().describe("Counterparty wallet (0x...) or merchant identifier"),
421
473
  destinationType: zod.z.enum(["address", "domain", "category", "entity_id"]).optional(),
422
- reasoning: zod.z.string().optional(),
474
+ reasoning: zod.z.string().optional().describe("Why the agent wants this; shown to the operator. Required for a mandate to be created when approval is needed."),
423
475
  metadata: zod.z.record(zod.z.unknown()).optional()
424
476
  },
425
477
  // NOT read-only despite being a dry run: when the decision requires human
@@ -598,6 +650,118 @@ function registerEscrowTools(server) {
598
650
  "aura_receive_and_split"
599
651
  ];
600
652
  }
653
+ function validationError(error) {
654
+ const detail = error.issues.map((issue) => `${issue.path.join(".") || "(input)"}: ${issue.message}`).join("; ");
655
+ return toolError("VALIDATION_ERROR", detail);
656
+ }
657
+ function addCustomRangeIssues(ctx, field, selector, start, end) {
658
+ if (selector === "custom" && (start === void 0 || end === void 0)) {
659
+ ctx.addIssue({
660
+ code: zod.z.ZodIssueCode.custom,
661
+ path: [start === void 0 ? "start" : "end"],
662
+ message: `start and end are both required when ${field} is 'custom'`
663
+ });
664
+ }
665
+ if (start !== void 0 && end !== void 0 && Date.parse(start) > Date.parse(end)) {
666
+ ctx.addIssue({
667
+ code: zod.z.ZodIssueCode.custom,
668
+ path: ["end"],
669
+ message: "end must be at or after start"
670
+ });
671
+ }
672
+ }
673
+
674
+ // src/tools/insights.ts
675
+ var PeriodSchema = zod.z.enum(["today", "7d", "30d", "90d", "custom"]);
676
+ var DateTimeSchema = zod.z.string().datetime();
677
+ var overviewShape = {
678
+ period: PeriodSchema.optional().describe(
679
+ "Window to report on (default 7d). 'custom' requires start and end."
680
+ ),
681
+ start: DateTimeSchema.optional().describe("ISO 8601 datetime; required when period is custom"),
682
+ end: DateTimeSchema.optional().describe("ISO 8601 datetime; required when period is custom")
683
+ };
684
+ var InsightsOverviewInput = zod.z.object(overviewShape).superRefine(
685
+ (value, ctx) => addCustomRangeIssues(ctx, "period", value.period, value.start, value.end)
686
+ );
687
+ var auditShape = {
688
+ action: zod.z.string().min(1).optional().describe("Audit action name, e.g. escrow.released"),
689
+ actor: zod.z.enum(["user", "system", "api", "cron", "webhook"]).optional(),
690
+ resourceType: zod.z.string().min(1).optional().describe("Resource kind, e.g. escrow"),
691
+ // `.min(1)`, not `.uuid()`: the route accepts any string here
692
+ // (`resourceId: z.string().optional()`, insights/audit/route.ts:26) and the
693
+ // audit log records ids from several subsystems, not all of them UUIDs.
694
+ resourceId: zod.z.string().min(1).optional().describe("Id of the audited resource"),
695
+ range: PeriodSchema.optional().describe(
696
+ "Window to query (default 30d). 'custom' requires start and end."
697
+ ),
698
+ start: DateTimeSchema.optional().describe("ISO 8601 datetime; required when range is custom"),
699
+ end: DateTimeSchema.optional().describe("ISO 8601 datetime; required when range is custom"),
700
+ page: zod.z.number().int().min(1).optional().describe("1-based page number (default 1)"),
701
+ limit: zod.z.number().int().min(1).max(100).optional().describe("Page size, 1-100 (default 50)")
702
+ };
703
+ var InsightsAuditInput = zod.z.object(auditShape).superRefine(
704
+ (value, ctx) => addCustomRangeIssues(ctx, "range", value.range, value.start, value.end)
705
+ );
706
+ function registerInsightsTools(server, clientFactory = getClient) {
707
+ server.tool(
708
+ "aura_insights_overview",
709
+ "Revenue, transaction count, active escrows and commissions for a period, each with its change against the previous period, plus sparkline and success-rate charts.",
710
+ overviewShape,
711
+ readOnly("Insights Overview"),
712
+ async (args) => {
713
+ const parsed = InsightsOverviewInput.safeParse(args);
714
+ if (!parsed.success) return validationError(parsed.error);
715
+ const { period, start, end } = parsed.data;
716
+ return withToolErrorHandling(
717
+ async () => clientFactory().insights.overview(period, start, end)
718
+ );
719
+ }
720
+ );
721
+ server.tool(
722
+ "aura_insights_forecast",
723
+ "Project a metric forward over a horizon using the requested algorithm. Requires a Growth or higher plan \u2014 lower tiers return feature_not_available.",
724
+ {
725
+ metric: zod.z.enum([
726
+ "revenue",
727
+ "transaction_count",
728
+ "escrow_count",
729
+ "commission",
730
+ "avg_transaction_value"
731
+ ]),
732
+ algorithm: zod.z.enum([
733
+ "linear_regression",
734
+ "moving_average",
735
+ "exponential_smoothing",
736
+ "arima",
737
+ "prophet",
738
+ "ensemble"
739
+ ]).optional(),
740
+ period: zod.z.enum(["daily", "weekly", "monthly"]).optional().describe("Granularity of each projected point"),
741
+ horizon: zod.z.number().int().min(1).max(365).optional().describe("Number of periods to project"),
742
+ // Known platform quirk: the route parses this with `z.coerce.boolean()`
743
+ // on a query string, where any non-empty value — including "false" —
744
+ // coerces to true. Passing false therefore does not currently suppress
745
+ // history; that is a platform-side fix, not one to paper over here.
746
+ includeHistory: zod.z.boolean().optional().describe("Include the historical series alongside the projection"),
747
+ historyPeriods: zod.z.number().int().min(1).max(365).optional()
748
+ },
749
+ readOnly("Insights Forecast"),
750
+ async (args) => withToolErrorHandling(async () => clientFactory().insights.forecast(args))
751
+ );
752
+ server.tool(
753
+ "aura_insights_audit",
754
+ "Query the account audit log by action, actor, resource and date range. Paginated, most recent first.",
755
+ auditShape,
756
+ readOnly("Insights Audit"),
757
+ async (args) => {
758
+ const parsed = InsightsAuditInput.safeParse(args);
759
+ if (!parsed.success) return validationError(parsed.error);
760
+ return withToolErrorHandling(async () => clientFactory().insights.audit(parsed.data));
761
+ }
762
+ );
763
+ return ["aura_insights_overview", "aura_insights_forecast", "aura_insights_audit"];
764
+ }
601
765
  function registerMandateTools(server) {
602
766
  server.tool(
603
767
  "aura_list_mandates",
@@ -666,6 +830,18 @@ function registerMandateTools(server) {
666
830
  "aura_reject_mandate"
667
831
  ];
668
832
  }
833
+
834
+ // src/tools/treasury.ts
835
+ function registerTreasuryTools(server, clientFactory = getClient) {
836
+ server.tool(
837
+ "aura_treasury_optimize",
838
+ "Analyze treasury balances, active escrows and pending payouts, and return an AI recommendation on how to rebalance. Read-only: it recommends, it does not move funds. Requires a Growth or higher plan \u2014 lower tiers return feature_not_available.",
839
+ {},
840
+ readOnly("Treasury Optimize"),
841
+ async () => withToolErrorHandling(async () => clientFactory().treasury.optimize())
842
+ );
843
+ return ["aura_treasury_optimize"];
844
+ }
669
845
  var TestnetChainSchema = zod.z.enum(["ARC", "ARB", "BASE"]);
670
846
  function walletCreateEnabled() {
671
847
  const v = (process.env.AURA_MCP_ALLOW_WALLET_CREATE ?? "").trim().toLowerCase();
@@ -801,10 +977,113 @@ function registerWebhookTools(server) {
801
977
  "aura_delete_webhook_config"
802
978
  ];
803
979
  }
980
+ var ChainSchema3 = zod.z.enum(["ARC", "ETH", "BASE", "ARB", "MATIC"]);
981
+ var AmountSchema = zod.z.string().regex(
982
+ /^\d+(\.\d{1,6})?$/,
983
+ 'Amount must be a number string with up to 6 decimal places, e.g. "100.00"'
984
+ );
985
+ var EvmAddressSchema = zod.z.string().regex(
986
+ /^0x[a-fA-F0-9]{40}$/,
987
+ "Must be an EVM address: 0x followed by 40 hexadecimal characters"
988
+ );
989
+ var ExchangeSchema = zod.z.enum(["binance", "coinbase", "kraken", "other"]);
990
+ var FeeConfigSchema = zod.z.enum(["FREE", "GAS_ONLY", "STANDARD"]);
991
+ var StatusSchema = zod.z.enum(["pending", "submitted", "confirmed", "failed", "cancelled"]);
992
+ var WithdrawalIdSchema2 = zod.z.string().uuid("Withdrawal id must be a UUID");
993
+ var estimateShape = {
994
+ // `.min(1)`, not `.uuid()`: the route accepts any non-empty string here
995
+ // (`walletId: z.string().min(1)`, estimate/route.ts:56). Requiring a UUID
996
+ // would make this tool reject wallet ids the platform itself accepts.
997
+ walletId: zod.z.string().min(1).describe("Source wallet id to debit"),
998
+ amount: AmountSchema.describe('USDC amount as a string, e.g. "100.00"'),
999
+ destinationType: zod.z.enum(["exchange", "wallet"]).describe("Where the funds land. 'exchange' also requires `exchange`."),
1000
+ destinationAddress: EvmAddressSchema.describe("Destination EVM address"),
1001
+ chain: ChainSchema3.describe("Chain the funds are delivered on"),
1002
+ exchange: ExchangeSchema.optional().describe(
1003
+ "Required when destinationType is 'exchange'"
1004
+ ),
1005
+ sourceChain: ChainSchema3.optional().describe(
1006
+ "Chain the funds start on. Differs from `chain` for a bridged withdrawal; defaults to ARC."
1007
+ ),
1008
+ feeConfig: FeeConfigSchema.optional()
1009
+ };
1010
+ var EstimateWithdrawalInput = zod.z.object(estimateShape).superRefine((value, ctx) => {
1011
+ if (value.destinationType === "exchange" && value.exchange === void 0) {
1012
+ ctx.addIssue({
1013
+ code: zod.z.ZodIssueCode.custom,
1014
+ path: ["exchange"],
1015
+ message: "exchange is required when destinationType is 'exchange'"
1016
+ });
1017
+ }
1018
+ });
1019
+ function registerWithdrawalTools(server, clientFactory = getClient) {
1020
+ server.tool(
1021
+ "aura_get_withdrawal",
1022
+ "Get a single withdrawal by id: status, amount, fees, destination, chain and transaction hash.",
1023
+ { withdrawalId: WithdrawalIdSchema2.describe("The withdrawal id (UUID)") },
1024
+ readOnly("Get Withdrawal"),
1025
+ async ({ withdrawalId }) => withToolErrorHandling(async () => clientFactory().withdrawals.get(withdrawalId))
1026
+ );
1027
+ server.tool(
1028
+ "aura_list_withdrawals",
1029
+ "List withdrawals for the account, most recent first. Filter by status, chain and date range.",
1030
+ {
1031
+ limit: zod.z.number().int().min(1).max(100).optional().describe("Page size, 1-100 (default 50)"),
1032
+ offset: zod.z.number().int().min(0).optional().describe("Rows to skip (default 0)"),
1033
+ status: StatusSchema.optional(),
1034
+ chain: ChainSchema3.optional(),
1035
+ fromDate: zod.z.string().datetime().optional().describe("ISO 8601 datetime, inclusive lower bound"),
1036
+ toDate: zod.z.string().datetime().optional().describe("ISO 8601 datetime, inclusive upper bound")
1037
+ },
1038
+ readOnly("List Withdrawals"),
1039
+ async (args) => withToolErrorHandling(async () => clientFactory().withdrawals.list(args))
1040
+ );
1041
+ server.tool(
1042
+ "aura_estimate_withdrawal",
1043
+ "Preview the fees, net amount and confirmation time for a withdrawal WITHOUT creating it. Moves no funds. Use this before quoting a payout to a user.",
1044
+ estimateShape,
1045
+ readOnly("Estimate Withdrawal"),
1046
+ async (args) => {
1047
+ const parsed = EstimateWithdrawalInput.safeParse(args);
1048
+ if (!parsed.success) return validationError(parsed.error);
1049
+ return withToolErrorHandling(
1050
+ async () => clientFactory().withdrawals.estimate(parsed.data)
1051
+ );
1052
+ }
1053
+ );
1054
+ server.tool(
1055
+ "aura_get_withdrawal_limits",
1056
+ "Get the account KYC-tier withdrawal limits and how much of the daily and monthly allowance is still available.",
1057
+ {},
1058
+ readOnly("Get Withdrawal Limits"),
1059
+ async () => withToolErrorHandling(async () => clientFactory().withdrawals.limits())
1060
+ );
1061
+ server.tool(
1062
+ "aura_validate_withdrawal_address",
1063
+ "Check that a destination address is well-formed and usable on a chain, and preview the fee when an amount is given. Moves no funds.",
1064
+ {
1065
+ address: EvmAddressSchema.describe("Destination EVM address to check"),
1066
+ chain: ChainSchema3,
1067
+ amount: AmountSchema.optional().describe(
1068
+ "Optional \u2014 when supplied the response includes a fee preview"
1069
+ ),
1070
+ feeConfig: FeeConfigSchema.optional()
1071
+ },
1072
+ readOnly("Validate Withdrawal Address"),
1073
+ async (args) => withToolErrorHandling(async () => clientFactory().withdrawals.validate(args))
1074
+ );
1075
+ return [
1076
+ "aura_get_withdrawal",
1077
+ "aura_list_withdrawals",
1078
+ "aura_estimate_withdrawal",
1079
+ "aura_get_withdrawal_limits",
1080
+ "aura_validate_withdrawal_address"
1081
+ ];
1082
+ }
804
1083
 
805
1084
  // src/index.ts
806
1085
  var SERVER_NAME = "aura-payments";
807
- var SERVER_VERSION = "1.1.0";
1086
+ var SERVER_VERSION = "1.2.1";
808
1087
  var toolManifests = /* @__PURE__ */ new WeakMap();
809
1088
  function getRegisteredToolNames(server) {
810
1089
  return toolManifests.get(server) ?? [];
@@ -819,13 +1098,18 @@ function createServer(options = {}) {
819
1098
  ...registerAgentTools(server),
820
1099
  ...registerMandateTools(server),
821
1100
  ...registerWalletTools(server),
822
- ...registerWebhookTools(server)
1101
+ ...registerWebhookTools(server),
1102
+ ...registerWithdrawalTools(server),
1103
+ ...registerTreasuryTools(server),
1104
+ ...registerInsightsTools(server)
823
1105
  ];
824
1106
  toolManifests.set(server, Object.freeze(toolNames));
825
1107
  registerAgentResources(server);
826
1108
  registerMandateResources(server);
827
1109
  registerEscrowResources(server);
828
1110
  registerWalletResources(server);
1111
+ registerWithdrawalResources(server);
1112
+ registerInsightsResources(server);
829
1113
  return server;
830
1114
  }
831
1115