ebay-mcp 1.7.1 → 1.7.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.
- package/README.md +2 -0
- package/build/api/client.js +19 -8
- package/build/api/listing-management/inventory.js +7 -35
- package/build/config/environment.js +23 -37
- package/build/scripts/auto-setup.js +6 -0
- package/build/scripts/diagnostics.js +2 -0
- package/build/scripts/interactive-setup.js +6 -0
- package/build/scripts/setup.js +241 -33
- package/build/tools/definitions/token-management.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -223,6 +223,8 @@ EBAY_CLIENT_ID=your_client_id
|
|
|
223
223
|
EBAY_CLIENT_SECRET=your_client_secret
|
|
224
224
|
EBAY_ENVIRONMENT=sandbox # or "production"
|
|
225
225
|
EBAY_REDIRECT_URI=your_runame
|
|
226
|
+
EBAY_MARKETPLACE_ID=EBAY_US # Default marketplace (overridable by many tools)
|
|
227
|
+
EBAY_CONTENT_LANGUAGE=en-US # Default request content language (global)
|
|
226
228
|
EBAY_USER_REFRESH_TOKEN=your_refresh_token # For higher rate limits
|
|
227
229
|
```
|
|
228
230
|
|
package/build/api/client.js
CHANGED
|
@@ -37,6 +37,22 @@ export class EbayApiClient {
|
|
|
37
37
|
baseUrl;
|
|
38
38
|
rateLimitTracker;
|
|
39
39
|
config;
|
|
40
|
+
/**
|
|
41
|
+
* Build default request headers based on configured marketplace and language.
|
|
42
|
+
*/
|
|
43
|
+
getDefaultHeaders() {
|
|
44
|
+
const headers = {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
Accept: 'application/json',
|
|
47
|
+
};
|
|
48
|
+
if (this.config.contentLanguage) {
|
|
49
|
+
headers['Content-Language'] = this.config.contentLanguage;
|
|
50
|
+
}
|
|
51
|
+
if (this.config.marketplaceId) {
|
|
52
|
+
headers['X-EBAY-C-MARKETPLACE-ID'] = this.config.marketplaceId;
|
|
53
|
+
}
|
|
54
|
+
return headers;
|
|
55
|
+
}
|
|
40
56
|
constructor(config) {
|
|
41
57
|
this.config = config;
|
|
42
58
|
this.authClient = new EbayOAuthClient(config);
|
|
@@ -45,10 +61,7 @@ export class EbayApiClient {
|
|
|
45
61
|
this.httpClient = axios.create({
|
|
46
62
|
baseURL: this.baseUrl,
|
|
47
63
|
timeout: 30000,
|
|
48
|
-
headers:
|
|
49
|
-
'Content-Type': 'application/json',
|
|
50
|
-
Accept: 'application/json',
|
|
51
|
-
},
|
|
64
|
+
headers: this.getDefaultHeaders(),
|
|
52
65
|
});
|
|
53
66
|
// Add request interceptor to inject auth token and check rate limits
|
|
54
67
|
this.httpClient.interceptors.request.use(async (config) => {
|
|
@@ -283,8 +296,7 @@ export class EbayApiClient {
|
|
|
283
296
|
params,
|
|
284
297
|
headers: {
|
|
285
298
|
Authorization: `Bearer ${token}`,
|
|
286
|
-
|
|
287
|
-
Accept: 'application/json',
|
|
299
|
+
...this.getDefaultHeaders(),
|
|
288
300
|
},
|
|
289
301
|
timeout: 30000,
|
|
290
302
|
});
|
|
@@ -305,8 +317,7 @@ export class EbayApiClient {
|
|
|
305
317
|
params,
|
|
306
318
|
headers: {
|
|
307
319
|
Authorization: `Bearer ${token}`,
|
|
308
|
-
|
|
309
|
-
Accept: 'application/json',
|
|
320
|
+
...this.getDefaultHeaders(),
|
|
310
321
|
},
|
|
311
322
|
timeout: 30000,
|
|
312
323
|
});
|
|
@@ -60,11 +60,7 @@ export class InventoryApi {
|
|
|
60
60
|
throw new Error('inventoryItem is required and must be an object');
|
|
61
61
|
}
|
|
62
62
|
try {
|
|
63
|
-
return await this.client.put(`${this.basePath}/inventory_item/${sku}`, inventoryItem
|
|
64
|
-
headers: {
|
|
65
|
-
'Content-Language': 'en-US',
|
|
66
|
-
},
|
|
67
|
-
});
|
|
63
|
+
return await this.client.put(`${this.basePath}/inventory_item/${sku}`, inventoryItem);
|
|
68
64
|
}
|
|
69
65
|
catch (error) {
|
|
70
66
|
throw new Error(`Failed to create or replace inventory item: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -95,11 +91,7 @@ export class InventoryApi {
|
|
|
95
91
|
throw new Error('requests is required and must be an object');
|
|
96
92
|
}
|
|
97
93
|
try {
|
|
98
|
-
return await this.client.post(`${this.basePath}/bulk_create_or_replace_inventory_item`, requests
|
|
99
|
-
headers: {
|
|
100
|
-
'Content-Language': 'en-US',
|
|
101
|
-
},
|
|
102
|
-
});
|
|
94
|
+
return await this.client.post(`${this.basePath}/bulk_create_or_replace_inventory_item`, requests);
|
|
103
95
|
}
|
|
104
96
|
catch (error) {
|
|
105
97
|
throw new Error(`Failed to bulk create or replace inventory items: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -166,11 +158,7 @@ export class InventoryApi {
|
|
|
166
158
|
throw new Error('compatibility is required and must be an object');
|
|
167
159
|
}
|
|
168
160
|
try {
|
|
169
|
-
return await this.client.put(`${this.basePath}/inventory_item/${sku}/product_compatibility`, compatibility
|
|
170
|
-
headers: {
|
|
171
|
-
'Content-Language': 'en-US',
|
|
172
|
-
},
|
|
173
|
-
});
|
|
161
|
+
return await this.client.put(`${this.basePath}/inventory_item/${sku}/product_compatibility`, compatibility);
|
|
174
162
|
}
|
|
175
163
|
catch (error) {
|
|
176
164
|
throw new Error(`Failed to create or replace product compatibility: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -221,11 +209,7 @@ export class InventoryApi {
|
|
|
221
209
|
throw new Error('inventoryItemGroup is required and must be an object');
|
|
222
210
|
}
|
|
223
211
|
try {
|
|
224
|
-
return await this.client.put(`${this.basePath}/inventory_item_group/${inventoryItemGroupKey}`, inventoryItemGroup
|
|
225
|
-
headers: {
|
|
226
|
-
'Content-Language': 'en-US',
|
|
227
|
-
},
|
|
228
|
-
});
|
|
212
|
+
return await this.client.put(`${this.basePath}/inventory_item_group/${inventoryItemGroupKey}`, inventoryItemGroup);
|
|
229
213
|
}
|
|
230
214
|
catch (error) {
|
|
231
215
|
throw new Error(`Failed to create or replace inventory item group: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -431,11 +415,7 @@ export class InventoryApi {
|
|
|
431
415
|
throw new Error('offer is required and must be an object');
|
|
432
416
|
}
|
|
433
417
|
try {
|
|
434
|
-
return await this.client.post(`${this.basePath}/offer`, offer
|
|
435
|
-
headers: {
|
|
436
|
-
'Content-Language': 'en-US',
|
|
437
|
-
},
|
|
438
|
-
});
|
|
418
|
+
return await this.client.post(`${this.basePath}/offer`, offer);
|
|
439
419
|
}
|
|
440
420
|
catch (error) {
|
|
441
421
|
throw new Error(`Failed to create offer: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -454,11 +434,7 @@ export class InventoryApi {
|
|
|
454
434
|
throw new Error('offer is required and must be an object');
|
|
455
435
|
}
|
|
456
436
|
try {
|
|
457
|
-
return await this.client.put(`${this.basePath}/offer/${offerId}`, offer
|
|
458
|
-
headers: {
|
|
459
|
-
'Content-Language': 'en-US',
|
|
460
|
-
},
|
|
461
|
-
});
|
|
437
|
+
return await this.client.put(`${this.basePath}/offer/${offerId}`, offer);
|
|
462
438
|
}
|
|
463
439
|
catch (error) {
|
|
464
440
|
throw new Error(`Failed to update offer: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -521,11 +497,7 @@ export class InventoryApi {
|
|
|
521
497
|
throw new Error('requests is required and must be an object');
|
|
522
498
|
}
|
|
523
499
|
try {
|
|
524
|
-
return await this.client.post(`${this.basePath}/bulk_create_offer`, requests
|
|
525
|
-
headers: {
|
|
526
|
-
'Content-Language': 'en-US',
|
|
527
|
-
},
|
|
528
|
-
});
|
|
500
|
+
return await this.client.post(`${this.basePath}/bulk_create_offer`, requests);
|
|
529
501
|
}
|
|
530
502
|
catch (error) {
|
|
531
503
|
throw new Error(`Failed to bulk create offers: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -62,13 +62,7 @@ export function getDefaultScopes(environment) {
|
|
|
62
62
|
if (environment === 'production') {
|
|
63
63
|
return getProductionScopes();
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
const productionScopes = getProductionScopes();
|
|
67
|
-
const productionWithoutEdelivery = productionScopes.filter((scope) => scope !== 'https://api.ebay.com/oauth/scope/sell.edelivery');
|
|
68
|
-
const mergedScopes = new Set([...sandboxScopes, ...productionWithoutEdelivery]);
|
|
69
|
-
mergedScopes.add('https://api.ebay.com/oauth/api_scope/sell.edelivery');
|
|
70
|
-
mergedScopes.add('https://api.ebay.com/oauth/scope/sell.edelivery');
|
|
71
|
-
return Array.from(mergedScopes);
|
|
65
|
+
return getSandboxScopes();
|
|
72
66
|
}
|
|
73
67
|
/**
|
|
74
68
|
* Validate scopes against environment and return warnings for invalid scopes
|
|
@@ -144,6 +138,9 @@ export function validateEnvironmentConfig() {
|
|
|
144
138
|
errors,
|
|
145
139
|
};
|
|
146
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Build EbayConfig from environment variables with safe defaults.
|
|
143
|
+
*/
|
|
147
144
|
export function getEbayConfig() {
|
|
148
145
|
const clientId = process.env.EBAY_CLIENT_ID ?? '';
|
|
149
146
|
const clientSecret = process.env.EBAY_CLIENT_SECRET ?? '';
|
|
@@ -151,6 +148,8 @@ export function getEbayConfig() {
|
|
|
151
148
|
const accessToken = process.env.EBAY_USER_ACCESS_TOKEN ?? '';
|
|
152
149
|
const refreshToken = process.env.EBAY_USER_REFRESH_TOKEN ?? '';
|
|
153
150
|
const appAccessToken = process.env.EBAY_APP_ACCESS_TOKEN ?? '';
|
|
151
|
+
const marketplaceId = (process.env.EBAY_MARKETPLACE_ID ?? '').trim() || 'EBAY_US';
|
|
152
|
+
const contentLanguage = (process.env.EBAY_CONTENT_LANGUAGE ?? '').trim() || 'en-US';
|
|
154
153
|
// Only require client credentials - tokens can be optional (generated from refresh token)
|
|
155
154
|
if (clientId === '' || clientSecret === '') {
|
|
156
155
|
console.error('Missing required eBay credentials. Please set:\n1) EBAY_CLIENT_ID\n2) EBAY_CLIENT_SECRET\nin your .env file at project root');
|
|
@@ -159,6 +158,8 @@ export function getEbayConfig() {
|
|
|
159
158
|
clientId,
|
|
160
159
|
clientSecret,
|
|
161
160
|
redirectUri: process.env.EBAY_REDIRECT_URI,
|
|
161
|
+
marketplaceId,
|
|
162
|
+
contentLanguage,
|
|
162
163
|
environment,
|
|
163
164
|
accessToken,
|
|
164
165
|
refreshToken,
|
|
@@ -188,21 +189,17 @@ export function getAuthUrl(clientIdOrEnvironment, redirectUri, environment, loca
|
|
|
188
189
|
console.error('clientId, redirectUri (RuName), and scope are required,please initialize the class properly.');
|
|
189
190
|
return '';
|
|
190
191
|
}
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
const
|
|
192
|
+
const authBase = env === 'production' ? 'https://auth.ebay.com' : 'https://auth.sandbox.ebay.com';
|
|
193
|
+
const scopeList = scopes?.join('%20') || scope.join('%20');
|
|
194
|
+
const authorizeParams = new URLSearchParams({
|
|
194
195
|
client_id: clientId,
|
|
195
196
|
redirect_uri: redirectUri,
|
|
196
197
|
response_type: responseType,
|
|
197
|
-
scope: scopes?.join(' ') || scope.join(' '),
|
|
198
198
|
prompt,
|
|
199
199
|
locale,
|
|
200
200
|
...(state ? { state } : {}),
|
|
201
201
|
});
|
|
202
|
-
|
|
203
|
-
// Build signin URL that redirects to consent
|
|
204
|
-
const signinDomain = env === 'production' ? 'https://signin.ebay.com' : 'https://signin.sandbox.ebay.com';
|
|
205
|
-
return `${signinDomain}/signin?ru=${encodeURIComponent(consentUrl)}&sgfl=oauth2&AppName=${encodeURIComponent(clientId)}`;
|
|
202
|
+
return `${authBase}/oauth2/authorize?${authorizeParams.toString()}&scope=${scopeList}`;
|
|
206
203
|
}
|
|
207
204
|
/**
|
|
208
205
|
* Generate the OAuth authorization URL for user consent
|
|
@@ -213,33 +210,22 @@ export function getAuthUrl(clientIdOrEnvironment, redirectUri, environment, loca
|
|
|
213
210
|
*/
|
|
214
211
|
export function getOAuthAuthorizationUrl(clientId, redirectUri, // MUST be eBay RuName, NOT a URL
|
|
215
212
|
environment, scopes, locale, state) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const authorizeEndpoint = `${authDomain}/oauth2/authorize`;
|
|
219
|
-
// Build query parameters for the authorize endpoint
|
|
220
|
-
const params = new URLSearchParams({
|
|
221
|
-
client_id: clientId,
|
|
222
|
-
redirect_uri: redirectUri,
|
|
223
|
-
});
|
|
224
|
-
// Add scopes only if provided (optional - eBay handles automatically if not specified)
|
|
213
|
+
const authBase = environment === 'production' ? 'https://auth.ebay.com' : 'https://auth.sandbox.ebay.com';
|
|
214
|
+
let scopeList;
|
|
225
215
|
if (scopes && scopes.length > 0) {
|
|
226
|
-
|
|
216
|
+
scopeList = scopes.join('%20');
|
|
227
217
|
}
|
|
228
218
|
else {
|
|
229
|
-
// Use default scopes for the environment if no scopes are specified
|
|
230
219
|
const defaultScopes = getDefaultScopes(environment);
|
|
231
|
-
|
|
220
|
+
scopeList = defaultScopes.join('%20');
|
|
232
221
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const signinDomain = environment === 'production' ? 'https://signin.ebay.com' : 'https://signin.sandbox.ebay.com';
|
|
241
|
-
const ruParam = encodeURIComponent(`${authorizeEndpoint}?${params.toString()}`);
|
|
242
|
-
return `${signinDomain}/signin?ru=${ruParam}&sgfl=oauth2_login&AppName=${clientId}`;
|
|
222
|
+
const params = new URLSearchParams({
|
|
223
|
+
client_id: clientId,
|
|
224
|
+
redirect_uri: redirectUri,
|
|
225
|
+
response_type: 'code',
|
|
226
|
+
...(state ? { state } : {}),
|
|
227
|
+
});
|
|
228
|
+
return `${authBase}/oauth2/authorize?${params.toString()}&scope=${scopeList}`;
|
|
243
229
|
}
|
|
244
230
|
const iconUrl = (size) => {
|
|
245
231
|
const url = new URL(`../../public/icons/${size}.png`, import.meta.url);
|
|
@@ -135,6 +135,12 @@ function generateMCPServerConfig() {
|
|
|
135
135
|
if (process.env.EBAY_REDIRECT_URI) {
|
|
136
136
|
config.env.EBAY_REDIRECT_URI = process.env.EBAY_REDIRECT_URI;
|
|
137
137
|
}
|
|
138
|
+
if (process.env.EBAY_MARKETPLACE_ID) {
|
|
139
|
+
config.env.EBAY_MARKETPLACE_ID = process.env.EBAY_MARKETPLACE_ID;
|
|
140
|
+
}
|
|
141
|
+
if (process.env.EBAY_CONTENT_LANGUAGE) {
|
|
142
|
+
config.env.EBAY_CONTENT_LANGUAGE = process.env.EBAY_CONTENT_LANGUAGE;
|
|
143
|
+
}
|
|
138
144
|
if (process.env.EBAY_USER_ACCESS_TOKEN) {
|
|
139
145
|
config.env.EBAY_USER_ACCESS_TOKEN = process.env.EBAY_USER_ACCESS_TOKEN;
|
|
140
146
|
}
|
|
@@ -118,6 +118,8 @@ function displayConfigurationStatus(envVars) {
|
|
|
118
118
|
{ key: 'EBAY_CLIENT_SECRET', label: 'Client Secret', redact: true },
|
|
119
119
|
{ key: 'EBAY_REDIRECT_URI', label: 'Redirect URI', redact: false },
|
|
120
120
|
{ key: 'EBAY_ENVIRONMENT', label: 'Environment', redact: false },
|
|
121
|
+
{ key: 'EBAY_MARKETPLACE_ID', label: 'Marketplace ID', redact: false },
|
|
122
|
+
{ key: 'EBAY_CONTENT_LANGUAGE', label: 'Content Language', redact: false },
|
|
121
123
|
{ key: 'EBAY_USER_REFRESH_TOKEN', label: 'User Refresh Token', redact: true },
|
|
122
124
|
{ key: 'EBAY_USER_ACCESS_TOKEN', label: 'User Access Token', redact: true },
|
|
123
125
|
{ key: 'EBAY_APP_ACCESS_TOKEN', label: 'App Access Token', redact: true },
|
|
@@ -143,6 +143,10 @@ EBAY_REDIRECT_URI=${config.EBAY_REDIRECT_URI || 'http://localhost:3000/oauth/cal
|
|
|
143
143
|
# ═══════════════════════════════════════════════════════════════════
|
|
144
144
|
|
|
145
145
|
EBAY_ENVIRONMENT=${config.EBAY_ENVIRONMENT || 'sandbox'}
|
|
146
|
+
# Optional: e.g. EBAY_US, EBAY_DE, EBAY_FR
|
|
147
|
+
EBAY_MARKETPLACE_ID=${config.EBAY_MARKETPLACE_ID || ''}
|
|
148
|
+
# Optional: e.g. en-US, de-DE, fr-FR
|
|
149
|
+
EBAY_CONTENT_LANGUAGE=${config.EBAY_CONTENT_LANGUAGE || ''}
|
|
146
150
|
|
|
147
151
|
# ═══════════════════════════════════════════════════════════════════
|
|
148
152
|
# User Tokens (Auto-generated from refresh token)
|
|
@@ -667,6 +671,8 @@ async function runInteractiveSetup(args) {
|
|
|
667
671
|
EBAY_CLIENT_SECRET: credentials.EBAY_CLIENT_SECRET,
|
|
668
672
|
EBAY_REDIRECT_URI: credentials.EBAY_REDIRECT_URI,
|
|
669
673
|
EBAY_ENVIRONMENT: environment,
|
|
674
|
+
EBAY_MARKETPLACE_ID: existingConfig.EBAY_MARKETPLACE_ID || '',
|
|
675
|
+
EBAY_CONTENT_LANGUAGE: existingConfig.EBAY_CONTENT_LANGUAGE || '',
|
|
670
676
|
EBAY_USER_REFRESH_TOKEN: refreshToken,
|
|
671
677
|
EBAY_USER_ACCESS_TOKEN: '',
|
|
672
678
|
EBAY_APP_ACCESS_TOKEN: '',
|
package/build/scripts/setup.js
CHANGED
|
@@ -4,18 +4,18 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
|
4
4
|
import { homedir, platform } from 'os';
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
import { checkForUpdates } from '../utils/version.js';
|
|
7
8
|
import { config } from 'dotenv';
|
|
8
9
|
import { exec } from 'child_process';
|
|
9
10
|
import { fileURLToPath } from 'url';
|
|
11
|
+
import { getOAuthAuthorizationUrl } from '../config/environment.js';
|
|
10
12
|
import prompts from 'prompts';
|
|
11
|
-
import { getDefaultScopes } from '../config/environment.js';
|
|
12
|
-
import { checkForUpdates } from '../utils/version.js';
|
|
13
13
|
config({ quiet: true });
|
|
14
14
|
checkForUpdates();
|
|
15
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
16
|
const __dirname = dirname(__filename);
|
|
17
17
|
const PROJECT_ROOT = join(__dirname, '../..');
|
|
18
|
-
const TOTAL_STEPS =
|
|
18
|
+
const TOTAL_STEPS = 6;
|
|
19
19
|
const ebay = {
|
|
20
20
|
red: chalk.hex('#E53238'),
|
|
21
21
|
blue: chalk.hex('#0064D2'),
|
|
@@ -31,6 +31,26 @@ const ui = {
|
|
|
31
31
|
info: chalk.cyan,
|
|
32
32
|
hint: chalk.gray,
|
|
33
33
|
};
|
|
34
|
+
const MARKETPLACE_OPTIONS = [
|
|
35
|
+
{ value: 'EBAY_US', label: 'EBAY_US — United States' },
|
|
36
|
+
{ value: 'EBAY_GB', label: 'EBAY_GB — United Kingdom' },
|
|
37
|
+
{ value: 'EBAY_DE', label: 'EBAY_DE — Germany' },
|
|
38
|
+
{ value: 'EBAY_FR', label: 'EBAY_FR — France' },
|
|
39
|
+
{ value: 'EBAY_IT', label: 'EBAY_IT — Italy' },
|
|
40
|
+
{ value: 'EBAY_ES', label: 'EBAY_ES — Spain' },
|
|
41
|
+
{ value: 'EBAY_CA', label: 'EBAY_CA — Canada' },
|
|
42
|
+
{ value: 'EBAY_AU', label: 'EBAY_AU — Australia' },
|
|
43
|
+
];
|
|
44
|
+
const CONTENT_LANGUAGE_OPTIONS = [
|
|
45
|
+
{ value: 'en-US', label: 'en-US — English (United States)' },
|
|
46
|
+
{ value: 'en-GB', label: 'en-GB — English (United Kingdom)' },
|
|
47
|
+
{ value: 'de-DE', label: 'de-DE — German (Germany)' },
|
|
48
|
+
{ value: 'fr-FR', label: 'fr-FR — French (France)' },
|
|
49
|
+
{ value: 'it-IT', label: 'it-IT — Italian (Italy)' },
|
|
50
|
+
{ value: 'es-ES', label: 'es-ES — Spanish (Spain)' },
|
|
51
|
+
{ value: 'fr-CA', label: 'fr-CA — French (Canada)' },
|
|
52
|
+
{ value: 'nl-BE', label: 'nl-BE — Dutch (Belgium)' },
|
|
53
|
+
];
|
|
34
54
|
const LOGO = `
|
|
35
55
|
${ebay.red('███████╗')}${ebay.blue('██████╗ ')}${ebay.yellow('█████╗ ')}${ebay.green('██╗ ██╗')}
|
|
36
56
|
${ebay.red('██╔════╝')}${ebay.blue('██╔══██╗')}${ebay.yellow('██╔══██╗')}${ebay.green('╚██╗ ██╔╝')}
|
|
@@ -39,13 +59,22 @@ const LOGO = `
|
|
|
39
59
|
${ebay.red('███████╗')}${ebay.blue('██████╔╝')}${ebay.yellow('██║ ██║')}${ebay.green(' ██║ ')}
|
|
40
60
|
${ebay.red('╚══════╝')}${ebay.blue('╚═════╝ ')}${ebay.yellow('╚═╝ ╚═╝')}${ebay.green(' ╚═╝ ')}
|
|
41
61
|
`;
|
|
62
|
+
/**
|
|
63
|
+
* Clear the terminal screen.
|
|
64
|
+
*/
|
|
42
65
|
function clearScreen() {
|
|
43
66
|
console.clear();
|
|
44
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Render the eBay ASCII logo and heading.
|
|
70
|
+
*/
|
|
45
71
|
function showLogo() {
|
|
46
72
|
console.log(LOGO);
|
|
47
|
-
console.log(ui.bold.white(' MCP Server Setup Wizard\n'));
|
|
73
|
+
console.log(ui.bold.white(' MCP Server Setup Wizard by Yosef Hayim Sabag\n'));
|
|
48
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Render a step progress bar with title.
|
|
77
|
+
*/
|
|
49
78
|
function showProgress(step, title) {
|
|
50
79
|
const filled = '●'.repeat(step);
|
|
51
80
|
const empty = '○'.repeat(TOTAL_STEPS - step);
|
|
@@ -54,21 +83,33 @@ function showProgress(step, title) {
|
|
|
54
83
|
console.log(` ${progress} ${ui.bold(`Step ${step}/${TOTAL_STEPS}`)}: ${title}`);
|
|
55
84
|
console.log(ui.dim('─'.repeat(60)) + '\n');
|
|
56
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Render keyboard hints for the current step.
|
|
88
|
+
*/
|
|
57
89
|
function showKeyboardHints(hints) {
|
|
58
90
|
const hintText = hints.map((h) => ui.dim(h)).join(' │ ');
|
|
59
91
|
console.log(`\n ${hintText}\n`);
|
|
60
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Render a tip callout.
|
|
95
|
+
*/
|
|
61
96
|
function showTip(message) {
|
|
62
97
|
console.log(` ${ebay.yellow('💡 Tip:')} ${ui.dim(message)}\n`);
|
|
63
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Render a success line.
|
|
101
|
+
*/
|
|
64
102
|
function showSuccess(message) {
|
|
65
103
|
console.log(` ${ui.success('✓')} ${message}`);
|
|
66
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Render an error line.
|
|
107
|
+
*/
|
|
67
108
|
function showError(message) {
|
|
68
109
|
console.log(` ${ui.error('✗')} ${message}`);
|
|
69
110
|
}
|
|
70
111
|
/**
|
|
71
|
-
* Open a URL in the default browser (cross-platform)
|
|
112
|
+
* Open a URL in the default browser (cross-platform).
|
|
72
113
|
*/
|
|
73
114
|
function openBrowser(url) {
|
|
74
115
|
return new Promise((resolve, reject) => {
|
|
@@ -94,6 +135,9 @@ function openBrowser(url) {
|
|
|
94
135
|
});
|
|
95
136
|
});
|
|
96
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Render a warning line.
|
|
140
|
+
*/
|
|
97
141
|
function showWarning(message) {
|
|
98
142
|
console.log(` ${ui.warning('⚠')} ${message}`);
|
|
99
143
|
}
|
|
@@ -260,9 +304,15 @@ function displayUserInfo(userInfo) {
|
|
|
260
304
|
`User ID: ${userInfo.userId?.slice(0, 30)}...`,
|
|
261
305
|
]);
|
|
262
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Render an informational line.
|
|
309
|
+
*/
|
|
263
310
|
function showInfo(message) {
|
|
264
311
|
console.log(` ${ui.info('ℹ')} ${message}`);
|
|
265
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Render a spinner and return a stop callback.
|
|
315
|
+
*/
|
|
266
316
|
function showSpinner(message) {
|
|
267
317
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
268
318
|
let i = 0;
|
|
@@ -276,6 +326,9 @@ function showSpinner(message) {
|
|
|
276
326
|
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r');
|
|
277
327
|
};
|
|
278
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Render a bordered info box.
|
|
331
|
+
*/
|
|
279
332
|
function showBox(title, content) {
|
|
280
333
|
const width = 60;
|
|
281
334
|
const line = '─'.repeat(width - 2);
|
|
@@ -288,6 +341,9 @@ function showBox(title, content) {
|
|
|
288
341
|
}
|
|
289
342
|
console.log(` ${ui.dim('└' + line + '┘')}\n`);
|
|
290
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Compute MCP client config paths by OS.
|
|
346
|
+
*/
|
|
291
347
|
function getConfigPaths() {
|
|
292
348
|
const home = homedir();
|
|
293
349
|
const os = platform();
|
|
@@ -328,6 +384,9 @@ function getConfigPaths() {
|
|
|
328
384
|
};
|
|
329
385
|
return paths;
|
|
330
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Detect installed MCP-compatible clients.
|
|
389
|
+
*/
|
|
331
390
|
function detectLLMClients() {
|
|
332
391
|
const paths = getConfigPaths();
|
|
333
392
|
const clients = [];
|
|
@@ -344,6 +403,9 @@ function detectLLMClients() {
|
|
|
344
403
|
}
|
|
345
404
|
return clients;
|
|
346
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Write MCP server config for a detected client.
|
|
408
|
+
*/
|
|
347
409
|
function configureLLMClient(client, projectRoot) {
|
|
348
410
|
try {
|
|
349
411
|
const configDir = dirname(client.configPath);
|
|
@@ -462,6 +524,12 @@ function updateClaudeDesktopConfig(envConfig, environment) {
|
|
|
462
524
|
if (envConfig.EBAY_REDIRECT_URI) {
|
|
463
525
|
envVars.EBAY_REDIRECT_URI = envConfig.EBAY_REDIRECT_URI;
|
|
464
526
|
}
|
|
527
|
+
if (envConfig.EBAY_MARKETPLACE_ID) {
|
|
528
|
+
envVars.EBAY_MARKETPLACE_ID = envConfig.EBAY_MARKETPLACE_ID;
|
|
529
|
+
}
|
|
530
|
+
if (envConfig.EBAY_CONTENT_LANGUAGE) {
|
|
531
|
+
envVars.EBAY_CONTENT_LANGUAGE = envConfig.EBAY_CONTENT_LANGUAGE;
|
|
532
|
+
}
|
|
465
533
|
if (envConfig.EBAY_USER_REFRESH_TOKEN) {
|
|
466
534
|
envVars.EBAY_USER_REFRESH_TOKEN = envConfig.EBAY_USER_REFRESH_TOKEN;
|
|
467
535
|
}
|
|
@@ -504,6 +572,9 @@ function updateClaudeDesktopConfig(envConfig, environment) {
|
|
|
504
572
|
};
|
|
505
573
|
}
|
|
506
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Load existing environment variables from the .env file.
|
|
577
|
+
*/
|
|
507
578
|
function loadExistingConfig() {
|
|
508
579
|
const envPath = join(PROJECT_ROOT, '.env');
|
|
509
580
|
const envConfig = {};
|
|
@@ -521,6 +592,9 @@ function loadExistingConfig() {
|
|
|
521
592
|
}
|
|
522
593
|
return envConfig;
|
|
523
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Format a date for display in the .env header.
|
|
597
|
+
*/
|
|
524
598
|
function formatDate(date) {
|
|
525
599
|
const options = {
|
|
526
600
|
weekday: 'long',
|
|
@@ -534,9 +608,18 @@ function formatDate(date) {
|
|
|
534
608
|
};
|
|
535
609
|
return date.toLocaleString('en-US', options);
|
|
536
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* Persist setup configuration to the project .env file.
|
|
613
|
+
*/
|
|
537
614
|
function saveConfig(envConfig, environment) {
|
|
538
615
|
const envPath = join(PROJECT_ROOT, '.env');
|
|
539
616
|
const now = new Date();
|
|
617
|
+
const marketplaceLine = envConfig.EBAY_MARKETPLACE_ID
|
|
618
|
+
? `EBAY_MARKETPLACE_ID=${envConfig.EBAY_MARKETPLACE_ID}`
|
|
619
|
+
: '# EBAY_MARKETPLACE_ID=EBAY_US';
|
|
620
|
+
const contentLanguageLine = envConfig.EBAY_CONTENT_LANGUAGE
|
|
621
|
+
? `EBAY_CONTENT_LANGUAGE=${envConfig.EBAY_CONTENT_LANGUAGE}`
|
|
622
|
+
: '# EBAY_CONTENT_LANGUAGE=en-US';
|
|
540
623
|
const content = `# eBay MCP Server Configuration
|
|
541
624
|
# Last Updated: ${formatDate(now)}
|
|
542
625
|
# Environment: ${environment}
|
|
@@ -545,6 +628,8 @@ EBAY_CLIENT_ID=${envConfig.EBAY_CLIENT_ID || ''}
|
|
|
545
628
|
EBAY_CLIENT_SECRET=${envConfig.EBAY_CLIENT_SECRET || ''}
|
|
546
629
|
EBAY_REDIRECT_URI=${envConfig.EBAY_REDIRECT_URI || ''}
|
|
547
630
|
EBAY_ENVIRONMENT=${environment}
|
|
631
|
+
${marketplaceLine}
|
|
632
|
+
${contentLanguageLine}
|
|
548
633
|
|
|
549
634
|
EBAY_USER_REFRESH_TOKEN=${envConfig.EBAY_USER_REFRESH_TOKEN || ''}
|
|
550
635
|
EBAY_USER_ACCESS_TOKEN=${envConfig.EBAY_USER_ACCESS_TOKEN || ''}
|
|
@@ -557,10 +642,12 @@ async function stepWelcome(state) {
|
|
|
557
642
|
showLogo();
|
|
558
643
|
console.log(ui.dim(' Welcome to the eBay MCP Server setup wizard!\n'));
|
|
559
644
|
console.log(' This wizard will help you:\n');
|
|
560
|
-
console.log(` ${ui.success('1.')}
|
|
561
|
-
console.log(` ${ui.success('2.')} Set
|
|
562
|
-
console.log(` ${ui.success('3.')} Configure your
|
|
563
|
-
console.log(` ${ui.success('4.')}
|
|
645
|
+
console.log(` ${ui.success('1.')} Choose environment (sandbox/production)`);
|
|
646
|
+
console.log(` ${ui.success('2.')} Set default marketplace and language (optional)`);
|
|
647
|
+
console.log(` ${ui.success('3.')} Configure your eBay Developer credentials`);
|
|
648
|
+
console.log(` ${ui.success('4.')} Set up OAuth authentication`);
|
|
649
|
+
console.log(` ${ui.success('5.')} Configure your MCP client (Claude, Cline, etc.)`);
|
|
650
|
+
console.log(` ${ui.success('6.')} Validate your setup\n`);
|
|
564
651
|
if (state.hasExistingConfig) {
|
|
565
652
|
showInfo('Existing configuration detected. You can update or keep current values.');
|
|
566
653
|
}
|
|
@@ -573,6 +660,9 @@ async function stepWelcome(state) {
|
|
|
573
660
|
});
|
|
574
661
|
return response.continue !== false ? 'continue' : 'cancel';
|
|
575
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Select the eBay environment for this configuration.
|
|
665
|
+
*/
|
|
576
666
|
async function stepEnvironment(state) {
|
|
577
667
|
clearScreen();
|
|
578
668
|
showLogo();
|
|
@@ -609,10 +699,128 @@ async function stepEnvironment(state) {
|
|
|
609
699
|
state.config.EBAY_ENVIRONMENT = response.environment;
|
|
610
700
|
return 'continue';
|
|
611
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Configure optional marketplace and content-language defaults.
|
|
704
|
+
*/
|
|
705
|
+
async function stepMarketplaceSettings(state) {
|
|
706
|
+
clearScreen();
|
|
707
|
+
showLogo();
|
|
708
|
+
showProgress(2, 'Marketplace Settings');
|
|
709
|
+
if (state.isQuickMode) {
|
|
710
|
+
showInfo('Quick setup enabled. Skipping optional marketplace configuration.');
|
|
711
|
+
await new Promise((r) => setTimeout(r, 600));
|
|
712
|
+
return 'continue';
|
|
713
|
+
}
|
|
714
|
+
console.log(' Configure default marketplace and language for API requests.\n');
|
|
715
|
+
showBox('Marketplace Settings', [
|
|
716
|
+
'These are optional defaults used for request headers.',
|
|
717
|
+
'Marketplace can be overridden in many tools; language is global.',
|
|
718
|
+
]);
|
|
719
|
+
const marketplaceChoices = [
|
|
720
|
+
{ title: ui.dim('← Go back'), value: '__back__' },
|
|
721
|
+
{ title: 'Skip (leave unset)', value: '' },
|
|
722
|
+
...MARKETPLACE_OPTIONS.map((option) => ({
|
|
723
|
+
title: option.label,
|
|
724
|
+
value: option.value,
|
|
725
|
+
})),
|
|
726
|
+
{ title: 'Other (enter manually)', value: '__custom__' },
|
|
727
|
+
];
|
|
728
|
+
const currentMarketplace = state.config.EBAY_MARKETPLACE_ID || '';
|
|
729
|
+
const marketplaceDefault = currentMarketplace || 'EBAY_US';
|
|
730
|
+
const marketplaceMatchIndex = marketplaceChoices.findIndex((choice) => choice.value === marketplaceDefault);
|
|
731
|
+
const marketplaceInitial = marketplaceMatchIndex >= 0
|
|
732
|
+
? marketplaceMatchIndex
|
|
733
|
+
: marketplaceChoices.findIndex((choice) => choice.value === '__custom__');
|
|
734
|
+
const marketplaceResponse = await prompts({
|
|
735
|
+
type: 'select',
|
|
736
|
+
name: 'marketplaceId',
|
|
737
|
+
message: 'Select your default eBay marketplace:',
|
|
738
|
+
choices: marketplaceChoices,
|
|
739
|
+
initial: marketplaceInitial >= 0 ? marketplaceInitial : 0,
|
|
740
|
+
});
|
|
741
|
+
if (marketplaceResponse.marketplaceId === undefined) {
|
|
742
|
+
return 'cancel';
|
|
743
|
+
}
|
|
744
|
+
if (marketplaceResponse.marketplaceId === '__back__') {
|
|
745
|
+
return 'back';
|
|
746
|
+
}
|
|
747
|
+
let marketplaceId = marketplaceResponse.marketplaceId;
|
|
748
|
+
if (marketplaceId === '__custom__') {
|
|
749
|
+
const customMarketplace = await prompts({
|
|
750
|
+
type: 'text',
|
|
751
|
+
name: 'customMarketplaceId',
|
|
752
|
+
message: 'Enter marketplace ID (e.g., EBAY_US, EBAY_DE):',
|
|
753
|
+
initial: currentMarketplace || 'EBAY_US',
|
|
754
|
+
validate: (value) => value.trim().length === 0 ? 'Marketplace ID cannot be empty' : true,
|
|
755
|
+
});
|
|
756
|
+
if (customMarketplace.customMarketplaceId === undefined) {
|
|
757
|
+
return 'cancel';
|
|
758
|
+
}
|
|
759
|
+
marketplaceId = customMarketplace.customMarketplaceId.trim();
|
|
760
|
+
}
|
|
761
|
+
if (marketplaceId) {
|
|
762
|
+
state.config.EBAY_MARKETPLACE_ID = marketplaceId;
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
delete state.config.EBAY_MARKETPLACE_ID;
|
|
766
|
+
}
|
|
767
|
+
const languageChoices = [
|
|
768
|
+
{ title: ui.dim('← Go back'), value: '__back__' },
|
|
769
|
+
{ title: 'Skip (leave unset)', value: '' },
|
|
770
|
+
...CONTENT_LANGUAGE_OPTIONS.map((option) => ({
|
|
771
|
+
title: option.label,
|
|
772
|
+
value: option.value,
|
|
773
|
+
})),
|
|
774
|
+
{ title: 'Other (enter manually)', value: '__custom__' },
|
|
775
|
+
];
|
|
776
|
+
const currentLanguage = state.config.EBAY_CONTENT_LANGUAGE || '';
|
|
777
|
+
const languageDefault = currentLanguage || 'en-US';
|
|
778
|
+
const languageMatchIndex = languageChoices.findIndex((choice) => choice.value === languageDefault);
|
|
779
|
+
const languageInitial = languageMatchIndex >= 0
|
|
780
|
+
? languageMatchIndex
|
|
781
|
+
: languageChoices.findIndex((choice) => choice.value === '__custom__');
|
|
782
|
+
const languageResponse = await prompts({
|
|
783
|
+
type: 'select',
|
|
784
|
+
name: 'contentLanguage',
|
|
785
|
+
message: 'Select your preferred Content-Language:',
|
|
786
|
+
choices: languageChoices,
|
|
787
|
+
initial: languageInitial >= 0 ? languageInitial : 0,
|
|
788
|
+
});
|
|
789
|
+
if (languageResponse.contentLanguage === undefined) {
|
|
790
|
+
return 'cancel';
|
|
791
|
+
}
|
|
792
|
+
if (languageResponse.contentLanguage === '__back__') {
|
|
793
|
+
return 'back';
|
|
794
|
+
}
|
|
795
|
+
let contentLanguage = languageResponse.contentLanguage;
|
|
796
|
+
if (contentLanguage === '__custom__') {
|
|
797
|
+
const customLanguage = await prompts({
|
|
798
|
+
type: 'text',
|
|
799
|
+
name: 'customContentLanguage',
|
|
800
|
+
message: 'Enter Content-Language (e.g., en-US, de-DE):',
|
|
801
|
+
initial: currentLanguage || 'en-US',
|
|
802
|
+
validate: (value) => value.trim().length === 0 ? 'Content-Language cannot be empty' : true,
|
|
803
|
+
});
|
|
804
|
+
if (customLanguage.customContentLanguage === undefined) {
|
|
805
|
+
return 'cancel';
|
|
806
|
+
}
|
|
807
|
+
contentLanguage = customLanguage.customContentLanguage.trim();
|
|
808
|
+
}
|
|
809
|
+
if (contentLanguage) {
|
|
810
|
+
state.config.EBAY_CONTENT_LANGUAGE = contentLanguage;
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
delete state.config.EBAY_CONTENT_LANGUAGE;
|
|
814
|
+
}
|
|
815
|
+
return 'continue';
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Collect eBay app credentials from the user.
|
|
819
|
+
*/
|
|
612
820
|
async function stepCredentials(state) {
|
|
613
821
|
clearScreen();
|
|
614
822
|
showLogo();
|
|
615
|
-
showProgress(
|
|
823
|
+
showProgress(3, 'eBay Credentials');
|
|
616
824
|
console.log(' Enter your eBay Developer credentials:\n');
|
|
617
825
|
showTip('Get credentials at: https://developer.ebay.com/my/keys');
|
|
618
826
|
showKeyboardHints(['Tab: Next field', 'Enter: Submit', 'Ctrl+C: Cancel']);
|
|
@@ -661,10 +869,13 @@ async function stepCredentials(state) {
|
|
|
661
869
|
state.config.EBAY_REDIRECT_URI = responses.redirectUri;
|
|
662
870
|
return 'continue';
|
|
663
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* Acquire and validate OAuth tokens for the configured credentials.
|
|
874
|
+
*/
|
|
664
875
|
async function stepOAuth(state) {
|
|
665
876
|
clearScreen();
|
|
666
877
|
showLogo();
|
|
667
|
-
showProgress(
|
|
878
|
+
showProgress(4, 'OAuth Setup');
|
|
668
879
|
console.log(' Configure user authentication for higher API rate limits:\n');
|
|
669
880
|
showBox('Rate Limits by Auth Type', [
|
|
670
881
|
'App Credentials Only: 1,000 req/day',
|
|
@@ -855,25 +1066,7 @@ async function stepOAuth(state) {
|
|
|
855
1066
|
}
|
|
856
1067
|
}
|
|
857
1068
|
else if (tokenChoice.method === 'manual') {
|
|
858
|
-
|
|
859
|
-
const consentDomain = state.environment === 'production'
|
|
860
|
-
? 'https://auth2.ebay.com'
|
|
861
|
-
: 'https://auth2.sandbox.ebay.com';
|
|
862
|
-
// Get scopes from environment config
|
|
863
|
-
const scopes = getDefaultScopes(state.environment);
|
|
864
|
-
// Build the consent URL parameters
|
|
865
|
-
const consentParams = new URLSearchParams({
|
|
866
|
-
client_id: state.config.EBAY_CLIENT_ID,
|
|
867
|
-
redirect_uri: state.config.EBAY_REDIRECT_URI,
|
|
868
|
-
response_type: 'code',
|
|
869
|
-
scope: scopes.join(' '),
|
|
870
|
-
});
|
|
871
|
-
const consentUrl = `${consentDomain}/oauth2/consents?${consentParams.toString()}`;
|
|
872
|
-
// Build the signin URL that redirects to consent
|
|
873
|
-
const signinDomain = state.environment === 'production'
|
|
874
|
-
? 'https://signin.ebay.com'
|
|
875
|
-
: 'https://signin.sandbox.ebay.com';
|
|
876
|
-
const authUrl = `${signinDomain}/signin?ru=${encodeURIComponent(consentUrl)}&sgfl=oauth2&AppName=${encodeURIComponent(state.config.EBAY_CLIENT_ID)}`;
|
|
1069
|
+
const authUrl = getOAuthAuthorizationUrl(state.config.EBAY_CLIENT_ID, state.config.EBAY_REDIRECT_URI, state.environment);
|
|
877
1070
|
console.log('\n ' + ui.bold('OAuth Authorization URL:'));
|
|
878
1071
|
console.log(ui.dim(' ' + '─'.repeat(56)));
|
|
879
1072
|
console.log(` ${ui.info(authUrl)}`);
|
|
@@ -1094,10 +1287,13 @@ async function stepOAuth(state) {
|
|
|
1094
1287
|
}
|
|
1095
1288
|
return 'continue';
|
|
1096
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Configure MCP clients with the generated environment variables.
|
|
1292
|
+
*/
|
|
1097
1293
|
async function stepMCPClients(state) {
|
|
1098
1294
|
clearScreen();
|
|
1099
1295
|
showLogo();
|
|
1100
|
-
showProgress(
|
|
1296
|
+
showProgress(5, 'MCP Client Setup');
|
|
1101
1297
|
console.log(' Configure your AI assistant to use the eBay MCP server:\n');
|
|
1102
1298
|
state.detectedClients = detectLLMClients();
|
|
1103
1299
|
const detected = state.detectedClients.filter((c) => c.detected);
|
|
@@ -1184,10 +1380,13 @@ async function stepMCPClients(state) {
|
|
|
1184
1380
|
}
|
|
1185
1381
|
return 'continue';
|
|
1186
1382
|
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Finalize setup and display summary information.
|
|
1385
|
+
*/
|
|
1187
1386
|
async function stepComplete(state) {
|
|
1188
1387
|
clearScreen();
|
|
1189
1388
|
showLogo();
|
|
1190
|
-
showProgress(
|
|
1389
|
+
showProgress(6, 'Setup Complete');
|
|
1191
1390
|
const stopSpinner = showSpinner('Saving configuration...');
|
|
1192
1391
|
await new Promise((r) => setTimeout(r, 300));
|
|
1193
1392
|
saveConfig(state.config, state.environment);
|
|
@@ -1196,6 +1395,8 @@ async function stepComplete(state) {
|
|
|
1196
1395
|
console.log(ui.bold.green('\n 🎉 Setup Complete!\n'));
|
|
1197
1396
|
showBox('Configuration Summary', [
|
|
1198
1397
|
`Environment: ${state.environment}`,
|
|
1398
|
+
`Marketplace ID: ${state.config.EBAY_MARKETPLACE_ID || 'Not set'}`,
|
|
1399
|
+
`Content-Lang: ${state.config.EBAY_CONTENT_LANGUAGE || 'Not set'}`,
|
|
1199
1400
|
`Client ID: ${state.config.EBAY_CLIENT_ID?.slice(0, 20)}...`,
|
|
1200
1401
|
`Redirect URI: ${state.config.EBAY_REDIRECT_URI?.slice(0, 30)}...`,
|
|
1201
1402
|
`OAuth Token: ${state.config.EBAY_USER_REFRESH_TOKEN ? '✓ Configured' : '✗ Not set'}`,
|
|
@@ -1268,7 +1469,14 @@ async function main() {
|
|
|
1268
1469
|
hasExistingConfig: Object.keys(existingConfig).length > 0,
|
|
1269
1470
|
isQuickMode: args.quick,
|
|
1270
1471
|
};
|
|
1271
|
-
const steps = [
|
|
1472
|
+
const steps = [
|
|
1473
|
+
stepWelcome,
|
|
1474
|
+
stepEnvironment,
|
|
1475
|
+
stepMarketplaceSettings,
|
|
1476
|
+
stepCredentials,
|
|
1477
|
+
stepOAuth,
|
|
1478
|
+
stepMCPClients,
|
|
1479
|
+
];
|
|
1272
1480
|
let stepIndex = 0;
|
|
1273
1481
|
while (stepIndex < steps.length) {
|
|
1274
1482
|
const result = await steps[stepIndex](state);
|
|
@@ -126,7 +126,7 @@ export const tokenManagementTools = [
|
|
|
126
126
|
'IMPORTANT NOTES:\n' +
|
|
127
127
|
'- Authorization codes expire in ~5 minutes - if you get "invalid grant" error, get a fresh code\n' +
|
|
128
128
|
'- Codes can be URL-encoded (e.g., v%5E1.1%23...) - this tool automatically decodes them\n' +
|
|
129
|
-
'- Extract the code parameter from the redirect URL: https://
|
|
129
|
+
'- Extract the code parameter from the redirect URL (your RuName Accept URL): https://your-redirect-uri?code=YOUR_CODE&expires_in=299\n' +
|
|
130
130
|
'- Tokens are saved to .env file and will auto-refresh every 2 hours\n' +
|
|
131
131
|
'- Refresh tokens last 18 months before requiring re-authorization\n\n' +
|
|
132
132
|
'COMMON ERRORS:\n' +
|
package/package.json
CHANGED