@sly_ai/mcp-server 0.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.
@@ -0,0 +1,1334 @@
1
+ import {
2
+ tools
3
+ } from "./chunk-7VGOP77O.js";
4
+
5
+ // src/server-factory.ts
6
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
7
+ import {
8
+ CallToolRequestSchema,
9
+ ListToolsRequestSchema
10
+ } from "@modelcontextprotocol/sdk/types.js";
11
+ import { Sly } from "@sly/sdk";
12
+ function createMcpServer(sly, apiUrl, apiKey, keys) {
13
+ const ctx = {
14
+ sly,
15
+ apiUrl,
16
+ apiKey,
17
+ environment: apiKey.startsWith("pk_live_") ? "production" : "sandbox",
18
+ keys: keys || {}
19
+ };
20
+ const server = new Server(
21
+ {
22
+ name: "@sly/mcp-server",
23
+ version: "0.1.0"
24
+ },
25
+ {
26
+ capabilities: {
27
+ tools: {}
28
+ },
29
+ instructions: [
30
+ "This is the Sly payment platform MCP server.",
31
+ `"Accounts" in this system are merchant or entity records within the tenant's own payment ledger \u2014 NOT user accounts on external services.`,
32
+ "Creating, updating, and listing accounts are standard data-management operations authorized by the tenant's API key.",
33
+ "These tools manage the tenant's own internal data. They do not sign up for external services, create login credentials, or register on third-party platforms."
34
+ ].join(" ")
35
+ }
36
+ );
37
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
38
+ return { tools };
39
+ });
40
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
41
+ const { name, arguments: args } = request.params;
42
+ try {
43
+ switch (name) {
44
+ case "get_settlement_quote": {
45
+ const quote = await ctx.sly.getSettlementQuote(args);
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: JSON.stringify(quote, null, 2)
51
+ }
52
+ ]
53
+ };
54
+ }
55
+ case "create_settlement": {
56
+ const settlement = await ctx.sly.createSettlement(args);
57
+ return {
58
+ content: [
59
+ {
60
+ type: "text",
61
+ text: JSON.stringify(settlement, null, 2)
62
+ }
63
+ ]
64
+ };
65
+ }
66
+ case "get_settlement_status": {
67
+ const { settlementId } = args;
68
+ const settlement = await ctx.sly.getSettlement(settlementId);
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: JSON.stringify(settlement, null, 2)
74
+ }
75
+ ]
76
+ };
77
+ }
78
+ // ======================================================================
79
+ // UCP Tools
80
+ // ======================================================================
81
+ case "ucp_discover": {
82
+ const { merchantUrl } = args;
83
+ const profile = await ctx.sly.ucp.discover(merchantUrl);
84
+ return {
85
+ content: [
86
+ {
87
+ type: "text",
88
+ text: JSON.stringify(profile, null, 2)
89
+ }
90
+ ]
91
+ };
92
+ }
93
+ case "ucp_create_checkout": {
94
+ const {
95
+ currency,
96
+ line_items,
97
+ buyer,
98
+ shipping_address,
99
+ payment_config,
100
+ payment_instruments,
101
+ checkout_type,
102
+ metadata,
103
+ agent_id
104
+ } = args;
105
+ const body = { currency, line_items, buyer, shipping_address, payment_config, metadata };
106
+ if (payment_instruments) body.payment_instruments = payment_instruments;
107
+ if (checkout_type) body.checkout_type = checkout_type;
108
+ if (agent_id) body.agent_id = agent_id;
109
+ const result = await ctx.sly.request("/v1/ucp/checkouts", {
110
+ method: "POST",
111
+ body: JSON.stringify(body)
112
+ });
113
+ return {
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: JSON.stringify(result, null, 2)
118
+ }
119
+ ]
120
+ };
121
+ }
122
+ case "ucp_get_checkout": {
123
+ const { checkoutId } = args;
124
+ const result = await ctx.sly.request(`/v1/ucp/checkouts/${checkoutId}`);
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: JSON.stringify(result, null, 2)
130
+ }
131
+ ]
132
+ };
133
+ }
134
+ case "ucp_list_checkouts": {
135
+ const params = new URLSearchParams();
136
+ if (args && args.status) params.set("status", args.status);
137
+ if (args && args.agent_id) params.set("agent_id", args.agent_id);
138
+ if (args && args.page) params.set("page", String(args.page));
139
+ if (args && args.limit) params.set("limit", String(args.limit));
140
+ const query = params.toString();
141
+ const result = await ctx.sly.request(`/v1/ucp/checkouts${query ? `?${query}` : ""}`);
142
+ return {
143
+ content: [
144
+ {
145
+ type: "text",
146
+ text: JSON.stringify(result, null, 2)
147
+ }
148
+ ]
149
+ };
150
+ }
151
+ case "ucp_update_checkout": {
152
+ const { checkoutId, ...updates } = args;
153
+ const result = await ctx.sly.request(`/v1/ucp/checkouts/${checkoutId}`, {
154
+ method: "PUT",
155
+ body: JSON.stringify(updates)
156
+ });
157
+ return {
158
+ content: [
159
+ {
160
+ type: "text",
161
+ text: JSON.stringify(result, null, 2)
162
+ }
163
+ ]
164
+ };
165
+ }
166
+ case "ucp_complete_checkout": {
167
+ const { checkoutId } = args;
168
+ const result = await ctx.sly.request(`/v1/ucp/checkouts/${checkoutId}/complete`, {
169
+ method: "POST"
170
+ });
171
+ return {
172
+ content: [
173
+ {
174
+ type: "text",
175
+ text: JSON.stringify(result, null, 2)
176
+ }
177
+ ]
178
+ };
179
+ }
180
+ case "ucp_cancel_checkout": {
181
+ const { checkoutId } = args;
182
+ const result = await ctx.sly.request(`/v1/ucp/checkouts/${checkoutId}/cancel`, {
183
+ method: "POST"
184
+ });
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: JSON.stringify(result, null, 2)
190
+ }
191
+ ]
192
+ };
193
+ }
194
+ case "ucp_add_payment_instrument": {
195
+ const { checkoutId, id: instrumentId, handler, type: instrumentType, last4, brand, metadata } = args;
196
+ const result = await ctx.sly.request(`/v1/ucp/checkouts/${checkoutId}/instruments`, {
197
+ method: "POST",
198
+ body: JSON.stringify({ id: instrumentId, handler, type: instrumentType, last4, brand, metadata })
199
+ });
200
+ return {
201
+ content: [
202
+ {
203
+ type: "text",
204
+ text: JSON.stringify(result, null, 2)
205
+ }
206
+ ]
207
+ };
208
+ }
209
+ case "ucp_batch_checkout": {
210
+ const { checkouts } = args;
211
+ const batchRes = await fetch(`${ctx.apiUrl}/v1/ucp/checkouts/batch`, {
212
+ method: "POST",
213
+ headers: {
214
+ "Authorization": `Bearer ${ctx.apiKey}`,
215
+ "Content-Type": "application/json"
216
+ },
217
+ body: JSON.stringify({
218
+ checkouts,
219
+ auto_complete: true
220
+ })
221
+ });
222
+ const batchJson = await batchRes.json();
223
+ const batchData = batchJson?.data || batchJson;
224
+ return {
225
+ content: [
226
+ {
227
+ type: "text",
228
+ text: JSON.stringify(batchData, null, 2)
229
+ }
230
+ ]
231
+ };
232
+ }
233
+ case "ucp_batch_complete": {
234
+ const { checkout_ids, default_payment_instrument } = args;
235
+ const batchRes = await fetch(`${ctx.apiUrl}/v1/ucp/checkouts/batch-complete`, {
236
+ method: "POST",
237
+ headers: {
238
+ "Authorization": `Bearer ${ctx.apiKey}`,
239
+ "Content-Type": "application/json"
240
+ },
241
+ body: JSON.stringify({ checkout_ids, default_payment_instrument })
242
+ });
243
+ const batchJson = await batchRes.json();
244
+ const batchData = batchJson?.data || batchJson;
245
+ return {
246
+ content: [
247
+ {
248
+ type: "text",
249
+ text: JSON.stringify(batchData, null, 2)
250
+ }
251
+ ]
252
+ };
253
+ }
254
+ case "ucp_list_orders": {
255
+ const params = new URLSearchParams();
256
+ if (args && args.status) params.set("status", args.status);
257
+ if (args && args.agent_id) params.set("agent_id", args.agent_id);
258
+ if (args && args.page) params.set("page", String(args.page));
259
+ if (args && args.limit) params.set("limit", String(args.limit));
260
+ const query = params.toString();
261
+ const result = await ctx.sly.request(`/v1/ucp/orders${query ? `?${query}` : ""}`);
262
+ return {
263
+ content: [
264
+ {
265
+ type: "text",
266
+ text: JSON.stringify(result, null, 2)
267
+ }
268
+ ]
269
+ };
270
+ }
271
+ case "ucp_get_order": {
272
+ const { orderId } = args;
273
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}`);
274
+ return {
275
+ content: [
276
+ {
277
+ type: "text",
278
+ text: JSON.stringify(result, null, 2)
279
+ }
280
+ ]
281
+ };
282
+ }
283
+ case "ucp_update_order_status": {
284
+ const { orderId, status } = args;
285
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/status`, {
286
+ method: "PUT",
287
+ body: JSON.stringify({ status })
288
+ });
289
+ return {
290
+ content: [
291
+ {
292
+ type: "text",
293
+ text: JSON.stringify(result, null, 2)
294
+ }
295
+ ]
296
+ };
297
+ }
298
+ case "ucp_cancel_order": {
299
+ const { orderId, reason } = args;
300
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/cancel`, {
301
+ method: "POST",
302
+ body: JSON.stringify({ reason })
303
+ });
304
+ return {
305
+ content: [
306
+ {
307
+ type: "text",
308
+ text: JSON.stringify(result, null, 2)
309
+ }
310
+ ]
311
+ };
312
+ }
313
+ case "ucp_add_fulfillment_event": {
314
+ const { orderId, type: eventType, description, tracking_number, carrier } = args;
315
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/events`, {
316
+ method: "POST",
317
+ body: JSON.stringify({ type: eventType, description, tracking_number, carrier })
318
+ });
319
+ return {
320
+ content: [
321
+ {
322
+ type: "text",
323
+ text: JSON.stringify(result, null, 2)
324
+ }
325
+ ]
326
+ };
327
+ }
328
+ // ======================================================================
329
+ // Merchant Catalog Tools
330
+ // ======================================================================
331
+ case "list_merchants": {
332
+ const params = new URLSearchParams();
333
+ if (args && args.type) params.set("type", args.type);
334
+ if (args && args.country) params.set("country", args.country);
335
+ if (args && args.search) params.set("search", args.search);
336
+ if (args && args.limit) params.set("limit", String(args.limit));
337
+ const query = params.toString();
338
+ const result = await ctx.sly.request(`/v1/ucp/merchants${query ? `?${query}` : ""}`);
339
+ return {
340
+ content: [
341
+ {
342
+ type: "text",
343
+ text: JSON.stringify(result, null, 2)
344
+ }
345
+ ]
346
+ };
347
+ }
348
+ case "get_merchant": {
349
+ const { merchantId } = args;
350
+ const result = await ctx.sly.request(`/v1/ucp/merchants/${merchantId}`);
351
+ return {
352
+ content: [
353
+ {
354
+ type: "text",
355
+ text: JSON.stringify(result, null, 2)
356
+ }
357
+ ]
358
+ };
359
+ }
360
+ // ======================================================================
361
+ // Agent Management Tools
362
+ // ======================================================================
363
+ case "list_accounts": {
364
+ const params = new URLSearchParams();
365
+ if (args && args.type) params.set("type", args.type);
366
+ if (args && args.status) params.set("status", args.status);
367
+ const query = params.toString();
368
+ const result = await ctx.sly.request(`/v1/accounts${query ? `?${query}` : ""}`);
369
+ return {
370
+ content: [
371
+ {
372
+ type: "text",
373
+ text: JSON.stringify(result, null, 2)
374
+ }
375
+ ]
376
+ };
377
+ }
378
+ case "create_account": {
379
+ const { type, name: accountName, email, metadata } = args;
380
+ const body = { type, name: accountName };
381
+ if (email) body.email = email;
382
+ if (metadata) body.metadata = metadata;
383
+ const result = await ctx.sly.request("/v1/accounts", {
384
+ method: "POST",
385
+ body: JSON.stringify(body)
386
+ });
387
+ return {
388
+ content: [
389
+ {
390
+ type: "text",
391
+ text: JSON.stringify(result, null, 2)
392
+ }
393
+ ]
394
+ };
395
+ }
396
+ case "update_account": {
397
+ const {
398
+ accountId,
399
+ name: accountName,
400
+ email,
401
+ metadata
402
+ } = args;
403
+ const body = {};
404
+ if (accountName !== void 0) body.name = accountName;
405
+ if (email !== void 0) body.email = email;
406
+ if (metadata !== void 0) body.metadata = metadata;
407
+ const result = await ctx.sly.request(`/v1/accounts/${accountId}`, {
408
+ method: "PATCH",
409
+ body: JSON.stringify(body)
410
+ });
411
+ return {
412
+ content: [
413
+ {
414
+ type: "text",
415
+ text: JSON.stringify(result, null, 2)
416
+ }
417
+ ]
418
+ };
419
+ }
420
+ case "get_tenant_info": {
421
+ const result = await ctx.sly.request("/v1/context/whoami");
422
+ return {
423
+ content: [
424
+ {
425
+ type: "text",
426
+ text: JSON.stringify(result, null, 2)
427
+ }
428
+ ]
429
+ };
430
+ }
431
+ case "create_agent": {
432
+ const { accountId, name: agentName, description } = args;
433
+ const result = await ctx.sly.request("/v1/agents", {
434
+ method: "POST",
435
+ body: JSON.stringify({
436
+ accountId,
437
+ name: agentName,
438
+ description
439
+ })
440
+ });
441
+ return {
442
+ content: [
443
+ {
444
+ type: "text",
445
+ text: JSON.stringify(result, null, 2)
446
+ }
447
+ ]
448
+ };
449
+ }
450
+ case "verify_agent": {
451
+ const { agentId, tier } = args;
452
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/verify`, {
453
+ method: "POST",
454
+ body: JSON.stringify({ tier })
455
+ });
456
+ return {
457
+ content: [
458
+ {
459
+ type: "text",
460
+ text: JSON.stringify(result, null, 2)
461
+ }
462
+ ]
463
+ };
464
+ }
465
+ case "get_agent": {
466
+ const { agentId } = args;
467
+ const result = await ctx.sly.request(`/v1/agents/${agentId}`);
468
+ return {
469
+ content: [
470
+ {
471
+ type: "text",
472
+ text: JSON.stringify(result, null, 2)
473
+ }
474
+ ]
475
+ };
476
+ }
477
+ case "get_agent_limits": {
478
+ const { agentId } = args;
479
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/limits`);
480
+ return {
481
+ content: [
482
+ {
483
+ type: "text",
484
+ text: JSON.stringify(result, null, 2)
485
+ }
486
+ ]
487
+ };
488
+ }
489
+ case "get_agent_transactions": {
490
+ const { agentId, limit: txLimit, offset: txOffset, from, to } = args;
491
+ const params = new URLSearchParams();
492
+ if (txLimit) params.set("limit", String(txLimit));
493
+ if (txOffset) params.set("offset", String(txOffset));
494
+ if (from) params.set("from", from);
495
+ if (to) params.set("to", to);
496
+ const query = params.toString();
497
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/transactions${query ? `?${query}` : ""}`);
498
+ return {
499
+ content: [
500
+ {
501
+ type: "text",
502
+ text: JSON.stringify(result, null, 2)
503
+ }
504
+ ]
505
+ };
506
+ }
507
+ case "delete_agent": {
508
+ const { agentId } = args;
509
+ const result = await ctx.sly.request(`/v1/agents/${agentId}`, {
510
+ method: "DELETE"
511
+ });
512
+ return {
513
+ content: [
514
+ {
515
+ type: "text",
516
+ text: JSON.stringify(result, null, 2)
517
+ }
518
+ ]
519
+ };
520
+ }
521
+ // ======================================================================
522
+ // AP2 Mandate Tools
523
+ // ======================================================================
524
+ case "ap2_cancel_mandate": {
525
+ const { mandateId } = args;
526
+ const result = await ctx.sly.request(`/v1/ap2/mandates/${mandateId}/cancel`, {
527
+ method: "PATCH",
528
+ body: JSON.stringify({})
529
+ });
530
+ return {
531
+ content: [
532
+ {
533
+ type: "text",
534
+ text: JSON.stringify(result, null, 2)
535
+ }
536
+ ]
537
+ };
538
+ }
539
+ case "ap2_create_mandate": {
540
+ const {
541
+ mandate_id,
542
+ agent_id,
543
+ account_id,
544
+ authorized_amount,
545
+ currency,
546
+ mandate_type,
547
+ description,
548
+ expires_at,
549
+ metadata,
550
+ mandate_data
551
+ } = args;
552
+ const result = await ctx.sly.ap2.createMandate({
553
+ mandate_id,
554
+ agent_id,
555
+ account_id,
556
+ authorized_amount,
557
+ currency,
558
+ mandate_type: mandate_type || "payment",
559
+ mandate_data: mandate_data || (description ? { description } : void 0),
560
+ metadata,
561
+ expires_at
562
+ });
563
+ return {
564
+ content: [
565
+ {
566
+ type: "text",
567
+ text: JSON.stringify(result, null, 2)
568
+ }
569
+ ]
570
+ };
571
+ }
572
+ case "ap2_get_mandate": {
573
+ const { mandateId } = args;
574
+ const result = await ctx.sly.ap2.getMandate(mandateId);
575
+ return {
576
+ content: [
577
+ {
578
+ type: "text",
579
+ text: JSON.stringify(result, null, 2)
580
+ }
581
+ ]
582
+ };
583
+ }
584
+ case "ap2_execute_mandate": {
585
+ const { mandateId, amount, currency, description, order_ids } = args;
586
+ const result = await ctx.sly.ap2.executeMandate(mandateId, {
587
+ amount,
588
+ currency,
589
+ description,
590
+ order_ids
591
+ });
592
+ return {
593
+ content: [
594
+ {
595
+ type: "text",
596
+ text: JSON.stringify(result, null, 2)
597
+ }
598
+ ]
599
+ };
600
+ }
601
+ case "ap2_list_mandates": {
602
+ const { status, agent_id, account_id, limit } = args || {};
603
+ const result = await ctx.sly.ap2.listMandates({
604
+ status,
605
+ agent_id,
606
+ account_id,
607
+ limit
608
+ });
609
+ return {
610
+ content: [
611
+ {
612
+ type: "text",
613
+ text: JSON.stringify(result, null, 2)
614
+ }
615
+ ]
616
+ };
617
+ }
618
+ case "ap2_update_mandate": {
619
+ const { mandateId, ...updateFields } = args;
620
+ const result = await ctx.sly.request(`/v1/ap2/mandates/${mandateId}`, {
621
+ method: "PATCH",
622
+ body: JSON.stringify(updateFields)
623
+ });
624
+ return {
625
+ content: [
626
+ {
627
+ type: "text",
628
+ text: JSON.stringify(result, null, 2)
629
+ }
630
+ ]
631
+ };
632
+ }
633
+ // ======================================================================
634
+ // ACP Checkout Tools
635
+ // ======================================================================
636
+ case "acp_create_checkout": {
637
+ const {
638
+ checkout_id,
639
+ agent_id,
640
+ account_id,
641
+ merchant_id,
642
+ items,
643
+ tax_amount,
644
+ shipping_amount,
645
+ payment_method,
646
+ checkout_data
647
+ } = args;
648
+ const result = await ctx.sly.acp.createCheckout({
649
+ checkout_id,
650
+ agent_id,
651
+ account_id: account_id || "",
652
+ merchant_id,
653
+ items,
654
+ tax_amount,
655
+ shipping_amount,
656
+ payment_method,
657
+ checkout_data
658
+ });
659
+ return {
660
+ content: [
661
+ {
662
+ type: "text",
663
+ text: JSON.stringify(result, null, 2)
664
+ }
665
+ ]
666
+ };
667
+ }
668
+ case "acp_get_checkout": {
669
+ const { checkoutId } = args;
670
+ const result = await ctx.sly.acp.getCheckout(checkoutId);
671
+ return {
672
+ content: [
673
+ {
674
+ type: "text",
675
+ text: JSON.stringify(result, null, 2)
676
+ }
677
+ ]
678
+ };
679
+ }
680
+ case "acp_complete_checkout": {
681
+ const { checkoutId, shared_payment_token, payment_method } = args;
682
+ const token = shared_payment_token || `spt_test_${Date.now()}`;
683
+ const result = await ctx.sly.acp.completeCheckout(checkoutId, {
684
+ shared_payment_token: token,
685
+ payment_method
686
+ });
687
+ return {
688
+ content: [
689
+ {
690
+ type: "text",
691
+ text: JSON.stringify(result, null, 2)
692
+ }
693
+ ]
694
+ };
695
+ }
696
+ case "acp_list_checkouts": {
697
+ const { status, agent_id, merchant_id, limit } = args || {};
698
+ const result = await ctx.sly.acp.listCheckouts({
699
+ status,
700
+ agent_id,
701
+ merchant_id,
702
+ limit
703
+ });
704
+ return {
705
+ content: [
706
+ {
707
+ type: "text",
708
+ text: JSON.stringify(result, null, 2)
709
+ }
710
+ ]
711
+ };
712
+ }
713
+ case "acp_batch_checkout": {
714
+ const { checkouts } = args;
715
+ const batchRes = await fetch(`${ctx.apiUrl}/v1/acp/checkouts/batch`, {
716
+ method: "POST",
717
+ headers: {
718
+ "Authorization": `Bearer ${ctx.apiKey}`,
719
+ "Content-Type": "application/json"
720
+ },
721
+ body: JSON.stringify({ checkouts })
722
+ });
723
+ const batchJson = await batchRes.json();
724
+ const batchData = batchJson?.data || batchJson;
725
+ return {
726
+ content: [
727
+ {
728
+ type: "text",
729
+ text: JSON.stringify(batchData, null, 2)
730
+ }
731
+ ]
732
+ };
733
+ }
734
+ // ======================================================================
735
+ // Wallet Management Tools
736
+ // ======================================================================
737
+ case "list_wallets": {
738
+ const params = new URLSearchParams();
739
+ if (args && args.owner_account_id) params.set("owner_account_id", args.owner_account_id);
740
+ if (args && args.managed_by_agent_id) params.set("managed_by_agent_id", args.managed_by_agent_id);
741
+ if (args && args.status) params.set("status", args.status);
742
+ if (args && args.page) params.set("page", String(args.page));
743
+ if (args && args.limit) params.set("limit", String(args.limit));
744
+ const query = params.toString();
745
+ const result = await ctx.sly.request(`/v1/wallets${query ? `?${query}` : ""}`);
746
+ return {
747
+ content: [
748
+ {
749
+ type: "text",
750
+ text: JSON.stringify(result, null, 2)
751
+ }
752
+ ]
753
+ };
754
+ }
755
+ case "create_wallet": {
756
+ const {
757
+ accountId,
758
+ name: walletName,
759
+ currency,
760
+ walletType,
761
+ blockchain,
762
+ initialBalance,
763
+ managedByAgentId,
764
+ purpose
765
+ } = args;
766
+ const result = await ctx.sly.request("/v1/wallets", {
767
+ method: "POST",
768
+ body: JSON.stringify({
769
+ accountId,
770
+ name: walletName,
771
+ currency,
772
+ walletType,
773
+ blockchain,
774
+ initialBalance,
775
+ managedByAgentId,
776
+ purpose
777
+ })
778
+ });
779
+ return {
780
+ content: [
781
+ {
782
+ type: "text",
783
+ text: JSON.stringify(result, null, 2)
784
+ }
785
+ ]
786
+ };
787
+ }
788
+ case "get_wallet": {
789
+ const { walletId } = args;
790
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}`);
791
+ return {
792
+ content: [
793
+ {
794
+ type: "text",
795
+ text: JSON.stringify(result, null, 2)
796
+ }
797
+ ]
798
+ };
799
+ }
800
+ case "get_wallet_balance": {
801
+ const { walletId } = args;
802
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/balance`);
803
+ return {
804
+ content: [
805
+ {
806
+ type: "text",
807
+ text: JSON.stringify(result, null, 2)
808
+ }
809
+ ]
810
+ };
811
+ }
812
+ case "wallet_deposit": {
813
+ const { walletId, amount, fromAccountId, reference } = args;
814
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/deposit`, {
815
+ method: "POST",
816
+ body: JSON.stringify({ amount, fromAccountId, reference })
817
+ });
818
+ return {
819
+ content: [
820
+ {
821
+ type: "text",
822
+ text: JSON.stringify(result, null, 2)
823
+ }
824
+ ]
825
+ };
826
+ }
827
+ case "wallet_withdraw": {
828
+ const { walletId, amount, destinationAccountId, reference } = args;
829
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/withdraw`, {
830
+ method: "POST",
831
+ body: JSON.stringify({ amount, destinationAccountId, reference })
832
+ });
833
+ return {
834
+ content: [
835
+ {
836
+ type: "text",
837
+ text: JSON.stringify(result, null, 2)
838
+ }
839
+ ]
840
+ };
841
+ }
842
+ case "wallet_test_fund": {
843
+ const { walletId, amount, currency, reference } = args;
844
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/test-fund`, {
845
+ method: "POST",
846
+ body: JSON.stringify({ amount, currency, reference })
847
+ });
848
+ return {
849
+ content: [
850
+ {
851
+ type: "text",
852
+ text: JSON.stringify(result, null, 2)
853
+ }
854
+ ]
855
+ };
856
+ }
857
+ // ======================================================================
858
+ // Agent Wallet Policy Tools (Epic 18)
859
+ // ======================================================================
860
+ case "agent_wallet_evaluate_policy": {
861
+ const { agentId, amount, currency, action_type, contract_type, counterparty_agent_id, counterparty_address } = args;
862
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy/evaluate`, {
863
+ method: "POST",
864
+ body: JSON.stringify({
865
+ amount,
866
+ currency: currency || "USDC",
867
+ action_type: action_type || "negotiation_check",
868
+ contract_type,
869
+ counterparty_agent_id,
870
+ counterparty_address
871
+ })
872
+ });
873
+ return {
874
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
875
+ };
876
+ }
877
+ case "agent_wallet_get_exposures": {
878
+ const { agentId } = args;
879
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/exposures`);
880
+ return {
881
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
882
+ };
883
+ }
884
+ case "agent_wallet_get_evaluations": {
885
+ const { agentId, page, limit } = args;
886
+ const params = new URLSearchParams();
887
+ if (page) params.set("page", String(page));
888
+ if (limit) params.set("limit", String(limit));
889
+ const qs = params.toString();
890
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy/evaluations${qs ? `?${qs}` : ""}`);
891
+ return {
892
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
893
+ };
894
+ }
895
+ case "agent_wallet_get": {
896
+ const { agentId } = args;
897
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet`);
898
+ return {
899
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
900
+ };
901
+ }
902
+ case "agent_wallet_freeze": {
903
+ const { agentId } = args;
904
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/freeze`, {
905
+ method: "POST"
906
+ });
907
+ return {
908
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
909
+ };
910
+ }
911
+ case "agent_wallet_unfreeze": {
912
+ const { agentId } = args;
913
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/unfreeze`, {
914
+ method: "POST"
915
+ });
916
+ return {
917
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
918
+ };
919
+ }
920
+ case "agent_wallet_set_policy": {
921
+ const { agentId, ...policyFields } = args;
922
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy`, {
923
+ method: "PUT",
924
+ body: JSON.stringify(policyFields)
925
+ });
926
+ return {
927
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
928
+ };
929
+ }
930
+ // ======================================================================
931
+ // x402 Micropayment Tools
932
+ // ======================================================================
933
+ case "x402_create_endpoint": {
934
+ const {
935
+ name: endpointName,
936
+ path,
937
+ method,
938
+ description,
939
+ accountId,
940
+ basePrice,
941
+ currency,
942
+ volumeDiscounts,
943
+ webhookUrl
944
+ } = args;
945
+ const result = await ctx.sly.request("/v1/x402/endpoints", {
946
+ method: "POST",
947
+ body: JSON.stringify({
948
+ name: endpointName,
949
+ path,
950
+ method,
951
+ description,
952
+ accountId,
953
+ basePrice,
954
+ currency,
955
+ volumeDiscounts,
956
+ webhookUrl
957
+ })
958
+ });
959
+ return {
960
+ content: [
961
+ {
962
+ type: "text",
963
+ text: JSON.stringify(result, null, 2)
964
+ }
965
+ ]
966
+ };
967
+ }
968
+ case "x402_list_endpoints": {
969
+ const params = new URLSearchParams();
970
+ if (args && args.status) params.set("status", args.status);
971
+ if (args && args.account_id) params.set("account_id", args.account_id);
972
+ if (args && args.page) params.set("page", String(args.page));
973
+ if (args && args.limit) params.set("limit", String(args.limit));
974
+ const query = params.toString();
975
+ const result = await ctx.sly.request(`/v1/x402/endpoints${query ? `?${query}` : ""}`);
976
+ return {
977
+ content: [
978
+ {
979
+ type: "text",
980
+ text: JSON.stringify(result, null, 2)
981
+ }
982
+ ]
983
+ };
984
+ }
985
+ case "x402_get_endpoint": {
986
+ const { endpointId } = args;
987
+ const result = await ctx.sly.request(`/v1/x402/endpoints/${endpointId}`);
988
+ return {
989
+ content: [
990
+ {
991
+ type: "text",
992
+ text: JSON.stringify(result, null, 2)
993
+ }
994
+ ]
995
+ };
996
+ }
997
+ case "x402_pay": {
998
+ const { endpointId, walletId, amount, currency, method: httpMethod, path: endpointPath } = args;
999
+ const requestId = crypto.randomUUID();
1000
+ const result = await ctx.sly.request("/v1/x402/pay", {
1001
+ method: "POST",
1002
+ body: JSON.stringify({
1003
+ endpointId,
1004
+ requestId,
1005
+ amount,
1006
+ currency,
1007
+ walletId,
1008
+ method: httpMethod,
1009
+ path: endpointPath,
1010
+ timestamp: Math.floor(Date.now() / 1e3)
1011
+ })
1012
+ });
1013
+ return {
1014
+ content: [
1015
+ {
1016
+ type: "text",
1017
+ text: JSON.stringify(result, null, 2)
1018
+ }
1019
+ ]
1020
+ };
1021
+ }
1022
+ case "x402_verify": {
1023
+ const { jwt, requestId, transferId } = args;
1024
+ const result = await ctx.sly.request("/v1/x402/verify", {
1025
+ method: "POST",
1026
+ body: JSON.stringify({ jwt, requestId, transferId })
1027
+ });
1028
+ return {
1029
+ content: [
1030
+ {
1031
+ type: "text",
1032
+ text: JSON.stringify(result, null, 2)
1033
+ }
1034
+ ]
1035
+ };
1036
+ }
1037
+ // ====================================================================
1038
+ // A2A Tools
1039
+ // ====================================================================
1040
+ case "a2a_discover_agent": {
1041
+ const { url } = args;
1042
+ const result = await ctx.sly.request("/v1/a2a/discover", {
1043
+ method: "POST",
1044
+ body: JSON.stringify({ url })
1045
+ });
1046
+ return {
1047
+ content: [
1048
+ {
1049
+ type: "text",
1050
+ text: JSON.stringify(result, null, 2)
1051
+ }
1052
+ ]
1053
+ };
1054
+ }
1055
+ case "a2a_send_task": {
1056
+ const { agent_id, remote_url, message, context_id } = args;
1057
+ const result = await ctx.sly.request("/v1/a2a/tasks", {
1058
+ method: "POST",
1059
+ body: JSON.stringify({
1060
+ agent_id,
1061
+ remote_url,
1062
+ message: {
1063
+ parts: [{ text: message }]
1064
+ },
1065
+ context_id
1066
+ })
1067
+ });
1068
+ return {
1069
+ content: [
1070
+ {
1071
+ type: "text",
1072
+ text: JSON.stringify(result, null, 2)
1073
+ }
1074
+ ]
1075
+ };
1076
+ }
1077
+ case "a2a_get_task": {
1078
+ const { task_id } = args;
1079
+ const result = await ctx.sly.request(`/v1/a2a/tasks/${task_id}`, {
1080
+ method: "GET"
1081
+ });
1082
+ return {
1083
+ content: [
1084
+ {
1085
+ type: "text",
1086
+ text: JSON.stringify(result, null, 2)
1087
+ }
1088
+ ]
1089
+ };
1090
+ }
1091
+ case "a2a_list_tasks": {
1092
+ const { agent_id, state, direction, limit, page } = args;
1093
+ const params = new URLSearchParams();
1094
+ if (agent_id) params.set("agent_id", agent_id);
1095
+ if (state) params.set("state", state);
1096
+ if (direction) params.set("direction", direction);
1097
+ if (limit) params.set("limit", String(limit));
1098
+ if (page) params.set("page", String(page));
1099
+ const query = params.toString();
1100
+ const result = await ctx.sly.request(`/v1/a2a/tasks${query ? `?${query}` : ""}`, {
1101
+ method: "GET"
1102
+ });
1103
+ return {
1104
+ content: [
1105
+ {
1106
+ type: "text",
1107
+ text: JSON.stringify(result, null, 2)
1108
+ }
1109
+ ]
1110
+ };
1111
+ }
1112
+ // ======================================================================
1113
+ // MPP Tools
1114
+ // ======================================================================
1115
+ case "mpp_pay": {
1116
+ const { service_url, amount, currency, intent, agent_id, wallet_id } = args;
1117
+ const result = await ctx.sly.request("/v1/mpp/pay", {
1118
+ method: "POST",
1119
+ body: JSON.stringify({ service_url, amount, currency, intent, agent_id, wallet_id })
1120
+ });
1121
+ return {
1122
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1123
+ };
1124
+ }
1125
+ case "mpp_open_session": {
1126
+ const { service_url, deposit_amount, max_budget, agent_id, wallet_id, currency } = args;
1127
+ const result = await ctx.sly.request("/v1/mpp/sessions", {
1128
+ method: "POST",
1129
+ body: JSON.stringify({ service_url, deposit_amount, max_budget, agent_id, wallet_id, currency })
1130
+ });
1131
+ return {
1132
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1133
+ };
1134
+ }
1135
+ case "mpp_get_session": {
1136
+ const { session_id } = args;
1137
+ const result = await ctx.sly.request(`/v1/mpp/sessions/${session_id}`);
1138
+ return {
1139
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1140
+ };
1141
+ }
1142
+ case "mpp_list_sessions": {
1143
+ const { agent_id, status, limit, offset } = args;
1144
+ const params = new URLSearchParams();
1145
+ if (agent_id) params.set("agent_id", agent_id);
1146
+ if (status) params.set("status", status);
1147
+ if (limit) params.set("limit", String(limit));
1148
+ if (offset) params.set("offset", String(offset));
1149
+ const query = params.toString();
1150
+ const result = await ctx.sly.request(`/v1/mpp/sessions${query ? `?${query}` : ""}`);
1151
+ return {
1152
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1153
+ };
1154
+ }
1155
+ case "mpp_close_session": {
1156
+ const { session_id } = args;
1157
+ const result = await ctx.sly.request(`/v1/mpp/sessions/${session_id}/close`, {
1158
+ method: "POST"
1159
+ });
1160
+ return {
1161
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1162
+ };
1163
+ }
1164
+ case "mpp_list_transfers": {
1165
+ const { service_url, session_id, limit, offset } = args;
1166
+ const params = new URLSearchParams();
1167
+ if (service_url) params.set("service_url", service_url);
1168
+ if (session_id) params.set("session_id", session_id);
1169
+ if (limit) params.set("limit", String(limit));
1170
+ if (offset) params.set("offset", String(offset));
1171
+ const query = params.toString();
1172
+ const result = await ctx.sly.request(`/v1/mpp/transfers${query ? `?${query}` : ""}`);
1173
+ return {
1174
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1175
+ };
1176
+ }
1177
+ case "mpp_verify_receipt": {
1178
+ const { receipt_id } = args;
1179
+ const result = await ctx.sly.request("/v1/mpp/receipts/verify", {
1180
+ method: "POST",
1181
+ body: JSON.stringify({ receipt_id })
1182
+ });
1183
+ return {
1184
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1185
+ };
1186
+ }
1187
+ // ====================================================================
1188
+ // Support Tools (Intercom Fin)
1189
+ // ====================================================================
1190
+ case "explain_rejection": {
1191
+ const { error_code, transaction_id, agent_id } = args;
1192
+ const params = new URLSearchParams();
1193
+ if (error_code) params.set("error_code", error_code);
1194
+ if (transaction_id) params.set("transaction_id", transaction_id);
1195
+ if (agent_id) params.set("agent_id", agent_id);
1196
+ const query = params.toString();
1197
+ const result = await ctx.sly.request(`/v1/support/explain-rejection${query ? `?${query}` : ""}`, {
1198
+ method: "GET"
1199
+ });
1200
+ return {
1201
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1202
+ };
1203
+ }
1204
+ case "request_limit_increase": {
1205
+ const { agent_id, limit_type, requested_amount, reason, duration } = args;
1206
+ const body = { agent_id, limit_type, requested_amount, reason };
1207
+ if (duration) body.duration = duration;
1208
+ const result = await ctx.sly.request("/v1/support/limit-requests", {
1209
+ method: "POST",
1210
+ body: JSON.stringify(body)
1211
+ });
1212
+ return {
1213
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1214
+ };
1215
+ }
1216
+ case "open_dispute": {
1217
+ const { transaction_id, reason, description, requested_resolution } = args;
1218
+ const body = {
1219
+ transferId: transaction_id,
1220
+ reason,
1221
+ description
1222
+ };
1223
+ if (requested_resolution) body.requestedResolution = requested_resolution;
1224
+ const result = await ctx.sly.request("/v1/disputes", {
1225
+ method: "POST",
1226
+ body: JSON.stringify(body)
1227
+ });
1228
+ return {
1229
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1230
+ };
1231
+ }
1232
+ case "escalate_to_human": {
1233
+ const { agent_id, reason, summary, priority } = args;
1234
+ const body = { reason, summary };
1235
+ if (agent_id) body.agent_id = agent_id;
1236
+ if (priority) body.priority = priority;
1237
+ const result = await ctx.sly.request("/v1/support/escalations", {
1238
+ method: "POST",
1239
+ body: JSON.stringify(body)
1240
+ });
1241
+ return {
1242
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1243
+ };
1244
+ }
1245
+ // ======================================================================
1246
+ // Environment Management Tools
1247
+ // ======================================================================
1248
+ case "get_environment": {
1249
+ const masked = ctx.apiKey.slice(0, 12) + "***";
1250
+ return {
1251
+ content: [
1252
+ {
1253
+ type: "text",
1254
+ text: JSON.stringify({
1255
+ environment: ctx.environment,
1256
+ apiKeyPrefix: masked,
1257
+ availableEnvironments: Object.keys(ctx.keys)
1258
+ }, null, 2)
1259
+ }
1260
+ ]
1261
+ };
1262
+ }
1263
+ case "switch_environment": {
1264
+ const { environment: targetEnv } = args;
1265
+ if (targetEnv === ctx.environment) {
1266
+ return {
1267
+ content: [
1268
+ {
1269
+ type: "text",
1270
+ text: JSON.stringify({
1271
+ message: `Already in ${targetEnv} environment`,
1272
+ environment: ctx.environment,
1273
+ apiKeyPrefix: ctx.apiKey.slice(0, 12) + "***"
1274
+ }, null, 2)
1275
+ }
1276
+ ]
1277
+ };
1278
+ }
1279
+ const targetKey = ctx.keys[targetEnv];
1280
+ if (!targetKey) {
1281
+ const hint = targetEnv === "production" ? "Set SLY_API_KEY_LIVE in your MCP server config (.mcp.json)" : "Set SLY_API_KEY in your MCP server config (.mcp.json)";
1282
+ return {
1283
+ content: [
1284
+ {
1285
+ type: "text",
1286
+ text: `Error: No API key configured for "${targetEnv}" environment. ${hint}`
1287
+ }
1288
+ ],
1289
+ isError: true
1290
+ };
1291
+ }
1292
+ ctx.sly = new Sly({
1293
+ apiKey: targetKey,
1294
+ apiUrl: ctx.apiUrl
1295
+ });
1296
+ ctx.apiKey = targetKey;
1297
+ ctx.environment = targetEnv;
1298
+ return {
1299
+ content: [
1300
+ {
1301
+ type: "text",
1302
+ text: JSON.stringify({
1303
+ message: `Switched to ${targetEnv} environment`,
1304
+ environment: ctx.environment,
1305
+ apiKeyPrefix: ctx.apiKey.slice(0, 12) + "***"
1306
+ }, null, 2)
1307
+ }
1308
+ ]
1309
+ };
1310
+ }
1311
+ default:
1312
+ throw new Error(`Unknown tool: ${name}`);
1313
+ }
1314
+ } catch (error) {
1315
+ const details = error.details || error.errors || "";
1316
+ const detailsStr = details ? `
1317
+ Details: ${JSON.stringify(details, null, 2)}` : "";
1318
+ return {
1319
+ content: [
1320
+ {
1321
+ type: "text",
1322
+ text: `Error: ${error.message}${detailsStr}`
1323
+ }
1324
+ ],
1325
+ isError: true
1326
+ };
1327
+ }
1328
+ });
1329
+ return server;
1330
+ }
1331
+
1332
+ export {
1333
+ createMcpServer
1334
+ };