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/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://mseep.ai/app/yosefhayim-ebay-api-mcp-server)
|
|
12
12
|
<a href="https://www.buymeacoffee.com/yosefhayim" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
|
13
13
|
|
|
14
|
-
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server providing AI assistants with comprehensive access to eBay's Sell APIs. Includes **
|
|
14
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server providing AI assistants with comprehensive access to eBay's Sell APIs. Includes **325 tools** for inventory management, order fulfillment, marketing campaigns, analytics, developer tools, and more.
|
|
15
15
|
|
|
16
16
|
**API Coverage:** 100% (270 unique eBay API endpoints)
|
|
17
17
|
|
|
@@ -113,7 +113,7 @@ For official eBay API support, please refer to the [eBay Developer Program](http
|
|
|
113
113
|
|
|
114
114
|
## Features
|
|
115
115
|
|
|
116
|
-
- **
|
|
116
|
+
- **325 eBay API Tools** - 100% coverage of eBay Sell APIs across inventory, orders, marketing, analytics, developer tools, and more
|
|
117
117
|
- **9 AI Clients Supported** - Auto-configuration for Claude Desktop, Cursor, Zed, Cline, Continue.dev, Windsurf, Roo Code, Claude Code CLI, and Amazon Q
|
|
118
118
|
- **OAuth 2.0 Support** - Full user token management with automatic refresh
|
|
119
119
|
- **Type Safety** - Built with TypeScript, Zod validation, and OpenAPI-generated types
|
|
@@ -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
|
|
|
@@ -260,7 +262,7 @@ This server supports **9 AI clients** with auto-configuration via `npm run setup
|
|
|
260
262
|
|
|
261
263
|
```bash
|
|
262
264
|
npm install -g ebay-mcp
|
|
263
|
-
npx ebay-mcp # Interactive setup wizard - auto-detects installed clients
|
|
265
|
+
npx ebay-mcp setup # Interactive setup wizard - auto-detects installed clients
|
|
264
266
|
```
|
|
265
267
|
|
|
266
268
|
The setup wizard will automatically detect which AI clients you have installed and configure them for you.
|
|
@@ -310,7 +312,7 @@ Monitor your API usage in the [eBay Developer Portal](https://developer.ebay.com
|
|
|
310
312
|
|
|
311
313
|
## Available Tools
|
|
312
314
|
|
|
313
|
-
The server provides **
|
|
315
|
+
The server provides **325 tools** with **100% API coverage** organized into the following categories:
|
|
314
316
|
|
|
315
317
|
- **Account Management** - Policies, programs, subscriptions, sales tax
|
|
316
318
|
- **Inventory Management** - Items, offers, locations, bulk operations, SKU location mapping
|
|
@@ -564,7 +566,7 @@ Log files are stored in `~/.ebay-mcp/logs/`:
|
|
|
564
566
|
|
|
565
567
|
1. Verify you're using the correct environment (sandbox vs production)
|
|
566
568
|
2. Ensure you have proper permissions/scopes for the operation
|
|
567
|
-
3. Check
|
|
569
|
+
3. Check current API status with the `ebay_get_api_status` tool or the [eBay API Status](https://developer.ebay.com/support/api-status) page
|
|
568
570
|
4. Run `npm run diagnose` to check your configuration
|
|
569
571
|
5. Review the [eBay API documentation](https://developer.ebay.com/docs) for endpoint requirements
|
|
570
572
|
|
|
@@ -602,12 +604,20 @@ If you're still experiencing issues:
|
|
|
602
604
|
|
|
603
605
|
## Resources
|
|
604
606
|
|
|
607
|
+
### API Status
|
|
608
|
+
|
|
609
|
+
Check current eBay API health, incidents, and fixes:
|
|
610
|
+
|
|
611
|
+
- [eBay API Status](https://developer.ebay.com/support/api-status) - Official status page
|
|
612
|
+
- [API Status RSS feed](https://developer.ebay.com/rss/api-status) - Latest issues and resolutions (XML)
|
|
613
|
+
- **`ebay_get_api_status`** - MCP tool that returns the latest items from this feed (filter by status or API name, optional limit)
|
|
614
|
+
- [Latest snapshot (auto-updated)](docs/API_STATUS.md) - In-repo digest of recent status items
|
|
615
|
+
|
|
605
616
|
### Documentation
|
|
606
617
|
|
|
607
618
|
- [eBay Developer Portal](https://developer.ebay.com/) - API documentation and credentials
|
|
608
619
|
- [eBay API License Agreement](https://developer.ebay.com/join/api-license-agreement) - Terms of use and compliance requirements
|
|
609
620
|
- [eBay Data Handling Requirements](https://developer.ebay.com/api-docs/static/data-handling-update.html) - Important data protection and privacy guidelines
|
|
610
|
-
- [eBay API Status](https://developer.ebay.com/support/api-status) - Real-time API health and status
|
|
611
621
|
- [MCP Documentation](https://modelcontextprotocol.io/) - Model Context Protocol specification
|
|
612
622
|
- [OAuth Quick Reference](docs/auth/OAUTH_QUICK_REFERENCE.md) - **Complete OAuth authentication guide with scopes, troubleshooting, and examples**
|
|
613
623
|
- [OAuth Setup Guide](docs/auth/) - Detailed authentication configuration
|
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) => {
|
|
@@ -149,7 +162,9 @@ export class EbayApiClient {
|
|
|
149
162
|
attempt: `${retryCount + 1}/3`,
|
|
150
163
|
delayMs: Math.min(delay, 5000),
|
|
151
164
|
});
|
|
152
|
-
await new Promise((resolve) =>
|
|
165
|
+
await new Promise((resolve) => {
|
|
166
|
+
setTimeout(resolve, Math.min(delay, 5000));
|
|
167
|
+
});
|
|
153
168
|
return await this.httpClient.request(config);
|
|
154
169
|
}
|
|
155
170
|
}
|
|
@@ -168,8 +183,8 @@ export class EbayApiClient {
|
|
|
168
183
|
* Validate that access token is available before making API request
|
|
169
184
|
*/
|
|
170
185
|
validateAccessToken() {
|
|
171
|
-
if (!this.
|
|
172
|
-
throw new Error('
|
|
186
|
+
if (!this.config.clientId || !this.config.clientSecret) {
|
|
187
|
+
throw new Error('Missing required eBay credentials. Please set EBAY_CLIENT_ID and EBAY_CLIENT_SECRET in your .env file.');
|
|
173
188
|
}
|
|
174
189
|
}
|
|
175
190
|
/**
|
|
@@ -225,8 +240,8 @@ export class EbayApiClient {
|
|
|
225
240
|
/**
|
|
226
241
|
* Set user access and refresh tokens
|
|
227
242
|
*/
|
|
228
|
-
async setUserTokens(accessToken, refreshToken) {
|
|
229
|
-
|
|
243
|
+
async setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry) {
|
|
244
|
+
this.authClient.setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry);
|
|
230
245
|
}
|
|
231
246
|
/**
|
|
232
247
|
* Get token information for debugging
|
|
@@ -281,8 +296,7 @@ export class EbayApiClient {
|
|
|
281
296
|
params,
|
|
282
297
|
headers: {
|
|
283
298
|
Authorization: `Bearer ${token}`,
|
|
284
|
-
|
|
285
|
-
Accept: 'application/json',
|
|
299
|
+
...this.getDefaultHeaders(),
|
|
286
300
|
},
|
|
287
301
|
timeout: 30000,
|
|
288
302
|
});
|
|
@@ -303,8 +317,7 @@ export class EbayApiClient {
|
|
|
303
317
|
params,
|
|
304
318
|
headers: {
|
|
305
319
|
Authorization: `Bearer ${token}`,
|
|
306
|
-
|
|
307
|
-
Accept: 'application/json',
|
|
320
|
+
...this.getDefaultHeaders(),
|
|
308
321
|
},
|
|
309
322
|
timeout: 30000,
|
|
310
323
|
});
|
package/build/api/index.js
CHANGED
|
@@ -87,8 +87,8 @@ export class EbaySellerApi {
|
|
|
87
87
|
/**
|
|
88
88
|
* Set user access and refresh tokens
|
|
89
89
|
*/
|
|
90
|
-
async setUserTokens(accessToken, refreshToken) {
|
|
91
|
-
await this.client.setUserTokens(accessToken, refreshToken);
|
|
90
|
+
async setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry) {
|
|
91
|
+
await this.client.setUserTokens(accessToken, refreshToken, accessTokenExpiry, refreshTokenExpiry);
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
94
|
* Get OAuth client for advanced operations
|
|
@@ -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'}`);
|
|
@@ -18,7 +18,7 @@ export class IdentityApi {
|
|
|
18
18
|
async getUser() {
|
|
19
19
|
const config = this.client.getConfig();
|
|
20
20
|
const identityBaseUrl = getIdentityBaseUrl(config.environment);
|
|
21
|
-
const fullUrl = `${identityBaseUrl}${this.basePath}/user
|
|
21
|
+
const fullUrl = `${identityBaseUrl}${this.basePath}/user`;
|
|
22
22
|
return await this.client.getWithFullUrl(fullUrl);
|
|
23
23
|
}
|
|
24
24
|
}
|
package/build/auth/oauth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { getBaseUrl, getDefaultScopes } from '../config/environment.js';
|
|
3
3
|
import { LocaleEnum } from '../types/ebay-enums.js';
|
|
4
|
-
import { readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { authLogger } from '../utils/logger.js';
|
|
7
7
|
/**
|
|
@@ -10,7 +10,7 @@ import { authLogger } from '../utils/logger.js';
|
|
|
10
10
|
function updateEnvFile(updates) {
|
|
11
11
|
try {
|
|
12
12
|
const envPath = join(process.cwd(), '.env');
|
|
13
|
-
let envContent = readFileSync(envPath, 'utf-8');
|
|
13
|
+
let envContent = existsSync(envPath) ? readFileSync(envPath, 'utf-8') : '';
|
|
14
14
|
// Update each key-value pair
|
|
15
15
|
for (const [key, value] of Object.entries(updates)) {
|
|
16
16
|
// Match the key with or without value, handling comments
|
|
@@ -28,7 +28,7 @@ function updateEnvFile(updates) {
|
|
|
28
28
|
writeFileSync(envPath, envContent, 'utf-8');
|
|
29
29
|
// Tokens updated silently - console output interferes with MCP JSON protocol
|
|
30
30
|
}
|
|
31
|
-
catch (
|
|
31
|
+
catch (_error) {
|
|
32
32
|
// Silent failure - error logging interferes with MCP JSON protocol
|
|
33
33
|
// If needed, check .env file manually
|
|
34
34
|
}
|
|
@@ -180,7 +180,7 @@ export class EbayOAuthClient {
|
|
|
180
180
|
*/
|
|
181
181
|
async getOrRefreshAppAccessToken() {
|
|
182
182
|
// Return cached token if still valid
|
|
183
|
-
if (this.appAccessToken) {
|
|
183
|
+
if (this.appAccessToken && Date.now() < this.appAccessTokenExpiry) {
|
|
184
184
|
return this.appAccessToken;
|
|
185
185
|
}
|
|
186
186
|
const authUrl = `${getBaseUrl(this.config.environment)}/identity/v1/oauth2/token`;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { config } from 'dotenv';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
5
|
import { LocaleEnum } from '../types/ebay-enums.js';
|
|
6
|
+
import { getVersion } from '../utils/version.js';
|
|
6
7
|
// Load .env silently - suppress dotenv output to keep stdout clean for MCP JSON-RPC
|
|
7
8
|
config({ quiet: true });
|
|
8
9
|
// Get the current directory for loading scope files
|
|
@@ -58,7 +59,10 @@ function getSandboxScopes() {
|
|
|
58
59
|
* Get default scopes for the specified environment
|
|
59
60
|
*/
|
|
60
61
|
export function getDefaultScopes(environment) {
|
|
61
|
-
|
|
62
|
+
if (environment === 'production') {
|
|
63
|
+
return getProductionScopes();
|
|
64
|
+
}
|
|
65
|
+
return getSandboxScopes();
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
64
68
|
* Validate scopes against environment and return warnings for invalid scopes
|
|
@@ -134,6 +138,9 @@ export function validateEnvironmentConfig() {
|
|
|
134
138
|
errors,
|
|
135
139
|
};
|
|
136
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Build EbayConfig from environment variables with safe defaults.
|
|
143
|
+
*/
|
|
137
144
|
export function getEbayConfig() {
|
|
138
145
|
const clientId = process.env.EBAY_CLIENT_ID ?? '';
|
|
139
146
|
const clientSecret = process.env.EBAY_CLIENT_SECRET ?? '';
|
|
@@ -141,6 +148,8 @@ export function getEbayConfig() {
|
|
|
141
148
|
const accessToken = process.env.EBAY_USER_ACCESS_TOKEN ?? '';
|
|
142
149
|
const refreshToken = process.env.EBAY_USER_REFRESH_TOKEN ?? '';
|
|
143
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';
|
|
144
153
|
// Only require client credentials - tokens can be optional (generated from refresh token)
|
|
145
154
|
if (clientId === '' || clientSecret === '') {
|
|
146
155
|
console.error('Missing required eBay credentials. Please set:\n1) EBAY_CLIENT_ID\n2) EBAY_CLIENT_SECRET\nin your .env file at project root');
|
|
@@ -149,6 +158,8 @@ export function getEbayConfig() {
|
|
|
149
158
|
clientId,
|
|
150
159
|
clientSecret,
|
|
151
160
|
redirectUri: process.env.EBAY_REDIRECT_URI,
|
|
161
|
+
marketplaceId,
|
|
162
|
+
contentLanguage,
|
|
152
163
|
environment,
|
|
153
164
|
accessToken,
|
|
154
165
|
refreshToken,
|
|
@@ -172,23 +183,23 @@ export function getAuthUrl(clientIdOrEnvironment, redirectUri, environment, loca
|
|
|
172
183
|
}
|
|
173
184
|
// Otherwise, generate the full OAuth authorization URL
|
|
174
185
|
const clientId = clientIdOrEnvironment;
|
|
175
|
-
const env = environment
|
|
186
|
+
const env = environment ?? 'sandbox';
|
|
176
187
|
const scope = getDefaultScopes(env);
|
|
177
188
|
if (!(clientId && redirectUri)) {
|
|
178
189
|
console.error('clientId, redirectUri (RuName), and scope are required,please initialize the class properly.');
|
|
179
190
|
return '';
|
|
180
191
|
}
|
|
181
|
-
const
|
|
182
|
-
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({
|
|
183
195
|
client_id: clientId,
|
|
184
196
|
redirect_uri: redirectUri,
|
|
185
197
|
response_type: responseType,
|
|
186
|
-
scope: scopes?.join(' ') || scope.join(' '),
|
|
187
198
|
prompt,
|
|
188
199
|
locale,
|
|
189
200
|
...(state ? { state } : {}),
|
|
190
201
|
});
|
|
191
|
-
return `${
|
|
202
|
+
return `${authBase}/oauth2/authorize?${authorizeParams.toString()}&scope=${scopeList}`;
|
|
192
203
|
}
|
|
193
204
|
/**
|
|
194
205
|
* Generate the OAuth authorization URL for user consent
|
|
@@ -199,62 +210,69 @@ export function getAuthUrl(clientIdOrEnvironment, redirectUri, environment, loca
|
|
|
199
210
|
*/
|
|
200
211
|
export function getOAuthAuthorizationUrl(clientId, redirectUri, // MUST be eBay RuName, NOT a URL
|
|
201
212
|
environment, scopes, locale, state) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const authorizeEndpoint = `${authDomain}/oauth2/authorize`;
|
|
205
|
-
// Build query parameters for the authorize endpoint
|
|
206
|
-
const params = new URLSearchParams({
|
|
207
|
-
client_id: clientId,
|
|
208
|
-
redirect_uri: redirectUri,
|
|
209
|
-
});
|
|
210
|
-
// 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;
|
|
211
215
|
if (scopes && scopes.length > 0) {
|
|
212
|
-
|
|
216
|
+
scopeList = scopes.join('%20');
|
|
213
217
|
}
|
|
214
218
|
else {
|
|
215
|
-
// Use default scopes for the environment if no scopes are specified
|
|
216
219
|
const defaultScopes = getDefaultScopes(environment);
|
|
217
|
-
|
|
220
|
+
scopeList = defaultScopes.join('%20');
|
|
218
221
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const signinDomain = environment === 'production' ? 'https://signin.ebay.com' : 'https://signin.sandbox.ebay.com';
|
|
227
|
-
const ruParam = encodeURIComponent(`${authorizeEndpoint}?${params.toString()}`);
|
|
228
|
-
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}`;
|
|
229
229
|
}
|
|
230
|
+
const iconUrl = (size) => {
|
|
231
|
+
const url = new URL(`../../public/icons/${size}.png`, import.meta.url);
|
|
232
|
+
const path = fileURLToPath(url);
|
|
233
|
+
if (!existsSync(path)) {
|
|
234
|
+
console.warn(`[eBay MCP] Icon not found at ${path}. Ensure public/icons is included in the package.`);
|
|
235
|
+
}
|
|
236
|
+
return url.toString();
|
|
237
|
+
};
|
|
230
238
|
export const mcpConfig = {
|
|
231
239
|
name: 'eBay API Model Context Protocol Server',
|
|
232
|
-
version:
|
|
240
|
+
version: getVersion(),
|
|
233
241
|
title: 'eBay API Model Context Protocol Server',
|
|
234
|
-
websiteUrl: 'https://github.com/
|
|
242
|
+
websiteUrl: 'https://github.com/YosefHayim/ebay-mcp',
|
|
235
243
|
icons: [
|
|
236
244
|
{
|
|
237
|
-
src: '
|
|
245
|
+
src: iconUrl('16x16'),
|
|
246
|
+
mimeType: 'image/png',
|
|
247
|
+
sizes: ['16x16'],
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
src: iconUrl('32x32'),
|
|
251
|
+
mimeType: 'image/png',
|
|
252
|
+
sizes: ['32x32'],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
src: iconUrl('48x48'),
|
|
238
256
|
mimeType: 'image/png',
|
|
239
257
|
sizes: ['48x48'],
|
|
240
258
|
},
|
|
241
259
|
{
|
|
242
|
-
src: '
|
|
260
|
+
src: iconUrl('128x128'),
|
|
243
261
|
mimeType: 'image/png',
|
|
244
262
|
sizes: ['128x128'],
|
|
245
263
|
},
|
|
246
264
|
{
|
|
247
|
-
src: '
|
|
265
|
+
src: iconUrl('256x256'),
|
|
248
266
|
mimeType: 'image/png',
|
|
249
267
|
sizes: ['256x256'],
|
|
250
268
|
},
|
|
251
269
|
{
|
|
252
|
-
src: '
|
|
270
|
+
src: iconUrl('512x512'),
|
|
253
271
|
mimeType: 'image/png',
|
|
254
272
|
sizes: ['512x512'],
|
|
255
273
|
},
|
|
256
274
|
{
|
|
257
|
-
src: '
|
|
275
|
+
src: iconUrl('1024x1024'),
|
|
258
276
|
mimeType: 'image/png',
|
|
259
277
|
sizes: ['1024x1024'],
|
|
260
278
|
},
|
package/build/index.js
CHANGED
|
@@ -5,6 +5,20 @@ import { EbaySellerApi } from './api/index.js';
|
|
|
5
5
|
import { getEbayConfig, mcpConfig, validateEnvironmentConfig } from './config/environment.js';
|
|
6
6
|
import { getToolDefinitions, executeTool } from './tools/index.js';
|
|
7
7
|
import { serverLogger, toolLogger, getLogPaths } from './utils/logger.js';
|
|
8
|
+
import { checkForUpdates } from './utils/version.js';
|
|
9
|
+
checkForUpdates({ defer: true });
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
if (args.includes('setup')) {
|
|
12
|
+
try {
|
|
13
|
+
const { runSetup } = await import('./scripts/setup.js');
|
|
14
|
+
await runSetup();
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error('Setup failed:', error instanceof Error ? error.message : error);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
8
22
|
/**
|
|
9
23
|
* eBay API MCP Server
|
|
10
24
|
* Provides access to eBay APIs through Model Context Protocol
|
|
@@ -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: '',
|