ebay-mcp 1.6.2 → 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 +16 -6
- package/build/api/client.js +26 -13
- package/build/api/index.js +2 -2
- package/build/api/listing-management/inventory.js +7 -35
- package/build/api/other/identity.js +1 -1
- package/build/auth/oauth.js +4 -4
- package/build/config/environment.js +54 -36
- package/build/index.js +14 -0
- 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 +254 -25
- package/build/scripts/update-api-status-doc.js +44 -0
- package/build/server-http.js +32 -13
- package/build/tools/definitions/developer.js +43 -0
- package/build/tools/definitions/token-management.js +1 -1
- package/build/tools/index.js +46 -5
- package/build/utils/api-status-feed.js +85 -0
- package/build/utils/version.js +56 -0
- package/package.json +5 -1
- package/public/icons/1024x1024.png +0 -0
- package/public/icons/128x128.png +0 -0
- package/public/icons/16x16.png +0 -0
- package/public/icons/256x256.png +0 -0
- package/public/icons/32x32.png +0 -0
- package/public/icons/48x48.png +0 -0
- package/public/icons/512x512.png +0 -0
package/build/scripts/setup.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { dirname, join } from 'path';
|
|
2
|
+
import { dirname, join, resolve } from 'path';
|
|
3
3
|
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
13
|
config({ quiet: true });
|
|
14
|
+
checkForUpdates();
|
|
13
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
16
|
const __dirname = dirname(__filename);
|
|
15
17
|
const PROJECT_ROOT = join(__dirname, '../..');
|
|
16
|
-
const TOTAL_STEPS =
|
|
18
|
+
const TOTAL_STEPS = 6;
|
|
17
19
|
const ebay = {
|
|
18
20
|
red: chalk.hex('#E53238'),
|
|
19
21
|
blue: chalk.hex('#0064D2'),
|
|
@@ -29,6 +31,26 @@ const ui = {
|
|
|
29
31
|
info: chalk.cyan,
|
|
30
32
|
hint: chalk.gray,
|
|
31
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
|
+
];
|
|
32
54
|
const LOGO = `
|
|
33
55
|
${ebay.red('███████╗')}${ebay.blue('██████╗ ')}${ebay.yellow('█████╗ ')}${ebay.green('██╗ ██╗')}
|
|
34
56
|
${ebay.red('██╔════╝')}${ebay.blue('██╔══██╗')}${ebay.yellow('██╔══██╗')}${ebay.green('╚██╗ ██╔╝')}
|
|
@@ -37,13 +59,22 @@ const LOGO = `
|
|
|
37
59
|
${ebay.red('███████╗')}${ebay.blue('██████╔╝')}${ebay.yellow('██║ ██║')}${ebay.green(' ██║ ')}
|
|
38
60
|
${ebay.red('╚══════╝')}${ebay.blue('╚═════╝ ')}${ebay.yellow('╚═╝ ╚═╝')}${ebay.green(' ╚═╝ ')}
|
|
39
61
|
`;
|
|
62
|
+
/**
|
|
63
|
+
* Clear the terminal screen.
|
|
64
|
+
*/
|
|
40
65
|
function clearScreen() {
|
|
41
66
|
console.clear();
|
|
42
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Render the eBay ASCII logo and heading.
|
|
70
|
+
*/
|
|
43
71
|
function showLogo() {
|
|
44
72
|
console.log(LOGO);
|
|
45
|
-
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'));
|
|
46
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Render a step progress bar with title.
|
|
77
|
+
*/
|
|
47
78
|
function showProgress(step, title) {
|
|
48
79
|
const filled = '●'.repeat(step);
|
|
49
80
|
const empty = '○'.repeat(TOTAL_STEPS - step);
|
|
@@ -52,21 +83,33 @@ function showProgress(step, title) {
|
|
|
52
83
|
console.log(` ${progress} ${ui.bold(`Step ${step}/${TOTAL_STEPS}`)}: ${title}`);
|
|
53
84
|
console.log(ui.dim('─'.repeat(60)) + '\n');
|
|
54
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Render keyboard hints for the current step.
|
|
88
|
+
*/
|
|
55
89
|
function showKeyboardHints(hints) {
|
|
56
90
|
const hintText = hints.map((h) => ui.dim(h)).join(' │ ');
|
|
57
91
|
console.log(`\n ${hintText}\n`);
|
|
58
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Render a tip callout.
|
|
95
|
+
*/
|
|
59
96
|
function showTip(message) {
|
|
60
97
|
console.log(` ${ebay.yellow('💡 Tip:')} ${ui.dim(message)}\n`);
|
|
61
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Render a success line.
|
|
101
|
+
*/
|
|
62
102
|
function showSuccess(message) {
|
|
63
103
|
console.log(` ${ui.success('✓')} ${message}`);
|
|
64
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Render an error line.
|
|
107
|
+
*/
|
|
65
108
|
function showError(message) {
|
|
66
109
|
console.log(` ${ui.error('✗')} ${message}`);
|
|
67
110
|
}
|
|
68
111
|
/**
|
|
69
|
-
* Open a URL in the default browser (cross-platform)
|
|
112
|
+
* Open a URL in the default browser (cross-platform).
|
|
70
113
|
*/
|
|
71
114
|
function openBrowser(url) {
|
|
72
115
|
return new Promise((resolve, reject) => {
|
|
@@ -92,6 +135,9 @@ function openBrowser(url) {
|
|
|
92
135
|
});
|
|
93
136
|
});
|
|
94
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Render a warning line.
|
|
140
|
+
*/
|
|
95
141
|
function showWarning(message) {
|
|
96
142
|
console.log(` ${ui.warning('⚠')} ${message}`);
|
|
97
143
|
}
|
|
@@ -258,9 +304,15 @@ function displayUserInfo(userInfo) {
|
|
|
258
304
|
`User ID: ${userInfo.userId?.slice(0, 30)}...`,
|
|
259
305
|
]);
|
|
260
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Render an informational line.
|
|
309
|
+
*/
|
|
261
310
|
function showInfo(message) {
|
|
262
311
|
console.log(` ${ui.info('ℹ')} ${message}`);
|
|
263
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Render a spinner and return a stop callback.
|
|
315
|
+
*/
|
|
264
316
|
function showSpinner(message) {
|
|
265
317
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
266
318
|
let i = 0;
|
|
@@ -274,6 +326,9 @@ function showSpinner(message) {
|
|
|
274
326
|
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r');
|
|
275
327
|
};
|
|
276
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* Render a bordered info box.
|
|
331
|
+
*/
|
|
277
332
|
function showBox(title, content) {
|
|
278
333
|
const width = 60;
|
|
279
334
|
const line = '─'.repeat(width - 2);
|
|
@@ -286,6 +341,9 @@ function showBox(title, content) {
|
|
|
286
341
|
}
|
|
287
342
|
console.log(` ${ui.dim('└' + line + '┘')}\n`);
|
|
288
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Compute MCP client config paths by OS.
|
|
346
|
+
*/
|
|
289
347
|
function getConfigPaths() {
|
|
290
348
|
const home = homedir();
|
|
291
349
|
const os = platform();
|
|
@@ -326,6 +384,9 @@ function getConfigPaths() {
|
|
|
326
384
|
};
|
|
327
385
|
return paths;
|
|
328
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Detect installed MCP-compatible clients.
|
|
389
|
+
*/
|
|
329
390
|
function detectLLMClients() {
|
|
330
391
|
const paths = getConfigPaths();
|
|
331
392
|
const clients = [];
|
|
@@ -342,6 +403,9 @@ function detectLLMClients() {
|
|
|
342
403
|
}
|
|
343
404
|
return clients;
|
|
344
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Write MCP server config for a detected client.
|
|
408
|
+
*/
|
|
345
409
|
function configureLLMClient(client, projectRoot) {
|
|
346
410
|
try {
|
|
347
411
|
const configDir = dirname(client.configPath);
|
|
@@ -460,6 +524,12 @@ function updateClaudeDesktopConfig(envConfig, environment) {
|
|
|
460
524
|
if (envConfig.EBAY_REDIRECT_URI) {
|
|
461
525
|
envVars.EBAY_REDIRECT_URI = envConfig.EBAY_REDIRECT_URI;
|
|
462
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
|
+
}
|
|
463
533
|
if (envConfig.EBAY_USER_REFRESH_TOKEN) {
|
|
464
534
|
envVars.EBAY_USER_REFRESH_TOKEN = envConfig.EBAY_USER_REFRESH_TOKEN;
|
|
465
535
|
}
|
|
@@ -502,6 +572,9 @@ function updateClaudeDesktopConfig(envConfig, environment) {
|
|
|
502
572
|
};
|
|
503
573
|
}
|
|
504
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Load existing environment variables from the .env file.
|
|
577
|
+
*/
|
|
505
578
|
function loadExistingConfig() {
|
|
506
579
|
const envPath = join(PROJECT_ROOT, '.env');
|
|
507
580
|
const envConfig = {};
|
|
@@ -519,6 +592,9 @@ function loadExistingConfig() {
|
|
|
519
592
|
}
|
|
520
593
|
return envConfig;
|
|
521
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Format a date for display in the .env header.
|
|
597
|
+
*/
|
|
522
598
|
function formatDate(date) {
|
|
523
599
|
const options = {
|
|
524
600
|
weekday: 'long',
|
|
@@ -532,9 +608,18 @@ function formatDate(date) {
|
|
|
532
608
|
};
|
|
533
609
|
return date.toLocaleString('en-US', options);
|
|
534
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* Persist setup configuration to the project .env file.
|
|
613
|
+
*/
|
|
535
614
|
function saveConfig(envConfig, environment) {
|
|
536
615
|
const envPath = join(PROJECT_ROOT, '.env');
|
|
537
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';
|
|
538
623
|
const content = `# eBay MCP Server Configuration
|
|
539
624
|
# Last Updated: ${formatDate(now)}
|
|
540
625
|
# Environment: ${environment}
|
|
@@ -543,6 +628,8 @@ EBAY_CLIENT_ID=${envConfig.EBAY_CLIENT_ID || ''}
|
|
|
543
628
|
EBAY_CLIENT_SECRET=${envConfig.EBAY_CLIENT_SECRET || ''}
|
|
544
629
|
EBAY_REDIRECT_URI=${envConfig.EBAY_REDIRECT_URI || ''}
|
|
545
630
|
EBAY_ENVIRONMENT=${environment}
|
|
631
|
+
${marketplaceLine}
|
|
632
|
+
${contentLanguageLine}
|
|
546
633
|
|
|
547
634
|
EBAY_USER_REFRESH_TOKEN=${envConfig.EBAY_USER_REFRESH_TOKEN || ''}
|
|
548
635
|
EBAY_USER_ACCESS_TOKEN=${envConfig.EBAY_USER_ACCESS_TOKEN || ''}
|
|
@@ -555,10 +642,12 @@ async function stepWelcome(state) {
|
|
|
555
642
|
showLogo();
|
|
556
643
|
console.log(ui.dim(' Welcome to the eBay MCP Server setup wizard!\n'));
|
|
557
644
|
console.log(' This wizard will help you:\n');
|
|
558
|
-
console.log(` ${ui.success('1.')}
|
|
559
|
-
console.log(` ${ui.success('2.')} Set
|
|
560
|
-
console.log(` ${ui.success('3.')} Configure your
|
|
561
|
-
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`);
|
|
562
651
|
if (state.hasExistingConfig) {
|
|
563
652
|
showInfo('Existing configuration detected. You can update or keep current values.');
|
|
564
653
|
}
|
|
@@ -571,6 +660,9 @@ async function stepWelcome(state) {
|
|
|
571
660
|
});
|
|
572
661
|
return response.continue !== false ? 'continue' : 'cancel';
|
|
573
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Select the eBay environment for this configuration.
|
|
665
|
+
*/
|
|
574
666
|
async function stepEnvironment(state) {
|
|
575
667
|
clearScreen();
|
|
576
668
|
showLogo();
|
|
@@ -607,10 +699,128 @@ async function stepEnvironment(state) {
|
|
|
607
699
|
state.config.EBAY_ENVIRONMENT = response.environment;
|
|
608
700
|
return 'continue';
|
|
609
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
|
+
*/
|
|
610
820
|
async function stepCredentials(state) {
|
|
611
821
|
clearScreen();
|
|
612
822
|
showLogo();
|
|
613
|
-
showProgress(
|
|
823
|
+
showProgress(3, 'eBay Credentials');
|
|
614
824
|
console.log(' Enter your eBay Developer credentials:\n');
|
|
615
825
|
showTip('Get credentials at: https://developer.ebay.com/my/keys');
|
|
616
826
|
showKeyboardHints(['Tab: Next field', 'Enter: Submit', 'Ctrl+C: Cancel']);
|
|
@@ -659,10 +869,13 @@ async function stepCredentials(state) {
|
|
|
659
869
|
state.config.EBAY_REDIRECT_URI = responses.redirectUri;
|
|
660
870
|
return 'continue';
|
|
661
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* Acquire and validate OAuth tokens for the configured credentials.
|
|
874
|
+
*/
|
|
662
875
|
async function stepOAuth(state) {
|
|
663
876
|
clearScreen();
|
|
664
877
|
showLogo();
|
|
665
|
-
showProgress(
|
|
878
|
+
showProgress(4, 'OAuth Setup');
|
|
666
879
|
console.log(' Configure user authentication for higher API rate limits:\n');
|
|
667
880
|
showBox('Rate Limits by Auth Type', [
|
|
668
881
|
'App Credentials Only: 1,000 req/day',
|
|
@@ -853,13 +1066,7 @@ async function stepOAuth(state) {
|
|
|
853
1066
|
}
|
|
854
1067
|
}
|
|
855
1068
|
else if (tokenChoice.method === 'manual') {
|
|
856
|
-
const
|
|
857
|
-
? 'https://auth.ebay.com/oauth2/authorize'
|
|
858
|
-
: 'https://auth.sandbox.ebay.com/oauth2/authorize';
|
|
859
|
-
// Get scopes from environment config
|
|
860
|
-
const scopes = getDefaultScopes(state.environment);
|
|
861
|
-
const scopeParam = encodeURIComponent(scopes.join(' '));
|
|
862
|
-
const authUrl = `${baseUrl}?client_id=${encodeURIComponent(state.config.EBAY_CLIENT_ID)}&redirect_uri=${encodeURIComponent(state.config.EBAY_REDIRECT_URI)}&response_type=code&scope=${scopeParam}`;
|
|
1069
|
+
const authUrl = getOAuthAuthorizationUrl(state.config.EBAY_CLIENT_ID, state.config.EBAY_REDIRECT_URI, state.environment);
|
|
863
1070
|
console.log('\n ' + ui.bold('OAuth Authorization URL:'));
|
|
864
1071
|
console.log(ui.dim(' ' + '─'.repeat(56)));
|
|
865
1072
|
console.log(` ${ui.info(authUrl)}`);
|
|
@@ -1080,10 +1287,13 @@ async function stepOAuth(state) {
|
|
|
1080
1287
|
}
|
|
1081
1288
|
return 'continue';
|
|
1082
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Configure MCP clients with the generated environment variables.
|
|
1292
|
+
*/
|
|
1083
1293
|
async function stepMCPClients(state) {
|
|
1084
1294
|
clearScreen();
|
|
1085
1295
|
showLogo();
|
|
1086
|
-
showProgress(
|
|
1296
|
+
showProgress(5, 'MCP Client Setup');
|
|
1087
1297
|
console.log(' Configure your AI assistant to use the eBay MCP server:\n');
|
|
1088
1298
|
state.detectedClients = detectLLMClients();
|
|
1089
1299
|
const detected = state.detectedClients.filter((c) => c.detected);
|
|
@@ -1170,10 +1380,13 @@ async function stepMCPClients(state) {
|
|
|
1170
1380
|
}
|
|
1171
1381
|
return 'continue';
|
|
1172
1382
|
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Finalize setup and display summary information.
|
|
1385
|
+
*/
|
|
1173
1386
|
async function stepComplete(state) {
|
|
1174
1387
|
clearScreen();
|
|
1175
1388
|
showLogo();
|
|
1176
|
-
showProgress(
|
|
1389
|
+
showProgress(6, 'Setup Complete');
|
|
1177
1390
|
const stopSpinner = showSpinner('Saving configuration...');
|
|
1178
1391
|
await new Promise((r) => setTimeout(r, 300));
|
|
1179
1392
|
saveConfig(state.config, state.environment);
|
|
@@ -1182,6 +1395,8 @@ async function stepComplete(state) {
|
|
|
1182
1395
|
console.log(ui.bold.green('\n 🎉 Setup Complete!\n'));
|
|
1183
1396
|
showBox('Configuration Summary', [
|
|
1184
1397
|
`Environment: ${state.environment}`,
|
|
1398
|
+
`Marketplace ID: ${state.config.EBAY_MARKETPLACE_ID || 'Not set'}`,
|
|
1399
|
+
`Content-Lang: ${state.config.EBAY_CONTENT_LANGUAGE || 'Not set'}`,
|
|
1185
1400
|
`Client ID: ${state.config.EBAY_CLIENT_ID?.slice(0, 20)}...`,
|
|
1186
1401
|
`Redirect URI: ${state.config.EBAY_REDIRECT_URI?.slice(0, 30)}...`,
|
|
1187
1402
|
`OAuth Token: ${state.config.EBAY_USER_REFRESH_TOKEN ? '✓ Configured' : '✗ Not set'}`,
|
|
@@ -1254,7 +1469,14 @@ async function main() {
|
|
|
1254
1469
|
hasExistingConfig: Object.keys(existingConfig).length > 0,
|
|
1255
1470
|
isQuickMode: args.quick,
|
|
1256
1471
|
};
|
|
1257
|
-
const steps = [
|
|
1472
|
+
const steps = [
|
|
1473
|
+
stepWelcome,
|
|
1474
|
+
stepEnvironment,
|
|
1475
|
+
stepMarketplaceSettings,
|
|
1476
|
+
stepCredentials,
|
|
1477
|
+
stepOAuth,
|
|
1478
|
+
stepMCPClients,
|
|
1479
|
+
];
|
|
1258
1480
|
let stepIndex = 0;
|
|
1259
1481
|
while (stepIndex < steps.length) {
|
|
1260
1482
|
const result = await steps[stepIndex](state);
|
|
@@ -1275,7 +1497,14 @@ process.on('SIGINT', () => {
|
|
|
1275
1497
|
console.log(ui.warning('\n\n Setup interrupted.\n'));
|
|
1276
1498
|
process.exit(0);
|
|
1277
1499
|
});
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1500
|
+
export async function runSetup() {
|
|
1501
|
+
await main();
|
|
1502
|
+
}
|
|
1503
|
+
const entryPath = process.argv[1] ? resolve(process.argv[1]) : undefined;
|
|
1504
|
+
const modulePath = resolve(fileURLToPath(import.meta.url));
|
|
1505
|
+
if (entryPath && modulePath === entryPath) {
|
|
1506
|
+
runSetup().catch((error) => {
|
|
1507
|
+
console.error(ui.error('\n Setup failed:'), error);
|
|
1508
|
+
process.exit(1);
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches the eBay API Status RSS feed and writes the latest items to docs/API_STATUS.md.
|
|
3
|
+
* Used by the GitHub Action to keep an in-repo snapshot. Run with: npx tsx src/scripts/update-api-status-doc.ts
|
|
4
|
+
*/
|
|
5
|
+
import { writeFileSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { getApiStatusFeed } from '../utils/api-status-feed.js';
|
|
8
|
+
const DEFAULT_LIMIT = 15;
|
|
9
|
+
const OUT_PATH = join(process.cwd(), 'docs', 'API_STATUS.md');
|
|
10
|
+
function escapeCell(s) {
|
|
11
|
+
return s.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
12
|
+
}
|
|
13
|
+
function buildMarkdown(items) {
|
|
14
|
+
const lines = [
|
|
15
|
+
'# eBay API Status (latest)',
|
|
16
|
+
'',
|
|
17
|
+
'Auto-updated snapshot from the [eBay API Status RSS feed](https://developer.ebay.com/rss/api-status).',
|
|
18
|
+
'Full list: [developer.ebay.com/support/api-status](https://developer.ebay.com/support/api-status).',
|
|
19
|
+
'',
|
|
20
|
+
`*Last updated: ${new Date().toISOString()}*`,
|
|
21
|
+
'',
|
|
22
|
+
'| Title | API | Site | Status | Last updated | Link |',
|
|
23
|
+
'|-------|-----|------|--------|--------------|------|',
|
|
24
|
+
];
|
|
25
|
+
for (const item of items) {
|
|
26
|
+
const link = item.link ? `[Details](${item.link})` : '';
|
|
27
|
+
lines.push(`| ${escapeCell(item.title)} | ${escapeCell(item.api)} | ${escapeCell(item.site)} | ${escapeCell(item.status)} | ${escapeCell(item.lastUpdated)} | ${link} |`);
|
|
28
|
+
}
|
|
29
|
+
lines.push('', '---', '', '*Generated by [ebay-mcp](https://github.com/YosefHayim/ebay-mcp) API status sync.*');
|
|
30
|
+
return lines.join('\n');
|
|
31
|
+
}
|
|
32
|
+
async function main() {
|
|
33
|
+
const { items, error } = await getApiStatusFeed({ limit: DEFAULT_LIMIT });
|
|
34
|
+
if (error && items.length === 0) {
|
|
35
|
+
throw new Error(`Failed to fetch API status feed: ${error}`);
|
|
36
|
+
}
|
|
37
|
+
const markdown = buildMarkdown(items);
|
|
38
|
+
writeFileSync(OUT_PATH, markdown, 'utf8');
|
|
39
|
+
console.log(`Wrote ${items.length} items to ${OUT_PATH}`);
|
|
40
|
+
}
|
|
41
|
+
main().catch((err) => {
|
|
42
|
+
console.error(err);
|
|
43
|
+
process.exitCode = 1;
|
|
44
|
+
});
|
package/build/server-http.js
CHANGED
|
@@ -12,6 +12,8 @@ import express from 'express';
|
|
|
12
12
|
import helmet from 'helmet';
|
|
13
13
|
import cors from 'cors';
|
|
14
14
|
import { randomUUID } from 'crypto';
|
|
15
|
+
import { dirname, join, resolve } from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
15
17
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
16
18
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
17
19
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
@@ -21,6 +23,7 @@ import { getToolDefinitions, executeTool } from './tools/index.js';
|
|
|
21
23
|
import { TokenVerifier } from './auth/token-verifier.js';
|
|
22
24
|
import { createBearerAuthMiddleware } from './auth/oauth-middleware.js';
|
|
23
25
|
import { createMetadataRouter, getProtectedResourceMetadataUrl } from './auth/oauth-metadata.js';
|
|
26
|
+
import { getVersion } from './utils/version.js';
|
|
24
27
|
// Configuration from environment
|
|
25
28
|
const CONFIG = {
|
|
26
29
|
// Server settings
|
|
@@ -62,6 +65,9 @@ function getAuthServerMetadataUrl() {
|
|
|
62
65
|
*/
|
|
63
66
|
async function createApp() {
|
|
64
67
|
const app = express();
|
|
68
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
69
|
+
const __dirname = dirname(__filename);
|
|
70
|
+
const projectRoot = join(__dirname, '..');
|
|
65
71
|
// Enable CORS
|
|
66
72
|
app.use(cors({
|
|
67
73
|
// TODO: Restrict origin to known clients in production
|
|
@@ -84,6 +90,9 @@ async function createApp() {
|
|
|
84
90
|
});
|
|
85
91
|
// Server URL
|
|
86
92
|
const serverUrl = `http://${CONFIG.host}:${CONFIG.port}`;
|
|
93
|
+
const iconBaseUrl = `${serverUrl}/icons`;
|
|
94
|
+
// Static assets (icons)
|
|
95
|
+
app.use('/icons', express.static(join(projectRoot, 'public', 'icons')));
|
|
87
96
|
// Get eBay configuration for metadata
|
|
88
97
|
const ebayConfig = getEbayConfig();
|
|
89
98
|
// Add OAuth metadata endpoints
|
|
@@ -140,47 +149,55 @@ async function createApp() {
|
|
|
140
149
|
/**
|
|
141
150
|
* Create a new MCP server instance
|
|
142
151
|
*/
|
|
143
|
-
function createMcpServer() {
|
|
152
|
+
async function createMcpServer() {
|
|
144
153
|
const ebayConfig = getEbayConfig();
|
|
145
154
|
const api = new EbaySellerApi(ebayConfig);
|
|
155
|
+
try {
|
|
156
|
+
await api.initialize();
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
+
console.error(`Failed to initialize eBay API client: ${message}`);
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
146
163
|
const server = new McpServer({
|
|
147
164
|
name: 'ebay-mcp',
|
|
148
|
-
version:
|
|
165
|
+
version: getVersion(),
|
|
149
166
|
title: 'eBay API MCP Server',
|
|
150
|
-
websiteUrl: 'https://
|
|
167
|
+
websiteUrl: 'https://github.com/YosefHayim/ebay-mcp',
|
|
151
168
|
icons: [
|
|
152
169
|
{
|
|
153
|
-
src:
|
|
170
|
+
src: `${iconBaseUrl}/16x16.png`,
|
|
154
171
|
mimeType: 'image/png',
|
|
155
172
|
sizes: ['16x16'],
|
|
156
173
|
},
|
|
157
174
|
{
|
|
158
|
-
src:
|
|
175
|
+
src: `${iconBaseUrl}/32x32.png`,
|
|
159
176
|
mimeType: 'image/png',
|
|
160
177
|
sizes: ['32x32'],
|
|
161
178
|
},
|
|
162
179
|
{
|
|
163
|
-
src:
|
|
180
|
+
src: `${iconBaseUrl}/48x48.png`,
|
|
164
181
|
mimeType: 'image/png',
|
|
165
182
|
sizes: ['48x48'],
|
|
166
183
|
},
|
|
167
184
|
{
|
|
168
|
-
src:
|
|
185
|
+
src: `${iconBaseUrl}/128x128.png`,
|
|
169
186
|
mimeType: 'image/png',
|
|
170
187
|
sizes: ['128x128'],
|
|
171
188
|
},
|
|
172
189
|
{
|
|
173
|
-
src:
|
|
190
|
+
src: `${iconBaseUrl}/256x256.png`,
|
|
174
191
|
mimeType: 'image/png',
|
|
175
192
|
sizes: ['256x256'],
|
|
176
193
|
},
|
|
177
194
|
{
|
|
178
|
-
src:
|
|
195
|
+
src: `${iconBaseUrl}/512x512.png`,
|
|
179
196
|
mimeType: 'image/png',
|
|
180
197
|
sizes: ['512x512'],
|
|
181
198
|
},
|
|
182
199
|
{
|
|
183
|
-
src:
|
|
200
|
+
src: `${iconBaseUrl}/1024x1024.png`,
|
|
184
201
|
mimeType: 'image/png',
|
|
185
202
|
sizes: ['1024x1024'],
|
|
186
203
|
},
|
|
@@ -246,7 +263,7 @@ async function createApp() {
|
|
|
246
263
|
console.log(`MCP session closed: ${transport.sessionId}`);
|
|
247
264
|
}
|
|
248
265
|
};
|
|
249
|
-
const server = createMcpServer();
|
|
266
|
+
const server = await createMcpServer();
|
|
250
267
|
await server.connect(transport);
|
|
251
268
|
}
|
|
252
269
|
else {
|
|
@@ -338,7 +355,7 @@ async function main() {
|
|
|
338
355
|
}
|
|
339
356
|
else {
|
|
340
357
|
console.log('Authorization is DISABLED');
|
|
341
|
-
console.log('Set OAUTH_ENABLED=true to enable OAuth protection');
|
|
358
|
+
console.log('Set OAUTH_ENABLED=true (or remove OAUTH_ENABLED=false) to enable OAuth protection');
|
|
342
359
|
}
|
|
343
360
|
});
|
|
344
361
|
// Graceful shutdown
|
|
@@ -356,6 +373,8 @@ async function main() {
|
|
|
356
373
|
}
|
|
357
374
|
}
|
|
358
375
|
// Start server if run directly
|
|
359
|
-
|
|
376
|
+
const entryPath = process.argv[1] ? resolve(process.argv[1]) : undefined;
|
|
377
|
+
const modulePath = resolve(fileURLToPath(import.meta.url));
|
|
378
|
+
if (entryPath && modulePath === entryPath) {
|
|
360
379
|
await main();
|
|
361
380
|
}
|