ebay-mcp-remote-edition 1.0.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +755 -0
  3. package/build/api/account-management/account.js +301 -0
  4. package/build/api/analytics-and-report/analytics.js +102 -0
  5. package/build/api/client-trading.js +96 -0
  6. package/build/api/client.js +173 -0
  7. package/build/api/communication/feedback.js +119 -0
  8. package/build/api/communication/message.js +131 -0
  9. package/build/api/communication/negotiation.js +97 -0
  10. package/build/api/communication/notification.js +373 -0
  11. package/build/api/developer/developer.js +81 -0
  12. package/build/api/index.js +109 -0
  13. package/build/api/listing-management/inventory.js +640 -0
  14. package/build/api/listing-metadata/metadata.js +485 -0
  15. package/build/api/listing-metadata/taxonomy.js +58 -0
  16. package/build/api/marketing-and-promotions/marketing.js +768 -0
  17. package/build/api/marketing-and-promotions/recommendation.js +32 -0
  18. package/build/api/order-management/dispute.js +69 -0
  19. package/build/api/order-management/fulfillment.js +89 -0
  20. package/build/api/other/compliance.js +47 -0
  21. package/build/api/other/edelivery.js +219 -0
  22. package/build/api/other/identity.js +24 -0
  23. package/build/api/other/translation.js +22 -0
  24. package/build/api/other/vero.js +48 -0
  25. package/build/api/trading/trading.js +78 -0
  26. package/build/auth/kv-store.js +40 -0
  27. package/build/auth/multi-user-store.js +120 -0
  28. package/build/auth/oauth-metadata.js +59 -0
  29. package/build/auth/oauth-middleware.js +99 -0
  30. package/build/auth/oauth-types.js +4 -0
  31. package/build/auth/oauth.js +235 -0
  32. package/build/auth/scope-utils.js +304 -0
  33. package/build/auth/token-store.js +46 -0
  34. package/build/auth/token-verifier.js +172 -0
  35. package/build/config/environment.js +297 -0
  36. package/build/index.d.ts +1 -0
  37. package/build/index.js +129 -0
  38. package/build/schemas/account-management/account.js +375 -0
  39. package/build/schemas/analytics/analytics.js +191 -0
  40. package/build/schemas/communication/messages.js +345 -0
  41. package/build/schemas/fulfillment/orders.js +338 -0
  42. package/build/schemas/index.js +68 -0
  43. package/build/schemas/inventory-management/inventory.js +471 -0
  44. package/build/schemas/marketing/marketing.js +1103 -0
  45. package/build/schemas/metadata/metadata.js +618 -0
  46. package/build/schemas/other/other-apis.js +390 -0
  47. package/build/schemas/taxonomy/taxonomy.js +575 -0
  48. package/build/scripts/auto-setup.js +364 -0
  49. package/build/scripts/dev-sync.js +512 -0
  50. package/build/scripts/diagnostics.js +301 -0
  51. package/build/scripts/download-specs.js +116 -0
  52. package/build/scripts/interactive-setup.js +757 -0
  53. package/build/scripts/setup.js +1515 -0
  54. package/build/scripts/update-api-status-doc.js +44 -0
  55. package/build/server-http.d.ts +1 -0
  56. package/build/server-http.js +581 -0
  57. package/build/tools/definitions/account-with-schemas.js +170 -0
  58. package/build/tools/definitions/account.js +428 -0
  59. package/build/tools/definitions/analytics.js +66 -0
  60. package/build/tools/definitions/communication.js +394 -0
  61. package/build/tools/definitions/developer.js +195 -0
  62. package/build/tools/definitions/fulfillment.js +326 -0
  63. package/build/tools/definitions/index.js +41 -0
  64. package/build/tools/definitions/inventory.js +464 -0
  65. package/build/tools/definitions/marketing.js +1486 -0
  66. package/build/tools/definitions/metadata.js +188 -0
  67. package/build/tools/definitions/other.js +309 -0
  68. package/build/tools/definitions/taxonomy.js +64 -0
  69. package/build/tools/definitions/token-management.js +148 -0
  70. package/build/tools/definitions/trading.js +71 -0
  71. package/build/tools/index.js +1200 -0
  72. package/build/tools/schemas.js +667 -0
  73. package/build/tools/tool-definitions.js +3534 -0
  74. package/build/types/application-settings/developerAnalyticsV1BetaOas3.js +5 -0
  75. package/build/types/application-settings/developerClientRegistrationV1Oas3.js +5 -0
  76. package/build/types/application-settings/developerKeyManagementV1Oas3.js +5 -0
  77. package/build/types/ebay-enums.js +1330 -0
  78. package/build/types/ebay.js +123 -0
  79. package/build/types/index.js +10 -0
  80. package/build/types/sell-apps/account-management/sellAccountV1Oas3.js +5 -0
  81. package/build/types/sell-apps/analytics-and-report/sellAnalyticsV1Oas3.js +5 -0
  82. package/build/types/sell-apps/communication/commerceFeedbackV1BetaOas3.js +5 -0
  83. package/build/types/sell-apps/communication/commerceMessageV1Oas3.js +5 -0
  84. package/build/types/sell-apps/communication/commerceNotificationV1Oas3.js +5 -0
  85. package/build/types/sell-apps/communication/sellNegotiationV1Oas3.js +5 -0
  86. package/build/types/sell-apps/listing-management/sellInventoryV1Oas3.js +5 -0
  87. package/build/types/sell-apps/listing-metadata/sellMetadataV1Oas3.js +5 -0
  88. package/build/types/sell-apps/markeitng-and-promotions/sellMarketingV1Oas3.js +5 -0
  89. package/build/types/sell-apps/markeitng-and-promotions/sellRecommendationV1Oas3.js +5 -0
  90. package/build/types/sell-apps/order-management/sellFulfillmentV1Oas3.js +5 -0
  91. package/build/types/sell-apps/other-apis/commerceIdentityV1Oas3.js +5 -0
  92. package/build/types/sell-apps/other-apis/commerceTranslationV1BetaOas3.js +5 -0
  93. package/build/types/sell-apps/other-apis/commerceVeroV1Oas3.js +5 -0
  94. package/build/types/sell-apps/other-apis/sellComplianceV1Oas3.js +5 -0
  95. package/build/types/sell-apps/other-apis/sellEdeliveryInternationalShippingOas3.js +5 -0
  96. package/build/types/sell-apps/other-apis/sellMarketingV1Oas3.js +5 -0
  97. package/build/types/sell-apps/other-apis/sellRecommendationV1Oas3.js +5 -0
  98. package/build/utils/account-management/account.js +831 -0
  99. package/build/utils/api-status-feed.js +83 -0
  100. package/build/utils/communication/feedback.js +216 -0
  101. package/build/utils/communication/message.js +242 -0
  102. package/build/utils/communication/negotiation.js +150 -0
  103. package/build/utils/communication/notification.js +369 -0
  104. package/build/utils/date-converter.js +160 -0
  105. package/build/utils/llm-client-detector.js +758 -0
  106. package/build/utils/logger.js +198 -0
  107. package/build/utils/oauth-helper.js +315 -0
  108. package/build/utils/order-management/dispute.js +369 -0
  109. package/build/utils/order-management/fulfillment.js +205 -0
  110. package/build/utils/other/compliance.js +76 -0
  111. package/build/utils/other/edelivery.js +241 -0
  112. package/build/utils/other/identity.js +13 -0
  113. package/build/utils/other/translation.js +41 -0
  114. package/build/utils/other/vero.js +90 -0
  115. package/build/utils/scope-helper.js +207 -0
  116. package/build/utils/security-checker.js +248 -0
  117. package/build/utils/setup-validator.js +305 -0
  118. package/build/utils/token-utils.js +40 -0
  119. package/build/utils/version.js +56 -0
  120. package/docs/auth/production_scopes.json +111 -0
  121. package/docs/auth/sandbox_scopes.json +142 -0
  122. package/package.json +122 -0
  123. package/public/icons/1024x1024.png +0 -0
  124. package/public/icons/128x128.png +0 -0
  125. package/public/icons/16x16.png +0 -0
  126. package/public/icons/256x256.png +0 -0
  127. package/public/icons/32x32.png +0 -0
  128. package/public/icons/48x48.png +0 -0
  129. package/public/icons/512x512.png +0 -0
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Security Checker - Pre-flight security and environment checks
3
+ */
4
+ import { existsSync, readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { execSync } from 'child_process';
7
+ import chalk from 'chalk';
8
+ /**
9
+ * Check Node.js version meets requirements
10
+ */
11
+ export function checkNodeVersion() {
12
+ const requiredVersion = 18;
13
+ const currentVersion = parseInt(process.version.slice(1).split('.')[0], 10);
14
+ if (currentVersion >= requiredVersion) {
15
+ return {
16
+ check: 'Node.js Version',
17
+ passed: true,
18
+ message: `Node.js ${process.version} meets requirements (>= ${requiredVersion})`,
19
+ severity: 'info',
20
+ };
21
+ }
22
+ return {
23
+ check: 'Node.js Version',
24
+ passed: false,
25
+ message: `Node.js ${process.version} is below required version ${requiredVersion}`,
26
+ severity: 'critical',
27
+ fix: `Install Node.js ${requiredVersion} or higher from https://nodejs.org/`,
28
+ };
29
+ }
30
+ /**
31
+ * Check if .env is in .gitignore
32
+ */
33
+ export function checkGitignore(projectRoot) {
34
+ const gitignorePath = join(projectRoot, '.gitignore');
35
+ if (!existsSync(gitignorePath)) {
36
+ return {
37
+ check: '.gitignore Security',
38
+ passed: false,
39
+ message: 'No .gitignore file found',
40
+ severity: 'warning',
41
+ fix: 'Create a .gitignore file and add .env to it',
42
+ };
43
+ }
44
+ const gitignoreContent = readFileSync(gitignorePath, 'utf-8');
45
+ const hasEnv = gitignoreContent.split('\n').some((line) => {
46
+ const trimmed = line.trim();
47
+ return trimmed === '.env' || trimmed === '*.env' || trimmed.startsWith('.env');
48
+ });
49
+ if (hasEnv) {
50
+ return {
51
+ check: '.gitignore Security',
52
+ passed: true,
53
+ message: '.env files are properly ignored by git',
54
+ severity: 'info',
55
+ };
56
+ }
57
+ return {
58
+ check: '.gitignore Security',
59
+ passed: false,
60
+ message: '.env is not in .gitignore - credentials could be committed!',
61
+ severity: 'critical',
62
+ fix: 'Add ".env" to your .gitignore file immediately',
63
+ };
64
+ }
65
+ /**
66
+ * Check network connectivity to eBay APIs
67
+ */
68
+ export async function checkNetworkConnectivity() {
69
+ try {
70
+ const controller = new AbortController();
71
+ const timeout = setTimeout(() => controller.abort(), 5000);
72
+ const response = await fetch('https://api.ebay.com/health', {
73
+ signal: controller.signal,
74
+ });
75
+ clearTimeout(timeout);
76
+ if (response.ok || response.status === 404) {
77
+ // 404 is fine, means we can reach eBay servers
78
+ return {
79
+ check: 'Network Connectivity',
80
+ passed: true,
81
+ message: 'Successfully connected to eBay API servers',
82
+ severity: 'info',
83
+ };
84
+ }
85
+ return {
86
+ check: 'Network Connectivity',
87
+ passed: false,
88
+ message: `Unexpected response from eBay API: ${response.status}`,
89
+ severity: 'warning',
90
+ fix: 'Check your internet connection and firewall settings',
91
+ };
92
+ }
93
+ catch (_error) {
94
+ return {
95
+ check: 'Network Connectivity',
96
+ passed: false,
97
+ message: 'Cannot reach eBay API servers',
98
+ severity: 'critical',
99
+ fix: 'Check your internet connection, proxy settings, and firewall',
100
+ };
101
+ }
102
+ }
103
+ /**
104
+ * Check if project is built
105
+ */
106
+ export function checkProjectBuild(projectRoot) {
107
+ const buildPath = join(projectRoot, 'build', 'index.js');
108
+ if (existsSync(buildPath)) {
109
+ return {
110
+ check: 'Project Build',
111
+ passed: true,
112
+ message: 'Project is built and ready',
113
+ severity: 'info',
114
+ };
115
+ }
116
+ return {
117
+ check: 'Project Build',
118
+ passed: false,
119
+ message: 'Project has not been built yet',
120
+ severity: 'warning',
121
+ fix: 'Run "npm run build" to build the project',
122
+ };
123
+ }
124
+ /**
125
+ * Check if dependencies are installed
126
+ */
127
+ export function checkDependencies(projectRoot) {
128
+ const nodeModulesPath = join(projectRoot, 'node_modules');
129
+ if (existsSync(nodeModulesPath)) {
130
+ return {
131
+ check: 'Dependencies',
132
+ passed: true,
133
+ message: 'Dependencies are installed',
134
+ severity: 'info',
135
+ };
136
+ }
137
+ return {
138
+ check: 'Project Dependencies',
139
+ passed: false,
140
+ message: 'Dependencies not installed',
141
+ severity: 'critical',
142
+ fix: 'Run "npm install" to install dependencies',
143
+ };
144
+ }
145
+ /**
146
+ * Check if git repo is initialized and .env is not tracked
147
+ */
148
+ export function checkGitTracking(projectRoot) {
149
+ const gitPath = join(projectRoot, '.git');
150
+ const envPath = join(projectRoot, '.env');
151
+ if (!existsSync(gitPath)) {
152
+ return {
153
+ check: 'Git Repository',
154
+ passed: true,
155
+ message: 'Not a git repository (no tracking risk)',
156
+ severity: 'info',
157
+ };
158
+ }
159
+ if (!existsSync(envPath)) {
160
+ return {
161
+ check: 'Git Tracking',
162
+ passed: true,
163
+ message: '.env file does not exist yet',
164
+ severity: 'info',
165
+ };
166
+ }
167
+ try {
168
+ const result = execSync('git ls-files .env', {
169
+ cwd: projectRoot,
170
+ encoding: 'utf-8',
171
+ }).trim();
172
+ if (result === '') {
173
+ return {
174
+ check: 'Git Tracking',
175
+ passed: true,
176
+ message: '.env is not tracked by git',
177
+ severity: 'info',
178
+ };
179
+ }
180
+ return {
181
+ check: 'Git Tracking',
182
+ passed: false,
183
+ message: '.env is tracked by git - SECURITY RISK!',
184
+ severity: 'critical',
185
+ fix: 'Run: git rm --cached .env && git commit -m "Remove .env from tracking"',
186
+ };
187
+ }
188
+ catch {
189
+ return {
190
+ check: 'Git Tracking',
191
+ passed: true,
192
+ message: 'Unable to check git tracking (likely not tracked)',
193
+ severity: 'info',
194
+ };
195
+ }
196
+ }
197
+ /**
198
+ * Run all security checks
199
+ */
200
+ export async function runSecurityChecks(projectRoot) {
201
+ const results = [];
202
+ // Synchronous checks
203
+ results.push(checkNodeVersion());
204
+ results.push(checkGitignore(projectRoot));
205
+ results.push(checkProjectBuild(projectRoot));
206
+ results.push(checkDependencies(projectRoot));
207
+ results.push(checkGitTracking(projectRoot));
208
+ // Asynchronous checks
209
+ results.push(await checkNetworkConnectivity());
210
+ return results;
211
+ }
212
+ /**
213
+ * Display security check results
214
+ */
215
+ export function displaySecurityResults(results) {
216
+ console.log(chalk.bold.cyan('\n🔒 Security & Environment Checks\n'));
217
+ for (const result of results) {
218
+ const icon = result.passed ? chalk.green('✓') : chalk.red('✗');
219
+ const severity = result.severity === 'critical'
220
+ ? chalk.red('[CRITICAL]')
221
+ : result.severity === 'warning'
222
+ ? chalk.yellow('[WARNING]')
223
+ : chalk.gray('[INFO]');
224
+ console.log(`${icon} ${chalk.bold(result.check)}: ${severity}`);
225
+ console.log(` ${chalk.gray(result.message)}`);
226
+ if (result.fix) {
227
+ console.log(` ${chalk.yellow('→ Fix:')} ${result.fix}`);
228
+ }
229
+ console.log('');
230
+ }
231
+ const critical = results.filter((r) => !r.passed && r.severity === 'critical');
232
+ const warnings = results.filter((r) => !r.passed && r.severity === 'warning');
233
+ if (critical.length > 0) {
234
+ console.log(chalk.red.bold(`⚠️ ${critical.length} critical issue(s) found. Please fix before continuing.\n`));
235
+ }
236
+ else if (warnings.length > 0) {
237
+ console.log(chalk.yellow.bold(`⚠️ ${warnings.length} warning(s) found. Recommended to fix.\n`));
238
+ }
239
+ else {
240
+ console.log(chalk.green.bold('✅ All security checks passed!\n'));
241
+ }
242
+ }
243
+ /**
244
+ * Check if there are critical failures
245
+ */
246
+ export function hasCriticalFailures(results) {
247
+ return results.some((r) => !r.passed && r.severity === 'critical');
248
+ }
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Setup Validation Module
3
+ *
4
+ * Tests the configuration after setup to ensure everything is working properly.
5
+ */
6
+ import { existsSync, readFileSync } from 'fs';
7
+ import { join } from 'path';
8
+ import chalk from 'chalk';
9
+ import { EbayOAuthClient } from '../auth/oauth.js';
10
+ import { getOAuthAuthorizationUrl } from '../config/environment.js';
11
+ /**
12
+ * Parse .env file manually
13
+ */
14
+ function parseEnvFile(filePath) {
15
+ const env = {};
16
+ if (!existsSync(filePath)) {
17
+ return env;
18
+ }
19
+ const content = readFileSync(filePath, 'utf-8');
20
+ const lines = content.split('\n');
21
+ for (const line of lines) {
22
+ const trimmed = line.trim();
23
+ // Skip empty lines and comments
24
+ if (!trimmed || trimmed.startsWith('#')) {
25
+ continue;
26
+ }
27
+ // Parse KEY=VALUE
28
+ const match = /^([^=]+)=(.*)$/.exec(trimmed);
29
+ if (match) {
30
+ const key = match[1].trim();
31
+ let value = match[2].trim();
32
+ // Remove quotes if present
33
+ if ((value.startsWith('"') && value.endsWith('"')) ||
34
+ (value.startsWith("'") && value.endsWith("'"))) {
35
+ value = value.slice(1, -1);
36
+ }
37
+ env[key] = value;
38
+ }
39
+ }
40
+ return env;
41
+ }
42
+ /**
43
+ * Validate .env file exists and is readable
44
+ */
45
+ function validateEnvFile(projectRoot) {
46
+ const envPath = join(projectRoot, '.env');
47
+ if (!existsSync(envPath)) {
48
+ return {
49
+ test: '.env File Existence',
50
+ passed: false,
51
+ message: 'Configuration file not found',
52
+ error: `.env file does not exist at ${envPath}`,
53
+ };
54
+ }
55
+ try {
56
+ readFileSync(envPath, 'utf-8');
57
+ return {
58
+ test: '.env File Existence',
59
+ passed: true,
60
+ message: 'Configuration file exists and is readable',
61
+ };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ test: '.env File Existence',
66
+ passed: false,
67
+ message: 'Configuration file cannot be read',
68
+ error: error instanceof Error ? error.message : 'Unknown error',
69
+ };
70
+ }
71
+ }
72
+ /**
73
+ * Validate required app credentials are present
74
+ */
75
+ function validateAppCredentials(envVars) {
76
+ const required = ['EBAY_CLIENT_ID', 'EBAY_CLIENT_SECRET', 'EBAY_REDIRECT_URI'];
77
+ const missing = [];
78
+ for (const key of required) {
79
+ if (!envVars[key] || envVars[key].trim() === '') {
80
+ missing.push(key);
81
+ }
82
+ }
83
+ if (missing.length > 0) {
84
+ return {
85
+ test: 'App Credentials',
86
+ passed: false,
87
+ message: 'Missing required app credentials',
88
+ error: `Missing: ${missing.join(', ')}`,
89
+ };
90
+ }
91
+ return {
92
+ test: 'App Credentials',
93
+ passed: true,
94
+ message: 'All required app credentials are present',
95
+ };
96
+ }
97
+ /**
98
+ * Validate environment setting
99
+ */
100
+ function validateEnvironment(envVars) {
101
+ const env = envVars.EBAY_ENVIRONMENT || 'sandbox';
102
+ if (env !== 'sandbox' && env !== 'production') {
103
+ return {
104
+ test: 'Environment Setting',
105
+ passed: false,
106
+ message: 'Invalid environment value',
107
+ error: `EBAY_ENVIRONMENT must be "sandbox" or "production", got "${env}"`,
108
+ };
109
+ }
110
+ return {
111
+ test: 'Environment Setting',
112
+ passed: true,
113
+ message: `Environment set to "${env}"`,
114
+ };
115
+ }
116
+ /**
117
+ * Check if user tokens are configured
118
+ */
119
+ function validateUserTokens(envVars) {
120
+ const hasRefreshToken = envVars.EBAY_USER_REFRESH_TOKEN && envVars.EBAY_USER_REFRESH_TOKEN.trim() !== '';
121
+ if (!hasRefreshToken) {
122
+ return {
123
+ test: 'User Tokens (Optional)',
124
+ passed: true,
125
+ message: 'No user tokens configured (app token only mode)',
126
+ error: 'To enable user-specific API calls, set EBAY_USER_REFRESH_TOKEN',
127
+ };
128
+ }
129
+ return {
130
+ test: 'User Tokens',
131
+ passed: true,
132
+ message: 'User refresh token is configured',
133
+ };
134
+ }
135
+ /**
136
+ * Test OAuth client initialization
137
+ */
138
+ async function validateOAuthInitialization(config) {
139
+ try {
140
+ const oauthClient = new EbayOAuthClient(config);
141
+ await oauthClient.initialize();
142
+ return {
143
+ test: 'OAuth Client Initialization',
144
+ passed: true,
145
+ message: 'OAuth client initialized successfully',
146
+ };
147
+ }
148
+ catch (error) {
149
+ return {
150
+ test: 'OAuth Client Initialization',
151
+ passed: false,
152
+ message: 'Failed to initialize OAuth client',
153
+ error: error instanceof Error ? error.message : 'Unknown error',
154
+ };
155
+ }
156
+ }
157
+ /**
158
+ * Test OAuth URL generation
159
+ */
160
+ function validateOAuthURL(config) {
161
+ try {
162
+ if (!config.redirectUri) {
163
+ return {
164
+ test: 'OAuth URL Generation',
165
+ passed: false,
166
+ message: 'Redirect URI is required for OAuth URL generation',
167
+ error: 'EBAY_REDIRECT_URI is not configured',
168
+ };
169
+ }
170
+ const url = getOAuthAuthorizationUrl(config.clientId, config.redirectUri, config.environment);
171
+ if (!url.startsWith('http')) {
172
+ return {
173
+ test: 'OAuth URL Generation',
174
+ passed: false,
175
+ message: 'Invalid OAuth URL generated',
176
+ error: 'Generated URL is not valid',
177
+ };
178
+ }
179
+ return {
180
+ test: 'OAuth URL Generation',
181
+ passed: true,
182
+ message: 'OAuth URL can be generated',
183
+ };
184
+ }
185
+ catch (error) {
186
+ return {
187
+ test: 'OAuth URL Generation',
188
+ passed: false,
189
+ message: 'Failed to generate OAuth URL',
190
+ error: error instanceof Error ? error.message : 'Unknown error',
191
+ };
192
+ }
193
+ }
194
+ /**
195
+ * Run all validation tests
196
+ */
197
+ export async function validateSetup(projectRoot) {
198
+ const results = [];
199
+ console.log(chalk.bold.cyan('\n🧪 Running Configuration Tests...\n'));
200
+ // Test 1: .env file exists
201
+ const envFileResult = validateEnvFile(projectRoot);
202
+ results.push(envFileResult);
203
+ printResult(envFileResult);
204
+ if (!envFileResult.passed) {
205
+ return {
206
+ totalTests: 1,
207
+ passed: 0,
208
+ failed: 1,
209
+ results,
210
+ };
211
+ }
212
+ // Parse .env file
213
+ const envPath = join(projectRoot, '.env');
214
+ const envVars = parseEnvFile(envPath);
215
+ // Test 2: App credentials
216
+ const appCredsResult = validateAppCredentials(envVars);
217
+ results.push(appCredsResult);
218
+ printResult(appCredsResult);
219
+ // Test 3: Environment setting
220
+ const envResult = validateEnvironment(envVars);
221
+ results.push(envResult);
222
+ printResult(envResult);
223
+ // Test 4: User tokens (optional)
224
+ const userTokensResult = validateUserTokens(envVars);
225
+ results.push(userTokensResult);
226
+ printResult(userTokensResult);
227
+ // If app credentials are valid, test OAuth functionality
228
+ if (appCredsResult.passed) {
229
+ const config = {
230
+ clientId: envVars.EBAY_CLIENT_ID,
231
+ clientSecret: envVars.EBAY_CLIENT_SECRET,
232
+ redirectUri: envVars.EBAY_REDIRECT_URI,
233
+ environment: (envVars.EBAY_ENVIRONMENT || 'sandbox'),
234
+ };
235
+ // Test 5: OAuth initialization
236
+ const oauthInitResult = await validateOAuthInitialization(config);
237
+ results.push(oauthInitResult);
238
+ printResult(oauthInitResult);
239
+ // Test 6: OAuth URL generation
240
+ if (oauthInitResult.passed) {
241
+ const oauthURLResult = validateOAuthURL(config);
242
+ results.push(oauthURLResult);
243
+ printResult(oauthURLResult);
244
+ }
245
+ }
246
+ // Calculate summary
247
+ const passed = results.filter((r) => r.passed).length;
248
+ const failed = results.length - passed;
249
+ // Print summary
250
+ console.log(chalk.gray('\n' + '─'.repeat(60)));
251
+ console.log(chalk.bold.white('\n📊 Validation Summary\n'));
252
+ console.log(` Total Tests: ${results.length}`);
253
+ console.log(` ${chalk.green('✓ Passed:')} ${passed}`);
254
+ console.log(` ${chalk.red('✗ Failed:')} ${failed}`);
255
+ if (failed === 0) {
256
+ console.log(chalk.green.bold('\n✨ All tests passed! Configuration is valid.\n'));
257
+ }
258
+ else {
259
+ console.log(chalk.yellow.bold('\n⚠️ Some tests failed. Please review the errors above.\n'));
260
+ }
261
+ return {
262
+ totalTests: results.length,
263
+ passed,
264
+ failed,
265
+ results,
266
+ };
267
+ }
268
+ /**
269
+ * Print a single validation result
270
+ */
271
+ function printResult(result) {
272
+ const icon = result.passed ? chalk.green('✓') : chalk.red('✗');
273
+ const status = result.passed ? chalk.green('PASS') : chalk.red('FAIL');
274
+ console.log(`${icon} ${chalk.bold(result.test)}: ${status}`);
275
+ console.log(` ${chalk.gray(result.message)}`);
276
+ if (result.error) {
277
+ console.log(` ${chalk.yellow('→')} ${chalk.yellow(result.error)}`);
278
+ }
279
+ console.log('');
280
+ }
281
+ /**
282
+ * Display recommendations based on validation results
283
+ */
284
+ export function displayRecommendations(summary) {
285
+ const hasUserTokens = summary.results.some((r) => r.test === 'User Tokens' && r.passed && !r.error);
286
+ console.log(chalk.bold.cyan('💡 Recommendations:\n'));
287
+ if (!hasUserTokens) {
288
+ console.log(chalk.yellow(' ⚠️ User tokens not configured'));
289
+ console.log(chalk.gray(' • You can only use app token for limited API access'));
290
+ console.log(chalk.gray(' • To enable full API access, use the ebay_get_oauth_url tool'));
291
+ console.log(chalk.gray(' • Then save your refresh token to EBAY_USER_REFRESH_TOKEN in .env\n'));
292
+ }
293
+ if (summary.failed > 0) {
294
+ console.log(chalk.red(' ❌ Configuration has errors'));
295
+ console.log(chalk.gray(' • Review the failed tests above'));
296
+ console.log(chalk.gray(' • Update your .env file with correct values'));
297
+ console.log(chalk.gray(' • Run the setup wizard again: npm run setup\n'));
298
+ }
299
+ else {
300
+ console.log(chalk.green(' ✅ Configuration is complete and valid'));
301
+ console.log(chalk.gray(' • Restart your MCP client (Claude Desktop, Cline, etc.)'));
302
+ console.log(chalk.gray(' • The eBay MCP server should now be available'));
303
+ console.log(chalk.gray(' • Try using tools like: ebay_get_user, ebay_get_oauth_url\n'));
304
+ }
305
+ }
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schemas for token utility tools
4
+ */
5
+ export const ConvertDateToTimestampSchema = z
6
+ .object({
7
+ dateInput: z
8
+ .union([z.string(), z.number()])
9
+ .describe('Date to convert. Supports ISO 8601 strings (e.g., "2025-01-15T10:30:00Z"), Unix timestamps (seconds or milliseconds), or relative time (e.g., "in 2 hours")'),
10
+ })
11
+ .passthrough();
12
+ export const ValidateTokenExpirySchema = z
13
+ .object({
14
+ accessTokenExpiry: z
15
+ .union([z.string(), z.number()])
16
+ .describe('Access token expiry time. Can be ISO date string, Unix timestamp (seconds or milliseconds), or relative time'),
17
+ refreshTokenExpiry: z
18
+ .union([z.string(), z.number()])
19
+ .describe('Refresh token expiry time. Can be ISO date string, Unix timestamp (seconds or milliseconds), or relative time'),
20
+ })
21
+ .passthrough();
22
+ export const SetUserTokensWithExpirySchema = z
23
+ .object({
24
+ accessToken: z.string().min(1).describe('eBay user access token'),
25
+ refreshToken: z.string().min(1).describe('eBay user refresh token'),
26
+ accessTokenExpiry: z
27
+ .union([z.string(), z.number()])
28
+ .optional()
29
+ .describe("Optional: Access token expiry time. If not provided, defaults to 2 hours from now. Can be ISO date string, Unix timestamp, or relative time (e.g., 'in 7200 seconds')"),
30
+ refreshTokenExpiry: z
31
+ .union([z.string(), z.number()])
32
+ .optional()
33
+ .describe('Optional: Refresh token expiry time. If not provided, defaults to 18 months from now. Can be ISO date string, Unix timestamp, or relative time'),
34
+ autoRefresh: z
35
+ .boolean()
36
+ .optional()
37
+ .default(true)
38
+ .describe('If true and access token is expired but refresh token is valid, automatically refresh the access token. Default: true'),
39
+ })
40
+ .passthrough();
@@ -0,0 +1,56 @@
1
+ import { readFileSync } from 'fs';
2
+ import { fileURLToPath } from 'url';
3
+ import { dirname, join } from 'path';
4
+ import updateNotifier from 'update-notifier';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ const PACKAGE_JSON_PATH = join(__dirname, '../../package.json');
8
+ let cachedPackageJson = null;
9
+ export function getPackageJson() {
10
+ if (cachedPackageJson) {
11
+ return cachedPackageJson;
12
+ }
13
+ try {
14
+ const content = readFileSync(PACKAGE_JSON_PATH, 'utf-8');
15
+ cachedPackageJson = JSON.parse(content);
16
+ return cachedPackageJson;
17
+ }
18
+ catch {
19
+ return { name: 'ebay-mcp-remote-edition', version: '1.0.0' };
20
+ }
21
+ }
22
+ export function getVersion() {
23
+ return getPackageJson().version;
24
+ }
25
+ export function getPackageName() {
26
+ return getPackageJson().name;
27
+ }
28
+ const ONE_DAY_MS = 1000 * 60 * 60 * 24;
29
+ export function checkForUpdates(options = {}) {
30
+ const pkg = getPackageJson();
31
+ const notifier = updateNotifier({
32
+ pkg,
33
+ updateCheckInterval: ONE_DAY_MS,
34
+ });
35
+ notifier.notify({
36
+ isGlobal: true,
37
+ defer: options.defer ?? false,
38
+ message: 'Update available {currentVersion} → {latestVersion}\n' + 'Run {updateCommand} to update',
39
+ });
40
+ }
41
+ export async function getUpdateInfo() {
42
+ const pkg = getPackageJson();
43
+ const notifier = updateNotifier({
44
+ pkg,
45
+ updateCheckInterval: 0,
46
+ });
47
+ await notifier.fetchInfo();
48
+ if (notifier.update && notifier.update.latest !== pkg.version) {
49
+ return {
50
+ current: pkg.version,
51
+ latest: notifier.update.latest,
52
+ name: pkg.name,
53
+ };
54
+ }
55
+ return undefined;
56
+ }