ebay-mcp 1.18.0 → 1.18.2

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.
Files changed (161) hide show
  1. package/README.md +24 -35
  2. package/build/api/account-management/accountV2.js +22 -22
  3. package/build/api/account-management/finances.js +10 -10
  4. package/build/api/analytics-and-report/analytics.js +1 -1
  5. package/build/api/{client.js → client/ebayApiClient.js} +37 -41
  6. package/build/api/{clientTrading.js → client/tradingApiClient.js} +22 -22
  7. package/build/api/communication/feedback.js +21 -21
  8. package/build/api/communication/message.js +23 -23
  9. package/build/api/communication/negotiation.js +7 -7
  10. package/build/api/communication/notification.js +52 -52
  11. package/build/api/developer/developer.js +3 -3
  12. package/build/api/{index.js → ebaySellerApi.js} +4 -4
  13. package/build/api/listing-management/feedReportTasks.js +6 -6
  14. package/build/api/listing-management/feedRequest.js +6 -6
  15. package/build/api/listing-management/feedSchedules.js +4 -4
  16. package/build/api/listing-management/feedTasks.js +2 -2
  17. package/build/api/listing-management/items.js +22 -22
  18. package/build/api/listing-management/locations.js +4 -4
  19. package/build/api/listing-management/media.js +14 -14
  20. package/build/api/listing-management/mediaAttach.js +14 -14
  21. package/build/api/listing-management/mediaResources.js +15 -13
  22. package/build/api/listing-management/offerFormat.js +1 -1
  23. package/build/api/listing-management/offers.js +23 -23
  24. package/build/api/listing-management/stores.js +9 -9
  25. package/build/api/listing-metadata/metadata.js +10 -10
  26. package/build/api/marketing-and-promotions/ads.js +34 -34
  27. package/build/api/marketing-and-promotions/campaigns.js +19 -19
  28. package/build/api/marketing-and-promotions/promotions.js +22 -22
  29. package/build/api/marketing-and-promotions/reports.js +7 -7
  30. package/build/api/order-management/dispute.js +11 -9
  31. package/build/api/order-management/fulfillment.js +4 -4
  32. package/build/api/order-management/logistics.js +7 -7
  33. package/build/api/other/browseMappers.js +15 -13
  34. package/build/api/other/browseValidators.js +4 -4
  35. package/build/api/other/edelivery.js +19 -19
  36. package/build/api/other/finding.js +13 -13
  37. package/build/api/other/translation.js +2 -2
  38. package/build/api/other/vero.js +2 -2
  39. package/build/api/shared/download.js +7 -7
  40. package/build/api/shared/request.js +28 -19
  41. package/build/api/trading/listingFormat.js +37 -30
  42. package/build/api/trading/trading.js +33 -33
  43. package/build/auth/credentialSession.js +5 -5
  44. package/build/auth/oauth.js +3 -3
  45. package/build/auth/oauthHelper.js +24 -24
  46. package/build/auth/oauthMetadata.js +4 -4
  47. package/build/auth/oauthMiddleware.js +16 -16
  48. package/build/auth/scopeUtils.js +2 -2
  49. package/build/auth/tokenVerifier.js +23 -23
  50. package/build/config/environment.js +4 -45
  51. package/build/config/oauthScopes.js +132 -0
  52. package/build/index.js +5 -5
  53. package/build/mcp/httpTransport.js +32 -20
  54. package/build/mcp/runtime.js +12 -12
  55. package/build/mcp/toolGating.js +6 -12
  56. package/build/mcp/uiBridge.js +3 -3
  57. package/build/schemas/account-management/account.js +2 -52
  58. package/build/schemas/account-management/accountV2.js +2 -2
  59. package/build/schemas/account-management/finances.js +1 -1
  60. package/build/schemas/analytics/analytics.js +2 -48
  61. package/build/schemas/communication/messages.js +2 -46
  62. package/build/schemas/developer/developer.js +1 -27
  63. package/build/schemas/fulfillment/logistics.js +1 -1
  64. package/build/schemas/fulfillment/orders.js +2 -47
  65. package/build/schemas/inventory-management/feed.js +1 -1
  66. package/build/schemas/inventory-management/inventory.js +2 -50
  67. package/build/schemas/inventory-management/media.js +2 -2
  68. package/build/schemas/inventory-management/mediaDocuments.js +1 -1
  69. package/build/schemas/inventory-management/stores.js +1 -1
  70. package/build/schemas/marketing/ads.js +2 -2
  71. package/build/schemas/marketing/campaigns.js +2 -2
  72. package/build/schemas/marketing/common.js +2 -2
  73. package/build/schemas/marketing/marketing.js +0 -1
  74. package/build/schemas/marketing/promotions.js +2 -2
  75. package/build/schemas/marketing/reports.js +2 -2
  76. package/build/schemas/metadata/metadata.js +2 -90
  77. package/build/schemas/metadata/shipping.js +1 -1
  78. package/build/schemas/other/browse.js +2 -2
  79. package/build/schemas/other/finding.js +2 -2
  80. package/build/schemas/other/otherApis.js +2 -114
  81. package/build/schemas/taxonomy/categoryTree.js +1 -1
  82. package/build/schemas/taxonomy/charity.js +1 -1
  83. package/build/schemas/taxonomy/taxonomy.js +2 -69
  84. package/build/scripts/autoSetup.js +3 -3
  85. package/build/scripts/{buildUi.js → buildMcpApps.js} +13 -13
  86. package/build/scripts/devSync.js +19 -68
  87. package/build/scripts/diagnostics.js +15 -16
  88. package/build/scripts/interactiveSetup.js +25 -25
  89. package/build/scripts/scopeHelper.js +2 -2
  90. package/build/scripts/securityChecker.js +20 -20
  91. package/build/scripts/setup.js +76 -76
  92. package/build/scripts/setupShared.js +5 -30
  93. package/build/scripts/setupValidator.js +9 -9
  94. package/build/scripts/setupWizard.js +23 -23
  95. package/build/scripts/skills.js +14 -17
  96. package/build/scripts/specRefs.js +1 -1
  97. package/build/scripts/specSources.js +144 -0
  98. package/build/serverHttp.js +4 -7
  99. package/build/skills/content.js +13 -13
  100. package/build/skills/install.js +9 -9
  101. package/build/skills/render.js +2 -2
  102. package/build/tools/categories/communication.js +1 -1
  103. package/build/tools/categories/connector.js +19 -16
  104. package/build/tools/categories/fulfillment.js +4 -4
  105. package/build/tools/categories/inventory.js +1 -1
  106. package/build/tools/categories/metadata.js +1 -1
  107. package/build/tools/categories/taxonomy.js +1 -1
  108. package/build/tools/categories/tokenManagement.js +8 -8
  109. package/build/tools/contracts.js +2 -2
  110. package/build/tools/defineTool.js +27 -12
  111. package/build/tools/registry.js +2 -2
  112. package/build/tools/schemas.js +2 -2
  113. package/build/tools/ui/mapHelpers.js +12 -12
  114. package/build/tools/ui/maps.js +101 -97
  115. package/build/tools/ui/viewModels.js +2 -2
  116. package/build/utils/apiStatusFeed.js +12 -12
  117. package/build/utils/communication/feedback.js +3 -3
  118. package/build/utils/communication/message.js +3 -3
  119. package/build/utils/communication/negotiation.js +3 -3
  120. package/build/utils/communication/notification.js +3 -3
  121. package/build/utils/entryModule.js +33 -0
  122. package/build/utils/envFile.js +47 -0
  123. package/build/utils/envParser.js +5 -5
  124. package/build/utils/errors.js +4 -4
  125. package/build/utils/http.js +38 -38
  126. package/build/utils/localFeedFiles.js +3 -3
  127. package/build/utils/logRedaction.js +21 -0
  128. package/build/utils/logger.js +49 -35
  129. package/build/utils/other/compliance.js +3 -3
  130. package/build/utils/other/identity.js +3 -3
  131. package/build/utils/other/translation.js +3 -3
  132. package/build/utils/other/vero.js +3 -3
  133. package/build/utils/schemaHelpers.js +2 -2
  134. package/build/utils/tokenUtils.js +2 -2
  135. package/build/utils/trading/trading.js +1 -1
  136. package/build/utils/version.js +1 -1
  137. package/build/utils/zodIssues.js +14 -0
  138. package/package.json +8 -11
  139. package/README.de.md +0 -426
  140. package/README.es.md +0 -426
  141. package/README.fr.md +0 -426
  142. package/README.ja.md +0 -426
  143. package/README.ko.md +0 -426
  144. package/README.pt-BR.md +0 -426
  145. package/README.ru.md +0 -426
  146. package/README.zh-CN.md +0 -426
  147. package/build/schemas/index.js +0 -76
  148. package/build/schemas/marketing/jsonSchemas.js +0 -118
  149. package/build/scripts/downloadSpecs.js +0 -117
  150. package/build/scripts/updateApiStatusDoc.js +0 -71
  151. package/build/utils/effectSchema.js +0 -203
  152. package/build/utils/effectSchemaAdapter.js +0 -121
  153. package/build/utils/effectSchemaChainMethods.js +0 -146
  154. package/build/utils/effectSchemaRefinements.js +0 -104
  155. package/build/utils/effectSchemaStringMethods.js +0 -63
  156. package/build/utils/effectSchemaTypes.js +0 -47
  157. package/docs/auth/production_scopes.json +0 -111
  158. package/docs/auth/sandbox_scopes.json +0 -142
  159. /package/build/api/{clientRequestError.js → client/ebayClientRequestError.js} +0 -0
  160. /package/build/api/{rateLimitTracker.js → client/rateLimitTracker.js} +0 -0
  161. /package/build/api/{clientTradingError.js → client/tradingApiFailure.js} +0 -0
package/README.md CHANGED
@@ -31,23 +31,11 @@
31
31
  <a href="https://mseep.ai/app/yosefhayim-ebay-api-mcp-server"><img src="https://mseep.net/pr/yosefhayim-ebay-api-mcp-server-badge.png" alt="MseeP.ai Security Assessment Badge" height="40" /></a>
32
32
  </p>
33
33
 
34
- <p align="center">
35
- <strong>English</strong> ·
36
- <a href="README.zh-CN.md">简体中文</a> ·
37
- <a href="README.es.md">Español</a> ·
38
- <a href="README.pt-BR.md">Português (BR)</a> ·
39
- <a href="README.ja.md">日本語</a> ·
40
- <a href="README.ko.md">한국어</a> ·
41
- <a href="README.fr.md">Français</a> ·
42
- <a href="README.de.md">Deutsch</a> ·
43
- <a href="README.ru.md">Русский</a>
44
- </p>
45
-
46
34
  ---
47
35
 
48
36
  **eBay MCP** is a local [Model Context Protocol](https://modelcontextprotocol.io) server that connects AI assistants — [Claude Desktop](https://claude.ai/download), [Claude Code](https://code.claude.com/docs/en/overview), [Cursor](https://cursor.com/), [Cline](https://cline.bot/), [Windsurf](https://windsurf.com/), [Zed](https://zed.dev/), [Continue.dev](https://docs.continue.dev/), [Roo Code](https://roocode.com/), and [Amazon Q Developer](https://aws.amazon.com/q/developer/) — directly to **[eBay's Sell APIs](https://developer.ebay.com/api-docs/sell/static/overview.html)**. It exposes **384 tools** spanning **100% of eBay's Sell API surface** (360 unique endpoints) for inventory management, order fulfillment, promoted-listings marketing, analytics, and developer tooling. Everything runs on your machine over STDIO or local HTTP — **no cloud relay**, and your eBay credentials never leave your computer.
49
37
 
50
- > **Disclaimer:** Unofficial, third-party project — **not affiliated with or endorsed by eBay Inc.** Provided "as is" without warranty. You are responsible for complying with [eBay's API License Agreement](https://developer.ebay.com/join/api-license-agreement) and [data-handling requirements](https://developer.ebay.com/api-docs/static/data-handling-update.html), keeping your credentials secure, and staying within rate limits. Test in sandbox before production. See [LICENSE](LICENSE), [SECURITY.md](SECURITY.md), and [EBAY_COMPLIANCE.md](EBAY_COMPLIANCE.md).
38
+ > **Disclaimer:** Unofficial, third-party project — **not affiliated with or endorsed by eBay Inc.** Provided "as is" without warranty. You are responsible for complying with [eBay's API License Agreement](https://developer.ebay.com/join/api-license-agreement) and [data-handling requirements](https://developer.ebay.com/api-docs/static/data-handling-update.html), keeping your credentials secure, and staying within rate limits. Test in sandbox before production. See [LICENSE](LICENSE).
51
39
 
52
40
  ## Table of contents
53
41
 
@@ -75,7 +63,7 @@
75
63
  - **9 AI clients, auto-configured** — Claude Desktop, Cursor, Zed, Cline, Continue.dev, Windsurf, Roo Code, Claude Code CLI, and Amazon Q Developer.
76
64
  - **OAuth 2.0 built in** — full user-token management with automatic refresh, and smart fallback from user tokens (10k–50k req/day) to client credentials (1k req/day).
77
65
  - **Resilient by default** — automatic retry with exponential backoff on `429` rate limits, and consistent, loud error surfacing.
78
- - **Type-safe** — [TypeScript](https://www.typescriptlang.org/) end to end, [Effect](https://effect.website/docs)-backed tool input validation, and [OpenAPI](https://www.openapis.org/)-generated types.
66
+ - **Type-safe** — [TypeScript](https://www.typescriptlang.org/) end to end, [Zod](https://zod.dev/)-validated tool inputs, and [OpenAPI](https://www.openapis.org/)-generated types.
79
67
  - **Local-first & private** — runs over STDIO or local HTTP; your credentials and data never leave your machine.
80
68
  - **Sandbox and production** — switch environments with a single variable.
81
69
  - **One-command setup** — `npm run setup` configures credentials, OAuth, and your MCP client, with a browser auto-opened for the OAuth flow.
@@ -276,7 +264,7 @@ Both talk to the same eBay endpoints — the difference is everything you'd othe
276
264
  | Interface | Natural language through your AI assistant | Hand-written HTTP requests and JSON parsing |
277
265
  | OAuth & token refresh | Built in, with automatic refresh | You implement and maintain it |
278
266
  | Rate-limit handling | Automatic retry with exponential backoff | Manual `429` handling and backoff |
279
- | Input validation | Effect-backed schemas + TypeScript types on every tool | None — you validate your own payloads |
267
+ | Input validation | Zod schemas + TypeScript types on every tool | None — you validate your own payloads |
280
268
  | Setup | One wizard (`npm run setup`) | Per-call auth, headers, and marketplace wiring |
281
269
  | AI client support | 9 clients auto-configured | Not applicable |
282
270
  | API coverage | 384 tools across 100% of the Sell APIs, ready to call | Build each request from the docs |
@@ -393,7 +381,7 @@ https://github.com/user-attachments/assets/0173c8df-221c-4943-a4ce-cd20bce79f4b
393
381
  <details open>
394
382
  <summary><strong>Environment variables, tool exposure, auth &amp; client compatibility</strong></summary>
395
383
 
396
- > 📖 Full reference — every environment variable, OAuth step, and scope — is in the [Configuration Guide](docs/auth/CONFIGURATION.md). `npm run setup` writes the `.env` for you; the variables below are for reference.
384
+ > `npm run setup` writes the `.env` for you; the variables below are for reference.
397
385
 
398
386
  ```bash
399
387
  EBAY_CLIENT_ID=your_client_id
@@ -414,6 +402,7 @@ EBAY_READ_ONLY=false # when true, only register read-only tools (
414
402
  # MCP_HOST=0.0.0.0 # default is 0.0.0.0 when PORT is set
415
403
  # MCP_PORT=3000 # preferred over platform PORT
416
404
  # MCP_AUTH_TOKEN=secret # static Bearer for HTTP MCP (skips OAuth verifier)
405
+ # MCP_CORS_ORIGINS=https://app.example.com # browser origins allowed cross-origin (comma-separated); default: loopback origins only
417
406
  ```
418
407
 
419
408
  ### Tool exposure (`EBAY_MCP_TOOLS`)
@@ -435,7 +424,7 @@ The family list is literal — you get exactly what you name. ChatGPT connectors
435
424
  | **Client credentials** (default) | 1,000 req/day | Development, testing | Automatic with Client ID + Secret |
436
425
  | **User token** (recommended) | 10k–50k req/day | Production, high volume | OAuth via `npm run setup` |
437
426
 
438
- User-token limits vary by account tier (Individual 10k · Commercial 25k · Enterprise 50k+). On a `429`, the server retries with exponential backoff and surfaces the error. See the [Configuration Guide](docs/auth/CONFIGURATION.md) and [OAuth Quick Reference](docs/auth/OAUTH_QUICK_REFERENCE.md) for details, and monitor usage in the [Developer Portal](https://developer.ebay.com/my/api_usage).
427
+ User-token limits vary by account tier (Individual 10k · Commercial 25k · Enterprise 50k+). On a `429`, the server retries with exponential backoff and surfaces the error. Monitor usage in the [Developer Portal](https://developer.ebay.com/my/api_usage).
439
428
 
440
429
  ### MCP client compatibility
441
430
 
@@ -511,7 +500,7 @@ On hosts that support [MCP Apps](https://modelcontextprotocol.io), common read t
511
500
  | **Chart** | `ebay_get_traffic_report`, `ebay_get_customer_service_metric` |
512
501
  | **Stat** | `ebay_get_rate_limits`, `ebay_get_user_rate_limits` |
513
502
 
514
- The views build into self-contained HTML with `npm run build` (or `npm run build:ui`); they ship in the published package and load with no network access of their own.
503
+ The views build into self-contained HTML with `pnpm build` (or `pnpm build:mcp-apps`); they ship in the published package and load with no network access of their own.
515
504
 
516
505
  </details>
517
506
 
@@ -540,8 +529,8 @@ Common tasks, phrased as you'd ask your AI assistant:
540
529
 
541
530
  ## Logging & troubleshooting
542
531
 
543
- - **Logging** — Winston-based, written to stderr (MCP-safe) with optional file output. See [docs/logging.md](docs/logging.md).
544
- - **Troubleshooting** — server not appearing, auth errors, rate limits, empty results. Start with `npm run diagnose`, then see [docs/troubleshooting.md](docs/troubleshooting.md).
532
+ - **Logging** — Winston-based, written to stderr (MCP-safe) with optional file output.
533
+ - **Troubleshooting** — server not appearing, auth errors, rate limits, empty results. Start with `npm run diagnose`.
545
534
 
546
535
  ## FAQ
547
536
 
@@ -576,7 +565,7 @@ Yes. It works with Claude Desktop and Claude Code out of the box, with Cursor an
576
565
  <details>
577
566
  <summary><strong>Why don't I see the interactive tables and charts?</strong></summary>
578
567
 
579
- Interactive [MCP Apps](#interactive-ui-mcp-apps) views only appear on hosts that announce the capability (e.g. Claude); other clients get the same data as plain JSON. Also confirm you have not set `EBAY_MCP_UI=off` and that the views are built (`npm run build` runs `build:ui`).
568
+ Interactive [MCP Apps](#interactive-ui-mcp-apps) views only appear on hosts that announce the capability (e.g. Claude); other clients get the same data as plain JSON. Also confirm you have not set `EBAY_MCP_UI=off` and that the views are built (`pnpm build` runs `build:mcp-apps`).
580
569
 
581
570
  </details>
582
571
 
@@ -625,14 +614,14 @@ Yes. Switch with the `EBAY_ENVIRONMENT` variable (`sandbox` or `production`).
625
614
  <details>
626
615
  <summary><strong>Are my credentials and data secure?</strong></summary>
627
616
 
628
- Credentials are stored locally in your `.env` file and used only to call eBay directly. See [SECURITY.md](SECURITY.md) and [EBAY_COMPLIANCE.md](EBAY_COMPLIANCE.md).
617
+ Credentials are stored locally in your `.env` file and used only to call eBay directly.
629
618
 
630
619
  </details>
631
620
 
632
621
  <details>
633
622
  <summary><strong>How is this different from calling the eBay API directly?</strong></summary>
634
623
 
635
- You interact in natural language through your AI assistant. OAuth token management, automatic retries with backoff, and type-safe Effect-backed validation are built in. See the [comparison table](#ebay-mcp-vs-the-raw-ebay-api) above.
624
+ You interact in natural language through your AI assistant. OAuth token management, automatic retries with backoff, and type-safe Zod validation are built in. See the [comparison table](#ebay-mcp-vs-the-raw-ebay-api) above.
636
625
 
637
626
  </details>
638
627
 
@@ -667,7 +656,7 @@ Complete the OAuth flow with `npm run setup` to authenticate with a user token (
667
656
  <details>
668
657
  <summary><strong>What is it built with?</strong></summary>
669
658
 
670
- TypeScript and Node.js (ESM), using the official MCP SDK, Effect-backed validation with a Zod-compatible MCP adapter, and OpenAPI-generated types.
659
+ TypeScript and Node.js (ESM), using the official MCP SDK, Zod schemas for tool inputs, Effect for typed async errors, and OpenAPI-generated types.
671
660
 
672
661
  </details>
673
662
 
@@ -687,28 +676,28 @@ No. "Runs locally" means the server process runs on your machine — it still ne
687
676
 
688
677
  ## Contributing
689
678
 
690
- Contributions welcome. Fork → branch → add tests → `npm run check && npm test` → commit with [Conventional Commits](https://www.conventionalcommits.org/) → open a PR.
679
+ Contributions welcome. Fork → branch → add tests → run the checks below → commit with [Conventional Commits](https://www.conventionalcommits.org/) → open a PR.
691
680
 
692
- - Working on the codebase or with a coding agent? Start with **[AGENTS.md](AGENTS.md)** — build/test commands, module map, and the add-an-endpoint workflow.
693
- - Code style lives in **[CODE-STYLE.md](CODE-STYLE.md)**. Architecture and decision context live in **[ARCHITECTURE.md](ARCHITECTURE.md)** and [ADRs](docs/adr/current/).
694
- - Full contribution guidelines: **[CONTRIBUTING.md](CONTRIBUTING.md)**.
681
+ ```bash
682
+ pnpm typecheck && pnpm typecheck:mcp-apps # TypeScript (server + MCP Apps views)
683
+ pnpm check:ci # Biome lint + format
684
+ pnpm test && pnpm test:integration # Vitest unit + integration
685
+ pnpm build # Build to build/
686
+ ```
695
687
 
696
688
  ## Resources
697
689
 
698
690
  Project docs:
699
691
 
700
- - [Configuration Guide](docs/auth/CONFIGURATION.md) — every environment variable, OAuth step, and eBay scope.
701
- - [OAuth Quick Reference](docs/auth/OAUTH_QUICK_REFERENCE.md) — scopes, troubleshooting, and examples.
702
- - [Logging Guide](docs/logging.md) and [Troubleshooting Guide](docs/troubleshooting.md) — operational help after setup.
703
- - [Architecture](ARCHITECTURE.md), [CODE-STYLE.md](CODE-STYLE.md), [AGENTS.md](AGENTS.md), and [llms.txt](llms.txt) — contributor and agent entry points.
704
- - [CHANGELOG.md](CHANGELOG.md), [SECURITY.md](SECURITY.md), [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), and the [Issue Tracker](https://github.com/YosefHayim/ebay-mcp/issues).
692
+ - [llms.txt](llms.txt) — a compact project summary for AI agents.
693
+ - [Releases](https://github.com/YosefHayim/ebay-mcp/releases) and the [Issue Tracker](https://github.com/YosefHayim/ebay-mcp/issues).
705
694
 
706
695
  Official specs and tooling:
707
696
 
708
697
  - [eBay Developer Portal](https://developer.ebay.com/), [Sell API docs](https://developer.ebay.com/api-docs/sell/static/overview.html), [API License Agreement](https://developer.ebay.com/join/api-license-agreement), [Data Handling Requirements](https://developer.ebay.com/api-docs/static/data-handling-update.html), and [API Status](https://developer.ebay.com/support/api-status).
709
698
  - [Model Context Protocol](https://modelcontextprotocol.io/) and the [MCP Apps SDK](https://github.com/modelcontextprotocol/ext-apps).
710
- - [Node.js](https://nodejs.org/en), [npm package](https://www.npmjs.com/package/ebay-mcp), [TypeScript](https://www.typescriptlang.org/), [Effect](https://effect.website/docs), [Biome](https://biomejs.dev/), [Vitest](https://vitest.dev/), and [GitHub Actions](https://docs.github.com/en/actions).
711
- - [AGENTS.md convention](https://agents.md/), [Claude Code](https://code.claude.com/docs/en/overview), [GitHub Copilot repository instructions](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions), and [llms.txt](https://llmstxt.org/).
699
+ - [Node.js](https://nodejs.org/en), [npm package](https://www.npmjs.com/package/ebay-mcp), [TypeScript](https://www.typescriptlang.org/), [Zod](https://zod.dev/), [Effect](https://effect.website/docs), [Biome](https://biomejs.dev/), [Vitest](https://vitest.dev/), and [GitHub Actions](https://docs.github.com/en/actions).
700
+ - [Claude Code](https://code.claude.com/docs/en/overview) and [llms.txt](https://llmstxt.org/).
712
701
 
713
702
  ## License
714
703
 
@@ -23,8 +23,8 @@ export class AccountV2Api {
23
23
  getRateTable = (input) => {
24
24
  const { client, basePath } = this;
25
25
  return Effect.gen(function* () {
26
- const request = yield* requireObjectEffect(input, 'input');
27
- const rateTableId = yield* requireStringEffect(request.rateTableId, 'rateTableId');
26
+ const validInput = yield* requireObjectEffect(input, 'input');
27
+ const rateTableId = yield* requireStringEffect(validInput.rateTableId, 'rateTableId');
28
28
  return yield* requestGetEffect(client, `${basePath}/rate_table/${encodeURIComponent(rateTableId)}`);
29
29
  });
30
30
  };
@@ -49,11 +49,11 @@ export class AccountV2Api {
49
49
  updateShippingCost = (input) => {
50
50
  const { client, basePath } = this;
51
51
  return Effect.gen(function* () {
52
- const request = yield* requireObjectEffect(input, 'input');
53
- const rateTableId = yield* requireStringEffect(request.rateTableId, 'rateTableId');
54
- const body = yield* requireObjectEffect(request.rateTableUpdate, 'rateTableUpdate');
52
+ const validInput = yield* requireObjectEffect(input, 'input');
53
+ const rateTableId = yield* requireStringEffect(validInput.rateTableId, 'rateTableId');
54
+ const rateTableUpdate = yield* requireObjectEffect(validInput.rateTableUpdate, 'rateTableUpdate');
55
55
  const path = `${basePath}/rate_table/${encodeURIComponent(rateTableId)}/update_shipping_cost`;
56
- return yield* requestPostEffect(client, path, body);
56
+ return yield* requestPostEffect(client, path, rateTableUpdate);
57
57
  });
58
58
  };
59
59
  /**
@@ -98,9 +98,9 @@ export class AccountV2Api {
98
98
  const { client } = this;
99
99
  const path = `${this.basePath}/payout_settings/update_percentage`;
100
100
  return Effect.gen(function* () {
101
- const request = yield* requireObjectEffect(input, 'input');
102
- const body = yield* requireObjectEffect(request.payoutSplit, 'payoutSplit');
103
- return yield* requestPostEffect(client, path, body);
101
+ const validInput = yield* requireObjectEffect(input, 'input');
102
+ const payoutSplit = yield* requireObjectEffect(validInput.payoutSplit, 'payoutSplit');
103
+ return yield* requestPostEffect(client, path, payoutSplit);
104
104
  });
105
105
  };
106
106
  /**
@@ -182,8 +182,8 @@ export class AccountV2Api {
182
182
  const { client } = this;
183
183
  const path = `${this.basePath}/combined_shipping_rules`;
184
184
  return Effect.gen(function* () {
185
- const request = yield* requireObjectEffect(input, 'input');
186
- const marketplaceId = yield* requireStringEffect(request.marketplaceId, 'marketplaceId');
185
+ const validInput = yield* requireObjectEffect(input, 'input');
186
+ const marketplaceId = yield* requireStringEffect(validInput.marketplaceId, 'marketplaceId');
187
187
  return yield* requestGetEffect(client, path, undefined, marketplaceHeader(marketplaceId));
188
188
  });
189
189
  };
@@ -286,9 +286,9 @@ export class AccountV2Api {
286
286
  const { client } = this;
287
287
  const path = `${this.basePath}/user_preferences`;
288
288
  return Effect.gen(function* () {
289
- const request = yield* requireObjectEffect(input, 'input');
290
- const marketplaceId = yield* requireStringEffect(request.marketplaceId, 'marketplaceId');
291
- const fieldgroups = yield* optionalStringEffect(request.fieldgroups, 'fieldgroups');
289
+ const validInput = yield* requireObjectEffect(input, 'input');
290
+ const marketplaceId = yield* requireStringEffect(validInput.marketplaceId, 'marketplaceId');
291
+ const fieldgroups = yield* optionalStringEffect(validInput.fieldgroups, 'fieldgroups');
292
292
  const params = buildEndpointParams({
293
293
  fieldgroups: { wireName: 'fieldgroups', value: fieldgroups },
294
294
  });
@@ -324,10 +324,10 @@ export class AccountV2Api {
324
324
  const { client } = this;
325
325
  const path = `${this.basePath}/user_preferences`;
326
326
  return Effect.gen(function* () {
327
- const request = yield* requireObjectEffect(input, 'input');
328
- const marketplaceId = yield* requireStringEffect(request.marketplaceId, 'marketplaceId');
329
- const body = yield* requireObjectEffect(request.preferences, 'preferences');
330
- return yield* requestPatchEffect(client, path, body, marketplaceHeader(marketplaceId));
327
+ const validInput = yield* requireObjectEffect(input, 'input');
328
+ const marketplaceId = yield* requireStringEffect(validInput.marketplaceId, 'marketplaceId');
329
+ const preferences = yield* requireObjectEffect(validInput.preferences, 'preferences');
330
+ return yield* requestPatchEffect(client, path, preferences, marketplaceHeader(marketplaceId));
331
331
  });
332
332
  };
333
333
  /**
@@ -338,10 +338,10 @@ export class AccountV2Api {
338
338
  const { client } = this;
339
339
  const path = `${this.basePath}/combined_shipping_rules/${operation}`;
340
340
  return Effect.gen(function* () {
341
- const request = yield* requireObjectEffect(input, 'input');
342
- const marketplaceId = yield* requireStringEffect(request.marketplaceId, 'marketplaceId');
343
- const body = yield* requireObjectEffect(request[bodyField], bodyField);
344
- return yield* requestPostEffect(client, path, body, marketplaceHeader(marketplaceId));
341
+ const validInput = yield* requireObjectEffect(input, 'input');
342
+ const marketplaceId = yield* requireStringEffect(validInput.marketplaceId, 'marketplaceId');
343
+ const rules = yield* requireObjectEffect(validInput[bodyField], bodyField);
344
+ return yield* requestPostEffect(client, path, rules, marketplaceHeader(marketplaceId));
345
345
  });
346
346
  };
347
347
  }
@@ -61,8 +61,8 @@ export class FinancesApi {
61
61
  getOrderEarnings = (input = {}) => {
62
62
  const getFromApiz = this.getFromApiz;
63
63
  return Effect.gen(function* () {
64
- const request = yield* decodeEndpointInputEffect(getOrderEarningsInputSchema, input);
65
- return yield* getFromApiz(`${BASE_PATH}/order_earnings`, pageQuery(request), request.marketplaceId);
64
+ const validatedInput = yield* decodeEndpointInputEffect(getOrderEarningsInputSchema, input);
65
+ return yield* getFromApiz(`${BASE_PATH}/order_earnings`, pageQuery(validatedInput), validatedInput.marketplaceId);
66
66
  });
67
67
  };
68
68
  /**
@@ -146,8 +146,8 @@ export class FinancesApi {
146
146
  getPayouts = (input = {}) => {
147
147
  const getFromApiz = this.getFromApiz;
148
148
  return Effect.gen(function* () {
149
- const request = yield* decodeEndpointInputEffect(getPayoutsInputSchema, input);
150
- return yield* getFromApiz(`${BASE_PATH}/payout`, pageQuery(request), request.marketplaceId);
149
+ const validatedInput = yield* decodeEndpointInputEffect(getPayoutsInputSchema, input);
150
+ return yield* getFromApiz(`${BASE_PATH}/payout`, pageQuery(validatedInput), validatedInput.marketplaceId);
151
151
  });
152
152
  };
153
153
  /**
@@ -211,8 +211,8 @@ export class FinancesApi {
211
211
  getTransactions = (input = {}) => {
212
212
  const getFromApiz = this.getFromApiz;
213
213
  return Effect.gen(function* () {
214
- const request = yield* decodeEndpointInputEffect(getTransactionsInputSchema, input);
215
- return yield* getFromApiz(`${BASE_PATH}/transaction`, pageQuery(request), request.marketplaceId);
214
+ const validatedInput = yield* decodeEndpointInputEffect(getTransactionsInputSchema, input);
215
+ return yield* getFromApiz(`${BASE_PATH}/transaction`, pageQuery(validatedInput), validatedInput.marketplaceId);
216
216
  });
217
217
  };
218
218
  /**
@@ -279,11 +279,11 @@ export class FinancesApi {
279
279
  getBillingActivities = (input) => {
280
280
  const client = this.client;
281
281
  return Effect.gen(function* () {
282
- const request = yield* decodeEndpointInputEffect(getBillingActivitiesInputSchema, input);
283
- const config = request.acceptLanguage === undefined
282
+ const validatedInput = yield* decodeEndpointInputEffect(getBillingActivitiesInputSchema, input);
283
+ const config = validatedInput.acceptLanguage === undefined
284
284
  ? undefined
285
- : { headers: { 'Accept-Language': request.acceptLanguage } };
286
- return yield* requestGetEffect(client, `${BASE_PATH}/billing_activity`, pageQuery(request), config);
285
+ : { headers: { 'Accept-Language': validatedInput.acceptLanguage } };
286
+ return yield* requestGetEffect(client, `${BASE_PATH}/billing_activity`, pageQuery(validatedInput), config);
287
287
  });
288
288
  };
289
289
  }
@@ -2,7 +2,7 @@ import { buildEndpointParams, optionalStringEffect, requestGetEffect, requireObj
2
2
  import { Effect } from 'effect';
3
3
  /**
4
4
  * Analytics API - Sales and traffic analytics
5
- * Based on: docs/sell-apps/analytics-and-report/sell_analytics_v1_oas3.json
5
+ * Based on: sell_analytics_v1_oas3.json
6
6
  */
7
7
  export class AnalyticsApi {
8
8
  basePath = '/sell/analytics/v1';
@@ -1,17 +1,17 @@
1
- import { EbayOAuthClient } from '../auth/oauth.js';
2
- import { clientRequestError } from '../api/clientRequestError.js';
3
- import { RateLimitTracker } from '../api/rateLimitTracker.js';
4
- import { getBaseUrl } from '../config/environment.js';
5
- import { getErrorMessage } from '../utils/errors.js';
6
- import { httpRequestEffect, isHttpError, } from '../utils/http.js';
7
- import { isRecord } from '../utils/typeGuards.js';
8
- import { apiLogger, logRequest, logResponse, logErrorResponse } from '../utils/logger.js';
1
+ import { EbayOAuthClient } from '../../auth/oauth.js';
2
+ import { clientRequestError, } from '../../api/client/ebayClientRequestError.js';
3
+ import { RateLimitTracker } from '../../api/client/rateLimitTracker.js';
4
+ import { getBaseUrl } from '../../config/environment.js';
5
+ import { getErrorMessage } from '../../utils/errors.js';
6
+ import { httpRequestEffect, isHttpError, } from '../../utils/http.js';
7
+ import { isRecord } from '../../utils/typeGuards.js';
8
+ import { apiLogger, logRequest, logResponse, logErrorResponse } from '../../utils/logger.js';
9
9
  import { Cause, Effect, Exit } from 'effect';
10
10
  /** Bodies that must never be echoed into debug logs. */
11
- const isBinaryBody = (data) => data instanceof FormData ||
12
- data instanceof Blob ||
13
- data instanceof Uint8Array ||
14
- data instanceof ArrayBuffer;
11
+ const isBinaryBody = (requestBody) => requestBody instanceof FormData ||
12
+ requestBody instanceof Blob ||
13
+ requestBody instanceof Uint8Array ||
14
+ requestBody instanceof ArrayBuffer;
15
15
  const CONTENT_TYPE_HEADER = 'content-type';
16
16
  const hasHeader = (headers, name) => headers !== undefined && Object.keys(headers).some((key) => key.toLowerCase() === name);
17
17
  /** Removes every spelling of a header so fetch can derive it from the body. */
@@ -31,10 +31,6 @@ const deleteHeader = (headers, name) => {
31
31
  const tokenFailureRemediation = (tokenType) => tokenType === 'application'
32
32
  ? 'This endpoint requires an application access token minted from client credentials, which a user token cannot supply. Check EBAY_CLIENT_ID and EBAY_CLIENT_SECRET.'
33
33
  : 'Please use the ebay_set_user_tokens_with_expiry tool to provide valid tokens.';
34
- /** Sleep for a retry backoff delay without exposing timers to callers. */
35
- const sleep = (delayMs) => Effect.promise(() => new Promise((resolve) => {
36
- setTimeout(resolve, delayMs);
37
- }));
38
34
  /**
39
35
  * Base client for making eBay API requests.
40
36
  *
@@ -103,9 +99,9 @@ export class EbayApiClient {
103
99
  * Pull the most descriptive eBay error string from a response body when present.
104
100
  * eBay REST errors arrive as `{ errors: [{ message, longMessage }] }`.
105
101
  */
106
- ebayErrorDetail(data) {
107
- if (isRecord(data) && Array.isArray(data.errors)) {
108
- const [firstError] = data.errors;
102
+ ebayErrorDetail(errorBody) {
103
+ if (isRecord(errorBody) && Array.isArray(errorBody.errors)) {
104
+ const [firstError] = errorBody.errors;
109
105
  if (isRecord(firstError)) {
110
106
  const detail = firstError.longMessage ?? firstError.message;
111
107
  if (typeof detail === 'string') {
@@ -118,11 +114,11 @@ export class EbayApiClient {
118
114
  * Serialize the full error response body so structured fields (errorId, parameters)
119
115
  * survive into the thrown message for diagnostics.
120
116
  */
121
- ebayErrorBody(data) {
122
- if (data == null)
117
+ ebayErrorBody(errorBody) {
118
+ if (errorBody == null)
123
119
  return '';
124
120
  try {
125
- return ` | response: ${JSON.stringify(data)}`;
121
+ return ` | response: ${JSON.stringify(errorBody)}`;
126
122
  }
127
123
  catch {
128
124
  return '';
@@ -142,8 +138,8 @@ export class EbayApiClient {
142
138
  // rejects with a FiberFailure whose generic message hides eBay response data.
143
139
  const exit = await Effect.runPromiseExit(this.requestEffect(method, endpoint, options));
144
140
  if (Exit.isSuccess(exit)) {
145
- const { data, status, headers } = exit.value;
146
- return { data, status, headers };
141
+ const { data: responseBody, status, headers } = exit.value;
142
+ return { data: responseBody, status, headers };
147
143
  }
148
144
  throw Cause.squash(exit.cause);
149
145
  }
@@ -222,9 +218,9 @@ export class EbayApiClient {
222
218
  timeoutMs: options.timeoutMs ?? this.timeoutMs,
223
219
  responseType: options.responseType,
224
220
  maxBytes: options.maxBytes,
225
- }).pipe(Effect.map((response) => {
226
- logResponse(response.status, response.statusText, response.data, response.headers['x-ebay-c-ratelimit-remaining'], response.headers['x-ebay-c-ratelimit-limit']);
227
- return response;
221
+ }).pipe(Effect.map((httpResponse) => {
222
+ logResponse(httpResponse.status, httpResponse.statusText, httpResponse.data, httpResponse.headers['x-ebay-c-ratelimit-remaining'], httpResponse.headers['x-ebay-c-ratelimit-limit']);
223
+ return httpResponse;
228
224
  }), Effect.catchAll((error) => this.handleRequestFailure(error, { method, url, options, state })));
229
225
  });
230
226
  }
@@ -309,7 +305,7 @@ export class EbayApiClient {
309
305
  attempt: `${nextServerRetries}/3`,
310
306
  delayMs,
311
307
  });
312
- return sleep(delayMs).pipe(Effect.flatMap(() => this.sendWithRetry(method, url, options, {
308
+ return Effect.sleep(delayMs).pipe(Effect.flatMap(() => this.sendWithRetry(method, url, options, {
313
309
  ...state,
314
310
  serverRetries: nextServerRetries,
315
311
  })));
@@ -364,16 +360,16 @@ export class EbayApiClient {
364
360
  /**
365
361
  * Make a POST request to eBay API
366
362
  */
367
- async post(endpoint, data, config) {
368
- return (await this.postForResponse(endpoint, data, config)).data;
363
+ async post(endpoint, requestBody, config) {
364
+ return (await this.postForResponse(endpoint, requestBody, config)).data;
369
365
  }
370
366
  /**
371
367
  * Make a POST request and keep the status and headers of the successful
372
368
  * response — for endpoints that return their result in a `Location` header.
373
369
  */
374
- async postForResponse(endpoint, data, config) {
370
+ async postForResponse(endpoint, requestBody, config) {
375
371
  return await this.requestResponse('POST', endpoint, {
376
- data,
372
+ data: requestBody,
377
373
  params: config?.params,
378
374
  headers: config?.headers,
379
375
  responseType: config?.responseType,
@@ -386,16 +382,16 @@ export class EbayApiClient {
386
382
  /**
387
383
  * Make a PUT request to eBay API
388
384
  */
389
- async put(endpoint, data, config) {
390
- return (await this.putForResponse(endpoint, data, config)).data;
385
+ async put(endpoint, requestBody, config) {
386
+ return (await this.putForResponse(endpoint, requestBody, config)).data;
391
387
  }
392
388
  /**
393
389
  * Make a PUT request and keep the status and headers of the successful
394
390
  * response — for asynchronous updates that return a task `Location` header.
395
391
  */
396
- async putForResponse(endpoint, data, config) {
392
+ async putForResponse(endpoint, requestBody, config) {
397
393
  return await this.requestResponse('PUT', endpoint, {
398
- data,
394
+ data: requestBody,
399
395
  params: config?.params,
400
396
  headers: config?.headers,
401
397
  responseType: config?.responseType,
@@ -408,9 +404,9 @@ export class EbayApiClient {
408
404
  /**
409
405
  * Make a PATCH request to eBay API
410
406
  */
411
- async patch(endpoint, data, config) {
407
+ async patch(endpoint, requestBody, config) {
412
408
  return await this.request('PATCH', endpoint, {
413
- data,
409
+ data: requestBody,
414
410
  params: config?.params,
415
411
  headers: config?.headers,
416
412
  responseType: config?.responseType,
@@ -429,11 +425,11 @@ export class EbayApiClient {
429
425
  /**
430
426
  * Make a DELETE request and keep the status and headers of the successful
431
427
  * response — for asynchronous deletes that return a task `Location` header.
432
- * `data` is the optional body a few eBay DELETE calls document.
428
+ * `requestBody` is the optional body a few eBay DELETE calls document.
433
429
  */
434
- async deleteForResponse(endpoint, config, data) {
430
+ async deleteForResponse(endpoint, config, requestBody) {
435
431
  return await this.requestResponse('DELETE', endpoint, {
436
- data,
432
+ data: requestBody,
437
433
  params: config?.params,
438
434
  headers: config?.headers,
439
435
  responseType: config?.responseType,
@@ -1,12 +1,12 @@
1
1
  import XmlBuilder from 'fast-xml-builder';
2
2
  import { XMLParser } from 'fast-xml-parser';
3
- import { TradingApiFailure } from '../api/clientTradingError.js';
4
- import { EbayApiError } from '../api/shared/request.js';
5
- import { getBaseUrl, getTradingSiteId } from '../config/environment.js';
6
- import { getErrorMessage } from '../utils/errors.js';
7
- import { httpRequestEffect } from '../utils/http.js';
8
- import { apiLogger } from '../utils/logger.js';
9
- import { isRecord } from '../utils/typeGuards.js';
3
+ import { TradingApiFailure } from '../../api/client/tradingApiFailure.js';
4
+ import { EbayApiError } from '../../api/shared/request.js';
5
+ import { getBaseUrl, getTradingSiteId } from '../../config/environment.js';
6
+ import { getErrorMessage } from '../../utils/errors.js';
7
+ import { httpRequestEffect } from '../../utils/http.js';
8
+ import { apiLogger } from '../../utils/logger.js';
9
+ import { isRecord } from '../../utils/typeGuards.js';
10
10
  import { Effect } from 'effect';
11
11
  const COMPAT_LEVEL = '1451';
12
12
  const TRADING_ENDPOINT_PATH = '/ws/api.dll';
@@ -73,9 +73,9 @@ const parseTradingXml = ({ parser, responseText, callName, path, }) => Effect.tr
73
73
  return Effect.fail(createTradingApiError({ callName, path }, 'response must be an object'));
74
74
  }));
75
75
  const readTradingPayload = (parsed, responseTag, { callName, path }) => {
76
- const resultValue = parsed[responseTag] === undefined ? parsed : parsed[responseTag];
77
- if (isRecord(resultValue)) {
78
- return Effect.succeed(resultValue);
76
+ const responsePayload = parsed[responseTag] === undefined ? parsed : parsed[responseTag];
77
+ if (isRecord(responsePayload)) {
78
+ return Effect.succeed(responsePayload);
79
79
  }
80
80
  return Effect.fail(createTradingApiError({ callName, path }, 'response payload is not an object'));
81
81
  };
@@ -94,25 +94,25 @@ const extractTradingErrorMessage = (errors) => {
94
94
  }
95
95
  return 'Trading API returned a failure without an error message';
96
96
  };
97
- const validateTradingAck = (result, { callName, path }) => {
98
- if (result.Ack === 'Warning') {
97
+ const validateTradingAck = (tradingPayload, { callName, path }) => {
98
+ if (tradingPayload.Ack === 'Warning') {
99
99
  apiLogger.warn(`Trading API ${callName} returned warnings`, {
100
- errors: result.Errors,
100
+ errors: tradingPayload.Errors,
101
101
  });
102
102
  }
103
- if (result.Ack === 'Failure' || result.Ack === 'PartialFailure') {
103
+ if (tradingPayload.Ack === 'Failure' || tradingPayload.Ack === 'PartialFailure') {
104
104
  return Effect.fail(new EbayApiError({
105
105
  method: 'POST',
106
106
  path,
107
107
  cause: new TradingApiFailure({
108
108
  callName,
109
109
  path,
110
- message: extractTradingErrorMessage(result.Errors),
111
- cause: result.Errors,
110
+ message: extractTradingErrorMessage(tradingPayload.Errors),
111
+ cause: tradingPayload.Errors,
112
112
  }),
113
113
  }));
114
114
  }
115
- return Effect.succeed(result);
115
+ return Effect.succeed(tradingPayload);
116
116
  };
117
117
  /**
118
118
  * XML-based client for eBay Trading API calls that are not covered by REST APIs.
@@ -173,7 +173,7 @@ export class TradingApiClient {
173
173
  *
174
174
  * @example
175
175
  * ```ts
176
- * const result = await Effect.runPromise(
176
+ * const tradingReply = await Effect.runPromise(
177
177
  * tradingClient.execute('GetItem', { ItemID: '12345' }),
178
178
  * );
179
179
  * ```
@@ -193,7 +193,7 @@ export class TradingApiClient {
193
193
  callName,
194
194
  path,
195
195
  });
196
- const response = yield* postTradingXml({
196
+ const xmlResponse = yield* postTradingXml({
197
197
  path,
198
198
  headers: authorizedHeaders,
199
199
  xmlBody,
@@ -201,12 +201,12 @@ export class TradingApiClient {
201
201
  });
202
202
  const parsed = yield* parseTradingXml({
203
203
  parser: tradingClient.parser,
204
- responseText: response.data,
204
+ responseText: xmlResponse.data,
205
205
  callName,
206
206
  path,
207
207
  });
208
- const result = yield* readTradingPayload(parsed, responseTag, { callName, path });
209
- return yield* validateTradingAck(result, { callName, path });
208
+ const tradingPayload = yield* readTradingPayload(parsed, responseTag, { callName, path });
209
+ return yield* validateTradingAck(tradingPayload, { callName, path });
210
210
  });
211
211
  };
212
212
  }