@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,1298 @@
1
+ import {
2
+ tools
3
+ } from "./chunk-YDZJAN2U.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
+ "X-Environment": ctx.apiKey.startsWith("pk_live_") ? "live" : "test"
217
+ },
218
+ body: JSON.stringify({
219
+ checkouts,
220
+ auto_complete: true
221
+ })
222
+ });
223
+ const batchJson = await batchRes.json();
224
+ const batchData = batchJson?.data || batchJson;
225
+ return {
226
+ content: [
227
+ {
228
+ type: "text",
229
+ text: JSON.stringify(batchData, null, 2)
230
+ }
231
+ ]
232
+ };
233
+ }
234
+ case "ucp_batch_complete": {
235
+ const { checkout_ids, default_payment_instrument } = args;
236
+ const batchRes = await fetch(`${ctx.apiUrl}/v1/ucp/checkouts/batch-complete`, {
237
+ method: "POST",
238
+ headers: {
239
+ "Authorization": `Bearer ${ctx.apiKey}`,
240
+ "Content-Type": "application/json",
241
+ "X-Environment": ctx.apiKey.startsWith("pk_live_") ? "live" : "test"
242
+ },
243
+ body: JSON.stringify({ checkout_ids, default_payment_instrument })
244
+ });
245
+ const batchJson = await batchRes.json();
246
+ const batchData = batchJson?.data || batchJson;
247
+ return {
248
+ content: [
249
+ {
250
+ type: "text",
251
+ text: JSON.stringify(batchData, null, 2)
252
+ }
253
+ ]
254
+ };
255
+ }
256
+ case "ucp_list_orders": {
257
+ const params = new URLSearchParams();
258
+ if (args && args.status) params.set("status", args.status);
259
+ if (args && args.agent_id) params.set("agent_id", args.agent_id);
260
+ if (args && args.page) params.set("page", String(args.page));
261
+ if (args && args.limit) params.set("limit", String(args.limit));
262
+ const query = params.toString();
263
+ const result = await ctx.sly.request(`/v1/ucp/orders${query ? `?${query}` : ""}`);
264
+ return {
265
+ content: [
266
+ {
267
+ type: "text",
268
+ text: JSON.stringify(result, null, 2)
269
+ }
270
+ ]
271
+ };
272
+ }
273
+ case "ucp_get_order": {
274
+ const { orderId } = args;
275
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}`);
276
+ return {
277
+ content: [
278
+ {
279
+ type: "text",
280
+ text: JSON.stringify(result, null, 2)
281
+ }
282
+ ]
283
+ };
284
+ }
285
+ case "ucp_update_order_status": {
286
+ const { orderId, status } = args;
287
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/status`, {
288
+ method: "PUT",
289
+ body: JSON.stringify({ status })
290
+ });
291
+ return {
292
+ content: [
293
+ {
294
+ type: "text",
295
+ text: JSON.stringify(result, null, 2)
296
+ }
297
+ ]
298
+ };
299
+ }
300
+ case "ucp_cancel_order": {
301
+ const { orderId, reason } = args;
302
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/cancel`, {
303
+ method: "POST",
304
+ body: JSON.stringify({ reason })
305
+ });
306
+ return {
307
+ content: [
308
+ {
309
+ type: "text",
310
+ text: JSON.stringify(result, null, 2)
311
+ }
312
+ ]
313
+ };
314
+ }
315
+ case "ucp_add_fulfillment_event": {
316
+ const { orderId, type: eventType, description, tracking_number, carrier } = args;
317
+ const result = await ctx.sly.request(`/v1/ucp/orders/${orderId}/events`, {
318
+ method: "POST",
319
+ body: JSON.stringify({ type: eventType, description, tracking_number, carrier })
320
+ });
321
+ return {
322
+ content: [
323
+ {
324
+ type: "text",
325
+ text: JSON.stringify(result, null, 2)
326
+ }
327
+ ]
328
+ };
329
+ }
330
+ // ======================================================================
331
+ // Merchant Catalog Tools
332
+ // ======================================================================
333
+ case "list_merchants": {
334
+ const params = new URLSearchParams();
335
+ if (args && args.type) params.set("type", args.type);
336
+ if (args && args.country) params.set("country", args.country);
337
+ if (args && args.search) params.set("search", args.search);
338
+ if (args && args.limit) params.set("limit", String(args.limit));
339
+ const query = params.toString();
340
+ const result = await ctx.sly.request(`/v1/ucp/merchants${query ? `?${query}` : ""}`);
341
+ return {
342
+ content: [
343
+ {
344
+ type: "text",
345
+ text: JSON.stringify(result, null, 2)
346
+ }
347
+ ]
348
+ };
349
+ }
350
+ case "get_merchant": {
351
+ const { merchantId } = args;
352
+ const result = await ctx.sly.request(`/v1/ucp/merchants/${merchantId}`);
353
+ return {
354
+ content: [
355
+ {
356
+ type: "text",
357
+ text: JSON.stringify(result, null, 2)
358
+ }
359
+ ]
360
+ };
361
+ }
362
+ // ======================================================================
363
+ // Agent Management Tools
364
+ // ======================================================================
365
+ case "list_accounts": {
366
+ const params = new URLSearchParams();
367
+ if (args && args.type) params.set("type", args.type);
368
+ if (args && args.status) params.set("status", args.status);
369
+ const query = params.toString();
370
+ const result = await ctx.sly.request(`/v1/accounts${query ? `?${query}` : ""}`);
371
+ return {
372
+ content: [
373
+ {
374
+ type: "text",
375
+ text: JSON.stringify(result, null, 2)
376
+ }
377
+ ]
378
+ };
379
+ }
380
+ case "create_account": {
381
+ const { type, name: accountName, email, metadata } = args;
382
+ const body = { type, name: accountName };
383
+ if (email) body.email = email;
384
+ if (metadata) body.metadata = metadata;
385
+ const result = await ctx.sly.request("/v1/accounts", {
386
+ method: "POST",
387
+ body: JSON.stringify(body)
388
+ });
389
+ return {
390
+ content: [
391
+ {
392
+ type: "text",
393
+ text: JSON.stringify(result, null, 2)
394
+ }
395
+ ]
396
+ };
397
+ }
398
+ case "update_account": {
399
+ const {
400
+ accountId,
401
+ name: accountName,
402
+ email,
403
+ metadata
404
+ } = args;
405
+ const body = {};
406
+ if (accountName !== void 0) body.name = accountName;
407
+ if (email !== void 0) body.email = email;
408
+ if (metadata !== void 0) body.metadata = metadata;
409
+ const result = await ctx.sly.request(`/v1/accounts/${accountId}`, {
410
+ method: "PATCH",
411
+ body: JSON.stringify(body)
412
+ });
413
+ return {
414
+ content: [
415
+ {
416
+ type: "text",
417
+ text: JSON.stringify(result, null, 2)
418
+ }
419
+ ]
420
+ };
421
+ }
422
+ case "get_tenant_info": {
423
+ const result = await ctx.sly.request("/v1/context/whoami");
424
+ return {
425
+ content: [
426
+ {
427
+ type: "text",
428
+ text: JSON.stringify(result, null, 2)
429
+ }
430
+ ]
431
+ };
432
+ }
433
+ case "create_agent": {
434
+ const { accountId, name: agentName, description } = args;
435
+ const result = await ctx.sly.request("/v1/agents", {
436
+ method: "POST",
437
+ body: JSON.stringify({
438
+ accountId,
439
+ name: agentName,
440
+ description
441
+ })
442
+ });
443
+ return {
444
+ content: [
445
+ {
446
+ type: "text",
447
+ text: JSON.stringify(result, null, 2)
448
+ }
449
+ ]
450
+ };
451
+ }
452
+ case "verify_agent": {
453
+ const { agentId, tier } = args;
454
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/verify`, {
455
+ method: "POST",
456
+ body: JSON.stringify({ tier })
457
+ });
458
+ return {
459
+ content: [
460
+ {
461
+ type: "text",
462
+ text: JSON.stringify(result, null, 2)
463
+ }
464
+ ]
465
+ };
466
+ }
467
+ case "get_agent": {
468
+ const { agentId } = args;
469
+ const result = await ctx.sly.request(`/v1/agents/${agentId}`);
470
+ return {
471
+ content: [
472
+ {
473
+ type: "text",
474
+ text: JSON.stringify(result, null, 2)
475
+ }
476
+ ]
477
+ };
478
+ }
479
+ case "get_agent_limits": {
480
+ const { agentId } = args;
481
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/limits`);
482
+ return {
483
+ content: [
484
+ {
485
+ type: "text",
486
+ text: JSON.stringify(result, null, 2)
487
+ }
488
+ ]
489
+ };
490
+ }
491
+ case "get_agent_transactions": {
492
+ const { agentId, limit: txLimit, offset: txOffset, from, to } = args;
493
+ const params = new URLSearchParams();
494
+ if (txLimit) params.set("limit", String(txLimit));
495
+ if (txOffset) params.set("offset", String(txOffset));
496
+ if (from) params.set("from", from);
497
+ if (to) params.set("to", to);
498
+ const query = params.toString();
499
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/transactions${query ? `?${query}` : ""}`);
500
+ return {
501
+ content: [
502
+ {
503
+ type: "text",
504
+ text: JSON.stringify(result, null, 2)
505
+ }
506
+ ]
507
+ };
508
+ }
509
+ case "delete_agent": {
510
+ const { agentId } = args;
511
+ const result = await ctx.sly.request(`/v1/agents/${agentId}`, {
512
+ method: "DELETE"
513
+ });
514
+ return {
515
+ content: [
516
+ {
517
+ type: "text",
518
+ text: JSON.stringify(result, null, 2)
519
+ }
520
+ ]
521
+ };
522
+ }
523
+ // ======================================================================
524
+ // AP2 Mandate Tools
525
+ // ======================================================================
526
+ case "ap2_cancel_mandate": {
527
+ const { mandateId } = args;
528
+ const result = await ctx.sly.request(`/v1/ap2/mandates/${mandateId}/cancel`, {
529
+ method: "PATCH",
530
+ body: JSON.stringify({})
531
+ });
532
+ return {
533
+ content: [
534
+ {
535
+ type: "text",
536
+ text: JSON.stringify(result, null, 2)
537
+ }
538
+ ]
539
+ };
540
+ }
541
+ case "ap2_create_mandate": {
542
+ const {
543
+ mandate_id,
544
+ agent_id,
545
+ account_id,
546
+ authorized_amount,
547
+ currency,
548
+ mandate_type,
549
+ description,
550
+ expires_at,
551
+ metadata,
552
+ mandate_data
553
+ } = args;
554
+ const result = await ctx.sly.ap2.createMandate({
555
+ mandate_id,
556
+ agent_id,
557
+ account_id,
558
+ authorized_amount,
559
+ currency,
560
+ mandate_type: mandate_type || "payment",
561
+ mandate_data: mandate_data || (description ? { description } : void 0),
562
+ metadata,
563
+ expires_at
564
+ });
565
+ return {
566
+ content: [
567
+ {
568
+ type: "text",
569
+ text: JSON.stringify(result, null, 2)
570
+ }
571
+ ]
572
+ };
573
+ }
574
+ case "ap2_get_mandate": {
575
+ const { mandateId } = args;
576
+ const result = await ctx.sly.ap2.getMandate(mandateId);
577
+ return {
578
+ content: [
579
+ {
580
+ type: "text",
581
+ text: JSON.stringify(result, null, 2)
582
+ }
583
+ ]
584
+ };
585
+ }
586
+ case "ap2_execute_mandate": {
587
+ const { mandateId, amount, currency, description, order_ids } = args;
588
+ const result = await ctx.sly.ap2.executeMandate(mandateId, {
589
+ amount,
590
+ currency,
591
+ description,
592
+ order_ids
593
+ });
594
+ return {
595
+ content: [
596
+ {
597
+ type: "text",
598
+ text: JSON.stringify(result, null, 2)
599
+ }
600
+ ]
601
+ };
602
+ }
603
+ case "ap2_list_mandates": {
604
+ const { status, agent_id, account_id, limit } = args || {};
605
+ const result = await ctx.sly.ap2.listMandates({
606
+ status,
607
+ agent_id,
608
+ account_id,
609
+ limit
610
+ });
611
+ return {
612
+ content: [
613
+ {
614
+ type: "text",
615
+ text: JSON.stringify(result, null, 2)
616
+ }
617
+ ]
618
+ };
619
+ }
620
+ case "ap2_update_mandate": {
621
+ const { mandateId, ...updateFields } = args;
622
+ const result = await ctx.sly.request(`/v1/ap2/mandates/${mandateId}`, {
623
+ method: "PATCH",
624
+ body: JSON.stringify(updateFields)
625
+ });
626
+ return {
627
+ content: [
628
+ {
629
+ type: "text",
630
+ text: JSON.stringify(result, null, 2)
631
+ }
632
+ ]
633
+ };
634
+ }
635
+ // ======================================================================
636
+ // ACP Checkout Tools
637
+ // ======================================================================
638
+ case "acp_create_checkout": {
639
+ const {
640
+ checkout_id,
641
+ agent_id,
642
+ account_id,
643
+ merchant_id,
644
+ items,
645
+ tax_amount,
646
+ shipping_amount,
647
+ payment_method,
648
+ checkout_data
649
+ } = args;
650
+ const result = await ctx.sly.acp.createCheckout({
651
+ checkout_id,
652
+ agent_id,
653
+ account_id: account_id || "",
654
+ merchant_id,
655
+ items,
656
+ tax_amount,
657
+ shipping_amount,
658
+ payment_method,
659
+ checkout_data
660
+ });
661
+ return {
662
+ content: [
663
+ {
664
+ type: "text",
665
+ text: JSON.stringify(result, null, 2)
666
+ }
667
+ ]
668
+ };
669
+ }
670
+ case "acp_get_checkout": {
671
+ const { checkoutId } = args;
672
+ const result = await ctx.sly.acp.getCheckout(checkoutId);
673
+ return {
674
+ content: [
675
+ {
676
+ type: "text",
677
+ text: JSON.stringify(result, null, 2)
678
+ }
679
+ ]
680
+ };
681
+ }
682
+ case "acp_complete_checkout": {
683
+ const { checkoutId, shared_payment_token, payment_method } = args;
684
+ const token = shared_payment_token || `spt_test_${Date.now()}`;
685
+ const result = await ctx.sly.acp.completeCheckout(checkoutId, {
686
+ shared_payment_token: token,
687
+ payment_method
688
+ });
689
+ return {
690
+ content: [
691
+ {
692
+ type: "text",
693
+ text: JSON.stringify(result, null, 2)
694
+ }
695
+ ]
696
+ };
697
+ }
698
+ case "acp_list_checkouts": {
699
+ const { status, agent_id, merchant_id, limit } = args || {};
700
+ const result = await ctx.sly.acp.listCheckouts({
701
+ status,
702
+ agent_id,
703
+ merchant_id,
704
+ limit
705
+ });
706
+ return {
707
+ content: [
708
+ {
709
+ type: "text",
710
+ text: JSON.stringify(result, null, 2)
711
+ }
712
+ ]
713
+ };
714
+ }
715
+ case "acp_batch_checkout": {
716
+ const { checkouts } = args;
717
+ const batchRes = await fetch(`${ctx.apiUrl}/v1/acp/checkouts/batch`, {
718
+ method: "POST",
719
+ headers: {
720
+ "Authorization": `Bearer ${ctx.apiKey}`,
721
+ "Content-Type": "application/json",
722
+ "X-Environment": ctx.apiKey.startsWith("pk_live_") ? "live" : "test"
723
+ },
724
+ body: JSON.stringify({ checkouts })
725
+ });
726
+ const batchJson = await batchRes.json();
727
+ const batchData = batchJson?.data || batchJson;
728
+ return {
729
+ content: [
730
+ {
731
+ type: "text",
732
+ text: JSON.stringify(batchData, null, 2)
733
+ }
734
+ ]
735
+ };
736
+ }
737
+ // ======================================================================
738
+ // Wallet Management Tools
739
+ // ======================================================================
740
+ case "list_wallets": {
741
+ const params = new URLSearchParams();
742
+ if (args && args.owner_account_id) params.set("owner_account_id", args.owner_account_id);
743
+ if (args && args.managed_by_agent_id) params.set("managed_by_agent_id", args.managed_by_agent_id);
744
+ if (args && args.status) params.set("status", args.status);
745
+ if (args && args.page) params.set("page", String(args.page));
746
+ if (args && args.limit) params.set("limit", String(args.limit));
747
+ const query = params.toString();
748
+ const result = await ctx.sly.request(`/v1/wallets${query ? `?${query}` : ""}`);
749
+ return {
750
+ content: [
751
+ {
752
+ type: "text",
753
+ text: JSON.stringify(result, null, 2)
754
+ }
755
+ ]
756
+ };
757
+ }
758
+ case "create_wallet": {
759
+ const {
760
+ accountId,
761
+ name: walletName,
762
+ currency,
763
+ walletType,
764
+ blockchain,
765
+ initialBalance,
766
+ managedByAgentId,
767
+ purpose
768
+ } = args;
769
+ const result = await ctx.sly.request("/v1/wallets", {
770
+ method: "POST",
771
+ body: JSON.stringify({
772
+ accountId,
773
+ name: walletName,
774
+ currency,
775
+ walletType,
776
+ blockchain,
777
+ initialBalance,
778
+ managedByAgentId,
779
+ purpose
780
+ })
781
+ });
782
+ return {
783
+ content: [
784
+ {
785
+ type: "text",
786
+ text: JSON.stringify(result, null, 2)
787
+ }
788
+ ]
789
+ };
790
+ }
791
+ case "get_wallet": {
792
+ const { walletId } = args;
793
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}`);
794
+ return {
795
+ content: [
796
+ {
797
+ type: "text",
798
+ text: JSON.stringify(result, null, 2)
799
+ }
800
+ ]
801
+ };
802
+ }
803
+ case "get_wallet_balance": {
804
+ const { walletId } = args;
805
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/balance`);
806
+ return {
807
+ content: [
808
+ {
809
+ type: "text",
810
+ text: JSON.stringify(result, null, 2)
811
+ }
812
+ ]
813
+ };
814
+ }
815
+ case "wallet_deposit": {
816
+ const { walletId, amount, fromAccountId, reference } = args;
817
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/deposit`, {
818
+ method: "POST",
819
+ body: JSON.stringify({ amount, fromAccountId, reference })
820
+ });
821
+ return {
822
+ content: [
823
+ {
824
+ type: "text",
825
+ text: JSON.stringify(result, null, 2)
826
+ }
827
+ ]
828
+ };
829
+ }
830
+ case "wallet_withdraw": {
831
+ const { walletId, amount, destinationAccountId, reference } = args;
832
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/withdraw`, {
833
+ method: "POST",
834
+ body: JSON.stringify({ amount, destinationAccountId, reference })
835
+ });
836
+ return {
837
+ content: [
838
+ {
839
+ type: "text",
840
+ text: JSON.stringify(result, null, 2)
841
+ }
842
+ ]
843
+ };
844
+ }
845
+ case "wallet_test_fund": {
846
+ const { walletId, amount, currency, reference } = args;
847
+ const result = await ctx.sly.request(`/v1/wallets/${walletId}/test-fund`, {
848
+ method: "POST",
849
+ body: JSON.stringify({ amount, currency, reference })
850
+ });
851
+ return {
852
+ content: [
853
+ {
854
+ type: "text",
855
+ text: JSON.stringify(result, null, 2)
856
+ }
857
+ ]
858
+ };
859
+ }
860
+ // ======================================================================
861
+ // Agent Wallet Policy Tools (Epic 18)
862
+ // ======================================================================
863
+ case "agent_wallet_evaluate_policy": {
864
+ const { agentId, amount, currency, action_type, contract_type, counterparty_agent_id, counterparty_address } = args;
865
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy/evaluate`, {
866
+ method: "POST",
867
+ body: JSON.stringify({
868
+ amount,
869
+ currency: currency || "USDC",
870
+ action_type: action_type || "negotiation_check",
871
+ contract_type,
872
+ counterparty_agent_id,
873
+ counterparty_address
874
+ })
875
+ });
876
+ return {
877
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
878
+ };
879
+ }
880
+ case "agent_wallet_get_exposures": {
881
+ const { agentId } = args;
882
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/exposures`);
883
+ return {
884
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
885
+ };
886
+ }
887
+ case "agent_wallet_get_evaluations": {
888
+ const { agentId, page, limit } = args;
889
+ const params = new URLSearchParams();
890
+ if (page) params.set("page", String(page));
891
+ if (limit) params.set("limit", String(limit));
892
+ const qs = params.toString();
893
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy/evaluations${qs ? `?${qs}` : ""}`);
894
+ return {
895
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
896
+ };
897
+ }
898
+ case "agent_wallet_get": {
899
+ const { agentId } = args;
900
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet`);
901
+ return {
902
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
903
+ };
904
+ }
905
+ case "agent_wallet_freeze": {
906
+ const { agentId } = args;
907
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/freeze`, {
908
+ method: "POST"
909
+ });
910
+ return {
911
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
912
+ };
913
+ }
914
+ case "agent_wallet_unfreeze": {
915
+ const { agentId } = args;
916
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/unfreeze`, {
917
+ method: "POST"
918
+ });
919
+ return {
920
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
921
+ };
922
+ }
923
+ case "agent_wallet_set_policy": {
924
+ const { agentId, ...policyFields } = args;
925
+ const result = await ctx.sly.request(`/v1/agents/${agentId}/wallet/policy`, {
926
+ method: "PUT",
927
+ body: JSON.stringify(policyFields)
928
+ });
929
+ return {
930
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
931
+ };
932
+ }
933
+ // ======================================================================
934
+ // x402 Micropayment Tools
935
+ // ======================================================================
936
+ case "x402_create_endpoint": {
937
+ const {
938
+ name: endpointName,
939
+ path,
940
+ method,
941
+ description,
942
+ accountId,
943
+ basePrice,
944
+ currency,
945
+ volumeDiscounts,
946
+ webhookUrl
947
+ } = args;
948
+ const result = await ctx.sly.request("/v1/x402/endpoints", {
949
+ method: "POST",
950
+ body: JSON.stringify({
951
+ name: endpointName,
952
+ path,
953
+ method,
954
+ description,
955
+ accountId,
956
+ basePrice,
957
+ currency,
958
+ volumeDiscounts,
959
+ webhookUrl
960
+ })
961
+ });
962
+ return {
963
+ content: [
964
+ {
965
+ type: "text",
966
+ text: JSON.stringify(result, null, 2)
967
+ }
968
+ ]
969
+ };
970
+ }
971
+ case "x402_list_endpoints": {
972
+ const params = new URLSearchParams();
973
+ if (args && args.status) params.set("status", args.status);
974
+ if (args && args.account_id) params.set("account_id", args.account_id);
975
+ if (args && args.page) params.set("page", String(args.page));
976
+ if (args && args.limit) params.set("limit", String(args.limit));
977
+ const query = params.toString();
978
+ const result = await ctx.sly.request(`/v1/x402/endpoints${query ? `?${query}` : ""}`);
979
+ return {
980
+ content: [
981
+ {
982
+ type: "text",
983
+ text: JSON.stringify(result, null, 2)
984
+ }
985
+ ]
986
+ };
987
+ }
988
+ case "x402_get_endpoint": {
989
+ const { endpointId } = args;
990
+ const result = await ctx.sly.request(`/v1/x402/endpoints/${endpointId}`);
991
+ return {
992
+ content: [
993
+ {
994
+ type: "text",
995
+ text: JSON.stringify(result, null, 2)
996
+ }
997
+ ]
998
+ };
999
+ }
1000
+ case "x402_pay": {
1001
+ const { endpointId, walletId, amount, currency, method: httpMethod, path: endpointPath } = args;
1002
+ const requestId = crypto.randomUUID();
1003
+ const result = await ctx.sly.request("/v1/x402/pay", {
1004
+ method: "POST",
1005
+ body: JSON.stringify({
1006
+ endpointId,
1007
+ requestId,
1008
+ amount,
1009
+ currency,
1010
+ walletId,
1011
+ method: httpMethod,
1012
+ path: endpointPath,
1013
+ timestamp: Math.floor(Date.now() / 1e3)
1014
+ })
1015
+ });
1016
+ return {
1017
+ content: [
1018
+ {
1019
+ type: "text",
1020
+ text: JSON.stringify(result, null, 2)
1021
+ }
1022
+ ]
1023
+ };
1024
+ }
1025
+ case "x402_verify": {
1026
+ const { jwt, requestId, transferId } = args;
1027
+ const result = await ctx.sly.request("/v1/x402/verify", {
1028
+ method: "POST",
1029
+ body: JSON.stringify({ jwt, requestId, transferId })
1030
+ });
1031
+ return {
1032
+ content: [
1033
+ {
1034
+ type: "text",
1035
+ text: JSON.stringify(result, null, 2)
1036
+ }
1037
+ ]
1038
+ };
1039
+ }
1040
+ // ====================================================================
1041
+ // A2A Tools
1042
+ // ====================================================================
1043
+ case "a2a_discover_agent": {
1044
+ const { url } = args;
1045
+ const result = await ctx.sly.request("/v1/a2a/discover", {
1046
+ method: "POST",
1047
+ body: JSON.stringify({ url })
1048
+ });
1049
+ return {
1050
+ content: [
1051
+ {
1052
+ type: "text",
1053
+ text: JSON.stringify(result, null, 2)
1054
+ }
1055
+ ]
1056
+ };
1057
+ }
1058
+ case "a2a_send_task": {
1059
+ const { agent_id, remote_url, message, context_id } = args;
1060
+ const result = await ctx.sly.request("/v1/a2a/tasks", {
1061
+ method: "POST",
1062
+ body: JSON.stringify({
1063
+ agent_id,
1064
+ remote_url,
1065
+ message: {
1066
+ parts: [{ text: message }]
1067
+ },
1068
+ context_id
1069
+ })
1070
+ });
1071
+ return {
1072
+ content: [
1073
+ {
1074
+ type: "text",
1075
+ text: JSON.stringify(result, null, 2)
1076
+ }
1077
+ ]
1078
+ };
1079
+ }
1080
+ case "a2a_get_task": {
1081
+ const { task_id } = args;
1082
+ const result = await ctx.sly.request(`/v1/a2a/tasks/${task_id}`, {
1083
+ method: "GET"
1084
+ });
1085
+ return {
1086
+ content: [
1087
+ {
1088
+ type: "text",
1089
+ text: JSON.stringify(result, null, 2)
1090
+ }
1091
+ ]
1092
+ };
1093
+ }
1094
+ case "a2a_list_tasks": {
1095
+ const { agent_id, state, direction, limit, page } = args;
1096
+ const params = new URLSearchParams();
1097
+ if (agent_id) params.set("agent_id", agent_id);
1098
+ if (state) params.set("state", state);
1099
+ if (direction) params.set("direction", direction);
1100
+ if (limit) params.set("limit", String(limit));
1101
+ if (page) params.set("page", String(page));
1102
+ const query = params.toString();
1103
+ const result = await ctx.sly.request(`/v1/a2a/tasks${query ? `?${query}` : ""}`, {
1104
+ method: "GET"
1105
+ });
1106
+ return {
1107
+ content: [
1108
+ {
1109
+ type: "text",
1110
+ text: JSON.stringify(result, null, 2)
1111
+ }
1112
+ ]
1113
+ };
1114
+ }
1115
+ // ======================================================================
1116
+ // MPP Tools
1117
+ // ======================================================================
1118
+ case "mpp_pay": {
1119
+ const { service_url, amount, currency, intent, agent_id, wallet_id } = args;
1120
+ const result = await ctx.sly.request("/v1/mpp/pay", {
1121
+ method: "POST",
1122
+ body: JSON.stringify({ service_url, amount, currency, intent, agent_id, wallet_id })
1123
+ });
1124
+ return {
1125
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1126
+ };
1127
+ }
1128
+ case "mpp_open_session": {
1129
+ const { service_url, deposit_amount, max_budget, agent_id, wallet_id, currency } = args;
1130
+ const result = await ctx.sly.request("/v1/mpp/sessions", {
1131
+ method: "POST",
1132
+ body: JSON.stringify({ service_url, deposit_amount, max_budget, agent_id, wallet_id, currency })
1133
+ });
1134
+ return {
1135
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1136
+ };
1137
+ }
1138
+ case "mpp_get_session": {
1139
+ const { session_id } = args;
1140
+ const result = await ctx.sly.request(`/v1/mpp/sessions/${session_id}`);
1141
+ return {
1142
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1143
+ };
1144
+ }
1145
+ case "mpp_list_sessions": {
1146
+ const { agent_id, status, limit, offset } = args;
1147
+ const params = new URLSearchParams();
1148
+ if (agent_id) params.set("agent_id", agent_id);
1149
+ if (status) params.set("status", status);
1150
+ if (limit) params.set("limit", String(limit));
1151
+ if (offset) params.set("offset", String(offset));
1152
+ const query = params.toString();
1153
+ const result = await ctx.sly.request(`/v1/mpp/sessions${query ? `?${query}` : ""}`);
1154
+ return {
1155
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1156
+ };
1157
+ }
1158
+ case "mpp_close_session": {
1159
+ const { session_id } = args;
1160
+ const result = await ctx.sly.request(`/v1/mpp/sessions/${session_id}/close`, {
1161
+ method: "POST"
1162
+ });
1163
+ return {
1164
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1165
+ };
1166
+ }
1167
+ case "mpp_list_transfers": {
1168
+ const { service_url, session_id, limit, offset } = args;
1169
+ const params = new URLSearchParams();
1170
+ if (service_url) params.set("service_url", service_url);
1171
+ if (session_id) params.set("session_id", session_id);
1172
+ if (limit) params.set("limit", String(limit));
1173
+ if (offset) params.set("offset", String(offset));
1174
+ const query = params.toString();
1175
+ const result = await ctx.sly.request(`/v1/mpp/transfers${query ? `?${query}` : ""}`);
1176
+ return {
1177
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1178
+ };
1179
+ }
1180
+ case "mpp_verify_receipt": {
1181
+ const { receipt_id } = args;
1182
+ const result = await ctx.sly.request("/v1/mpp/receipts/verify", {
1183
+ method: "POST",
1184
+ body: JSON.stringify({ receipt_id })
1185
+ });
1186
+ return {
1187
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1188
+ };
1189
+ }
1190
+ // ====================================================================
1191
+ // Support Tools (Intercom Fin)
1192
+ // ====================================================================
1193
+ case "explain_rejection": {
1194
+ const { error_code, transaction_id, agent_id } = args;
1195
+ const params = new URLSearchParams();
1196
+ if (error_code) params.set("error_code", error_code);
1197
+ if (transaction_id) params.set("transaction_id", transaction_id);
1198
+ if (agent_id) params.set("agent_id", agent_id);
1199
+ const query = params.toString();
1200
+ const result = await ctx.sly.request(`/v1/support/explain-rejection${query ? `?${query}` : ""}`, {
1201
+ method: "GET"
1202
+ });
1203
+ return {
1204
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1205
+ };
1206
+ }
1207
+ case "request_limit_increase": {
1208
+ const { agent_id, limit_type, requested_amount, reason, duration } = args;
1209
+ const body = { agent_id, limit_type, requested_amount, reason };
1210
+ if (duration) body.duration = duration;
1211
+ const result = await ctx.sly.request("/v1/support/limit-requests", {
1212
+ method: "POST",
1213
+ body: JSON.stringify(body)
1214
+ });
1215
+ return {
1216
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1217
+ };
1218
+ }
1219
+ case "open_dispute": {
1220
+ const { transaction_id, reason, description, requested_resolution } = args;
1221
+ const body = {
1222
+ transferId: transaction_id,
1223
+ reason,
1224
+ description
1225
+ };
1226
+ if (requested_resolution) body.requestedResolution = requested_resolution;
1227
+ const result = await ctx.sly.request("/v1/disputes", {
1228
+ method: "POST",
1229
+ body: JSON.stringify(body)
1230
+ });
1231
+ return {
1232
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1233
+ };
1234
+ }
1235
+ case "escalate_to_human": {
1236
+ const { agent_id, reason, summary, priority } = args;
1237
+ const body = { reason, summary };
1238
+ if (agent_id) body.agent_id = agent_id;
1239
+ if (priority) body.priority = priority;
1240
+ const result = await ctx.sly.request("/v1/support/escalations", {
1241
+ method: "POST",
1242
+ body: JSON.stringify(body)
1243
+ });
1244
+ return {
1245
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
1246
+ };
1247
+ }
1248
+ // ======================================================================
1249
+ // Environment Management Tools
1250
+ // ======================================================================
1251
+ case "get_environment": {
1252
+ const masked = ctx.apiKey.slice(0, 12) + "***";
1253
+ return {
1254
+ content: [{
1255
+ type: "text",
1256
+ text: JSON.stringify({ environment: ctx.environment, apiKeyPrefix: masked, availableEnvironments: Object.keys(ctx.keys) }, null, 2)
1257
+ }]
1258
+ };
1259
+ }
1260
+ case "switch_environment": {
1261
+ const { environment: targetEnv } = args;
1262
+ if (targetEnv === ctx.environment) {
1263
+ return { content: [{ type: "text", text: JSON.stringify({ message: `Already in ${targetEnv} environment`, environment: ctx.environment, apiKeyPrefix: ctx.apiKey.slice(0, 12) + "***" }, null, 2) }] };
1264
+ }
1265
+ const targetKey = ctx.keys[targetEnv];
1266
+ if (!targetKey) {
1267
+ 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)";
1268
+ return { content: [{ type: "text", text: `Error: No API key configured for "${targetEnv}" environment. ${hint}` }], isError: true };
1269
+ }
1270
+ ctx.sly = new Sly({ apiKey: targetKey, apiUrl: ctx.apiUrl });
1271
+ ctx.apiKey = targetKey;
1272
+ ctx.environment = targetEnv;
1273
+ return { content: [{ type: "text", text: JSON.stringify({ message: `Switched to ${targetEnv} environment`, environment: ctx.environment, apiKeyPrefix: ctx.apiKey.slice(0, 12) + "***" }, null, 2) }] };
1274
+ }
1275
+ default:
1276
+ throw new Error(`Unknown tool: ${name}`);
1277
+ }
1278
+ } catch (error) {
1279
+ const details = error.details || error.errors || "";
1280
+ const detailsStr = details ? `
1281
+ Details: ${JSON.stringify(details, null, 2)}` : "";
1282
+ return {
1283
+ content: [
1284
+ {
1285
+ type: "text",
1286
+ text: `Error: ${error.message}${detailsStr}`
1287
+ }
1288
+ ],
1289
+ isError: true
1290
+ };
1291
+ }
1292
+ });
1293
+ return server;
1294
+ }
1295
+
1296
+ export {
1297
+ createMcpServer
1298
+ };