ebay-mcp 1.8.5 → 1.8.9

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 (109) hide show
  1. package/README.md +1 -2
  2. package/build/api/client-trading.js +23 -10
  3. package/build/api/client.js +2 -1
  4. package/build/api/communication/feedback.js +6 -31
  5. package/build/api/communication/message.js +21 -34
  6. package/build/api/communication/negotiation.js +18 -38
  7. package/build/api/communication/notification.js +66 -223
  8. package/build/api/communication/shared.js +60 -0
  9. package/build/api/listing-management/inventory.js +94 -387
  10. package/build/api/listing-metadata/metadata.js +42 -306
  11. package/build/api/other/compliance.js +1 -1
  12. package/build/api/other/vero.js +2 -7
  13. package/build/api/shared/query-params.js +21 -0
  14. package/build/api/shared/request.js +140 -0
  15. package/build/api/trading/trading.js +50 -11
  16. package/build/auth/credential-session.js +166 -0
  17. package/build/auth/oauth.js +43 -100
  18. package/build/auth/scope-utils.js +7 -1
  19. package/build/auth/token-verifier.js +12 -4
  20. package/build/config/environment.js +10 -1
  21. package/build/index.js +9 -53
  22. package/build/schemas/account-management/account.js +90 -0
  23. package/build/schemas/communication/messages.js +84 -0
  24. package/build/schemas/fulfillment/orders.js +36 -0
  25. package/build/schemas/inventory-management/inventory.js +96 -4
  26. package/build/schemas/marketing/marketing.js +462 -0
  27. package/build/schemas/metadata/metadata.js +213 -0
  28. package/build/scripts/auto-setup.js +46 -26
  29. package/build/scripts/dev-sync.js +12 -3
  30. package/build/scripts/diagnostics.js +5 -31
  31. package/build/scripts/download-specs.js +1 -8
  32. package/build/scripts/interactive-setup.js +16 -27
  33. package/build/scripts/setup-shared.js +28 -0
  34. package/build/scripts/setup.js +116 -144
  35. package/build/server-http.d.ts +1 -8
  36. package/build/server-http.js +48 -346
  37. package/build/tools/contracts.js +69 -0
  38. package/build/tools/definitions/account.js +1 -0
  39. package/build/tools/definitions/analytics.js +1 -0
  40. package/build/tools/definitions/communication.js +1 -0
  41. package/build/tools/definitions/developer.js +1 -0
  42. package/build/tools/definitions/fulfillment.js +1 -0
  43. package/build/tools/definitions/index.js +1 -1
  44. package/build/tools/definitions/inventory.js +1 -0
  45. package/build/tools/definitions/marketing.js +9 -1
  46. package/build/tools/definitions/metadata.js +1 -0
  47. package/build/tools/definitions/other.js +2 -0
  48. package/build/tools/definitions/taxonomy.js +1 -0
  49. package/build/tools/definitions/token-management.js +1 -0
  50. package/build/tools/definitions/trading.js +3 -7
  51. package/build/tools/index.js +4 -1200
  52. package/build/tools/registry.js +82 -0
  53. package/build/tools/schemas.js +47 -0
  54. package/build/tools/tool-definitions.js +11 -0
  55. package/build/tools/tool-handlers/account.js +123 -0
  56. package/build/tools/tool-handlers/analytics.js +15 -0
  57. package/build/tools/tool-handlers/chat.js +76 -0
  58. package/build/tools/tool-handlers/communication.js +161 -0
  59. package/build/tools/tool-handlers/developer.js +40 -0
  60. package/build/tools/tool-handlers/fulfillment.js +54 -0
  61. package/build/tools/tool-handlers/index.js +29 -0
  62. package/build/tools/tool-handlers/inventory.js +111 -0
  63. package/build/tools/tool-handlers/marketing.js +384 -0
  64. package/build/tools/tool-handlers/metadata.js +72 -0
  65. package/build/tools/tool-handlers/other.js +120 -0
  66. package/build/tools/tool-handlers/taxonomy.js +15 -0
  67. package/build/tools/tool-handlers/token-management.js +246 -0
  68. package/build/tools/tool-handlers/trading.js +21 -0
  69. package/build/tools/tool-handlers/types.js +1 -0
  70. package/build/types/ebay.js +6 -0
  71. package/build/utils/account-management/account.js +1 -14
  72. package/build/utils/api-status-feed.js +1 -3
  73. package/build/utils/communication/notification.js +1 -7
  74. package/build/utils/date-converter.js +3 -0
  75. package/build/utils/env-parser.js +30 -0
  76. package/build/utils/llm-client-detector.js +1 -1
  77. package/build/utils/logger.js +9 -1
  78. package/build/utils/other/edelivery.js +1 -7
  79. package/build/utils/schema-helpers.js +13 -0
  80. package/build/utils/scope-helper.js +2 -2
  81. package/build/utils/security-checker.js +1 -1
  82. package/build/utils/setup-validator.js +1 -31
  83. package/build/utils/setup-wizard.js +187 -0
  84. package/build/utils/token-utils.js +9 -0
  85. package/build/utils/type-guards.js +6 -0
  86. package/build/utils/version.js +28 -1
  87. package/package.json +16 -6
  88. package/build/tools/definitions/account-with-schemas.js +0 -170
  89. package/build/types/application-settings/developerAnalyticsV1BetaOas3.js +0 -5
  90. package/build/types/application-settings/developerClientRegistrationV1Oas3.js +0 -5
  91. package/build/types/application-settings/developerKeyManagementV1Oas3.js +0 -5
  92. package/build/types/sell-apps/account-management/sellAccountV1Oas3.js +0 -5
  93. package/build/types/sell-apps/analytics-and-report/sellAnalyticsV1Oas3.js +0 -5
  94. package/build/types/sell-apps/communication/commerceFeedbackV1BetaOas3.js +0 -5
  95. package/build/types/sell-apps/communication/commerceMessageV1Oas3.js +0 -5
  96. package/build/types/sell-apps/communication/commerceNotificationV1Oas3.js +0 -5
  97. package/build/types/sell-apps/communication/sellNegotiationV1Oas3.js +0 -5
  98. package/build/types/sell-apps/listing-management/sellInventoryV1Oas3.js +0 -5
  99. package/build/types/sell-apps/listing-metadata/sellMetadataV1Oas3.js +0 -5
  100. package/build/types/sell-apps/markeitng-and-promotions/sellMarketingV1Oas3.js +0 -5
  101. package/build/types/sell-apps/markeitng-and-promotions/sellRecommendationV1Oas3.js +0 -5
  102. package/build/types/sell-apps/order-management/sellFulfillmentV1Oas3.js +0 -5
  103. package/build/types/sell-apps/other-apis/commerceIdentityV1Oas3.js +0 -5
  104. package/build/types/sell-apps/other-apis/commerceTranslationV1BetaOas3.js +0 -5
  105. package/build/types/sell-apps/other-apis/commerceVeroV1Oas3.js +0 -5
  106. package/build/types/sell-apps/other-apis/sellComplianceV1Oas3.js +0 -5
  107. package/build/types/sell-apps/other-apis/sellEdeliveryInternationalShippingOas3.js +0 -5
  108. package/build/types/sell-apps/other-apis/sellMarketingV1Oas3.js +0 -5
  109. package/build/types/sell-apps/other-apis/sellRecommendationV1Oas3.js +0 -5
package/README.md CHANGED
@@ -8,7 +8,6 @@
8
8
  [![API Coverage](https://img.shields.io/badge/API%20coverage-100%25-success)](src/tools/)
9
9
  [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
10
  [![Contributors Welcome](https://img.shields.io/badge/contributors-welcome-brightgreen.svg)](CONTRIBUTING.md)
11
- [![grimoire-wizard](https://img.shields.io/npm/v/grimoire-wizard?label=wizard%3A+grimoire&color=0064D2)](https://github.com/YosefHayim/grimoire)
12
11
 
13
12
  [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/yosefhayim-ebay-api-mcp-server-badge.png)](https://mseep.ai/app/yosefhayim-ebay-api-mcp-server)
14
13
  <a href="https://www.buymeacoffee.com/yosefhayim" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
@@ -158,7 +157,7 @@ The interactive setup wizard handles everything for you:
158
157
  npm run setup
159
158
  ```
160
159
 
161
- > **Powered by [grimoire-wizard](https://github.com/YosefHayim/grimoire)** a config-driven CLI wizard framework [![grimoire-wizard](https://img.shields.io/npm/v/grimoire-wizard?label=grimoire-wizard&color=0064D2)](https://www.npmjs.com/package/grimoire-wizard)
160
+ > Built with a standard Node CLI prompt stack for reliable interactive setup.
162
161
 
163
162
  The wizard will:
164
163
 
@@ -1,8 +1,12 @@
1
1
  import axios from 'axios';
2
2
  import { XMLBuilder, XMLParser } from 'fast-xml-parser';
3
3
  import { apiLogger } from '../utils/logger.js';
4
+ import { isRecord } from '../utils/type-guards.js';
4
5
  const COMPAT_LEVEL = '1451';
5
6
  const SITE_ID = '0';
7
+ /**
8
+ * XML-based client for eBay Trading API calls that are not covered by REST APIs.
9
+ */
6
10
  export class TradingApiClient {
7
11
  restClient;
8
12
  baseUrl;
@@ -11,10 +15,7 @@ export class TradingApiClient {
11
15
  constructor(restClient) {
12
16
  this.restClient = restClient;
13
17
  const env = restClient.getConfig().environment;
14
- this.baseUrl =
15
- env === 'sandbox'
16
- ? 'https://api.sandbox.ebay.com'
17
- : 'https://api.ebay.com';
18
+ this.baseUrl = env === 'sandbox' ? 'https://api.sandbox.ebay.com' : 'https://api.ebay.com';
18
19
  this.parser = new XMLParser({
19
20
  ignoreAttributes: false,
20
21
  removeNSPrefix: true,
@@ -42,9 +43,15 @@ export class TradingApiClient {
42
43
  suppressEmptyNode: true,
43
44
  });
44
45
  }
45
- getBaseUrl() {
46
+ /**
47
+ * Return the Trading API base URL for the configured eBay environment.
48
+ */
49
+ getTradingBaseUrl() {
46
50
  return this.baseUrl;
47
51
  }
52
+ /**
53
+ * Execute a named Trading API call with XML request/response conversion.
54
+ */
48
55
  async execute(callName, params) {
49
56
  const token = await this.restClient.getOAuthClient().getAccessToken();
50
57
  const requestTag = `${callName}Request`;
@@ -75,12 +82,20 @@ export class TradingApiClient {
75
82
  }
76
83
  let parsed;
77
84
  try {
78
- parsed = this.parser.parse(response.data);
85
+ const parsedValue = this.parser.parse(response.data);
86
+ if (!isRecord(parsedValue)) {
87
+ throw new Error('Trading API response must be an object');
88
+ }
89
+ parsed = parsedValue;
79
90
  }
80
91
  catch (e) {
81
92
  throw new Error(`Failed to parse Trading API ${callName} response: ${e instanceof Error ? e.message : String(e)}`);
82
93
  }
83
- const result = (parsed[responseTag] || parsed);
94
+ const resultValue = parsed[responseTag] || parsed;
95
+ if (!isRecord(resultValue)) {
96
+ throw new Error(`Trading API ${callName} response payload is not an object`);
97
+ }
98
+ const result = resultValue;
84
99
  // Log warnings without failing
85
100
  if (result.Ack === 'Warning') {
86
101
  apiLogger.warn(`Trading API ${callName} returned warnings`, {
@@ -91,9 +106,7 @@ export class TradingApiClient {
91
106
  if (result.Ack === 'Failure' || result.Ack === 'PartialFailure') {
92
107
  const errors = result.Errors;
93
108
  const firstError = Array.isArray(errors) ? errors[0] : errors;
94
- const message = firstError?.ShortMessage ||
95
- firstError?.LongMessage ||
96
- 'Unknown Trading API error';
109
+ const message = firstError?.ShortMessage || firstError?.LongMessage || 'Unknown Trading API error';
97
110
  throw new Error(message);
98
111
  }
99
112
  return result;
@@ -240,8 +240,9 @@ export class EbayApiClient {
240
240
  /**
241
241
  * Set user access and refresh tokens
242
242
  */
243
- async setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry) {
243
+ setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry) {
244
244
  this.authClient.setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry);
245
+ return Promise.resolve();
245
246
  }
246
247
  /**
247
248
  * Get token information for debugging
@@ -1,3 +1,4 @@
1
+ import { getPaginatedWithContextError, getPathWithContextError } from './shared.js';
1
2
  /**
2
3
  * Feedback API - Manage buyer and seller feedback
3
4
  * Based on: docs/sell-apps/communication/commerce_feedback_v1_beta_oas3.json
@@ -11,34 +12,13 @@ export class FeedbackApi {
11
12
  /**
12
13
  * Get items awaiting feedback
13
14
  * Endpoint: GET /awaiting_feedback
15
+ * @param filter API filter expression.
16
+ * @param limit Maximum number of records to return.
17
+ * @param offset Zero-based pagination offset.
14
18
  * @throws Error if the request fails
15
19
  */
16
20
  async getAwaitingFeedback(filter, limit, offset) {
17
- const params = {};
18
- if (filter !== undefined) {
19
- if (typeof filter !== 'string') {
20
- throw new Error('filter must be a string when provided');
21
- }
22
- params.filter = filter;
23
- }
24
- if (limit !== undefined) {
25
- if (typeof limit !== 'number' || limit < 1) {
26
- throw new Error('limit must be a positive number when provided');
27
- }
28
- params.limit = limit;
29
- }
30
- if (offset !== undefined) {
31
- if (typeof offset !== 'number' || offset < 0) {
32
- throw new Error('offset must be a non-negative number when provided');
33
- }
34
- params.offset = offset;
35
- }
36
- try {
37
- return await this.client.get(`${this.basePath}/awaiting_feedback`, params);
38
- }
39
- catch (error) {
40
- throw new Error(`Failed to get awaiting feedback: ${error instanceof Error ? error.message : 'Unknown error'}`);
41
- }
21
+ return await getPaginatedWithContextError(this.client, `${this.basePath}/awaiting_feedback`, 'Failed to get awaiting feedback', filter, limit, offset);
42
22
  }
43
23
  /**
44
24
  * Get feedback for a transaction
@@ -64,12 +44,7 @@ export class FeedbackApi {
64
44
  * @throws Error if the request fails
65
45
  */
66
46
  async getFeedbackRatingSummary() {
67
- try {
68
- return await this.client.get(`${this.basePath}/feedback_rating_summary`);
69
- }
70
- catch (error) {
71
- throw new Error(`Failed to get feedback rating summary: ${error instanceof Error ? error.message : 'Unknown error'}`);
72
- }
47
+ return await getPathWithContextError(this.client, `${this.basePath}/feedback_rating_summary`, 'Failed to get feedback rating summary');
73
48
  }
74
49
  /**
75
50
  * Leave feedback for a buyer
@@ -1,3 +1,4 @@
1
+ import { assertRequiredString, buildPaginatedQueryParams, getPathWithContextError, getWithContextError, } from './shared.js';
1
2
  /**
2
3
  * Message API - Buyer-seller messaging
3
4
  * Based on: docs/sell-apps/communication/commerce_message_v1_oas3.json
@@ -27,50 +28,36 @@ export class MessageApi {
27
28
  /**
28
29
  * Get conversations
29
30
  * Endpoint: GET /conversation
31
+ * @param filter API filter expression.
32
+ * @param limit Maximum number of records to return.
33
+ * @param offset Zero-based pagination offset.
30
34
  * @throws Error if the request fails
31
35
  */
32
36
  async getConversations(filter, limit, offset) {
33
- const params = {};
34
- if (filter !== undefined) {
35
- if (typeof filter !== 'string') {
36
- throw new Error('filter must be a string when provided');
37
- }
38
- params.filter = filter;
39
- }
40
- if (limit !== undefined) {
41
- if (typeof limit !== 'number' || limit < 1) {
42
- throw new Error('limit must be a positive number when provided');
43
- }
44
- params.limit = limit;
45
- }
46
- if (offset !== undefined) {
47
- if (typeof offset !== 'number' || offset < 0) {
48
- throw new Error('offset must be a non-negative number when provided');
49
- }
50
- params.offset = offset;
51
- }
52
- try {
53
- return await this.client.get(`${this.basePath}/conversation`, params);
54
- }
55
- catch (error) {
56
- throw new Error(`Failed to get conversations: ${error instanceof Error ? error.message : 'Unknown error'}`);
57
- }
37
+ const conversationPath = `${this.basePath}/conversation`;
38
+ const queryParams = this.buildConversationQueryParams(filter, limit, offset);
39
+ return await getWithContextError(this.client, conversationPath, queryParams, 'Failed to get conversations');
40
+ }
41
+ /**
42
+ * Build query params used by conversation listing endpoints.
43
+ *
44
+ * @param filter API filter expression.
45
+ * @param limit Maximum number of records to return.
46
+ * @param offset Zero-based pagination offset.
47
+ * @returns Validated conversation query params.
48
+ */
49
+ buildConversationQueryParams(filter, limit, offset) {
50
+ return buildPaginatedQueryParams(filter, limit, offset);
58
51
  }
59
52
  /**
60
53
  * Get a specific conversation
61
54
  * Endpoint: GET /conversation/{conversation_id}
55
+ * @param conversationId Conversation identifier.
62
56
  * @throws Error if required parameters are missing or invalid
63
57
  */
64
58
  async getConversation(conversationId) {
65
- if (!conversationId || typeof conversationId !== 'string') {
66
- throw new Error('conversationId is required and must be a string');
67
- }
68
- try {
69
- return await this.client.get(`${this.basePath}/conversation/${conversationId}`);
70
- }
71
- catch (error) {
72
- throw new Error(`Failed to get conversation: ${error instanceof Error ? error.message : 'Unknown error'}`);
73
- }
59
+ assertRequiredString(conversationId, 'conversationId');
60
+ return await getPathWithContextError(this.client, `${this.basePath}/conversation/${conversationId}`, 'Failed to get conversation');
74
61
  }
75
62
  /**
76
63
  * Send a message
@@ -1,3 +1,5 @@
1
+ import { assertRequiredString, buildPaginatedQueryParams, getPathWithContextError, getWithContextError, } from './shared.js';
2
+ import { buildTruthyPaginatedParams } from '../shared/query-params.js';
1
3
  /**
2
4
  * Negotiation API - Buyer-seller negotiations and offers
3
5
  * Based on: docs/sell-apps/communication/sell_negotiation_v1_oas3.json
@@ -11,30 +13,17 @@ export class NegotiationApi {
11
13
  /**
12
14
  * Find eligible items for a seller-initiated offer
13
15
  * Endpoint: GET /find_eligible_items
16
+ * @param filter API filter expression.
17
+ * @param limit Maximum number of records to return.
18
+ * @param offset Zero-based pagination offset.
14
19
  * @throws Error if the request fails
15
20
  */
16
21
  async findEligibleItems(filter, limit, offset) {
17
- const params = {};
18
- if (filter !== undefined) {
19
- if (typeof filter !== 'string') {
20
- throw new Error('filter must be a string when provided');
21
- }
22
- params.filter = filter;
23
- }
24
- if (limit !== undefined) {
25
- if (typeof limit !== 'number' || limit < 1) {
26
- throw new Error('limit must be a positive number when provided');
27
- }
28
- params.limit = limit;
29
- }
30
- if (offset !== undefined) {
31
- if (typeof offset !== 'number' || offset < 0) {
32
- throw new Error('offset must be a non-negative number when provided');
33
- }
34
- params.offset = offset;
35
- }
22
+ const eligibleItemsPath = `${this.basePath}/find_eligible_items`;
23
+ const queryParams = buildPaginatedQueryParams(filter, limit, offset);
36
24
  try {
37
- return await this.client.get(`${this.basePath}/find_eligible_items`, params);
25
+ const response = await this.client.get(eligibleItemsPath, queryParams);
26
+ return response;
38
27
  }
39
28
  catch (error) {
40
29
  throw new Error(`Failed to find eligible items: ${error instanceof Error ? error.message : 'Unknown error'}`);
@@ -58,17 +47,14 @@ export class NegotiationApi {
58
47
  }
59
48
  /**
60
49
  * Get offers to buyers (Best Offers)
50
+ * @param filter API filter expression.
51
+ * @param limit Maximum number of records to return.
52
+ * @param offset Zero-based pagination offset.
61
53
  * @deprecated This method does not match any endpoint in the OpenAPI spec
62
54
  */
63
55
  async getOffersToBuyers(filter, limit, offset) {
64
- const params = {};
65
- if (filter)
66
- params.filter = filter;
67
- if (limit)
68
- params.limit = limit;
69
- if (offset)
70
- params.offset = offset;
71
- return await this.client.get(`${this.basePath}/offer`, params);
56
+ const params = buildTruthyPaginatedParams(filter, limit, offset);
57
+ return await getWithContextError(this.client, `${this.basePath}/offer`, params, 'Failed to get offers to buyers');
72
58
  }
73
59
  /**
74
60
  * Get offers for listing (alias for getOffersToBuyers)
@@ -76,22 +62,16 @@ export class NegotiationApi {
76
62
  * @throws Error if the request fails
77
63
  */
78
64
  async getOffersForListing(filter, limit, offset) {
79
- return this.getOffersToBuyers(filter, limit, offset);
65
+ return await this.getOffersToBuyers(filter, limit, offset);
80
66
  }
81
67
  /**
82
68
  * Get a specific offer
83
69
  * Endpoint: GET /offer/{offerId}
70
+ * @param offerId Offer identifier.
84
71
  * @throws Error if required parameters are missing or invalid
85
72
  */
86
73
  async getOffer(offerId) {
87
- if (!offerId || typeof offerId !== 'string') {
88
- throw new Error('offerId is required and must be a string');
89
- }
90
- try {
91
- return await this.client.get(`${this.basePath}/offer/${offerId}`);
92
- }
93
- catch (error) {
94
- throw new Error(`Failed to get offer: ${error instanceof Error ? error.message : 'Unknown error'}`);
95
- }
74
+ assertRequiredString(offerId, 'offerId');
75
+ return await getPathWithContextError(this.client, `${this.basePath}/offer/${offerId}`, 'Failed to get offer');
96
76
  }
97
77
  }