@openclawcash/mcp-server 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,7 @@ Canonical docs page: `https://openclawcash.com/mcp`
16
16
  - `transfer_send`
17
17
  - `swap_quote`
18
18
  - `swap_execute`
19
+ - `checkout_fund` (quick-pay first, swap fallback)
19
20
  - `approve_token`
20
21
  - `wallet_create`
21
22
  - `wallet_import`
@@ -222,6 +223,10 @@ The MCP server itself does not hold approval memory. The MCP client or agent run
222
223
  - `swap_quote` is read-only, but still requires an agent key.
223
224
  - `supported_tokens_list` is read-only, but still requires an agent key.
224
225
  - `transfer_send`, `swap_execute`, `approve_token`, `wallet_create`, and `wallet_import` are write tools.
226
+ - `transfer_send` is for normal wallet transfers. For checkout escrow funding, use checkout tools:
227
+ - `checkout_quick_pay` for direct settlement funding
228
+ - `checkout_swap_and_pay` for asset mismatch funding
229
+ - `checkout_funding_confirm` to confirm external/manual funding transactions
225
230
  - For `wallet_get`, `transactions_list`, `supported_tokens_list`, and `swap_quote`, pass at most one wallet selector when using `walletId`, `walletLabel`, or `walletAddress`.
226
231
  - The server uses stdio transport and is intended for MCP-compatible desktop or agent clients.
227
232
 
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { z } from "zod";
8
8
 
9
9
  const SERVER_NAME = "openclawcash";
10
- const SERVER_VERSION = "0.1.3";
10
+ const SERVER_VERSION = "0.1.9";
11
11
  const PROTOCOL_VERSION = "2024-11-05";
12
12
  const DEFAULT_BASE_URL = "https://openclawcash.com";
13
13
 
@@ -178,7 +178,7 @@ const supportedTokensArgsSchema = walletSelectorBaseSchema
178
178
 
179
179
  const createWalletArgsSchema = z.object({
180
180
  label: z.string().min(1),
181
- network: z.enum(["sepolia", "mainnet", "solana-devnet", "solana-testnet", "solana-mainnet"]).optional(),
181
+ network: z.enum(["sepolia", "mainnet", "polygon-mainnet", "solana-devnet", "solana-testnet", "solana-mainnet"]).optional(),
182
182
  exportPassphrase: z.string().trim().min(12),
183
183
  exportPassphraseStorageType: z.enum(["env", "secret_manager", "vault", "other"]),
184
184
  exportPassphraseStorageRef: z.string().trim().min(3),
@@ -187,10 +187,185 @@ const createWalletArgsSchema = z.object({
187
187
 
188
188
  const importWalletArgsSchema = z.object({
189
189
  label: z.string().min(1),
190
- network: z.enum(["mainnet", "solana-mainnet"]),
190
+ network: z.enum(["mainnet", "polygon-mainnet", "solana-mainnet"]),
191
191
  privateKey: z.string().min(1),
192
192
  });
193
193
 
194
+ const userTagSetArgsSchema = z.object({
195
+ userTag: z
196
+ .string()
197
+ .trim()
198
+ .toLowerCase()
199
+ .min(3)
200
+ .max(64)
201
+ .regex(/^[a-z0-9][a-z0-9._-]{2,63}$/),
202
+ });
203
+
204
+ const polymarketLimitArgsSchema = z
205
+ .object({
206
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
207
+ walletAddress: z.string().min(1).optional(),
208
+ tokenId: z.string().min(1),
209
+ side: z.enum(["BUY", "SELL"]),
210
+ price: z.number().positive(),
211
+ size: z.number().positive(),
212
+ })
213
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
214
+ message: "Provide exactly one of walletId or walletAddress.",
215
+ });
216
+
217
+ const polymarketMarketArgsSchema = z
218
+ .object({
219
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
220
+ walletAddress: z.string().min(1).optional(),
221
+ tokenId: z.string().min(1),
222
+ side: z.enum(["BUY", "SELL"]),
223
+ amount: z.number().positive(),
224
+ orderType: z.enum(["FAK", "FOK", "GTC"]).optional(),
225
+ worstPrice: z.number().min(0).max(1).optional(),
226
+ })
227
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
228
+ message: "Provide exactly one of walletId or walletAddress.",
229
+ });
230
+
231
+ const polymarketReadArgsSchema = z
232
+ .object({
233
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
234
+ walletAddress: z.string().min(1).optional(),
235
+ status: z.string().min(1).optional(),
236
+ limit: z.number().int().positive().max(200).optional(),
237
+ cursor: z.string().min(1).optional(),
238
+ })
239
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
240
+ message: "Provide exactly one of walletId or walletAddress.",
241
+ });
242
+
243
+ const polymarketCancelArgsSchema = z
244
+ .object({
245
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
246
+ walletAddress: z.string().min(1).optional(),
247
+ orderId: z.string().min(1),
248
+ })
249
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
250
+ message: "Provide exactly one of walletId or walletAddress.",
251
+ });
252
+
253
+ const polymarketUnlinkArgsSchema = z
254
+ .object({
255
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
256
+ walletAddress: z.string().min(1).optional(),
257
+ })
258
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
259
+ message: "Provide exactly one of walletId or walletAddress.",
260
+ });
261
+
262
+ const polymarketMarketResolveArgsSchema = z
263
+ .object({
264
+ marketUrl: z.string().url().optional(),
265
+ slug: z.string().min(1).optional(),
266
+ outcome: z.string().min(1),
267
+ })
268
+ .refine((data) => [data.marketUrl, data.slug].filter((v) => v !== undefined).length === 1, {
269
+ message: "Provide exactly one of marketUrl or slug.",
270
+ });
271
+
272
+ const checkoutEscrowIdArgsSchema = z.object({
273
+ id: z.string().min(1),
274
+ });
275
+
276
+ const checkoutPayreqIdArgsSchema = z.object({
277
+ id: z.string().min(1),
278
+ });
279
+
280
+ const checkoutWalletSelectorArgsSchema = z
281
+ .object({
282
+ id: z.string().min(1),
283
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
284
+ walletAddress: z.string().min(1).optional(),
285
+ })
286
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
287
+ message: "Provide exactly one of walletId or walletAddress.",
288
+ });
289
+
290
+ const checkoutCreatePayreqArgsSchema = z
291
+ .object({
292
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
293
+ walletAddress: z.string().min(1).optional(),
294
+ amount: z.string().min(1),
295
+ expiresInSeconds: z.number().int().positive().optional(),
296
+ autoReleaseSeconds: z.number().int().positive().optional(),
297
+ disputeWindowSeconds: z.number().int().positive().optional(),
298
+ metadata: z.record(z.unknown()).optional(),
299
+ })
300
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
301
+ message: "Provide exactly one of walletId or walletAddress.",
302
+ });
303
+
304
+ const checkoutFundingConfirmArgsSchema = z.object({
305
+ id: z.string().min(1),
306
+ txHash: z.string().min(1),
307
+ minConfirmations: z.number().int().positive().optional(),
308
+ });
309
+
310
+ const checkoutAcceptArgsSchema = z.object({
311
+ id: z.string().min(1),
312
+ });
313
+
314
+ const checkoutProofArgsSchema = z.object({
315
+ id: z.string().min(1),
316
+ proofHash: z.string().trim().min(1).max(128),
317
+ proofUrl: z.string().url().optional(),
318
+ });
319
+
320
+ const checkoutDisputeArgsSchema = z.object({
321
+ id: z.string().min(1),
322
+ reasonCode: z.string().trim().min(3).max(64),
323
+ details: z.record(z.unknown()).optional(),
324
+ });
325
+
326
+ const checkoutSwapAndPayArgsSchema = z
327
+ .object({
328
+ id: z.string().min(1),
329
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
330
+ walletAddress: z.string().min(1).optional(),
331
+ confirm: z.boolean().optional(),
332
+ slippage: z.number().positive().max(5).optional(),
333
+ })
334
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
335
+ message: "Provide exactly one of walletId or walletAddress.",
336
+ });
337
+
338
+ const checkoutFundArgsSchema = z
339
+ .object({
340
+ id: z.string().min(1),
341
+ walletId: z.union([z.number().int().positive(), z.string().min(1)]).optional(),
342
+ walletAddress: z.string().min(1).optional(),
343
+ slippage: z.number().positive().max(5).optional(),
344
+ allowSwapFallback: z.boolean().optional(),
345
+ })
346
+ .refine((data) => [data.walletId, data.walletAddress].filter((v) => v !== undefined).length === 1, {
347
+ message: "Provide exactly one of walletId or walletAddress.",
348
+ });
349
+
350
+ const checkoutWebhookCreateArgsSchema = z.object({
351
+ url: z.string().url(),
352
+ eventTypes: z.array(z.string().min(1)).optional(),
353
+ enabled: z.boolean().optional(),
354
+ });
355
+
356
+ const checkoutWebhookUpdateArgsSchema = z.object({
357
+ id: z.union([z.number().int().positive(), z.string().min(1)]),
358
+ url: z.string().url().optional(),
359
+ eventTypes: z.array(z.string().min(1)).optional(),
360
+ enabled: z.boolean().optional(),
361
+ }).refine((data) => data.url !== undefined || data.eventTypes !== undefined || data.enabled !== undefined, {
362
+ message: "Provide at least one of url, eventTypes, or enabled.",
363
+ });
364
+
365
+ const checkoutWebhookDeleteArgsSchema = z.object({
366
+ id: z.union([z.number().int().positive(), z.string().min(1)]),
367
+ });
368
+
194
369
  function queryString(params) {
195
370
  const search = new URLSearchParams();
196
371
  for (const [key, value] of Object.entries(params)) {
@@ -232,6 +407,9 @@ async function callAgentApi({ method, pathName, query, body, requireAuth = true
232
407
  if (requireAuth) {
233
408
  headers["X-Agent-Key"] = requireAgentKey();
234
409
  }
410
+ if (["POST", "PATCH", "DELETE"].includes(String(method || "").toUpperCase())) {
411
+ headers["Idempotency-Key"] = `mcp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
412
+ }
235
413
 
236
414
  const url = `${getBaseUrl()}${pathName}${queryString(query || {})}`;
237
415
  const response = await fetch(url, {
@@ -376,7 +554,9 @@ const tools = [
376
554
  },
377
555
  {
378
556
  name: "transfer_send",
379
- description: withWriteSafety("Send a native asset or token transfer from a managed wallet."),
557
+ description: withWriteSafety(
558
+ "Send a native asset or token transfer from a managed wallet. Do not use for checkout escrow funding; use checkout_quick_pay or checkout_swap_and_pay.",
559
+ ),
380
560
  inputSchema: {
381
561
  type: "object",
382
562
  properties: {
@@ -394,12 +574,37 @@ const tools = [
394
574
  additionalProperties: false,
395
575
  },
396
576
  parse: (args) => transferArgsSchema.parse(args ?? {}),
397
- execute: async (args) =>
398
- callAgentApi({
399
- method: "POST",
400
- pathName: "/api/agent/transfer",
401
- body: args,
402
- }),
577
+ execute: async (args) => {
578
+ try {
579
+ return await callAgentApi({
580
+ method: "POST",
581
+ pathName: "/api/agent/transfer",
582
+ body: args,
583
+ });
584
+ } catch (error) {
585
+ const payload = error?.payload;
586
+ const code = typeof payload?.code === "string" ? payload.code : "";
587
+ if (code === "unsupported_funding_asset" || code === "unsupported_funding_network") {
588
+ const enriched = new Error(
589
+ [
590
+ "Checkout escrow funding is restricted to checkout funding endpoints.",
591
+ "Use `checkout_quick_pay` (direct settlement) or `checkout_swap_and_pay` (asset mismatch), then `checkout_funding_confirm` if needed.",
592
+ ].join(" "),
593
+ );
594
+ enriched.status = error?.status;
595
+ enriched.payload = {
596
+ ...(payload && typeof payload === "object" ? payload : {}),
597
+ mcpHints: {
598
+ quickPayTool: "checkout_quick_pay",
599
+ swapAndPayTool: "checkout_swap_and_pay",
600
+ fundingConfirmTool: "checkout_funding_confirm",
601
+ },
602
+ };
603
+ throw enriched;
604
+ }
605
+ throw error;
606
+ }
607
+ },
403
608
  },
404
609
  {
405
610
  name: "swap_quote",
@@ -488,7 +693,7 @@ const tools = [
488
693
  label: { type: "string" },
489
694
  network: {
490
695
  type: "string",
491
- enum: ["sepolia", "mainnet", "solana-devnet", "solana-testnet", "solana-mainnet"],
696
+ enum: ["sepolia", "mainnet", "polygon-mainnet", "solana-devnet", "solana-testnet", "solana-mainnet"],
492
697
  },
493
698
  exportPassphrase: { type: "string", minLength: 12 },
494
699
  exportPassphraseStorageType: { type: "string", enum: ["env", "secret_manager", "vault", "other"] },
@@ -524,12 +729,12 @@ const tools = [
524
729
  },
525
730
  {
526
731
  name: "wallet_import",
527
- description: withWriteSafety("Import a mainnet or Solana mainnet wallet under the configured agent key."),
732
+ description: withWriteSafety("Import a mainnet, polygon-mainnet, or Solana mainnet wallet under the configured agent key."),
528
733
  inputSchema: {
529
734
  type: "object",
530
735
  properties: {
531
736
  label: { type: "string" },
532
- network: { type: "string", enum: ["mainnet", "solana-mainnet"] },
737
+ network: { type: "string", enum: ["mainnet", "polygon-mainnet", "solana-mainnet"] },
533
738
  privateKey: { type: "string" },
534
739
  },
535
740
  required: ["label", "network", "privateKey"],
@@ -543,6 +748,636 @@ const tools = [
543
748
  body: args,
544
749
  }),
545
750
  },
751
+ {
752
+ name: "user_tag_get",
753
+ description: "Read global checkout user tag for the API key owner.",
754
+ inputSchema: {
755
+ type: "object",
756
+ properties: {},
757
+ additionalProperties: false,
758
+ },
759
+ parse: (args) => z.object({}).parse(args ?? {}),
760
+ execute: async () =>
761
+ callAgentApi({
762
+ method: "GET",
763
+ pathName: "/api/agent/user-tag",
764
+ }),
765
+ },
766
+ {
767
+ name: "user_tag_set",
768
+ description: withWriteSafety("Set global checkout user tag once (immutable after set)."),
769
+ inputSchema: {
770
+ type: "object",
771
+ properties: {
772
+ userTag: { type: "string" },
773
+ },
774
+ required: ["userTag"],
775
+ additionalProperties: false,
776
+ },
777
+ parse: (args) => userTagSetArgsSchema.parse(args ?? {}),
778
+ execute: async (args) =>
779
+ callAgentApi({
780
+ method: "PUT",
781
+ pathName: "/api/agent/user-tag",
782
+ body: args,
783
+ }),
784
+ },
785
+ {
786
+ name: "checkout_payreq_create",
787
+ description: withWriteSafety("Create a checkout pay request and escrow."),
788
+ inputSchema: {
789
+ type: "object",
790
+ properties: {
791
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
792
+ walletAddress: { type: "string" },
793
+ amount: { type: "string" },
794
+ expiresInSeconds: { type: "integer" },
795
+ autoReleaseSeconds: { type: "integer" },
796
+ disputeWindowSeconds: { type: "integer" },
797
+ metadata: { type: "object", additionalProperties: true },
798
+ },
799
+ required: ["amount"],
800
+ additionalProperties: false,
801
+ },
802
+ parse: (args) => checkoutCreatePayreqArgsSchema.parse(args ?? {}),
803
+ execute: async (args) =>
804
+ callAgentApi({
805
+ method: "POST",
806
+ pathName: "/api/agent/checkout/payreq",
807
+ body: args,
808
+ }),
809
+ },
810
+ {
811
+ name: "checkout_payreq_get",
812
+ description: "Get checkout pay request details by id.",
813
+ inputSchema: {
814
+ type: "object",
815
+ properties: { id: { type: "string" } },
816
+ required: ["id"],
817
+ additionalProperties: false,
818
+ },
819
+ parse: (args) => checkoutPayreqIdArgsSchema.parse(args ?? {}),
820
+ execute: async (args) =>
821
+ callAgentApi({
822
+ method: "GET",
823
+ pathName: `/api/agent/checkout/payreq/${encodeURIComponent(args.id)}`,
824
+ }),
825
+ },
826
+ {
827
+ name: "checkout_escrow_get",
828
+ description: "Get checkout escrow details by escrow id.",
829
+ inputSchema: {
830
+ type: "object",
831
+ properties: { id: { type: "string" } },
832
+ required: ["id"],
833
+ additionalProperties: false,
834
+ },
835
+ parse: (args) => checkoutEscrowIdArgsSchema.parse(args ?? {}),
836
+ execute: async (args) =>
837
+ callAgentApi({
838
+ method: "GET",
839
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(args.id)}`,
840
+ }),
841
+ },
842
+ {
843
+ name: "checkout_funding_confirm",
844
+ description: withWriteSafety("Confirm checkout escrow funding transaction."),
845
+ inputSchema: {
846
+ type: "object",
847
+ properties: {
848
+ id: { type: "string" },
849
+ txHash: { type: "string" },
850
+ minConfirmations: { type: "integer" },
851
+ },
852
+ required: ["id", "txHash"],
853
+ additionalProperties: false,
854
+ },
855
+ parse: (args) => checkoutFundingConfirmArgsSchema.parse(args ?? {}),
856
+ execute: async (args) => {
857
+ const { id, ...body } = args;
858
+ return callAgentApi({
859
+ method: "POST",
860
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/funding-confirm`,
861
+ body,
862
+ });
863
+ },
864
+ },
865
+ {
866
+ name: "checkout_accept",
867
+ description: withWriteSafety("Accept escrow as buyer."),
868
+ inputSchema: {
869
+ type: "object",
870
+ properties: {
871
+ id: { type: "string" },
872
+ },
873
+ required: ["id"],
874
+ additionalProperties: false,
875
+ },
876
+ parse: (args) => checkoutAcceptArgsSchema.parse(args ?? {}),
877
+ execute: async (args) => {
878
+ const { id, ...body } = args;
879
+ return callAgentApi({
880
+ method: "POST",
881
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/accept`,
882
+ body,
883
+ });
884
+ },
885
+ },
886
+ {
887
+ name: "checkout_proof_submit",
888
+ description: withWriteSafety("Submit checkout proof."),
889
+ inputSchema: {
890
+ type: "object",
891
+ properties: {
892
+ id: { type: "string" },
893
+ proofHash: { type: "string" },
894
+ proofUrl: { type: "string" },
895
+ },
896
+ required: ["id", "proofHash"],
897
+ additionalProperties: false,
898
+ },
899
+ parse: (args) => checkoutProofArgsSchema.parse(args ?? {}),
900
+ execute: async (args) => {
901
+ const { id, ...body } = args;
902
+ return callAgentApi({
903
+ method: "POST",
904
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/proof`,
905
+ body,
906
+ });
907
+ },
908
+ },
909
+ {
910
+ name: "checkout_dispute_open",
911
+ description: withWriteSafety("Open checkout dispute."),
912
+ inputSchema: {
913
+ type: "object",
914
+ properties: {
915
+ id: { type: "string" },
916
+ reasonCode: { type: "string" },
917
+ details: { type: "object", additionalProperties: true },
918
+ },
919
+ required: ["id", "reasonCode"],
920
+ additionalProperties: false,
921
+ },
922
+ parse: (args) => checkoutDisputeArgsSchema.parse(args ?? {}),
923
+ execute: async (args) => {
924
+ const { id, ...body } = args;
925
+ return callAgentApi({
926
+ method: "POST",
927
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/dispute`,
928
+ body,
929
+ });
930
+ },
931
+ },
932
+ {
933
+ name: "checkout_quick_pay",
934
+ description: withWriteSafety("Directly fund checkout escrow from buyer wallet."),
935
+ inputSchema: {
936
+ type: "object",
937
+ properties: {
938
+ id: { type: "string" },
939
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
940
+ walletAddress: { type: "string" },
941
+ },
942
+ required: ["id"],
943
+ additionalProperties: false,
944
+ },
945
+ parse: (args) => checkoutWalletSelectorArgsSchema.parse(args ?? {}),
946
+ execute: async (args) => {
947
+ const { id, ...body } = args;
948
+ return callAgentApi({
949
+ method: "POST",
950
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/quick-pay`,
951
+ body,
952
+ });
953
+ },
954
+ },
955
+ {
956
+ name: "checkout_swap_and_pay",
957
+ description: withWriteSafety("Swap source asset and fund checkout escrow."),
958
+ inputSchema: {
959
+ type: "object",
960
+ properties: {
961
+ id: { type: "string" },
962
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
963
+ walletAddress: { type: "string" },
964
+ confirm: { type: "boolean" },
965
+ slippage: { type: "number" },
966
+ },
967
+ required: ["id"],
968
+ additionalProperties: false,
969
+ },
970
+ parse: (args) => checkoutSwapAndPayArgsSchema.parse(args ?? {}),
971
+ execute: async (args) => {
972
+ const { id, ...body } = args;
973
+ return callAgentApi({
974
+ method: "POST",
975
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/swap-and-pay`,
976
+ body,
977
+ });
978
+ },
979
+ },
980
+ {
981
+ name: "checkout_fund",
982
+ description: withWriteSafety(
983
+ "Default escrow funding flow: try direct quick-pay first, then automatically fallback to swap-and-pay when required.",
984
+ ),
985
+ inputSchema: {
986
+ type: "object",
987
+ properties: {
988
+ id: { type: "string" },
989
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
990
+ walletAddress: { type: "string" },
991
+ slippage: { type: "number" },
992
+ allowSwapFallback: { type: "boolean", description: "Defaults to true." },
993
+ },
994
+ required: ["id"],
995
+ additionalProperties: false,
996
+ },
997
+ parse: (args) => checkoutFundArgsSchema.parse(args ?? {}),
998
+ execute: async (args) => {
999
+ const { id, walletId, walletAddress, slippage, allowSwapFallback = true } = args;
1000
+ const selector = {
1001
+ ...(walletId !== undefined ? { walletId } : {}),
1002
+ ...(walletAddress !== undefined ? { walletAddress } : {}),
1003
+ };
1004
+
1005
+ try {
1006
+ const quickPay = await callAgentApi({
1007
+ method: "POST",
1008
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/quick-pay`,
1009
+ body: selector,
1010
+ });
1011
+ return {
1012
+ strategy: "quick-pay",
1013
+ fallbackUsed: false,
1014
+ quickPay,
1015
+ };
1016
+ } catch (error) {
1017
+ const code = typeof error?.payload?.code === "string" ? error.payload.code : "";
1018
+ if (code !== "quick_pay_requires_swap" || !allowSwapFallback) {
1019
+ throw error;
1020
+ }
1021
+
1022
+ const quotePreview = await callAgentApi({
1023
+ method: "POST",
1024
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/swap-and-pay`,
1025
+ body: {
1026
+ ...selector,
1027
+ ...(slippage !== undefined ? { slippage } : {}),
1028
+ confirm: false,
1029
+ },
1030
+ });
1031
+
1032
+ const swapAndPay = await callAgentApi({
1033
+ method: "POST",
1034
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/swap-and-pay`,
1035
+ body: {
1036
+ ...selector,
1037
+ ...(slippage !== undefined ? { slippage } : {}),
1038
+ confirm: true,
1039
+ },
1040
+ });
1041
+
1042
+ return {
1043
+ strategy: "swap-and-pay",
1044
+ fallbackUsed: true,
1045
+ fallbackReason: code,
1046
+ quote: quotePreview?.quote || null,
1047
+ swapAndPay,
1048
+ };
1049
+ }
1050
+ },
1051
+ },
1052
+ {
1053
+ name: "checkout_release",
1054
+ description: withWriteSafety("Release checkout escrow to seller."),
1055
+ inputSchema: {
1056
+ type: "object",
1057
+ properties: {
1058
+ id: { type: "string" },
1059
+ force: { type: "boolean" },
1060
+ },
1061
+ required: ["id"],
1062
+ additionalProperties: false,
1063
+ },
1064
+ parse: (args) => checkoutEscrowIdArgsSchema.extend({ force: z.boolean().optional() }).parse(args ?? {}),
1065
+ execute: async (args) => {
1066
+ const { id, ...body } = args;
1067
+ return callAgentApi({
1068
+ method: "POST",
1069
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/release`,
1070
+ body,
1071
+ });
1072
+ },
1073
+ },
1074
+ {
1075
+ name: "checkout_refund",
1076
+ description: withWriteSafety("Refund checkout escrow to buyer."),
1077
+ inputSchema: {
1078
+ type: "object",
1079
+ properties: {
1080
+ id: { type: "string" },
1081
+ force: { type: "boolean" },
1082
+ },
1083
+ required: ["id"],
1084
+ additionalProperties: false,
1085
+ },
1086
+ parse: (args) => checkoutEscrowIdArgsSchema.extend({ force: z.boolean().optional() }).parse(args ?? {}),
1087
+ execute: async (args) => {
1088
+ const { id, ...body } = args;
1089
+ return callAgentApi({
1090
+ method: "POST",
1091
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(id)}/refund`,
1092
+ body,
1093
+ });
1094
+ },
1095
+ },
1096
+ {
1097
+ name: "checkout_cancel",
1098
+ description: withWriteSafety("Cancel checkout escrow."),
1099
+ inputSchema: {
1100
+ type: "object",
1101
+ properties: {
1102
+ id: { type: "string" },
1103
+ },
1104
+ required: ["id"],
1105
+ additionalProperties: false,
1106
+ },
1107
+ parse: (args) => checkoutEscrowIdArgsSchema.parse(args ?? {}),
1108
+ execute: async (args) =>
1109
+ callAgentApi({
1110
+ method: "POST",
1111
+ pathName: `/api/agent/checkout/escrows/${encodeURIComponent(args.id)}/cancel`,
1112
+ body: {},
1113
+ }),
1114
+ },
1115
+ {
1116
+ name: "checkout_webhooks_list",
1117
+ description: "List checkout webhook subscriptions.",
1118
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
1119
+ parse: (args) => z.object({}).parse(args ?? {}),
1120
+ execute: async () =>
1121
+ callAgentApi({
1122
+ method: "GET",
1123
+ pathName: "/api/agent/checkout/webhooks",
1124
+ }),
1125
+ },
1126
+ {
1127
+ name: "checkout_webhook_create",
1128
+ description: withWriteSafety("Create checkout webhook subscription."),
1129
+ inputSchema: {
1130
+ type: "object",
1131
+ properties: {
1132
+ url: { type: "string" },
1133
+ eventTypes: { type: "array", items: { type: "string" } },
1134
+ enabled: { type: "boolean" },
1135
+ },
1136
+ required: ["url"],
1137
+ additionalProperties: false,
1138
+ },
1139
+ parse: (args) => checkoutWebhookCreateArgsSchema.parse(args ?? {}),
1140
+ execute: async (args) =>
1141
+ callAgentApi({
1142
+ method: "POST",
1143
+ pathName: "/api/agent/checkout/webhooks",
1144
+ body: args,
1145
+ }),
1146
+ },
1147
+ {
1148
+ name: "checkout_webhook_update",
1149
+ description: withWriteSafety("Update checkout webhook subscription."),
1150
+ inputSchema: {
1151
+ type: "object",
1152
+ properties: {
1153
+ id: { oneOf: [{ type: "integer" }, { type: "string" }] },
1154
+ url: { type: "string" },
1155
+ eventTypes: { type: "array", items: { type: "string" } },
1156
+ enabled: { type: "boolean" },
1157
+ },
1158
+ required: ["id"],
1159
+ additionalProperties: false,
1160
+ },
1161
+ parse: (args) => checkoutWebhookUpdateArgsSchema.parse(args ?? {}),
1162
+ execute: async (args) => {
1163
+ const { id, ...body } = args;
1164
+ return callAgentApi({
1165
+ method: "PATCH",
1166
+ pathName: `/api/agent/checkout/webhooks/${encodeURIComponent(String(id))}`,
1167
+ body,
1168
+ });
1169
+ },
1170
+ },
1171
+ {
1172
+ name: "checkout_webhook_delete",
1173
+ description: withWriteSafety("Delete checkout webhook subscription."),
1174
+ inputSchema: {
1175
+ type: "object",
1176
+ properties: {
1177
+ id: { oneOf: [{ type: "integer" }, { type: "string" }] },
1178
+ },
1179
+ required: ["id"],
1180
+ additionalProperties: false,
1181
+ },
1182
+ parse: (args) => checkoutWebhookDeleteArgsSchema.parse(args ?? {}),
1183
+ execute: async (args) =>
1184
+ callAgentApi({
1185
+ method: "DELETE",
1186
+ pathName: `/api/agent/checkout/webhooks/${encodeURIComponent(String(args.id))}`,
1187
+ }),
1188
+ },
1189
+ {
1190
+ name: "polymarket_market_resolve",
1191
+ description: "Resolve a Polymarket market URL/slug and human-readable outcome label to the exact CLOB tokenId required by order tools.",
1192
+ inputSchema: {
1193
+ type: "object",
1194
+ properties: {
1195
+ marketUrl: { type: "string", description: "Polymarket market or event URL." },
1196
+ slug: { type: "string", description: "Polymarket market slug (alternative to marketUrl)." },
1197
+ outcome: { type: "string", description: "Outcome label, e.g. Yes, No, Trump, Harris." },
1198
+ },
1199
+ required: ["outcome"],
1200
+ additionalProperties: false,
1201
+ },
1202
+ parse: (args) => polymarketMarketResolveArgsSchema.parse(args ?? {}),
1203
+ execute: async (args) =>
1204
+ callAgentApi({
1205
+ method: "GET",
1206
+ pathName: "/api/agent/venues/polymarket/market/resolve",
1207
+ query: args,
1208
+ }),
1209
+ },
1210
+ {
1211
+ name: "polymarket_order_limit",
1212
+ description: withWriteSafety("Place a Polymarket limit order from a configured polygon-mainnet wallet. Use this for explicit target-price orders; for close-position intent, prefer market SELL unless a limit price is explicitly requested."),
1213
+ inputSchema: {
1214
+ type: "object",
1215
+ properties: {
1216
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1217
+ walletAddress: { type: "string" },
1218
+ tokenId: { type: "string" },
1219
+ side: { type: "string", enum: ["BUY", "SELL"] },
1220
+ price: { type: "number" },
1221
+ size: { type: "number" },
1222
+ },
1223
+ required: ["tokenId", "side", "price", "size"],
1224
+ additionalProperties: false,
1225
+ },
1226
+ parse: (args) => polymarketLimitArgsSchema.parse(args ?? {}),
1227
+ execute: async (args) =>
1228
+ callAgentApi({
1229
+ method: "POST",
1230
+ pathName: "/api/agent/venues/polymarket/orders/limit",
1231
+ body: args,
1232
+ }),
1233
+ },
1234
+ {
1235
+ name: "polymarket_order_market",
1236
+ description: withWriteSafety("Place a Polymarket market order from a configured polygon-mainnet wallet. For close-position intent on open markets, default to side=SELL (SELL amount is shares); use limit SELL only for explicit target-price requests."),
1237
+ inputSchema: {
1238
+ type: "object",
1239
+ properties: {
1240
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1241
+ walletAddress: { type: "string" },
1242
+ tokenId: { type: "string" },
1243
+ side: { type: "string", enum: ["BUY", "SELL"] },
1244
+ amount: { type: "number" },
1245
+ orderType: { type: "string", enum: ["FAK", "FOK", "GTC"] },
1246
+ worstPrice: { type: "number" },
1247
+ },
1248
+ required: ["tokenId", "side", "amount"],
1249
+ additionalProperties: false,
1250
+ },
1251
+ parse: (args) => polymarketMarketArgsSchema.parse(args ?? {}),
1252
+ execute: async (args) =>
1253
+ callAgentApi({
1254
+ method: "POST",
1255
+ pathName: "/api/agent/venues/polymarket/orders/market",
1256
+ body: args,
1257
+ }),
1258
+ },
1259
+ {
1260
+ name: "polymarket_account",
1261
+ description: "Read Polymarket account summary for a configured polygon-mainnet wallet.",
1262
+ inputSchema: {
1263
+ type: "object",
1264
+ properties: {
1265
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1266
+ walletAddress: { type: "string" },
1267
+ },
1268
+ additionalProperties: false,
1269
+ },
1270
+ parse: (args) => polymarketReadArgsSchema.parse(args ?? {}),
1271
+ execute: async (args) =>
1272
+ callAgentApi({
1273
+ method: "GET",
1274
+ pathName: "/api/agent/venues/polymarket/account",
1275
+ query: args,
1276
+ }),
1277
+ },
1278
+ {
1279
+ name: "polymarket_orders",
1280
+ description: "List Polymarket open orders for a configured polygon-mainnet wallet.",
1281
+ inputSchema: {
1282
+ type: "object",
1283
+ properties: {
1284
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1285
+ walletAddress: { type: "string" },
1286
+ status: { type: "string" },
1287
+ limit: { type: "integer" },
1288
+ cursor: { type: "string" },
1289
+ },
1290
+ additionalProperties: false,
1291
+ },
1292
+ parse: (args) => polymarketReadArgsSchema.parse(args ?? {}),
1293
+ execute: async (args) =>
1294
+ callAgentApi({
1295
+ method: "GET",
1296
+ pathName: "/api/agent/venues/polymarket/orders",
1297
+ query: args,
1298
+ }),
1299
+ },
1300
+ {
1301
+ name: "polymarket_cancel_order",
1302
+ description: withWriteSafety("Cancel a Polymarket order for a configured polygon-mainnet wallet."),
1303
+ inputSchema: {
1304
+ type: "object",
1305
+ properties: {
1306
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1307
+ walletAddress: { type: "string" },
1308
+ orderId: { type: "string" },
1309
+ },
1310
+ required: ["orderId"],
1311
+ additionalProperties: false,
1312
+ },
1313
+ parse: (args) => polymarketCancelArgsSchema.parse(args ?? {}),
1314
+ execute: async (args) =>
1315
+ callAgentApi({
1316
+ method: "POST",
1317
+ pathName: "/api/agent/venues/polymarket/orders/cancel",
1318
+ body: args,
1319
+ }),
1320
+ },
1321
+ {
1322
+ name: "polymarket_clear_integration",
1323
+ description: withWriteSafety("Clear Polymarket integration for a configured polygon-mainnet wallet."),
1324
+ inputSchema: {
1325
+ type: "object",
1326
+ properties: {
1327
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1328
+ walletAddress: { type: "string" },
1329
+ },
1330
+ additionalProperties: false,
1331
+ },
1332
+ parse: (args) => polymarketUnlinkArgsSchema.parse(args ?? {}),
1333
+ execute: async (args) =>
1334
+ callAgentApi({
1335
+ method: "POST",
1336
+ pathName: "/api/agent/venues/polymarket/unlink",
1337
+ body: args,
1338
+ }),
1339
+ },
1340
+ {
1341
+ name: "polymarket_activity",
1342
+ description: "List Polymarket trade activity for a configured polygon-mainnet wallet.",
1343
+ inputSchema: {
1344
+ type: "object",
1345
+ properties: {
1346
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1347
+ walletAddress: { type: "string" },
1348
+ limit: { type: "integer" },
1349
+ cursor: { type: "string" },
1350
+ },
1351
+ additionalProperties: false,
1352
+ },
1353
+ parse: (args) => polymarketReadArgsSchema.parse(args ?? {}),
1354
+ execute: async (args) =>
1355
+ callAgentApi({
1356
+ method: "GET",
1357
+ pathName: "/api/agent/venues/polymarket/activity",
1358
+ query: args,
1359
+ }),
1360
+ },
1361
+ {
1362
+ name: "polymarket_positions",
1363
+ description: "List Polymarket open positions (open-market filtered) for a configured polygon-mainnet wallet, including position PnL fields.",
1364
+ inputSchema: {
1365
+ type: "object",
1366
+ properties: {
1367
+ walletId: { oneOf: [{ type: "integer" }, { type: "string" }] },
1368
+ walletAddress: { type: "string" },
1369
+ limit: { type: "integer" },
1370
+ },
1371
+ additionalProperties: false,
1372
+ },
1373
+ parse: (args) => polymarketReadArgsSchema.parse(args ?? {}),
1374
+ execute: async (args) =>
1375
+ callAgentApi({
1376
+ method: "GET",
1377
+ pathName: "/api/agent/venues/polymarket/positions",
1378
+ query: args,
1379
+ }),
1380
+ },
546
1381
  ];
547
1382
 
548
1383
  const resources = [
@@ -570,7 +1405,9 @@ const resources = [
570
1405
  "2. Use `wallets_list` first to discover managed wallets.",
571
1406
  "3. Use `wallet_get` or `balances_get` before write actions.",
572
1407
  "4. For writes, establish approval mode once per session.",
573
- "5. Use `swap_quote` before `swap_execute`.",
1408
+ "5. For checkout escrow funding, use `checkout_fund` (quick-pay first, swap fallback when needed).",
1409
+ "6. Use `swap_quote` before `swap_execute` for non-checkout swaps.",
1410
+ "7. For Polymarket: ask your human to complete setup in dashboard (/venues/polymarket), then place/cancel orders and inspect account/activity/positions via polymarket tools.",
574
1411
  ].join("\n"),
575
1412
  },
576
1413
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclawcash/mcp-server",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "OpenClawCash MCP server for managed agent wallets, balances, transfers, swaps, and approvals.",
5
5
  "type": "module",
6
6
  "license": "Proprietary",