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
@@ -1,15 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { resolve } from 'path';
3
- import { fileURLToPath } from 'url';
4
2
  import prompts from 'prompts';
5
3
  import { ALL_PROVIDERS, applyWrite, buildRegistrySnapshot, detectProvider, planWrite, providerLabel, renderSkillTargets, } from '../skills/index.js';
6
4
  import { ebayPalette, printHeading, printInfo, printRule, printSuccess, printWarning, ui, } from '../utils/cliUi.js';
7
5
  import { getErrorMessage } from '../utils/errors.js';
8
6
  import { Effect, Either } from 'effect';
9
7
  import process from 'node:process';
8
+ import { isEntryModule } from '../utils/entryModule.js';
10
9
  const ALL_LAYERS = ['using', 'contributing'];
11
10
  /** Splits a comma list flag value into trimmed, non-empty tokens. */
12
- const parseList = (value) => (value ?? '')
11
+ const parseList = (rawList) => (rawList ?? '')
13
12
  .split(',')
14
13
  .map((token) => token.trim())
15
14
  .filter(Boolean);
@@ -25,8 +24,8 @@ const readFlagValue = (argv, flag) => {
25
24
  /** Parses skills CLI flags, ignoring the leading `skills` subcommand token. */
26
25
  const parseFlags = (argv) => {
27
26
  const args = argv.filter((arg) => arg !== 'skills');
28
- const providers = parseList(readFlagValue(args, '--providers')).filter((value) => ALL_PROVIDERS.includes(value));
29
- const layers = parseList(readFlagValue(args, '--layer') ?? readFlagValue(args, '--layers')).filter((value) => ALL_LAYERS.includes(value));
27
+ const providers = parseList(readFlagValue(args, '--providers')).filter((token) => ALL_PROVIDERS.includes(token));
28
+ const layers = parseList(readFlagValue(args, '--layer') ?? readFlagValue(args, '--layers')).filter((token) => ALL_LAYERS.includes(token));
30
29
  return {
31
30
  help: args.includes('--help') || args.includes('-h'),
32
31
  yes: args.includes('--yes') || args.includes('-y'),
@@ -188,7 +187,7 @@ export const runSkillsWizard = async (options = {}) => {
188
187
  }
189
188
  }
190
189
  const rendered = renderSkillTargets({ providers, layers, scope, cwd, home, snapshot });
191
- const plans = rendered.map((item) => planWrite(item.target, item.payload));
190
+ const plans = rendered.map((renderedTarget) => planWrite(renderedTarget.target, renderedTarget.payload));
192
191
  printPreview(plans);
193
192
  if (flags.dryRun) {
194
193
  printInfo('Dry run — no files written.');
@@ -220,26 +219,24 @@ export const runSkillsWizard = async (options = {}) => {
220
219
  // targets sharing one file (both Codex layers → one AGENTS.md) compose instead
221
220
  // of the second clobbering the first.
222
221
  let written = 0;
223
- for (const item of rendered) {
224
- const plan = planWrite(item.target, item.payload);
225
- const result = applyWrite(plan, { dryRun: false, force: flags.force });
226
- if (result.written) {
222
+ for (const renderedTarget of rendered) {
223
+ const plan = planWrite(renderedTarget.target, renderedTarget.payload);
224
+ const applied = applyWrite(plan, { dryRun: false, force: flags.force });
225
+ if (applied.written) {
227
226
  written += 1;
228
- printSuccess(`${result.action} ${plan.target.path}`);
227
+ printSuccess(`${applied.action} ${plan.target.path}`);
229
228
  }
230
229
  }
231
230
  printHeading('Done');
232
231
  printInfo(`${written} file(s) written. Restart your AI tool so it picks up the new skills.`);
233
232
  };
234
- const entryPath = process.argv[1] ? resolve(process.argv[1]) : undefined;
235
- const modulePath = resolve(fileURLToPath(import.meta.url));
236
- if (entryPath && modulePath === entryPath) {
233
+ if (isEntryModule(import.meta.url)) {
237
234
  void Effect.runPromise(Effect.either(Effect.tryPromise({
238
235
  try: () => runSkillsWizard(),
239
236
  catch: (error) => error,
240
- }))).then((result) => {
241
- if (Either.isLeft(result)) {
242
- console.error(ui.error('\n Skills install failed:'), getErrorMessage(result.left));
237
+ }))).then((skillsOutcome) => {
238
+ if (Either.isLeft(skillsOutcome)) {
239
+ console.error(ui.error('\n Skills install failed:'), getErrorMessage(skillsOutcome.left));
243
240
  process.exitCode = 1;
244
241
  }
245
242
  });
@@ -48,7 +48,7 @@ export const replaceDanglingSchemaRefs = (spec) => {
48
48
  return { description: `Undefined upstream schema ${name}` };
49
49
  }
50
50
  }
51
- return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, rewrite(value)]));
51
+ return Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
52
52
  };
53
53
  const rewritten = rewrite(spec);
54
54
  return { spec: dangling.size > 0 ? rewritten : spec, danglingRefs: [...dangling] };
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Official eBay OpenAPI specs that `pnpm sync` downloads into the local spec cache.
3
+ *
4
+ * Each spec lands in `.cache/ebay-specs/<folder>/`, and its generated types land in
5
+ * `src/types/<folder>/`, so `folder` must match the existing generated-type layout.
6
+ */
7
+ /** Every spec `pnpm sync` downloads, grouped the same way as `src/types/`. */
8
+ export const specSources = [
9
+ {
10
+ api: 'Developer Analytics API',
11
+ folder: 'application-settings',
12
+ url: 'https://developer.ebay.com/api-docs/master/developer/analytics/openapi/3/developer_analytics_v1_beta_oas3.json',
13
+ },
14
+ {
15
+ api: 'Key Management API',
16
+ folder: 'application-settings',
17
+ url: 'https://developer.ebay.com/api-docs/master/developer/key-management/openapi/3/developer_key_management_v1_oas3.json',
18
+ },
19
+ {
20
+ api: 'Client Registration API',
21
+ folder: 'application-settings',
22
+ url: 'https://developer.ebay.com/api-docs/master/developer/client-registration/openapi/3/developer_client_registration_v1_oas3.json',
23
+ },
24
+ {
25
+ api: 'Inventory API',
26
+ folder: 'sell-apps/listing-management',
27
+ url: 'https://developer.ebay.com/api-docs/master/sell/inventory/openapi/3/sell_inventory_v1_oas3.json',
28
+ },
29
+ {
30
+ api: 'Feed API',
31
+ folder: 'sell-apps/listing-management',
32
+ url: 'https://developer.ebay.com/api-docs/master/sell/feed/openapi/3/sell_feed_v1_oas3.json',
33
+ },
34
+ {
35
+ api: 'Media API',
36
+ folder: 'sell-apps/listing-management',
37
+ url: 'https://developer.ebay.com/api-docs/master/commerce/media/openapi/3/commerce_media_v1_beta_oas3.json',
38
+ },
39
+ {
40
+ api: 'Stores API',
41
+ folder: 'sell-apps/listing-management',
42
+ url: 'https://developer.ebay.com/api-docs/master/sell/stores/openapi/3/sell_stores_v1_oas3.json',
43
+ },
44
+ {
45
+ api: 'Metadata API',
46
+ folder: 'sell-apps/listing-metadata',
47
+ url: 'https://developer.ebay.com/api-docs/master/sell/metadata/openapi/3/sell_metadata_v1_oas3.json',
48
+ },
49
+ {
50
+ api: 'Taxonomy API',
51
+ folder: 'sell-apps/listing-metadata',
52
+ url: 'https://developer.ebay.com/api-docs/master/commerce/taxonomy/openapi/3/commerce_taxonomy_v1_oas3.json',
53
+ },
54
+ {
55
+ api: 'Charity API',
56
+ folder: 'sell-apps/listing-metadata',
57
+ url: 'https://developer.ebay.com/api-docs/master/commerce/charity/openapi/3/commerce_charity_v1_oas3.json',
58
+ },
59
+ {
60
+ api: 'Account API (v1)',
61
+ folder: 'sell-apps/account-management',
62
+ url: 'https://developer.ebay.com/api-docs/master/sell/account/openapi/3/sell_account_v1_oas3.json',
63
+ },
64
+ {
65
+ api: 'Account API (v2)',
66
+ folder: 'sell-apps/account-management',
67
+ url: 'https://developer.ebay.com/api-docs/master/sell/account/v2/openapi/3/sell_account_v2_oas3.json',
68
+ },
69
+ {
70
+ api: 'Finances API',
71
+ folder: 'sell-apps/account-management',
72
+ url: 'https://developer.ebay.com/api-docs/master/sell/finances/openapi/3/sell_finances_v1_oas3.json',
73
+ },
74
+ {
75
+ api: 'Message API',
76
+ folder: 'sell-apps/communication',
77
+ url: 'https://developer.ebay.com/api-docs/master/commerce/message/openapi/3/commerce_message_v1_oas3.json',
78
+ },
79
+ {
80
+ api: 'Notification API',
81
+ folder: 'sell-apps/communication',
82
+ url: 'https://developer.ebay.com/api-docs/master/commerce/notification/openapi/3/commerce_notification_v1_oas3.json',
83
+ },
84
+ {
85
+ api: 'Negotiation API',
86
+ folder: 'sell-apps/communication',
87
+ url: 'https://developer.ebay.com/api-docs/master/sell/negotiation/openapi/3/sell_negotiation_v1_oas3.json',
88
+ },
89
+ {
90
+ api: 'Feedback API',
91
+ folder: 'sell-apps/communication',
92
+ url: 'https://developer.ebay.com/api-docs/master/commerce/feedback/openapi/3/commerce_feedback_v1_beta_oas3.json',
93
+ },
94
+ {
95
+ api: 'Fulfillment API',
96
+ folder: 'sell-apps/order-management',
97
+ url: 'https://developer.ebay.com/api-docs/master/sell/fulfillment/openapi/3/sell_fulfillment_v1_oas3.json',
98
+ },
99
+ {
100
+ api: 'Logistics API',
101
+ folder: 'sell-apps/order-management',
102
+ url: 'https://developer.ebay.com/api-docs/master/sell/logistics/openapi/3/sell_logistics_v1_oas3.json',
103
+ },
104
+ {
105
+ api: 'Marketing API',
106
+ folder: 'sell-apps/marketing-and-promotions',
107
+ url: 'https://developer.ebay.com/api-docs/master/sell/marketing/openapi/3/sell_marketing_v1_oas3.json',
108
+ },
109
+ {
110
+ api: 'Recommendation API',
111
+ folder: 'sell-apps/marketing-and-promotions',
112
+ url: 'https://developer.ebay.com/api-docs/master/sell/recommendation/openapi/3/sell_recommendation_v1_oas3.json',
113
+ },
114
+ {
115
+ api: 'Analytics API',
116
+ folder: 'sell-apps/analytics-and-report',
117
+ url: 'https://developer.ebay.com/api-docs/master/sell/analytics/openapi/3/sell_analytics_v1_oas3.json',
118
+ },
119
+ {
120
+ api: 'Translation API',
121
+ folder: 'sell-apps/other-apis',
122
+ url: 'https://developer.ebay.com/api-docs/master/commerce/translation/openapi/3/commerce_translation_v1_beta_oas3.json',
123
+ },
124
+ {
125
+ api: 'Compliance API',
126
+ folder: 'sell-apps/other-apis',
127
+ url: 'https://developer.ebay.com/api-docs/master/sell/compliance/openapi/3/sell_compliance_v1_oas3.json',
128
+ },
129
+ {
130
+ api: 'Identity API',
131
+ folder: 'sell-apps/other-apis',
132
+ url: 'https://developer.ebay.com/api-docs/master/commerce/identity/openapi/3/commerce_identity_v1_oas3.json',
133
+ },
134
+ {
135
+ api: 'eDelivery International Shipping API',
136
+ folder: 'sell-apps/other-apis',
137
+ url: 'https://developer.ebay.com/api-docs/master/sell/edelivery_international_shipping/openapi/3/sell_edelivery_international_shipping_oas3.json',
138
+ },
139
+ {
140
+ api: 'Vero API',
141
+ folder: 'sell-apps/other-apis',
142
+ url: 'https://developer.ebay.com/api-docs/master/commerce/vero/openapi/3/commerce_vero_v1_oas3.json',
143
+ },
144
+ ];
@@ -1,19 +1,18 @@
1
1
  /**
2
2
  * eBay API MCP Server with HTTP Transport and OAuth 2.1 Authorization.
3
3
  */
4
- import { resolve } from 'path';
5
- import { fileURLToPath } from 'url';
6
4
  import { validateEnvironmentConfig } from './config/environment.js';
7
5
  import { createHttpMcpApp, createHttpTransportConfigFromEnv, getHttpServerUrl, } from './mcp/httpTransport.js';
8
6
  import { getErrorMessage } from './utils/errors.js';
9
7
  import { serverLogger } from './utils/logger.js';
10
8
  import { Effect, Either } from 'effect';
11
9
  import process from 'node:process';
10
+ import { isEntryModule } from './utils/entryModule.js';
12
11
  const CONFIG = createHttpTransportConfigFromEnv(process.env);
13
12
  function logEnvironmentValidation() {
14
13
  const validation = validateEnvironmentConfig();
15
- validation.infos.forEach((info) => {
16
- serverLogger.info(info);
14
+ validation.infos.forEach((notice) => {
15
+ serverLogger.info(notice);
17
16
  });
18
17
  if (validation.warnings.length > 0) {
19
18
  serverLogger.warn('Environment Configuration Warnings:');
@@ -83,8 +82,6 @@ async function main() {
83
82
  process.exit(1);
84
83
  }
85
84
  }
86
- const entryPath = process.argv[1] ? resolve(process.argv[1]) : undefined;
87
- const modulePath = resolve(fileURLToPath(import.meta.url));
88
- if (entryPath && modulePath === entryPath) {
85
+ if (isEntryModule(import.meta.url)) {
89
86
  await main();
90
87
  }
@@ -87,8 +87,8 @@ export const buildUsingDoc = (snapshot) => ({
87
87
  });
88
88
  /**
89
89
  * Builds the "contributing" skill: how an AI working on the ebay-mcp repo should
90
- * operate. Mirrors AGENTS.md (validation commands, module map, the add-a-tool
91
- * flow, conventions) against the real `src/tools/categories/` layout.
90
+ * operate: validation commands, module map, the add-a-tool flow, and
91
+ * conventions, against the real `src/tools/categories/` layout.
92
92
  *
93
93
  * @param snapshot Live tool count and family index.
94
94
  * @returns The provider-neutral skill document.
@@ -101,16 +101,16 @@ export const buildUsingDoc = (snapshot) => ({
101
101
  export const buildContributingDoc = (snapshot) => ({
102
102
  slug: 'ebay-mcp-contributing',
103
103
  title: 'Contributing to ebay-mcp',
104
- description: `Work on the ebay-mcp server itself: ${snapshot.toolCount} tools across eBay's Sell APIs (TypeScript/ESM, Effect-backed validation, OpenAPI-generated types). Use when adding or changing eBay tools/endpoints, wiring the registry, or running the project's checks.`,
105
- intro: `A local MCP server exposing **${snapshot.toolCount} tools across 100% of eBay's Sell APIs** — TypeScript/Node.js (ESM), \`@modelcontextprotocol/sdk\`, Effect-backed validation, OpenAPI-generated types. Entry points: \`src/index.ts\` (STDIO) and \`src/serverHttp.ts\` (HTTP).`,
104
+ description: `Work on the ebay-mcp server itself: ${snapshot.toolCount} tools across eBay's Sell APIs (TypeScript/ESM, Zod tool-input schemas, OpenAPI-generated types). Use when adding or changing eBay tools/endpoints, wiring the registry, or running the project's checks.`,
105
+ intro: `A local MCP server exposing **${snapshot.toolCount} tools across 100% of eBay's Sell APIs** — TypeScript/Node.js (ESM), \`@modelcontextprotocol/sdk\`, Zod tool-input schemas, Effect for typed async errors, OpenAPI-generated types. Entry points: \`src/index.ts\` (STDIO) and \`src/serverHttp.ts\` (HTTP).`,
106
106
  sections: [
107
107
  {
108
108
  heading: 'Validation (run before a PR)',
109
109
  body: [
110
110
  '```bash',
111
- 'npm run check # tsc --noEmit + eslint + prettier --check (must pass)',
112
- 'npm test # vitest run',
113
- 'npm run build # tsc + tsc-alias → build/',
111
+ 'pnpm check # tsc --noEmit (src + mcp-apps) + biome check (must pass)',
112
+ 'pnpm test # vitest run',
113
+ 'pnpm build # tsc + tsc-alias + MCP Apps views → build/',
114
114
  '```',
115
115
  ].join('\n'),
116
116
  },
@@ -120,12 +120,12 @@ export const buildContributingDoc = (snapshot) => ({
120
120
  '| Path | Owns |',
121
121
  '| --- | --- |',
122
122
  '| `index.ts` / `serverHttp.ts` | MCP entry points (STDIO / HTTP) |',
123
- '| `api/` | eBay API client implementations (one area per file) |',
123
+ '| `api/` | eBay API modules (one area per folder), `client/` (REST and Trading XML clients), and the `ebaySellerApi.ts` facade |',
124
124
  '| `auth/` | OAuth 2.0 flow and token management |',
125
125
  '| `config/` | Environment loading, constants, marketplace defaults |',
126
126
  '| `tools/` | Tool wiring — `registry.ts`, `contracts.ts`, `defineTool.ts`, and `categories/` (13 family files that co-locate each tool definition with its handler via `defineTool`) |',
127
127
  "| `skills/` | Agent-skills generator (this skill's source) |",
128
- '| `schemas/` | Shared Effect-backed schemas |',
128
+ '| `schemas/` | Shared Zod schemas per API family |',
129
129
  "| `types/` | TypeScript types — **auto-generated** from OpenAPI specs (don't hand-edit) |",
130
130
  '| `scripts/` | CLI tooling: `setup.ts`, `skills.ts`, `devSync.ts`, `diagnostics.ts` |',
131
131
  '| `utils/` | Shared utilities (logging, http, errors) |',
@@ -134,19 +134,19 @@ export const buildContributingDoc = (snapshot) => ({
134
134
  {
135
135
  heading: 'Add a tool or endpoint',
136
136
  body: [
137
- '1. `npm run sync` — download the latest eBay specs, regenerate types, report missing endpoints.',
137
+ '1. `pnpm sync` — download the latest eBay specs, regenerate types, report missing endpoints.',
138
138
  '2. Add the API method in `src/api/`.',
139
139
  '3. Add a `defineTool({ ... handler })` entry in the matching `src/tools/categories/<family>.ts` — definition and handler live together; `registry.ts` derives everything from `categories/index.ts`.',
140
140
  '4. Add tests in `tests/`.',
141
- '5. `npm run check && npm test`.',
141
+ '5. `pnpm check && pnpm test`.',
142
142
  ].join('\n'),
143
143
  },
144
144
  {
145
145
  heading: 'Conventions',
146
146
  body: [
147
147
  '- **No `any`** — specific types; prefer narrowing over assertions. `types/` is generated, so model new shapes from the specs.',
148
- '- Validate tool inputs with Effect-backed schemas from `@/utils/effectSchema.js`; derive related schemas rather than duplicating fields.',
149
- '- Commit with Conventional Commits (releases are changeset-driven).',
148
+ "- Validate tool inputs with Zod schemas (`import { z } from 'zod'`); derive related schemas rather than duplicating fields.",
149
+ '- Commit with Conventional Commits; merged PR labels (`major`/`minor`, else patch) pick the release bump.',
150
150
  '- Logs go to **stderr** only — stdout is reserved for the MCP protocol.',
151
151
  ].join('\n'),
152
152
  },
@@ -30,20 +30,20 @@ const mergeManagedBlock = (existing, layer, inner) => {
30
30
  * always preserved (never `skip-foreign`).
31
31
  *
32
32
  * @param target Resolved destination.
33
- * @param payload Rendered content — a full file for owned targets, inner block
33
+ * @param renderedContent Rendered content — a full file for owned targets, inner block
34
34
  * content for managed targets.
35
35
  * @returns The planned action and the exact bytes that would be written.
36
36
  *
37
37
  * @example
38
38
  * ```ts
39
- * const plan = planWrite(target, payload);
39
+ * const plan = planWrite(target, renderedContent);
40
40
  * ```
41
41
  */
42
- export const planWrite = (target, payload) => {
42
+ export const planWrite = (target, renderedContent) => {
43
43
  const exists = existsSync(target.path);
44
44
  const previousContents = exists ? readFileSync(target.path, 'utf-8') : undefined;
45
45
  if (target.kind === 'managed-block') {
46
- const nextContents = mergeManagedBlock(previousContents ?? '', target.layer, payload);
46
+ const nextContents = mergeManagedBlock(previousContents ?? '', target.layer, renderedContent);
47
47
  let action = 'create';
48
48
  if (exists) {
49
49
  action = nextContents === previousContents ? 'unchanged' : 'update';
@@ -52,13 +52,13 @@ export const planWrite = (target, payload) => {
52
52
  }
53
53
  // owned-file
54
54
  if (!exists) {
55
- return { target, action: 'create', nextContents: payload };
55
+ return { target, action: 'create', nextContents: renderedContent };
56
56
  }
57
57
  if (!isOwnedByUs(previousContents ?? '', target.layer)) {
58
- return { target, action: 'skip-foreign', nextContents: payload, previousContents };
58
+ return { target, action: 'skip-foreign', nextContents: renderedContent, previousContents };
59
59
  }
60
- const action = previousContents === payload ? 'unchanged' : 'update';
61
- return { target, action, nextContents: payload, previousContents };
60
+ const action = previousContents === renderedContent ? 'unchanged' : 'update';
61
+ return { target, action, nextContents: renderedContent, previousContents };
62
62
  };
63
63
  /**
64
64
  * Applies a write plan. Skips no-op writes (`unchanged`) and refuses to clobber
@@ -71,7 +71,7 @@ export const planWrite = (target, payload) => {
71
71
  *
72
72
  * @example
73
73
  * ```ts
74
- * const result = applyWrite(plan, { dryRun: true });
74
+ * const writeOutcome = applyWrite(plan, { dryRun: true });
75
75
  * ```
76
76
  */
77
77
  export const applyWrite = (plan, options = {}) => {
@@ -14,7 +14,7 @@ const renderBody = (doc, baseLevel) => {
14
14
  return parts.join('\n');
15
15
  };
16
16
  /** YAML frontmatter scalar that is safe for arbitrary text (JSON strings are valid YAML). */
17
- const yamlString = (value) => JSON.stringify(value);
17
+ const yamlString = (text) => JSON.stringify(text);
18
18
  /**
19
19
  * Renders a Claude Code skill file (`SKILL.md`): YAML frontmatter (`name`,
20
20
  * `description`) so the model can invoke it on demand, an ownership marker, then
@@ -87,7 +87,7 @@ export const renderCodexSection = (doc) => renderBody(doc, 2);
87
87
  *
88
88
  * @example
89
89
  * ```ts
90
- * const payload = renderSkill('codex', doc, 'using');
90
+ * const skillContent = renderSkill('codex', doc, 'using');
91
91
  * ```
92
92
  */
93
93
  export const renderSkill = (provider, doc, layer) => {
@@ -7,7 +7,7 @@ import { createDestinationSchema, createSubscriptionFilterSchema, createSubscrip
7
7
  /**
8
8
  * Communication API tools for member messages, notifications, and seller feedback.
9
9
  *
10
- * Each tool derives its transport schema from the same Effect-backed object whose inferred
10
+ * Each tool derives its transport schema from the same Zod object whose inferred
11
11
  * args are passed directly to the endpoint method. Handlers stay at the MCP
12
12
  * boundary: they run one endpoint Effect and avoid response or input reshaping.
13
13
  */
@@ -1,4 +1,4 @@
1
- import { z } from '../../utils/effectSchema.js';
1
+ import { z } from 'zod';
2
2
  import { Effect } from 'effect';
3
3
  import { defineTool } from '../../tools/defineTool.js';
4
4
  const connectorSearchInputSchema = z.object({
@@ -46,19 +46,22 @@ export const connectorEntries = [
46
46
  const matches = [];
47
47
  let offset = 0;
48
48
  while (matches.length < limit) {
49
- const response = yield* api.inventory.getInventoryItems({ limit: pageSize, offset });
50
- const pageItems = response.inventoryItems ?? [];
49
+ const inventoryPage = yield* api.inventory.getInventoryItems({
50
+ limit: pageSize,
51
+ offset,
52
+ });
53
+ const pageItems = inventoryPage.inventoryItems ?? [];
51
54
  if (pageItems.length === 0) {
52
55
  break;
53
56
  }
54
57
  // Only items with valid SKUs can be passed to getInventoryItem later.
55
- const itemsWithSku = pageItems.filter((item) => typeof item.sku === 'string' && item.sku.trim() !== '');
58
+ const itemsWithSku = pageItems.filter((inventoryItem) => typeof inventoryItem.sku === 'string' && inventoryItem.sku.trim() !== '');
56
59
  const filtered = query
57
- ? itemsWithSku.filter((item) => (item.product?.title ?? '').toLowerCase().includes(query))
60
+ ? itemsWithSku.filter((inventoryItem) => (inventoryItem.product?.title ?? '').toLowerCase().includes(query))
58
61
  : itemsWithSku;
59
62
  matches.push(...filtered);
60
63
  offset += pageSize;
61
- const total = response.total;
64
+ const total = inventoryPage.total;
62
65
  if (typeof total === 'number' && offset >= total) {
63
66
  break;
64
67
  }
@@ -66,9 +69,9 @@ export const connectorEntries = [
66
69
  break;
67
70
  }
68
71
  }
69
- const results = matches.slice(0, limit).map((item) => ({
70
- id: item.sku,
71
- title: item.product?.title ?? '',
72
+ const results = matches.slice(0, limit).map((match) => ({
73
+ id: match.sku,
74
+ title: match.product?.title ?? '',
72
75
  url: 'https://www.ebay.com/', // Placeholder: eBay does not expose a canonical item URL here.
73
76
  }));
74
77
  // The ChatGPT connector spec requires a single text content block.
@@ -104,23 +107,23 @@ export const connectorEntries = [
104
107
  },
105
108
  handler: (api, args) => Effect.runPromise(Effect.gen(function* () {
106
109
  const sku = args.id;
107
- const item = yield* api.inventory.getInventoryItem({ sku });
108
- const result = {
110
+ const inventoryItem = yield* api.inventory.getInventoryItem({ sku });
111
+ const connectorDocument = {
109
112
  id: sku,
110
- title: item.product?.title ?? '',
111
- text: item.product?.description ?? '',
113
+ title: inventoryItem.product?.title ?? '',
114
+ text: inventoryItem.product?.description ?? '',
112
115
  url: 'https://www.ebay.com/', // Placeholder: eBay does not expose a canonical item URL here.
113
116
  metadata: {
114
117
  source: 'ebay_inventory',
115
- aspects: item.product?.aspects,
116
- condition: item.condition,
118
+ aspects: inventoryItem.product?.aspects,
119
+ condition: inventoryItem.condition,
117
120
  },
118
121
  };
119
122
  return {
120
123
  content: [
121
124
  {
122
125
  type: 'text',
123
- text: JSON.stringify(result),
126
+ text: JSON.stringify(connectorDocument),
124
127
  },
125
128
  ],
126
129
  };
@@ -81,8 +81,8 @@ export const fulfillmentEntries = [
81
81
  filter: args.filter,
82
82
  limit: args.maxResults ?? DEFAULT_ORDER_SCAN_LIMIT,
83
83
  })
84
- .pipe(Effect.map((result) => {
85
- const orders = result.orders ?? [];
84
+ .pipe(Effect.map((orderPage) => {
85
+ const orders = orderPage.orders ?? [];
86
86
  const matches = filterOrdersWithCancellationRequests(orders);
87
87
  return {
88
88
  totalScanned: orders.length,
@@ -101,8 +101,8 @@ export const fulfillmentEntries = [
101
101
  filter: args.filter,
102
102
  limit: args.maxResults ?? DEFAULT_ORDER_SCAN_LIMIT,
103
103
  })
104
- .pipe(Effect.map((result) => {
105
- const orders = result.orders ?? [];
104
+ .pipe(Effect.map((orderPage) => {
105
+ const orders = orderPage.orders ?? [];
106
106
  const matches = filterRefundedOrders(orders);
107
107
  return {
108
108
  totalScanned: orders.length,
@@ -1,5 +1,5 @@
1
1
  import { Effect } from 'effect';
2
- import { z } from '../../utils/effectSchema.js';
2
+ import { z } from 'zod';
3
3
  import { zodToJsonSchema } from 'zod-to-json-schema';
4
4
  import { defineTool } from '../../tools/defineTool.js';
5
5
  import { mapInventoryItemsToTable, mapInventoryItemToCard, mapLocationsToTable, mapOffersToTable, mapOfferToCard, } from '../../tools/ui/maps.js';
@@ -1,4 +1,4 @@
1
- import { z } from '../../utils/effectSchema.js';
1
+ import { z } from 'zod';
2
2
  import { MarketplaceId } from '../../types/ebayEnums.js';
3
3
  import { shippingMetadataInputSchema } from '../../schemas/metadata/shipping.js';
4
4
  import { defineTool } from '../../tools/defineTool.js';
@@ -1,4 +1,4 @@
1
- import { z } from '../../utils/effectSchema.js';
1
+ import { z } from 'zod';
2
2
  import { categoryTreeIdInputSchema } from '../../schemas/taxonomy/categoryTree.js';
3
3
  import { defineTool } from '../../tools/defineTool.js';
4
4
  import { formatFileResult } from '../../tools/fileResult.js';
@@ -1,4 +1,4 @@
1
- import { z } from '../../utils/effectSchema.js';
1
+ import { z } from 'zod';
2
2
  import { buildCredentialDisplay, maskToken } from '../../auth/credentialSession.js';
3
3
  import { getOAuthAuthorizationUrl, validateScopes } from '../../config/environment.js';
4
4
  import { defineTool } from '../../tools/defineTool.js';
@@ -14,11 +14,11 @@ const tokenToolError = (operation, message, error) => new TokenManagementToolErr
14
14
  ...(error === undefined ? {} : { cause: error }),
15
15
  });
16
16
  /** Convert an optional token expiry value into a timestamp inside the token tool Effect. */
17
- const optionalTokenExpiryTimestamp = (value, operation, message) => {
18
- if (value === undefined) {
17
+ const optionalTokenExpiryTimestamp = (expiry, operation, message) => {
18
+ if (expiry === undefined) {
19
19
  return Effect.succeed(undefined);
20
20
  }
21
- return convertToTimestamp(value).pipe(Effect.mapError((error) => tokenToolError(operation, message, error)));
21
+ return convertToTimestamp(expiry).pipe(Effect.mapError((error) => tokenToolError(operation, message, error)));
22
22
  };
23
23
  const missingClientIdError = tokenToolError('getOAuthUrl', 'EBAY_CLIENT_ID environment variable is required to generate OAuth URL');
24
24
  const missingRedirectUriError = tokenToolError('getOAuthUrl', 'Redirect URI is required. Either provide it as a parameter or set EBAY_REDIRECT_URI in your .env file.');
@@ -121,7 +121,7 @@ export const tokenManagementEntries = [
121
121
  ? validateScopes(scopes, config.environment)
122
122
  : { warnings: [], validScopes: scopes };
123
123
  const authUrl = getOAuthAuthorizationUrl(config.clientId, redirectUri, config.environment, scopeValidation.validScopes, args.state);
124
- const result = {
124
+ const authorizationDetails = {
125
125
  authorizationUrl: authUrl,
126
126
  redirectUri,
127
127
  instructions: 'Open this URL in a browser to authorize the application. After authorization, you will be redirected to your redirect URI with an authorization code that can be exchanged for an access token.',
@@ -129,9 +129,9 @@ export const tokenManagementEntries = [
129
129
  scopes: scopes ?? 'default (all Sell API scopes)',
130
130
  };
131
131
  if (scopeValidation.warnings.length > 0) {
132
- result.warnings = scopeValidation.warnings;
132
+ authorizationDetails.warnings = scopeValidation.warnings;
133
133
  }
134
- return result;
134
+ return authorizationDetails;
135
135
  })),
136
136
  }),
137
137
  defineTool({
@@ -324,7 +324,7 @@ export const tokenManagementEntries = [
324
324
  'COMMON ERRORS:\n' +
325
325
  '- "invalid or was issued to another client": Code expired, get fresh code\n' +
326
326
  '- "Insufficient permissions": Re-run OAuth flow with additional scopes in ebay_get_oauth_url\n\n' +
327
- 'For complete OAuth guide with scopes, troubleshooting, and examples, see: docs/auth/OAUTH_QUICK_REFERENCE.md',
327
+ 'For scopes and rate limits, see the "Authentication & rate limits" section of the ebay-mcp README.',
328
328
  inputSchema: exchangeAuthorizationCodeInputSchema.shape,
329
329
  outputSchema: {
330
330
  type: 'object',
@@ -1,5 +1,5 @@
1
1
  import { getToolEntries } from '../tools/registry.js';
2
- import { isEffectBackedSchema } from '../utils/effectSchema.js';
2
+ import { z } from 'zod';
3
3
  const isJsonObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
4
4
  /**
5
5
  * Builds public tool contracts from the validated tool registry entries.
@@ -47,7 +47,7 @@ export const validateToolContracts = (contracts = getToolContracts()) => {
47
47
  }
48
48
  else {
49
49
  for (const [fieldName, schema] of Object.entries(contract.inputSchema)) {
50
- if (!isEffectBackedSchema(schema)) {
50
+ if (!(schema instanceof z.ZodType)) {
51
51
  invalidInputSchemaFields.push(`${contract.name}.${fieldName}`);
52
52
  }
53
53
  }