@codespar/mcp-circle 0.1.2 → 0.2.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/index.js +258 -42
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +278 -35
package/dist/index.js
CHANGED
|
@@ -3,15 +3,28 @@
|
|
|
3
3
|
* MCP Server for Circle — USDC stablecoin infrastructure.
|
|
4
4
|
*
|
|
5
5
|
* Tools:
|
|
6
|
-
* - create_wallet: Create a new Circle wallet
|
|
6
|
+
* - create_wallet: Create a new Circle business-account wallet
|
|
7
7
|
* - get_wallet: Get wallet details by ID
|
|
8
|
+
* - list_wallets: List all wallets
|
|
8
9
|
* - create_payment: Accept a USDC payment
|
|
9
10
|
* - get_payment: Get payment details by ID
|
|
10
11
|
* - create_payout: Create a payout (USDC to fiat)
|
|
11
12
|
* - get_payout: Get payout details by ID
|
|
13
|
+
* - list_payouts: List payouts with filters
|
|
12
14
|
* - create_transfer: Create a USDC transfer between wallets
|
|
13
15
|
* - get_transfer: Get transfer details by ID
|
|
14
|
-
* -
|
|
16
|
+
* - list_transfers: List transfers with filters
|
|
17
|
+
* - create_card: Register card data for on-ramp
|
|
18
|
+
* - get_card: Get card details by ID
|
|
19
|
+
* - list_cards: List cards
|
|
20
|
+
* - list_settlements: List settlements
|
|
21
|
+
* - get_settlement: Get settlement details by ID
|
|
22
|
+
* - list_chargebacks: List chargebacks
|
|
23
|
+
* - get_chargeback: Get chargeback by ID
|
|
24
|
+
* - create_subscription: Register a notification subscription (webhook)
|
|
25
|
+
* - list_subscriptions: List notification subscriptions
|
|
26
|
+
* - delete_subscription: Remove a notification subscription
|
|
27
|
+
* - get_balance: Get business-account balance
|
|
15
28
|
* - list_transactions: List transactions with filters
|
|
16
29
|
*
|
|
17
30
|
* Environment:
|
|
@@ -39,12 +52,29 @@ async function circleRequest(method, path, body) {
|
|
|
39
52
|
}
|
|
40
53
|
return res.json();
|
|
41
54
|
}
|
|
42
|
-
const server = new Server({ name: "mcp-circle", version: "0.
|
|
55
|
+
const server = new Server({ name: "mcp-circle", version: "0.2.0" }, { capabilities: { tools: {} } });
|
|
56
|
+
const amountSchema = {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
amount: { type: "string", description: "Amount (e.g. '10.00')" },
|
|
60
|
+
currency: { type: "string", description: "Currency (USD)" },
|
|
61
|
+
},
|
|
62
|
+
required: ["amount", "currency"],
|
|
63
|
+
};
|
|
64
|
+
const sourceDestSchema = (label) => ({
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
id: { type: "string", description: `${label} ID` },
|
|
68
|
+
type: { type: "string", description: `${label} type (e.g. wallet, card, ach, wire, blockchain)` },
|
|
69
|
+
},
|
|
70
|
+
required: ["id", "type"],
|
|
71
|
+
});
|
|
43
72
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
44
73
|
tools: [
|
|
74
|
+
// Wallets
|
|
45
75
|
{
|
|
46
76
|
name: "create_wallet",
|
|
47
|
-
description: "Create a new Circle wallet",
|
|
77
|
+
description: "Create a new Circle business-account wallet",
|
|
48
78
|
inputSchema: {
|
|
49
79
|
type: "object",
|
|
50
80
|
properties: {
|
|
@@ -57,14 +87,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
57
87
|
{
|
|
58
88
|
name: "get_wallet",
|
|
59
89
|
description: "Get wallet details by ID",
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: "object",
|
|
92
|
+
properties: { id: { type: "string", description: "Wallet ID" } },
|
|
93
|
+
required: ["id"],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "list_wallets",
|
|
98
|
+
description: "List all Circle wallets",
|
|
60
99
|
inputSchema: {
|
|
61
100
|
type: "object",
|
|
62
101
|
properties: {
|
|
63
|
-
|
|
102
|
+
pageSize: { type: "number", description: "Number of results per page" },
|
|
103
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
104
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
64
105
|
},
|
|
65
|
-
required: ["id"],
|
|
66
106
|
},
|
|
67
107
|
},
|
|
108
|
+
// Payments
|
|
68
109
|
{
|
|
69
110
|
name: "create_payment",
|
|
70
111
|
description: "Accept a USDC payment via Circle",
|
|
@@ -72,9 +113,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
72
113
|
type: "object",
|
|
73
114
|
properties: {
|
|
74
115
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
75
|
-
amount: {
|
|
76
|
-
source: {
|
|
116
|
+
amount: { ...amountSchema, description: "Payment amount" },
|
|
117
|
+
source: { ...sourceDestSchema("Source"), description: "Payment source" },
|
|
77
118
|
description: { type: "string", description: "Payment description" },
|
|
119
|
+
verification: { type: "string", description: "Verification method (cvv, three_d_secure, none)" },
|
|
120
|
+
metadata: { type: "object", description: "Payment metadata (email, phoneNumber, sessionId, ipAddress)" },
|
|
78
121
|
},
|
|
79
122
|
required: ["idempotencyKey", "amount", "source"],
|
|
80
123
|
},
|
|
@@ -84,12 +127,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
84
127
|
description: "Get payment details by ID",
|
|
85
128
|
inputSchema: {
|
|
86
129
|
type: "object",
|
|
87
|
-
properties: {
|
|
88
|
-
id: { type: "string", description: "Payment ID" },
|
|
89
|
-
},
|
|
130
|
+
properties: { id: { type: "string", description: "Payment ID" } },
|
|
90
131
|
required: ["id"],
|
|
91
132
|
},
|
|
92
133
|
},
|
|
134
|
+
// Payouts
|
|
93
135
|
{
|
|
94
136
|
name: "create_payout",
|
|
95
137
|
description: "Create a payout from Circle (USDC to fiat)",
|
|
@@ -97,8 +139,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
97
139
|
type: "object",
|
|
98
140
|
properties: {
|
|
99
141
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
100
|
-
amount: {
|
|
101
|
-
destination: {
|
|
142
|
+
amount: { ...amountSchema, description: "Payout amount" },
|
|
143
|
+
destination: { ...sourceDestSchema("Destination"), description: "Payout destination (bank account)" },
|
|
144
|
+
metadata: { type: "object", description: "Payout metadata (beneficiaryEmail)" },
|
|
102
145
|
},
|
|
103
146
|
required: ["idempotencyKey", "amount", "destination"],
|
|
104
147
|
},
|
|
@@ -106,24 +149,39 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
106
149
|
{
|
|
107
150
|
name: "get_payout",
|
|
108
151
|
description: "Get payout details by ID",
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: "object",
|
|
154
|
+
properties: { id: { type: "string", description: "Payout ID" } },
|
|
155
|
+
required: ["id"],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "list_payouts",
|
|
160
|
+
description: "List payouts with optional filters",
|
|
109
161
|
inputSchema: {
|
|
110
162
|
type: "object",
|
|
111
163
|
properties: {
|
|
112
|
-
|
|
164
|
+
source: { type: "string", description: "Filter by source wallet ID" },
|
|
165
|
+
destination: { type: "string", description: "Filter by destination ID" },
|
|
166
|
+
type: { type: "string", description: "Filter by type (wire, ach, sen)" },
|
|
167
|
+
status: { type: "string", description: "Filter by status (pending, complete, failed)" },
|
|
168
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
169
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
170
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
113
171
|
},
|
|
114
|
-
required: ["id"],
|
|
115
172
|
},
|
|
116
173
|
},
|
|
174
|
+
// Transfers
|
|
117
175
|
{
|
|
118
176
|
name: "create_transfer",
|
|
119
|
-
description: "Create a USDC transfer between Circle wallets",
|
|
177
|
+
description: "Create a USDC transfer between Circle wallets (or to blockchain address)",
|
|
120
178
|
inputSchema: {
|
|
121
179
|
type: "object",
|
|
122
180
|
properties: {
|
|
123
181
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
124
|
-
amount: {
|
|
125
|
-
source: {
|
|
126
|
-
destination: {
|
|
182
|
+
amount: { ...amountSchema, description: "Transfer amount" },
|
|
183
|
+
source: { ...sourceDestSchema("Source"), description: "Transfer source (wallet)" },
|
|
184
|
+
destination: { ...sourceDestSchema("Destination"), description: "Transfer destination (wallet or blockchain)" },
|
|
127
185
|
},
|
|
128
186
|
required: ["idempotencyKey", "amount", "source", "destination"],
|
|
129
187
|
},
|
|
@@ -131,17 +189,143 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
131
189
|
{
|
|
132
190
|
name: "get_transfer",
|
|
133
191
|
description: "Get transfer details by ID",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: { id: { type: "string", description: "Transfer ID" } },
|
|
195
|
+
required: ["id"],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "list_transfers",
|
|
200
|
+
description: "List transfers with optional filters",
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
walletId: { type: "string", description: "Filter by wallet ID" },
|
|
205
|
+
sourceWalletId: { type: "string", description: "Filter by source wallet ID" },
|
|
206
|
+
destinationWalletId: { type: "string", description: "Filter by destination wallet ID" },
|
|
207
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
208
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
209
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
// Cards
|
|
214
|
+
{
|
|
215
|
+
name: "create_card",
|
|
216
|
+
description: "Register card data for on-ramp payments",
|
|
217
|
+
inputSchema: {
|
|
218
|
+
type: "object",
|
|
219
|
+
properties: {
|
|
220
|
+
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
221
|
+
keyId: { type: "string", description: "Public key ID used to encrypt card data" },
|
|
222
|
+
encryptedData: { type: "string", description: "PGP-encrypted card number + CVV" },
|
|
223
|
+
billingDetails: { type: "object", description: "Billing address details (name, city, country, line1, postalCode, district)" },
|
|
224
|
+
expMonth: { type: "number", description: "Card expiration month (1-12)" },
|
|
225
|
+
expYear: { type: "number", description: "Card expiration year (4-digit)" },
|
|
226
|
+
metadata: { type: "object", description: "Card metadata (email, phoneNumber, sessionId, ipAddress)" },
|
|
227
|
+
},
|
|
228
|
+
required: ["idempotencyKey", "keyId", "encryptedData", "billingDetails", "expMonth", "expYear"],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: "get_card",
|
|
233
|
+
description: "Get card details by ID",
|
|
234
|
+
inputSchema: {
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: { id: { type: "string", description: "Card ID" } },
|
|
237
|
+
required: ["id"],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "list_cards",
|
|
242
|
+
description: "List registered cards",
|
|
243
|
+
inputSchema: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
247
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
248
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
// Settlements
|
|
253
|
+
{
|
|
254
|
+
name: "list_settlements",
|
|
255
|
+
description: "List settlements (card payment batches)",
|
|
256
|
+
inputSchema: {
|
|
257
|
+
type: "object",
|
|
258
|
+
properties: {
|
|
259
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
260
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
261
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
262
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
263
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "get_settlement",
|
|
269
|
+
description: "Get settlement details by ID",
|
|
270
|
+
inputSchema: {
|
|
271
|
+
type: "object",
|
|
272
|
+
properties: { id: { type: "string", description: "Settlement ID" } },
|
|
273
|
+
required: ["id"],
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
// Chargebacks
|
|
277
|
+
{
|
|
278
|
+
name: "list_chargebacks",
|
|
279
|
+
description: "List chargebacks",
|
|
280
|
+
inputSchema: {
|
|
281
|
+
type: "object",
|
|
282
|
+
properties: {
|
|
283
|
+
paymentId: { type: "string", description: "Filter by payment ID" },
|
|
284
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
285
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
286
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: "get_chargeback",
|
|
292
|
+
description: "Get chargeback details by ID",
|
|
293
|
+
inputSchema: {
|
|
294
|
+
type: "object",
|
|
295
|
+
properties: { id: { type: "string", description: "Chargeback ID" } },
|
|
296
|
+
required: ["id"],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
// Notification subscriptions (webhooks)
|
|
300
|
+
{
|
|
301
|
+
name: "create_subscription",
|
|
302
|
+
description: "Register a notification subscription (webhook)",
|
|
134
303
|
inputSchema: {
|
|
135
304
|
type: "object",
|
|
136
305
|
properties: {
|
|
137
|
-
|
|
306
|
+
endpoint: { type: "string", description: "HTTPS webhook endpoint URL" },
|
|
138
307
|
},
|
|
308
|
+
required: ["endpoint"],
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "list_subscriptions",
|
|
313
|
+
description: "List notification subscriptions (webhooks)",
|
|
314
|
+
inputSchema: { type: "object", properties: {} },
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "delete_subscription",
|
|
318
|
+
description: "Delete a notification subscription",
|
|
319
|
+
inputSchema: {
|
|
320
|
+
type: "object",
|
|
321
|
+
properties: { id: { type: "string", description: "Subscription ID" } },
|
|
139
322
|
required: ["id"],
|
|
140
323
|
},
|
|
141
324
|
},
|
|
325
|
+
// Balance + transactions
|
|
142
326
|
{
|
|
143
327
|
name: "get_balance",
|
|
144
|
-
description: "Get account balance",
|
|
328
|
+
description: "Get business-account balance",
|
|
145
329
|
inputSchema: { type: "object", properties: {} },
|
|
146
330
|
},
|
|
147
331
|
{
|
|
@@ -162,46 +346,78 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
162
346
|
},
|
|
163
347
|
],
|
|
164
348
|
}));
|
|
349
|
+
function buildQuery(args, keys) {
|
|
350
|
+
const params = new URLSearchParams();
|
|
351
|
+
if (args) {
|
|
352
|
+
for (const k of keys) {
|
|
353
|
+
const v = args[k];
|
|
354
|
+
if (v !== undefined && v !== null && v !== "")
|
|
355
|
+
params.set(k, String(v));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const q = params.toString();
|
|
359
|
+
return q ? `?${q}` : "";
|
|
360
|
+
}
|
|
165
361
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
166
362
|
const { name, arguments: args } = request.params;
|
|
167
363
|
try {
|
|
168
364
|
switch (name) {
|
|
365
|
+
// Wallets
|
|
169
366
|
case "create_wallet":
|
|
170
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/wallets", args), null, 2) }] };
|
|
367
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/businessAccount/wallets", args), null, 2) }] };
|
|
171
368
|
case "get_wallet":
|
|
172
369
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/wallets/${args?.id}`), null, 2) }] };
|
|
370
|
+
case "list_wallets":
|
|
371
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/wallets${buildQuery(args, ["pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
372
|
+
// Payments
|
|
173
373
|
case "create_payment":
|
|
174
374
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/payments", args), null, 2) }] };
|
|
175
375
|
case "get_payment":
|
|
176
376
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payments/${args?.id}`), null, 2) }] };
|
|
377
|
+
// Payouts
|
|
177
378
|
case "create_payout":
|
|
178
379
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/payouts", args), null, 2) }] };
|
|
179
380
|
case "get_payout":
|
|
180
381
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payouts/${args?.id}`), null, 2) }] };
|
|
382
|
+
case "list_payouts":
|
|
383
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payouts${buildQuery(args, ["source", "destination", "type", "status", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
384
|
+
// Transfers
|
|
181
385
|
case "create_transfer":
|
|
182
386
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/transfers", args), null, 2) }] };
|
|
183
387
|
case "get_transfer":
|
|
184
388
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transfers/${args?.id}`), null, 2) }] };
|
|
389
|
+
case "list_transfers":
|
|
390
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transfers${buildQuery(args, ["walletId", "sourceWalletId", "destinationWalletId", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
391
|
+
// Cards
|
|
392
|
+
case "create_card":
|
|
393
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/cards", args), null, 2) }] };
|
|
394
|
+
case "get_card":
|
|
395
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/cards/${args?.id}`), null, 2) }] };
|
|
396
|
+
case "list_cards":
|
|
397
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/cards${buildQuery(args, ["pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
398
|
+
// Settlements
|
|
399
|
+
case "list_settlements":
|
|
400
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/settlements${buildQuery(args, ["from", "to", "pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
401
|
+
case "get_settlement":
|
|
402
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/settlements/${args?.id}`), null, 2) }] };
|
|
403
|
+
// Chargebacks
|
|
404
|
+
case "list_chargebacks":
|
|
405
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/chargebacks${buildQuery(args, ["paymentId", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
406
|
+
case "get_chargeback":
|
|
407
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/chargebacks/${args?.id}`), null, 2) }] };
|
|
408
|
+
// Notification subscriptions
|
|
409
|
+
case "create_subscription":
|
|
410
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/notifications/subscriptions", args), null, 2) }] };
|
|
411
|
+
case "list_subscriptions":
|
|
412
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/notifications/subscriptions"), null, 2) }] };
|
|
413
|
+
case "delete_subscription":
|
|
414
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("DELETE", `/notifications/subscriptions/${args?.id}`), null, 2) }] };
|
|
415
|
+
// Balance
|
|
185
416
|
case "get_balance":
|
|
186
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/balances"), null, 2) }] };
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
params.set("type", String(args.type));
|
|
191
|
-
if (args?.status)
|
|
192
|
-
params.set("status", String(args.status));
|
|
193
|
-
if (args?.from)
|
|
194
|
-
params.set("from", String(args.from));
|
|
195
|
-
if (args?.to)
|
|
196
|
-
params.set("to", String(args.to));
|
|
197
|
-
if (args?.pageSize)
|
|
198
|
-
params.set("pageSize", String(args.pageSize));
|
|
199
|
-
if (args?.pageBefore)
|
|
200
|
-
params.set("pageBefore", String(args.pageBefore));
|
|
201
|
-
if (args?.pageAfter)
|
|
202
|
-
params.set("pageAfter", String(args.pageAfter));
|
|
203
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transactions?${params}`), null, 2) }] };
|
|
204
|
-
}
|
|
417
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/businessAccount/balances"), null, 2) }] };
|
|
418
|
+
// Transactions
|
|
419
|
+
case "list_transactions":
|
|
420
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transactions${buildQuery(args, ["type", "status", "from", "to", "pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
205
421
|
default:
|
|
206
422
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
207
423
|
}
|
|
@@ -228,7 +444,7 @@ async function main() {
|
|
|
228
444
|
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
|
|
229
445
|
t.onclose = () => { if (t.sessionId)
|
|
230
446
|
transports.delete(t.sessionId); };
|
|
231
|
-
const s = new Server({ name: "mcp-circle", version: "0.
|
|
447
|
+
const s = new Server({ name: "mcp-circle", version: "0.2.0" }, { capabilities: { tools: {} } });
|
|
232
448
|
server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
|
|
233
449
|
server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
|
|
234
450
|
await s.connect(t);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codespar/mcp-circle",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Circle — USDC payments, wallets, payouts, transfers",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for Circle — USDC payments, wallets, payouts, transfers, cards, settlements, chargebacks, webhooks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"bin": {
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github",
|
|
8
8
|
"subfolder": "packages/crypto/circle"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.2.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@codespar/mcp-circle",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.2.0",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
package/src/index.ts
CHANGED
|
@@ -4,15 +4,28 @@
|
|
|
4
4
|
* MCP Server for Circle — USDC stablecoin infrastructure.
|
|
5
5
|
*
|
|
6
6
|
* Tools:
|
|
7
|
-
* - create_wallet: Create a new Circle wallet
|
|
7
|
+
* - create_wallet: Create a new Circle business-account wallet
|
|
8
8
|
* - get_wallet: Get wallet details by ID
|
|
9
|
+
* - list_wallets: List all wallets
|
|
9
10
|
* - create_payment: Accept a USDC payment
|
|
10
11
|
* - get_payment: Get payment details by ID
|
|
11
12
|
* - create_payout: Create a payout (USDC to fiat)
|
|
12
13
|
* - get_payout: Get payout details by ID
|
|
14
|
+
* - list_payouts: List payouts with filters
|
|
13
15
|
* - create_transfer: Create a USDC transfer between wallets
|
|
14
16
|
* - get_transfer: Get transfer details by ID
|
|
15
|
-
* -
|
|
17
|
+
* - list_transfers: List transfers with filters
|
|
18
|
+
* - create_card: Register card data for on-ramp
|
|
19
|
+
* - get_card: Get card details by ID
|
|
20
|
+
* - list_cards: List cards
|
|
21
|
+
* - list_settlements: List settlements
|
|
22
|
+
* - get_settlement: Get settlement details by ID
|
|
23
|
+
* - list_chargebacks: List chargebacks
|
|
24
|
+
* - get_chargeback: Get chargeback by ID
|
|
25
|
+
* - create_subscription: Register a notification subscription (webhook)
|
|
26
|
+
* - list_subscriptions: List notification subscriptions
|
|
27
|
+
* - delete_subscription: Remove a notification subscription
|
|
28
|
+
* - get_balance: Get business-account balance
|
|
16
29
|
* - list_transactions: List transactions with filters
|
|
17
30
|
*
|
|
18
31
|
* Environment:
|
|
@@ -48,15 +61,34 @@ async function circleRequest(method: string, path: string, body?: unknown): Prom
|
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
const server = new Server(
|
|
51
|
-
{ name: "mcp-circle", version: "0.
|
|
64
|
+
{ name: "mcp-circle", version: "0.2.0" },
|
|
52
65
|
{ capabilities: { tools: {} } }
|
|
53
66
|
);
|
|
54
67
|
|
|
68
|
+
const amountSchema = {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
amount: { type: "string", description: "Amount (e.g. '10.00')" },
|
|
72
|
+
currency: { type: "string", description: "Currency (USD)" },
|
|
73
|
+
},
|
|
74
|
+
required: ["amount", "currency"],
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const sourceDestSchema = (label: string) => ({
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
id: { type: "string", description: `${label} ID` },
|
|
81
|
+
type: { type: "string", description: `${label} type (e.g. wallet, card, ach, wire, blockchain)` },
|
|
82
|
+
},
|
|
83
|
+
required: ["id", "type"],
|
|
84
|
+
});
|
|
85
|
+
|
|
55
86
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
56
87
|
tools: [
|
|
88
|
+
// Wallets
|
|
57
89
|
{
|
|
58
90
|
name: "create_wallet",
|
|
59
|
-
description: "Create a new Circle wallet",
|
|
91
|
+
description: "Create a new Circle business-account wallet",
|
|
60
92
|
inputSchema: {
|
|
61
93
|
type: "object",
|
|
62
94
|
properties: {
|
|
@@ -69,14 +101,26 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
69
101
|
{
|
|
70
102
|
name: "get_wallet",
|
|
71
103
|
description: "Get wallet details by ID",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: { id: { type: "string", description: "Wallet ID" } },
|
|
107
|
+
required: ["id"],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "list_wallets",
|
|
112
|
+
description: "List all Circle wallets",
|
|
72
113
|
inputSchema: {
|
|
73
114
|
type: "object",
|
|
74
115
|
properties: {
|
|
75
|
-
|
|
116
|
+
pageSize: { type: "number", description: "Number of results per page" },
|
|
117
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
118
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
76
119
|
},
|
|
77
|
-
required: ["id"],
|
|
78
120
|
},
|
|
79
121
|
},
|
|
122
|
+
|
|
123
|
+
// Payments
|
|
80
124
|
{
|
|
81
125
|
name: "create_payment",
|
|
82
126
|
description: "Accept a USDC payment via Circle",
|
|
@@ -84,9 +128,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
84
128
|
type: "object",
|
|
85
129
|
properties: {
|
|
86
130
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
87
|
-
amount: {
|
|
88
|
-
source: {
|
|
131
|
+
amount: { ...amountSchema, description: "Payment amount" },
|
|
132
|
+
source: { ...sourceDestSchema("Source"), description: "Payment source" },
|
|
89
133
|
description: { type: "string", description: "Payment description" },
|
|
134
|
+
verification: { type: "string", description: "Verification method (cvv, three_d_secure, none)" },
|
|
135
|
+
metadata: { type: "object", description: "Payment metadata (email, phoneNumber, sessionId, ipAddress)" },
|
|
90
136
|
},
|
|
91
137
|
required: ["idempotencyKey", "amount", "source"],
|
|
92
138
|
},
|
|
@@ -96,12 +142,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
96
142
|
description: "Get payment details by ID",
|
|
97
143
|
inputSchema: {
|
|
98
144
|
type: "object",
|
|
99
|
-
properties: {
|
|
100
|
-
id: { type: "string", description: "Payment ID" },
|
|
101
|
-
},
|
|
145
|
+
properties: { id: { type: "string", description: "Payment ID" } },
|
|
102
146
|
required: ["id"],
|
|
103
147
|
},
|
|
104
148
|
},
|
|
149
|
+
|
|
150
|
+
// Payouts
|
|
105
151
|
{
|
|
106
152
|
name: "create_payout",
|
|
107
153
|
description: "Create a payout from Circle (USDC to fiat)",
|
|
@@ -109,8 +155,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
109
155
|
type: "object",
|
|
110
156
|
properties: {
|
|
111
157
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
112
|
-
amount: {
|
|
113
|
-
destination: {
|
|
158
|
+
amount: { ...amountSchema, description: "Payout amount" },
|
|
159
|
+
destination: { ...sourceDestSchema("Destination"), description: "Payout destination (bank account)" },
|
|
160
|
+
metadata: { type: "object", description: "Payout metadata (beneficiaryEmail)" },
|
|
114
161
|
},
|
|
115
162
|
required: ["idempotencyKey", "amount", "destination"],
|
|
116
163
|
},
|
|
@@ -118,24 +165,40 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
118
165
|
{
|
|
119
166
|
name: "get_payout",
|
|
120
167
|
description: "Get payout details by ID",
|
|
168
|
+
inputSchema: {
|
|
169
|
+
type: "object",
|
|
170
|
+
properties: { id: { type: "string", description: "Payout ID" } },
|
|
171
|
+
required: ["id"],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "list_payouts",
|
|
176
|
+
description: "List payouts with optional filters",
|
|
121
177
|
inputSchema: {
|
|
122
178
|
type: "object",
|
|
123
179
|
properties: {
|
|
124
|
-
|
|
180
|
+
source: { type: "string", description: "Filter by source wallet ID" },
|
|
181
|
+
destination: { type: "string", description: "Filter by destination ID" },
|
|
182
|
+
type: { type: "string", description: "Filter by type (wire, ach, sen)" },
|
|
183
|
+
status: { type: "string", description: "Filter by status (pending, complete, failed)" },
|
|
184
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
185
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
186
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
125
187
|
},
|
|
126
|
-
required: ["id"],
|
|
127
188
|
},
|
|
128
189
|
},
|
|
190
|
+
|
|
191
|
+
// Transfers
|
|
129
192
|
{
|
|
130
193
|
name: "create_transfer",
|
|
131
|
-
description: "Create a USDC transfer between Circle wallets",
|
|
194
|
+
description: "Create a USDC transfer between Circle wallets (or to blockchain address)",
|
|
132
195
|
inputSchema: {
|
|
133
196
|
type: "object",
|
|
134
197
|
properties: {
|
|
135
198
|
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
136
|
-
amount: {
|
|
137
|
-
source: {
|
|
138
|
-
destination: {
|
|
199
|
+
amount: { ...amountSchema, description: "Transfer amount" },
|
|
200
|
+
source: { ...sourceDestSchema("Source"), description: "Transfer source (wallet)" },
|
|
201
|
+
destination: { ...sourceDestSchema("Destination"), description: "Transfer destination (wallet or blockchain)" },
|
|
139
202
|
},
|
|
140
203
|
required: ["idempotencyKey", "amount", "source", "destination"],
|
|
141
204
|
},
|
|
@@ -143,17 +206,148 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
143
206
|
{
|
|
144
207
|
name: "get_transfer",
|
|
145
208
|
description: "Get transfer details by ID",
|
|
209
|
+
inputSchema: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: { id: { type: "string", description: "Transfer ID" } },
|
|
212
|
+
required: ["id"],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "list_transfers",
|
|
217
|
+
description: "List transfers with optional filters",
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: {
|
|
221
|
+
walletId: { type: "string", description: "Filter by wallet ID" },
|
|
222
|
+
sourceWalletId: { type: "string", description: "Filter by source wallet ID" },
|
|
223
|
+
destinationWalletId: { type: "string", description: "Filter by destination wallet ID" },
|
|
224
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
225
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
226
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// Cards
|
|
232
|
+
{
|
|
233
|
+
name: "create_card",
|
|
234
|
+
description: "Register card data for on-ramp payments",
|
|
146
235
|
inputSchema: {
|
|
147
236
|
type: "object",
|
|
148
237
|
properties: {
|
|
149
|
-
|
|
238
|
+
idempotencyKey: { type: "string", description: "Unique idempotency key (UUID)" },
|
|
239
|
+
keyId: { type: "string", description: "Public key ID used to encrypt card data" },
|
|
240
|
+
encryptedData: { type: "string", description: "PGP-encrypted card number + CVV" },
|
|
241
|
+
billingDetails: { type: "object", description: "Billing address details (name, city, country, line1, postalCode, district)" },
|
|
242
|
+
expMonth: { type: "number", description: "Card expiration month (1-12)" },
|
|
243
|
+
expYear: { type: "number", description: "Card expiration year (4-digit)" },
|
|
244
|
+
metadata: { type: "object", description: "Card metadata (email, phoneNumber, sessionId, ipAddress)" },
|
|
150
245
|
},
|
|
246
|
+
required: ["idempotencyKey", "keyId", "encryptedData", "billingDetails", "expMonth", "expYear"],
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: "get_card",
|
|
251
|
+
description: "Get card details by ID",
|
|
252
|
+
inputSchema: {
|
|
253
|
+
type: "object",
|
|
254
|
+
properties: { id: { type: "string", description: "Card ID" } },
|
|
151
255
|
required: ["id"],
|
|
152
256
|
},
|
|
153
257
|
},
|
|
258
|
+
{
|
|
259
|
+
name: "list_cards",
|
|
260
|
+
description: "List registered cards",
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: "object",
|
|
263
|
+
properties: {
|
|
264
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
265
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
266
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// Settlements
|
|
272
|
+
{
|
|
273
|
+
name: "list_settlements",
|
|
274
|
+
description: "List settlements (card payment batches)",
|
|
275
|
+
inputSchema: {
|
|
276
|
+
type: "object",
|
|
277
|
+
properties: {
|
|
278
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
279
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
280
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
281
|
+
pageBefore: { type: "string", description: "Cursor for previous page" },
|
|
282
|
+
pageAfter: { type: "string", description: "Cursor for next page" },
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: "get_settlement",
|
|
288
|
+
description: "Get settlement details by ID",
|
|
289
|
+
inputSchema: {
|
|
290
|
+
type: "object",
|
|
291
|
+
properties: { id: { type: "string", description: "Settlement ID" } },
|
|
292
|
+
required: ["id"],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
// Chargebacks
|
|
297
|
+
{
|
|
298
|
+
name: "list_chargebacks",
|
|
299
|
+
description: "List chargebacks",
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: "object",
|
|
302
|
+
properties: {
|
|
303
|
+
paymentId: { type: "string", description: "Filter by payment ID" },
|
|
304
|
+
from: { type: "string", description: "Start date (ISO 8601)" },
|
|
305
|
+
to: { type: "string", description: "End date (ISO 8601)" },
|
|
306
|
+
pageSize: { type: "number", description: "Results per page" },
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: "get_chargeback",
|
|
312
|
+
description: "Get chargeback details by ID",
|
|
313
|
+
inputSchema: {
|
|
314
|
+
type: "object",
|
|
315
|
+
properties: { id: { type: "string", description: "Chargeback ID" } },
|
|
316
|
+
required: ["id"],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
|
|
320
|
+
// Notification subscriptions (webhooks)
|
|
321
|
+
{
|
|
322
|
+
name: "create_subscription",
|
|
323
|
+
description: "Register a notification subscription (webhook)",
|
|
324
|
+
inputSchema: {
|
|
325
|
+
type: "object",
|
|
326
|
+
properties: {
|
|
327
|
+
endpoint: { type: "string", description: "HTTPS webhook endpoint URL" },
|
|
328
|
+
},
|
|
329
|
+
required: ["endpoint"],
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
name: "list_subscriptions",
|
|
334
|
+
description: "List notification subscriptions (webhooks)",
|
|
335
|
+
inputSchema: { type: "object", properties: {} },
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
name: "delete_subscription",
|
|
339
|
+
description: "Delete a notification subscription",
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: "object",
|
|
342
|
+
properties: { id: { type: "string", description: "Subscription ID" } },
|
|
343
|
+
required: ["id"],
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
// Balance + transactions
|
|
154
348
|
{
|
|
155
349
|
name: "get_balance",
|
|
156
|
-
description: "Get account balance",
|
|
350
|
+
description: "Get business-account balance",
|
|
157
351
|
inputSchema: { type: "object", properties: {} },
|
|
158
352
|
},
|
|
159
353
|
{
|
|
@@ -175,40 +369,89 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
175
369
|
],
|
|
176
370
|
}));
|
|
177
371
|
|
|
372
|
+
function buildQuery(args: Record<string, unknown> | undefined, keys: string[]): string {
|
|
373
|
+
const params = new URLSearchParams();
|
|
374
|
+
if (args) {
|
|
375
|
+
for (const k of keys) {
|
|
376
|
+
const v = args[k];
|
|
377
|
+
if (v !== undefined && v !== null && v !== "") params.set(k, String(v));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const q = params.toString();
|
|
381
|
+
return q ? `?${q}` : "";
|
|
382
|
+
}
|
|
383
|
+
|
|
178
384
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
179
385
|
const { name, arguments: args } = request.params;
|
|
180
386
|
|
|
181
387
|
try {
|
|
182
388
|
switch (name) {
|
|
389
|
+
// Wallets
|
|
183
390
|
case "create_wallet":
|
|
184
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/wallets", args), null, 2) }] };
|
|
391
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/businessAccount/wallets", args), null, 2) }] };
|
|
185
392
|
case "get_wallet":
|
|
186
393
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/wallets/${args?.id}`), null, 2) }] };
|
|
394
|
+
case "list_wallets":
|
|
395
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/wallets${buildQuery(args as any, ["pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
396
|
+
|
|
397
|
+
// Payments
|
|
187
398
|
case "create_payment":
|
|
188
399
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/payments", args), null, 2) }] };
|
|
189
400
|
case "get_payment":
|
|
190
401
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payments/${args?.id}`), null, 2) }] };
|
|
402
|
+
|
|
403
|
+
// Payouts
|
|
191
404
|
case "create_payout":
|
|
192
405
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/payouts", args), null, 2) }] };
|
|
193
406
|
case "get_payout":
|
|
194
407
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payouts/${args?.id}`), null, 2) }] };
|
|
408
|
+
case "list_payouts":
|
|
409
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/payouts${buildQuery(args as any, ["source", "destination", "type", "status", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
410
|
+
|
|
411
|
+
// Transfers
|
|
195
412
|
case "create_transfer":
|
|
196
413
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/transfers", args), null, 2) }] };
|
|
197
414
|
case "get_transfer":
|
|
198
415
|
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transfers/${args?.id}`), null, 2) }] };
|
|
416
|
+
case "list_transfers":
|
|
417
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transfers${buildQuery(args as any, ["walletId", "sourceWalletId", "destinationWalletId", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
418
|
+
|
|
419
|
+
// Cards
|
|
420
|
+
case "create_card":
|
|
421
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/cards", args), null, 2) }] };
|
|
422
|
+
case "get_card":
|
|
423
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/cards/${args?.id}`), null, 2) }] };
|
|
424
|
+
case "list_cards":
|
|
425
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/cards${buildQuery(args as any, ["pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
426
|
+
|
|
427
|
+
// Settlements
|
|
428
|
+
case "list_settlements":
|
|
429
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/settlements${buildQuery(args as any, ["from", "to", "pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
430
|
+
case "get_settlement":
|
|
431
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/settlements/${args?.id}`), null, 2) }] };
|
|
432
|
+
|
|
433
|
+
// Chargebacks
|
|
434
|
+
case "list_chargebacks":
|
|
435
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/chargebacks${buildQuery(args as any, ["paymentId", "from", "to", "pageSize"])}`), null, 2) }] };
|
|
436
|
+
case "get_chargeback":
|
|
437
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/chargebacks/${args?.id}`), null, 2) }] };
|
|
438
|
+
|
|
439
|
+
// Notification subscriptions
|
|
440
|
+
case "create_subscription":
|
|
441
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("POST", "/notifications/subscriptions", args), null, 2) }] };
|
|
442
|
+
case "list_subscriptions":
|
|
443
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/notifications/subscriptions"), null, 2) }] };
|
|
444
|
+
case "delete_subscription":
|
|
445
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("DELETE", `/notifications/subscriptions/${args?.id}`), null, 2) }] };
|
|
446
|
+
|
|
447
|
+
// Balance
|
|
199
448
|
case "get_balance":
|
|
200
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/balances"), null, 2) }] };
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (args?.to) params.set("to", String(args.to));
|
|
207
|
-
if (args?.pageSize) params.set("pageSize", String(args.pageSize));
|
|
208
|
-
if (args?.pageBefore) params.set("pageBefore", String(args.pageBefore));
|
|
209
|
-
if (args?.pageAfter) params.set("pageAfter", String(args.pageAfter));
|
|
210
|
-
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transactions?${params}`), null, 2) }] };
|
|
211
|
-
}
|
|
449
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", "/businessAccount/balances"), null, 2) }] };
|
|
450
|
+
|
|
451
|
+
// Transactions
|
|
452
|
+
case "list_transactions":
|
|
453
|
+
return { content: [{ type: "text", text: JSON.stringify(await circleRequest("GET", `/transactions${buildQuery(args as any, ["type", "status", "from", "to", "pageSize", "pageBefore", "pageAfter"])}`), null, 2) }] };
|
|
454
|
+
|
|
212
455
|
default:
|
|
213
456
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
214
457
|
}
|
|
@@ -231,7 +474,7 @@ async function main() {
|
|
|
231
474
|
if (!sid && isInitializeRequest(req.body)) {
|
|
232
475
|
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
|
|
233
476
|
t.onclose = () => { if (t.sessionId) transports.delete(t.sessionId); };
|
|
234
|
-
const s = new Server({ name: "mcp-circle", version: "0.
|
|
477
|
+
const s = new Server({ name: "mcp-circle", version: "0.2.0" }, { capabilities: { tools: {} } }); (server as any)._requestHandlers.forEach((v: any, k: any) => (s as any)._requestHandlers.set(k, v)); (server as any)._notificationHandlers?.forEach((v: any, k: any) => (s as any)._notificationHandlers.set(k, v)); await s.connect(t);
|
|
235
478
|
await t.handleRequest(req, res, req.body); return;
|
|
236
479
|
}
|
|
237
480
|
res.status(400).json({ jsonrpc: "2.0", error: { code: -32000, message: "Bad Request" }, id: null });
|