ebay-mcp 1.13.2 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.de.md +3 -3
  2. package/README.es.md +3 -3
  3. package/README.fr.md +3 -3
  4. package/README.ja.md +3 -3
  5. package/README.ko.md +3 -3
  6. package/README.md +163 -41
  7. package/README.pt-BR.md +3 -3
  8. package/README.ru.md +3 -3
  9. package/README.zh-CN.md +3 -3
  10. package/build/api/account-management/account.js +633 -297
  11. package/build/api/analytics-and-report/analytics.js +111 -65
  12. package/build/api/client.js +199 -140
  13. package/build/api/clientRequestError.js +23 -0
  14. package/build/api/clientTrading.js +213 -0
  15. package/build/api/clientTradingError.js +4 -0
  16. package/build/api/communication/feedback.js +147 -59
  17. package/build/api/communication/message.js +134 -81
  18. package/build/api/communication/negotiation.js +65 -53
  19. package/build/api/communication/notification.js +458 -164
  20. package/build/api/developer/developer.js +99 -45
  21. package/build/api/index.js +23 -8
  22. package/build/api/listing-management/inventory.js +884 -338
  23. package/build/api/listing-metadata/metadata.js +416 -170
  24. package/build/api/listing-metadata/taxonomy.js +187 -42
  25. package/build/api/marketing-and-promotions/marketing.js +1392 -598
  26. package/build/api/marketing-and-promotions/recommendation.js +49 -24
  27. package/build/api/order-management/dispute.js +226 -45
  28. package/build/api/order-management/fulfillment.js +144 -71
  29. package/build/api/order-management/orderIssueHelpers.js +61 -0
  30. package/build/api/other/compliance.js +50 -38
  31. package/build/api/other/edelivery.js +603 -159
  32. package/build/api/other/finding.js +280 -0
  33. package/build/api/other/identity.js +30 -15
  34. package/build/api/other/translation.js +29 -14
  35. package/build/api/other/vero.js +113 -27
  36. package/build/api/rateLimitTracker.js +55 -0
  37. package/build/api/shared/request.js +189 -98
  38. package/build/api/trading/trading.js +154 -87
  39. package/build/auth/credentialSession.js +250 -0
  40. package/build/auth/oauth.js +298 -171
  41. package/build/auth/{oauth-metadata.js → oauthMetadata.js} +22 -6
  42. package/build/auth/oauthMiddleware.js +104 -0
  43. package/build/auth/{scope-utils.js → scopeUtils.js} +101 -28
  44. package/build/auth/tokenVerifier.js +243 -0
  45. package/build/auth/tokenVerifierError.js +21 -0
  46. package/build/config/environment.js +148 -113
  47. package/build/config/{tool-families.js → toolFamilies.js} +30 -14
  48. package/build/index.js +25 -19
  49. package/build/mcp/{http-transport.js → httpTransport.js} +102 -52
  50. package/build/mcp/readOnlyFilter.js +67 -0
  51. package/build/mcp/runtime.js +31 -13
  52. package/build/mcp/{tool-gating.js → toolGating.js} +77 -49
  53. package/build/mcp/{ui-bridge.js → uiBridge.js} +80 -23
  54. package/build/schemas/account-management/account.js +144 -6
  55. package/build/schemas/analytics/analytics.js +33 -19
  56. package/build/schemas/communication/messages.js +12 -42
  57. package/build/schemas/developer/developer.js +135 -0
  58. package/build/schemas/fulfillment/orders.js +183 -21
  59. package/build/schemas/index.js +27 -19
  60. package/build/schemas/inventory-management/inventory.js +17 -9
  61. package/build/schemas/marketing/marketing.js +480 -25
  62. package/build/schemas/metadata/metadata.js +11 -6
  63. package/build/schemas/other/finding.js +27 -0
  64. package/build/schemas/other/otherApis.js +424 -0
  65. package/build/schemas/taxonomy/taxonomy.js +11 -5
  66. package/build/scripts/{auto-setup.js → autoSetup.js} +87 -74
  67. package/build/scripts/{build-ui.js → buildUi.js} +6 -1
  68. package/build/scripts/{dev-sync.js → devSync.js} +169 -110
  69. package/build/scripts/diagnostics.js +52 -44
  70. package/build/scripts/{download-specs.js → downloadSpecs.js} +29 -21
  71. package/build/scripts/{interactive-setup.js → interactiveSetup.js} +84 -78
  72. package/build/scripts/setup.js +241 -178
  73. package/build/scripts/{setup-shared.js → setupShared.js} +29 -7
  74. package/build/scripts/skills.js +35 -27
  75. package/build/scripts/updateApiStatusDoc.js +71 -0
  76. package/build/serverHttp.js +90 -0
  77. package/build/skills/content.js +124 -118
  78. package/build/skills/index.js +22 -10
  79. package/build/skills/install.js +21 -10
  80. package/build/skills/markers.js +50 -15
  81. package/build/skills/{registry-snapshot.js → registrySnapshot.js} +8 -2
  82. package/build/skills/render.js +41 -14
  83. package/build/skills/targets.js +49 -17
  84. package/build/tools/categories/account.js +166 -264
  85. package/build/tools/categories/analytics.js +11 -22
  86. package/build/tools/categories/browse.js +17 -0
  87. package/build/tools/categories/communication.js +124 -399
  88. package/build/tools/categories/connector.js +23 -20
  89. package/build/tools/categories/developer.js +46 -159
  90. package/build/tools/categories/fulfillment.js +84 -215
  91. package/build/tools/categories/index.js +6 -14
  92. package/build/tools/categories/inventory.js +238 -293
  93. package/build/tools/categories/marketing.js +677 -39
  94. package/build/tools/categories/metadata.js +190 -117
  95. package/build/tools/categories/other.js +81 -208
  96. package/build/tools/categories/taxonomy.js +29 -20
  97. package/build/tools/categories/{token-management.js → tokenManagement.js} +187 -192
  98. package/build/tools/categories/trading.js +16 -47
  99. package/build/tools/contracts.js +34 -24
  100. package/build/tools/{define-tool.js → defineTool.js} +44 -29
  101. package/build/tools/registry.js +87 -29
  102. package/build/tools/schemas.js +3 -57
  103. package/build/tools/ui/archetypes.js +1 -0
  104. package/build/tools/ui/{map-helpers.js → mapHelpers.js} +69 -19
  105. package/build/tools/ui/maps.js +294 -80
  106. package/build/types/index.js +1 -1
  107. package/build/ui/card.html +14 -14
  108. package/build/ui/chart.html +14 -14
  109. package/build/ui/stat.html +87 -0
  110. package/build/ui/table.html +14 -14
  111. package/build/utils/apiStatusFeed.js +95 -0
  112. package/build/utils/cliOutput.js +15 -0
  113. package/build/utils/cliUi.js +108 -0
  114. package/build/utils/communication/feedback.js +57 -77
  115. package/build/utils/communication/message.js +69 -98
  116. package/build/utils/communication/negotiation.js +30 -57
  117. package/build/utils/communication/notification.js +112 -252
  118. package/build/utils/{date-converter.js → dateConverter.js} +62 -30
  119. package/build/utils/effectSchema.js +203 -0
  120. package/build/utils/effectSchemaAdapter.js +121 -0
  121. package/build/utils/effectSchemaChainMethods.js +146 -0
  122. package/build/utils/effectSchemaRefinements.js +104 -0
  123. package/build/utils/effectSchemaStringMethods.js +63 -0
  124. package/build/utils/effectSchemaTypes.js +47 -0
  125. package/build/utils/{env-parser.js → envParser.js} +10 -2
  126. package/build/utils/errors.js +7 -3
  127. package/build/utils/http.js +148 -89
  128. package/build/utils/{llm-client-detector.js → llmClientDetector.js} +295 -274
  129. package/build/utils/logger.js +127 -51
  130. package/build/utils/{oauth-helper.js → oauthHelper.js} +127 -90
  131. package/build/utils/other/compliance.js +18 -38
  132. package/build/utils/other/identity.js +2 -2
  133. package/build/utils/other/translation.js +4 -4
  134. package/build/utils/other/vero.js +36 -20
  135. package/build/utils/schemaHelpers.js +22 -0
  136. package/build/utils/scopeHelper.js +270 -0
  137. package/build/utils/securityChecker.js +316 -0
  138. package/build/utils/{setup-validator.js → setupValidator.js} +113 -94
  139. package/build/utils/{setup-wizard.js → setupWizard.js} +57 -46
  140. package/build/utils/{token-utils.js → tokenUtils.js} +2 -2
  141. package/build/utils/trading/trading.js +35 -0
  142. package/build/utils/typeGuards.js +12 -0
  143. package/build/utils/version.js +65 -29
  144. package/package.json +10 -8
  145. package/build/api/client-trading.js +0 -124
  146. package/build/api/communication/shared.js +0 -59
  147. package/build/api/shared/query-params.js +0 -16
  148. package/build/auth/credential-session.js +0 -166
  149. package/build/auth/oauth-middleware.js +0 -100
  150. package/build/auth/token-verifier.js +0 -186
  151. package/build/schemas/other/other-apis.js +0 -390
  152. package/build/scripts/update-api-status-doc.js +0 -44
  153. package/build/server-http.js +0 -85
  154. package/build/tools/definitions/marketing.js +0 -1381
  155. package/build/tools/tool-handlers/marketing.js +0 -312
  156. package/build/utils/account-management/account.js +0 -818
  157. package/build/utils/api-status-feed.js +0 -84
  158. package/build/utils/cli-ui.js +0 -47
  159. package/build/utils/order-management/dispute.js +0 -369
  160. package/build/utils/order-management/fulfillment.js +0 -205
  161. package/build/utils/other/edelivery.js +0 -235
  162. package/build/utils/schema-helpers.js +0 -13
  163. package/build/utils/scope-helper.js +0 -207
  164. package/build/utils/security-checker.js +0 -248
  165. package/build/utils/type-guards.js +0 -6
  166. /package/build/auth/{oauth-types.js → oauthTypes.js} +0 -0
  167. /package/build/{server-http.d.ts → serverHttp.d.ts} +0 -0
  168. /package/build/tools/ui/{view-models.js → viewModels.js} +0 -0
  169. /package/build/types/{ebay-enums.js → ebayEnums.js} +0 -0
@@ -7,10 +7,13 @@
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
8
8
  import { join, dirname } from 'path';
9
9
  import { homedir, platform } from 'os';
10
+ import { Effect, Either } from 'effect';
11
+ import { getErrorMessage } from './errors.js';
12
+ import { setupLogger } from './logger.js';
10
13
  /**
11
- * Get the config file path for Claude Desktop based on OS
14
+ * Gets the config file path for Claude Desktop based on OS.
12
15
  */
13
- function getClaudeConfigPath() {
16
+ const getClaudeConfigPath = () => {
14
17
  const os = platform();
15
18
  const home = homedir();
16
19
  switch (os) {
@@ -23,11 +26,11 @@ function getClaudeConfigPath() {
23
26
  default:
24
27
  return join(home, '.config', 'Claude', 'claude_desktop_config.json');
25
28
  }
26
- }
29
+ };
27
30
  /**
28
- * Get the config file path for Cline (VSCode extension)
31
+ * Gets the config file path for Cline (VSCode extension).
29
32
  */
30
- function getClineConfigPath() {
33
+ const getClineConfigPath = () => {
31
34
  const home = homedir();
32
35
  const os = platform();
33
36
  switch (os) {
@@ -38,18 +41,18 @@ function getClineConfigPath() {
38
41
  default:
39
42
  return join(home, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
40
43
  }
41
- }
44
+ };
42
45
  /**
43
- * Get config path for Continue.dev
46
+ * Gets the config path for Continue.dev.
44
47
  */
45
- function getContinueConfigPath() {
48
+ const getContinueConfigPath = () => {
46
49
  const home = homedir();
47
50
  return join(home, '.continue', 'config.json');
48
- }
51
+ };
49
52
  /**
50
- * Get config path for Zed editor
53
+ * Gets the config path for Zed editor.
51
54
  */
52
- function getZedConfigPath() {
55
+ const getZedConfigPath = () => {
53
56
  const home = homedir();
54
57
  const os = platform();
55
58
  switch (os) {
@@ -60,11 +63,11 @@ function getZedConfigPath() {
60
63
  default:
61
64
  return join(home, '.config', 'zed', 'settings.json');
62
65
  }
63
- }
66
+ };
64
67
  /**
65
- * Get config path for Cursor IDE
68
+ * Gets the config path for Cursor IDE.
66
69
  */
67
- function getCursorConfigPath() {
70
+ const getCursorConfigPath = () => {
68
71
  const home = homedir();
69
72
  const os = platform();
70
73
  switch (os) {
@@ -75,11 +78,11 @@ function getCursorConfigPath() {
75
78
  default:
76
79
  return join(home, '.cursor', 'mcp.json');
77
80
  }
78
- }
81
+ };
79
82
  /**
80
- * Get config path for Windsurf (Codeium)
83
+ * Gets the config path for Windsurf (Codeium).
81
84
  */
82
- function getWindsurfConfigPath() {
85
+ const getWindsurfConfigPath = () => {
83
86
  const home = homedir();
84
87
  const os = platform();
85
88
  switch (os) {
@@ -90,11 +93,11 @@ function getWindsurfConfigPath() {
90
93
  default:
91
94
  return join(home, '.codeium', 'windsurf', 'mcp_config.json');
92
95
  }
93
- }
96
+ };
94
97
  /**
95
- * Get config path for Roo Code (VSCode extension)
98
+ * Gets the config path for Roo Code (VSCode extension).
96
99
  */
97
- function getRooCodeConfigPath() {
100
+ const getRooCodeConfigPath = () => {
98
101
  const home = homedir();
99
102
  const os = platform();
100
103
  switch (os) {
@@ -105,18 +108,18 @@ function getRooCodeConfigPath() {
105
108
  default:
106
109
  return join(home, '.config', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'settings', 'mcp_settings.json');
107
110
  }
108
- }
111
+ };
109
112
  /**
110
- * Get config path for Claude Code CLI
113
+ * Gets the config path for Claude Code CLI.
111
114
  */
112
- function getClaudeCodeConfigPath() {
115
+ const getClaudeCodeConfigPath = () => {
113
116
  const home = homedir();
114
117
  return join(home, '.claude.json');
115
- }
118
+ };
116
119
  /**
117
- * Get config path for Amazon Q Developer
120
+ * Gets the config path for Amazon Q Developer.
118
121
  */
119
- function getAmazonQConfigPath() {
122
+ const getAmazonQConfigPath = () => {
120
123
  const home = homedir();
121
124
  const os = platform();
122
125
  switch (os) {
@@ -127,11 +130,17 @@ function getAmazonQConfigPath() {
127
130
  default:
128
131
  return join(home, '.aws', 'amazonq', 'mcp.json');
129
132
  }
130
- }
133
+ };
131
134
  /**
132
- * Detect all available LLM clients
135
+ * Detects all supported LLM clients and their configuration file locations.
136
+ *
137
+ * @returns LLM clients annotated with config file and installation-directory presence.
138
+ * @example
139
+ * ```ts
140
+ * const clients = detectLLMClients();
141
+ * ```
133
142
  */
134
- export function detectLLMClients() {
143
+ export const detectLLMClients = () => {
135
144
  const clients = [
136
145
  {
137
146
  name: 'claude',
@@ -205,45 +214,73 @@ export function detectLLMClients() {
205
214
  client.detected = existsSync(parentDir);
206
215
  }
207
216
  return clients;
208
- }
217
+ };
209
218
  /**
210
- * Read and parse JSON config file safely
219
+ * Reads and parses a JSON config file safely.
211
220
  */
212
- function readJSONConfig(path) {
213
- try {
221
+ const readJSONConfig = (path) => Effect.runSync(Effect.try({
222
+ try: () => {
214
223
  if (!existsSync(path)) {
215
224
  return {};
216
225
  }
217
226
  const content = readFileSync(path, 'utf-8');
218
227
  return JSON.parse(content);
219
- }
220
- catch {
221
- return {};
222
- }
223
- }
228
+ },
229
+ catch: () => ({}),
230
+ }).pipe(Effect.catchAll((fallbackConfig) => Effect.succeed(fallbackConfig))));
224
231
  /**
225
- * Write JSON config file safely
232
+ * Writes a JSON config file safely.
226
233
  */
227
- function writeJSONConfig(path, config) {
234
+ const writeJSONConfig = (path, config) => {
228
235
  // Ensure directory exists
229
236
  const dir = dirname(path);
230
237
  if (!existsSync(dir)) {
231
238
  mkdirSync(dir, { recursive: true });
232
239
  }
233
240
  writeFileSync(path, JSON.stringify(config, null, 2), 'utf-8');
234
- }
241
+ };
242
+ const runClientConfigurator = (clientLabel, configure) => {
243
+ const configured = Effect.runSync(Effect.either(Effect.try({
244
+ try: configure,
245
+ catch: (error) => error,
246
+ })));
247
+ if (Either.isRight(configured)) {
248
+ return true;
249
+ }
250
+ setupLogger.error(`Failed to configure ${clientLabel}`, {
251
+ error: getErrorMessage(configured.left),
252
+ });
253
+ return false;
254
+ };
255
+ const ensureMcpServersConfig = (config) => {
256
+ if (!config.mcpServers || typeof config.mcpServers !== 'object') {
257
+ config.mcpServers = {};
258
+ }
259
+ return config.mcpServers;
260
+ };
261
+ const hasMcpServerConfig = (configPath) => {
262
+ if (!existsSync(configPath)) {
263
+ return false;
264
+ }
265
+ const config = readJSONConfig(configPath);
266
+ const mcpServers = config.mcpServers;
267
+ return !!mcpServers?.['ebay-mcp-server'];
268
+ };
235
269
  /**
236
- * Configure Claude Desktop with eBay MCP server
270
+ * Configures Claude Desktop with the eBay MCP server command.
271
+ *
272
+ * @param projectRoot Absolute project root containing `build/index.js`.
273
+ * @returns `true` when the client config file was updated.
274
+ * @example
275
+ * ```ts
276
+ * const configured = configureClaudeDesktop(process.cwd());
277
+ * ```
237
278
  */
238
- export function configureClaudeDesktop(projectRoot) {
239
- try {
279
+ export const configureClaudeDesktop = (projectRoot) => {
280
+ return runClientConfigurator('Claude Desktop', () => {
240
281
  const configPath = getClaudeConfigPath();
241
282
  const config = readJSONConfig(configPath);
242
- // Initialize mcpServers if it doesn't exist
243
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
244
- config.mcpServers = {};
245
- }
246
- const mcpServers = config.mcpServers;
283
+ const mcpServers = ensureMcpServersConfig(config);
247
284
  // Add or update eBay MCP server configuration
248
285
  mcpServers['ebay-mcp-server'] = {
249
286
  command: 'node',
@@ -251,25 +288,23 @@ export function configureClaudeDesktop(projectRoot) {
251
288
  };
252
289
  config.mcpServers = mcpServers;
253
290
  writeJSONConfig(configPath, config);
254
- return true;
255
- }
256
- catch (error) {
257
- console.error('Failed to configure Claude Desktop:', error);
258
- return false;
259
- }
260
- }
291
+ });
292
+ };
261
293
  /**
262
- * Configure Cline (VSCode extension) with eBay MCP server
294
+ * Configures Cline (VSCode extension) with the eBay MCP server command.
295
+ *
296
+ * @param projectRoot Absolute project root containing `build/index.js`.
297
+ * @returns `true` when the client config file was updated.
298
+ * @example
299
+ * ```ts
300
+ * const configured = configureCline(process.cwd());
301
+ * ```
263
302
  */
264
- export function configureCline(projectRoot) {
265
- try {
303
+ export const configureCline = (projectRoot) => {
304
+ return runClientConfigurator('Cline', () => {
266
305
  const configPath = getClineConfigPath();
267
306
  const config = readJSONConfig(configPath);
268
- // Initialize mcpServers if it doesn't exist
269
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
270
- config.mcpServers = {};
271
- }
272
- const mcpServers = config.mcpServers;
307
+ const mcpServers = ensureMcpServersConfig(config);
273
308
  // Add or update eBay MCP server configuration
274
309
  mcpServers['ebay-mcp-server'] = {
275
310
  command: 'node',
@@ -277,18 +312,20 @@ export function configureCline(projectRoot) {
277
312
  };
278
313
  config.mcpServers = mcpServers;
279
314
  writeJSONConfig(configPath, config);
280
- return true;
281
- }
282
- catch (error) {
283
- console.error('Failed to configure Cline:', error);
284
- return false;
285
- }
286
- }
315
+ });
316
+ };
287
317
  /**
288
- * Configure Continue.dev with eBay MCP server
318
+ * Configures Continue.dev with the eBay MCP server command.
319
+ *
320
+ * @param projectRoot Absolute project root containing `build/index.js`.
321
+ * @returns `true` when the client config file was updated.
322
+ * @example
323
+ * ```ts
324
+ * const configured = configureContinue(process.cwd());
325
+ * ```
289
326
  */
290
- export function configureContinue(projectRoot) {
291
- try {
327
+ export const configureContinue = (projectRoot) => {
328
+ return runClientConfigurator('Continue.dev', () => {
292
329
  const configPath = getContinueConfigPath();
293
330
  const config = readJSONConfig(configPath);
294
331
  // Initialize experimental.modelContextProtocolServers if it doesn't exist
@@ -296,8 +333,8 @@ export function configureContinue(projectRoot) {
296
333
  config.experimental = {};
297
334
  }
298
335
  const experimental = config.experimental;
299
- if (!experimental.modelContextProtocolServers ||
300
- !Array.isArray(experimental.modelContextProtocolServers)) {
336
+ if (!(experimental.modelContextProtocolServers &&
337
+ Array.isArray(experimental.modelContextProtocolServers))) {
301
338
  experimental.modelContextProtocolServers = [];
302
339
  }
303
340
  const mcpServers = experimental.modelContextProtocolServers;
@@ -316,19 +353,22 @@ export function configureContinue(projectRoot) {
316
353
  experimental.modelContextProtocolServers = mcpServers;
317
354
  config.experimental = experimental;
318
355
  writeJSONConfig(configPath, config);
319
- return true;
320
- }
321
- catch (error) {
322
- console.error('Failed to configure Continue.dev:', error);
323
- return false;
324
- }
325
- }
356
+ });
357
+ };
326
358
  /**
327
- * Configure Zed editor with eBay MCP server
359
+ * Configures Zed editor with the eBay MCP server command.
360
+ *
328
361
  * Zed uses context_servers in settings.json
362
+ *
363
+ * @param projectRoot Absolute project root containing `build/index.js`.
364
+ * @returns `true` when the client config file was updated.
365
+ * @example
366
+ * ```ts
367
+ * const configured = configureZed(process.cwd());
368
+ * ```
329
369
  */
330
- export function configureZed(projectRoot) {
331
- try {
370
+ export const configureZed = (projectRoot) => {
371
+ return runClientConfigurator('Zed', () => {
332
372
  const configPath = getZedConfigPath();
333
373
  const config = readJSONConfig(configPath);
334
374
  // Initialize context_servers if it doesn't exist
@@ -346,26 +386,25 @@ export function configureZed(projectRoot) {
346
386
  };
347
387
  config.context_servers = contextServers;
348
388
  writeJSONConfig(configPath, config);
349
- return true;
350
- }
351
- catch (error) {
352
- console.error('Failed to configure Zed:', error);
353
- return false;
354
- }
355
- }
389
+ });
390
+ };
356
391
  /**
357
- * Configure Cursor IDE with eBay MCP server
392
+ * Configures Cursor IDE with the eBay MCP server command.
393
+ *
358
394
  * Cursor uses mcpServers in mcp.json
395
+ *
396
+ * @param projectRoot Absolute project root containing `build/index.js`.
397
+ * @returns `true` when the client config file was updated.
398
+ * @example
399
+ * ```ts
400
+ * const configured = configureCursor(process.cwd());
401
+ * ```
359
402
  */
360
- export function configureCursor(projectRoot) {
361
- try {
403
+ export const configureCursor = (projectRoot) => {
404
+ return runClientConfigurator('Cursor', () => {
362
405
  const configPath = getCursorConfigPath();
363
406
  const config = readJSONConfig(configPath);
364
- // Initialize mcpServers if it doesn't exist
365
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
366
- config.mcpServers = {};
367
- }
368
- const mcpServers = config.mcpServers;
407
+ const mcpServers = ensureMcpServersConfig(config);
369
408
  // Add or update eBay MCP server configuration
370
409
  mcpServers['ebay-mcp-server'] = {
371
410
  command: 'node',
@@ -373,25 +412,23 @@ export function configureCursor(projectRoot) {
373
412
  };
374
413
  config.mcpServers = mcpServers;
375
414
  writeJSONConfig(configPath, config);
376
- return true;
377
- }
378
- catch (error) {
379
- console.error('Failed to configure Cursor:', error);
380
- return false;
381
- }
382
- }
415
+ });
416
+ };
383
417
  /**
384
- * Configure Windsurf (Codeium) with eBay MCP server
418
+ * Configures Windsurf (Codeium) with the eBay MCP server command.
419
+ *
420
+ * @param projectRoot Absolute project root containing `build/index.js`.
421
+ * @returns `true` when the client config file was updated.
422
+ * @example
423
+ * ```ts
424
+ * const configured = configureWindsurf(process.cwd());
425
+ * ```
385
426
  */
386
- export function configureWindsurf(projectRoot) {
387
- try {
427
+ export const configureWindsurf = (projectRoot) => {
428
+ return runClientConfigurator('Windsurf', () => {
388
429
  const configPath = getWindsurfConfigPath();
389
430
  const config = readJSONConfig(configPath);
390
- // Initialize mcpServers if it doesn't exist
391
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
392
- config.mcpServers = {};
393
- }
394
- const mcpServers = config.mcpServers;
431
+ const mcpServers = ensureMcpServersConfig(config);
395
432
  // Add or update eBay MCP server configuration
396
433
  mcpServers['ebay-mcp-server'] = {
397
434
  command: 'node',
@@ -399,25 +436,23 @@ export function configureWindsurf(projectRoot) {
399
436
  };
400
437
  config.mcpServers = mcpServers;
401
438
  writeJSONConfig(configPath, config);
402
- return true;
403
- }
404
- catch (error) {
405
- console.error('Failed to configure Windsurf:', error);
406
- return false;
407
- }
408
- }
439
+ });
440
+ };
409
441
  /**
410
- * Configure Roo Code (VSCode extension) with eBay MCP server
442
+ * Configures Roo Code (VSCode extension) with the eBay MCP server command.
443
+ *
444
+ * @param projectRoot Absolute project root containing `build/index.js`.
445
+ * @returns `true` when the client config file was updated.
446
+ * @example
447
+ * ```ts
448
+ * const configured = configureRooCode(process.cwd());
449
+ * ```
411
450
  */
412
- export function configureRooCode(projectRoot) {
413
- try {
451
+ export const configureRooCode = (projectRoot) => {
452
+ return runClientConfigurator('Roo Code', () => {
414
453
  const configPath = getRooCodeConfigPath();
415
454
  const config = readJSONConfig(configPath);
416
- // Initialize mcpServers if it doesn't exist
417
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
418
- config.mcpServers = {};
419
- }
420
- const mcpServers = config.mcpServers;
455
+ const mcpServers = ensureMcpServersConfig(config);
421
456
  // Add or update eBay MCP server configuration
422
457
  mcpServers['ebay-mcp-server'] = {
423
458
  command: 'node',
@@ -425,26 +460,25 @@ export function configureRooCode(projectRoot) {
425
460
  };
426
461
  config.mcpServers = mcpServers;
427
462
  writeJSONConfig(configPath, config);
428
- return true;
429
- }
430
- catch (error) {
431
- console.error('Failed to configure Roo Code:', error);
432
- return false;
433
- }
434
- }
463
+ });
464
+ };
435
465
  /**
436
- * Configure Claude Code CLI with eBay MCP server
466
+ * Configures Claude Code CLI with the eBay MCP server command.
467
+ *
437
468
  * Claude Code CLI uses mcpServers in ~/.claude.json
469
+ *
470
+ * @param projectRoot Absolute project root containing `build/index.js`.
471
+ * @returns `true` when the client config file was updated.
472
+ * @example
473
+ * ```ts
474
+ * const configured = configureClaudeCode(process.cwd());
475
+ * ```
438
476
  */
439
- export function configureClaudeCode(projectRoot) {
440
- try {
477
+ export const configureClaudeCode = (projectRoot) => {
478
+ return runClientConfigurator('Claude Code CLI', () => {
441
479
  const configPath = getClaudeCodeConfigPath();
442
480
  const config = readJSONConfig(configPath);
443
- // Initialize mcpServers if it doesn't exist
444
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
445
- config.mcpServers = {};
446
- }
447
- const mcpServers = config.mcpServers;
481
+ const mcpServers = ensureMcpServersConfig(config);
448
482
  // Add or update eBay MCP server configuration
449
483
  mcpServers['ebay-mcp-server'] = {
450
484
  command: 'node',
@@ -452,25 +486,23 @@ export function configureClaudeCode(projectRoot) {
452
486
  };
453
487
  config.mcpServers = mcpServers;
454
488
  writeJSONConfig(configPath, config);
455
- return true;
456
- }
457
- catch (error) {
458
- console.error('Failed to configure Claude Code CLI:', error);
459
- return false;
460
- }
461
- }
489
+ });
490
+ };
462
491
  /**
463
- * Configure Amazon Q Developer with eBay MCP server
492
+ * Configures Amazon Q Developer with the eBay MCP server command.
493
+ *
494
+ * @param projectRoot Absolute project root containing `build/index.js`.
495
+ * @returns `true` when the client config file was updated.
496
+ * @example
497
+ * ```ts
498
+ * const configured = configureAmazonQ(process.cwd());
499
+ * ```
464
500
  */
465
- export function configureAmazonQ(projectRoot) {
466
- try {
501
+ export const configureAmazonQ = (projectRoot) => {
502
+ return runClientConfigurator('Amazon Q', () => {
467
503
  const configPath = getAmazonQConfigPath();
468
504
  const config = readJSONConfig(configPath);
469
- // Initialize mcpServers if it doesn't exist
470
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
471
- config.mcpServers = {};
472
- }
473
- const mcpServers = config.mcpServers;
505
+ const mcpServers = ensureMcpServersConfig(config);
474
506
  // Add or update eBay MCP server configuration
475
507
  mcpServers['ebay-mcp-server'] = {
476
508
  command: 'node',
@@ -478,17 +510,20 @@ export function configureAmazonQ(projectRoot) {
478
510
  };
479
511
  config.mcpServers = mcpServers;
480
512
  writeJSONConfig(configPath, config);
481
- return true;
482
- }
483
- catch (error) {
484
- console.error('Failed to configure Amazon Q:', error);
485
- return false;
486
- }
487
- }
513
+ });
514
+ };
488
515
  /**
489
- * Configure specified LLM client
516
+ * Configures a supported LLM client with the eBay MCP server command.
517
+ *
518
+ * @param clientName Stable client key such as `claude`, `cursor`, or `amazonq`.
519
+ * @param projectRoot Absolute project root containing `build/index.js`.
520
+ * @returns `true` when the named client configuration was updated.
521
+ * @example
522
+ * ```ts
523
+ * const configured = configureLLMClient('cursor', process.cwd());
524
+ * ```
490
525
  */
491
- export function configureLLMClient(clientName, projectRoot) {
526
+ export const configureLLMClient = (clientName, projectRoot) => {
492
527
  switch (clientName) {
493
528
  case 'claude':
494
529
  return configureClaudeDesktop(projectRoot);
@@ -511,11 +546,19 @@ export function configureLLMClient(clientName, projectRoot) {
511
546
  default:
512
547
  return false;
513
548
  }
514
- }
549
+ };
515
550
  /**
516
- * Get human-readable instructions for manual configuration
551
+ * Gets human-readable instructions for manual client configuration.
552
+ *
553
+ * @param clientName Stable client key such as `claude`, `cursor`, or `amazonq`.
554
+ * @param projectRoot Absolute project root containing `build/index.js`.
555
+ * @returns A formatted setup snippet for the requested client.
556
+ * @example
557
+ * ```ts
558
+ * const instructions = getManualConfigInstructions('claude', process.cwd());
559
+ * ```
517
560
  */
518
- export function getManualConfigInstructions(clientName, projectRoot) {
561
+ export const getManualConfigInstructions = (clientName, projectRoot) => {
519
562
  const buildPath = join(projectRoot, 'build', 'index.js');
520
563
  switch (clientName) {
521
564
  case 'claude':
@@ -634,114 +677,92 @@ Add this to ${getAmazonQConfigPath()}:
634
677
  default:
635
678
  return 'Manual configuration instructions not available for this client.';
636
679
  }
637
- }
680
+ };
638
681
  /**
639
- * Verify client configuration is correct
682
+ * Verifies that a client has an eBay MCP server entry.
683
+ *
684
+ * @param clientName Stable client key such as `claude`, `cursor`, or `amazonq`.
685
+ * @param _projectRoot Reserved project root parameter kept for signature parity with configuration helpers.
686
+ * @returns `true` when the expected eBay MCP server entry is present.
687
+ * @example
688
+ * ```ts
689
+ * const ready = verifyClientConfiguration('cursor', process.cwd());
690
+ * ```
640
691
  */
641
- export function verifyClientConfiguration(clientName, _projectRoot) {
642
- try {
643
- switch (clientName) {
644
- case 'claude': {
645
- const configPath = getClaudeConfigPath();
646
- if (!existsSync(configPath))
647
- return false;
648
- const config = readJSONConfig(configPath);
649
- const mcpServers = config.mcpServers;
650
- return !!mcpServers?.['ebay-mcp-server'];
651
- }
652
- case 'cline': {
653
- const configPath = getClineConfigPath();
654
- if (!existsSync(configPath))
655
- return false;
656
- const config = readJSONConfig(configPath);
657
- const mcpServers = config.mcpServers;
658
- return !!mcpServers?.['ebay-mcp-server'];
659
- }
660
- case 'continue': {
661
- const configPath = getContinueConfigPath();
662
- if (!existsSync(configPath))
663
- return false;
664
- const config = readJSONConfig(configPath);
665
- const experimental = config.experimental;
666
- const mcpServers = experimental?.modelContextProtocolServers;
667
- return !!mcpServers?.some((server) => server.args?.[0]?.includes('ebay-mcp-server'));
668
- }
669
- case 'zed': {
670
- const configPath = getZedConfigPath();
671
- if (!existsSync(configPath))
692
+ export const verifyClientConfiguration = (clientName, _projectRoot) => {
693
+ const verified = Effect.runSync(Effect.either(Effect.try({
694
+ try: () => {
695
+ switch (clientName) {
696
+ case 'claude':
697
+ return hasMcpServerConfig(getClaudeConfigPath());
698
+ case 'cline':
699
+ return hasMcpServerConfig(getClineConfigPath());
700
+ case 'continue': {
701
+ const configPath = getContinueConfigPath();
702
+ if (!existsSync(configPath))
703
+ return false;
704
+ const config = readJSONConfig(configPath);
705
+ const experimental = config.experimental;
706
+ const mcpServers = experimental?.modelContextProtocolServers;
707
+ return !!mcpServers?.some((server) => server.args?.[0]?.includes('ebay-mcp-server'));
708
+ }
709
+ case 'zed': {
710
+ const configPath = getZedConfigPath();
711
+ if (!existsSync(configPath))
712
+ return false;
713
+ const config = readJSONConfig(configPath);
714
+ const contextServers = config.context_servers;
715
+ return !!contextServers?.['ebay-mcp-server'];
716
+ }
717
+ case 'cursor':
718
+ return hasMcpServerConfig(getCursorConfigPath());
719
+ case 'windsurf':
720
+ return hasMcpServerConfig(getWindsurfConfigPath());
721
+ case 'roocode':
722
+ return hasMcpServerConfig(getRooCodeConfigPath());
723
+ case 'claudecode':
724
+ return hasMcpServerConfig(getClaudeCodeConfigPath());
725
+ case 'amazonq':
726
+ return hasMcpServerConfig(getAmazonQConfigPath());
727
+ default:
672
728
  return false;
673
- const config = readJSONConfig(configPath);
674
- const contextServers = config.context_servers;
675
- return !!contextServers?.['ebay-mcp-server'];
676
729
  }
677
- case 'cursor': {
678
- const configPath = getCursorConfigPath();
679
- if (!existsSync(configPath))
680
- return false;
681
- const config = readJSONConfig(configPath);
682
- const mcpServers = config.mcpServers;
683
- return !!mcpServers?.['ebay-mcp-server'];
684
- }
685
- case 'windsurf': {
686
- const configPath = getWindsurfConfigPath();
687
- if (!existsSync(configPath))
688
- return false;
689
- const config = readJSONConfig(configPath);
690
- const mcpServers = config.mcpServers;
691
- return !!mcpServers?.['ebay-mcp-server'];
692
- }
693
- case 'roocode': {
694
- const configPath = getRooCodeConfigPath();
695
- if (!existsSync(configPath))
696
- return false;
697
- const config = readJSONConfig(configPath);
698
- const mcpServers = config.mcpServers;
699
- return !!mcpServers?.['ebay-mcp-server'];
700
- }
701
- case 'claudecode': {
702
- const configPath = getClaudeCodeConfigPath();
703
- if (!existsSync(configPath))
704
- return false;
705
- const config = readJSONConfig(configPath);
706
- const mcpServers = config.mcpServers;
707
- return !!mcpServers?.['ebay-mcp-server'];
708
- }
709
- case 'amazonq': {
710
- const configPath = getAmazonQConfigPath();
711
- if (!existsSync(configPath))
712
- return false;
713
- const config = readJSONConfig(configPath);
714
- const mcpServers = config.mcpServers;
715
- return !!mcpServers?.['ebay-mcp-server'];
716
- }
717
- default:
718
- return false;
719
- }
720
- }
721
- catch {
722
- return false;
723
- }
724
- }
730
+ },
731
+ catch: () => false,
732
+ })));
733
+ return Either.isRight(verified) ? verified.right : false;
734
+ };
725
735
  /**
726
- * Get all LLM clients (detected and undetected)
736
+ * Gets all supported LLM client keys.
737
+ *
738
+ * @returns Stable client keys accepted by setup and configuration helpers.
739
+ * @example
740
+ * ```ts
741
+ * const clientNames = getAllSupportedClients();
742
+ * ```
727
743
  */
728
- export function getAllSupportedClients() {
729
- return [
730
- 'claude',
731
- 'cline',
732
- 'continue',
733
- 'zed',
734
- 'cursor',
735
- 'windsurf',
736
- 'roocode',
737
- 'claudecode',
738
- 'amazonq',
739
- ];
740
- }
744
+ export const getAllSupportedClients = () => [
745
+ 'claude',
746
+ 'cline',
747
+ 'continue',
748
+ 'zed',
749
+ 'cursor',
750
+ 'windsurf',
751
+ 'roocode',
752
+ 'claudecode',
753
+ 'amazonq',
754
+ ];
741
755
  /**
742
- * Check if client supports MCP protocol
756
+ * Checks if a client key supports native MCP configuration.
757
+ *
758
+ * @param clientName Stable client key to test.
759
+ * @returns `true` when this setup utility can configure the named client.
760
+ * @example
761
+ * ```ts
762
+ * const supported = supportsNativeMCP('claude');
763
+ * ```
743
764
  */
744
- export function supportsNativeMCP(clientName) {
765
+ export const supportsNativeMCP = (clientName) => {
745
766
  // All these clients support MCP (Model Context Protocol)
746
767
  const supportedClients = [
747
768
  'claude',
@@ -755,4 +776,4 @@ export function supportsNativeMCP(clientName) {
755
776
  'amazonq',
756
777
  ];
757
778
  return supportedClients.includes(clientName.toLowerCase());
758
- }
779
+ };