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.
- package/LICENSE +21 -0
- package/README.md +755 -0
- package/build/api/account-management/account.js +301 -0
- package/build/api/analytics-and-report/analytics.js +102 -0
- package/build/api/client-trading.js +96 -0
- package/build/api/client.js +173 -0
- package/build/api/communication/feedback.js +119 -0
- package/build/api/communication/message.js +131 -0
- package/build/api/communication/negotiation.js +97 -0
- package/build/api/communication/notification.js +373 -0
- package/build/api/developer/developer.js +81 -0
- package/build/api/index.js +109 -0
- package/build/api/listing-management/inventory.js +640 -0
- package/build/api/listing-metadata/metadata.js +485 -0
- package/build/api/listing-metadata/taxonomy.js +58 -0
- package/build/api/marketing-and-promotions/marketing.js +768 -0
- package/build/api/marketing-and-promotions/recommendation.js +32 -0
- package/build/api/order-management/dispute.js +69 -0
- package/build/api/order-management/fulfillment.js +89 -0
- package/build/api/other/compliance.js +47 -0
- package/build/api/other/edelivery.js +219 -0
- package/build/api/other/identity.js +24 -0
- package/build/api/other/translation.js +22 -0
- package/build/api/other/vero.js +48 -0
- package/build/api/trading/trading.js +78 -0
- package/build/auth/kv-store.js +40 -0
- package/build/auth/multi-user-store.js +120 -0
- package/build/auth/oauth-metadata.js +59 -0
- package/build/auth/oauth-middleware.js +99 -0
- package/build/auth/oauth-types.js +4 -0
- package/build/auth/oauth.js +235 -0
- package/build/auth/scope-utils.js +304 -0
- package/build/auth/token-store.js +46 -0
- package/build/auth/token-verifier.js +172 -0
- package/build/config/environment.js +297 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +129 -0
- package/build/schemas/account-management/account.js +375 -0
- package/build/schemas/analytics/analytics.js +191 -0
- package/build/schemas/communication/messages.js +345 -0
- package/build/schemas/fulfillment/orders.js +338 -0
- package/build/schemas/index.js +68 -0
- package/build/schemas/inventory-management/inventory.js +471 -0
- package/build/schemas/marketing/marketing.js +1103 -0
- package/build/schemas/metadata/metadata.js +618 -0
- package/build/schemas/other/other-apis.js +390 -0
- package/build/schemas/taxonomy/taxonomy.js +575 -0
- package/build/scripts/auto-setup.js +364 -0
- package/build/scripts/dev-sync.js +512 -0
- package/build/scripts/diagnostics.js +301 -0
- package/build/scripts/download-specs.js +116 -0
- package/build/scripts/interactive-setup.js +757 -0
- package/build/scripts/setup.js +1515 -0
- package/build/scripts/update-api-status-doc.js +44 -0
- package/build/server-http.d.ts +1 -0
- package/build/server-http.js +581 -0
- package/build/tools/definitions/account-with-schemas.js +170 -0
- package/build/tools/definitions/account.js +428 -0
- package/build/tools/definitions/analytics.js +66 -0
- package/build/tools/definitions/communication.js +394 -0
- package/build/tools/definitions/developer.js +195 -0
- package/build/tools/definitions/fulfillment.js +326 -0
- package/build/tools/definitions/index.js +41 -0
- package/build/tools/definitions/inventory.js +464 -0
- package/build/tools/definitions/marketing.js +1486 -0
- package/build/tools/definitions/metadata.js +188 -0
- package/build/tools/definitions/other.js +309 -0
- package/build/tools/definitions/taxonomy.js +64 -0
- package/build/tools/definitions/token-management.js +148 -0
- package/build/tools/definitions/trading.js +71 -0
- package/build/tools/index.js +1200 -0
- package/build/tools/schemas.js +667 -0
- package/build/tools/tool-definitions.js +3534 -0
- package/build/types/application-settings/developerAnalyticsV1BetaOas3.js +5 -0
- package/build/types/application-settings/developerClientRegistrationV1Oas3.js +5 -0
- package/build/types/application-settings/developerKeyManagementV1Oas3.js +5 -0
- package/build/types/ebay-enums.js +1330 -0
- package/build/types/ebay.js +123 -0
- package/build/types/index.js +10 -0
- package/build/types/sell-apps/account-management/sellAccountV1Oas3.js +5 -0
- package/build/types/sell-apps/analytics-and-report/sellAnalyticsV1Oas3.js +5 -0
- package/build/types/sell-apps/communication/commerceFeedbackV1BetaOas3.js +5 -0
- package/build/types/sell-apps/communication/commerceMessageV1Oas3.js +5 -0
- package/build/types/sell-apps/communication/commerceNotificationV1Oas3.js +5 -0
- package/build/types/sell-apps/communication/sellNegotiationV1Oas3.js +5 -0
- package/build/types/sell-apps/listing-management/sellInventoryV1Oas3.js +5 -0
- package/build/types/sell-apps/listing-metadata/sellMetadataV1Oas3.js +5 -0
- package/build/types/sell-apps/markeitng-and-promotions/sellMarketingV1Oas3.js +5 -0
- package/build/types/sell-apps/markeitng-and-promotions/sellRecommendationV1Oas3.js +5 -0
- package/build/types/sell-apps/order-management/sellFulfillmentV1Oas3.js +5 -0
- package/build/types/sell-apps/other-apis/commerceIdentityV1Oas3.js +5 -0
- package/build/types/sell-apps/other-apis/commerceTranslationV1BetaOas3.js +5 -0
- package/build/types/sell-apps/other-apis/commerceVeroV1Oas3.js +5 -0
- package/build/types/sell-apps/other-apis/sellComplianceV1Oas3.js +5 -0
- package/build/types/sell-apps/other-apis/sellEdeliveryInternationalShippingOas3.js +5 -0
- package/build/types/sell-apps/other-apis/sellMarketingV1Oas3.js +5 -0
- package/build/types/sell-apps/other-apis/sellRecommendationV1Oas3.js +5 -0
- package/build/utils/account-management/account.js +831 -0
- package/build/utils/api-status-feed.js +83 -0
- package/build/utils/communication/feedback.js +216 -0
- package/build/utils/communication/message.js +242 -0
- package/build/utils/communication/negotiation.js +150 -0
- package/build/utils/communication/notification.js +369 -0
- package/build/utils/date-converter.js +160 -0
- package/build/utils/llm-client-detector.js +758 -0
- package/build/utils/logger.js +198 -0
- package/build/utils/oauth-helper.js +315 -0
- package/build/utils/order-management/dispute.js +369 -0
- package/build/utils/order-management/fulfillment.js +205 -0
- package/build/utils/other/compliance.js +76 -0
- package/build/utils/other/edelivery.js +241 -0
- package/build/utils/other/identity.js +13 -0
- package/build/utils/other/translation.js +41 -0
- package/build/utils/other/vero.js +90 -0
- package/build/utils/scope-helper.js +207 -0
- package/build/utils/security-checker.js +248 -0
- package/build/utils/setup-validator.js +305 -0
- package/build/utils/token-utils.js +40 -0
- package/build/utils/version.js +56 -0
- package/docs/auth/production_scopes.json +111 -0
- package/docs/auth/sandbox_scopes.json +142 -0
- package/package.json +122 -0
- 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
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
/**
|
|
6
|
+
* Log directory for eBay MCP Server
|
|
7
|
+
* Stored in user's home directory under .ebay-mcp-remote-edition/logs
|
|
8
|
+
*/
|
|
9
|
+
const LOG_DIR = join(homedir(), '.ebay-mcp-remote-edition', 'logs');
|
|
10
|
+
// Ensure log directory exists
|
|
11
|
+
if (!existsSync(LOG_DIR)) {
|
|
12
|
+
mkdirSync(LOG_DIR, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Log level from environment variable or default to 'info'
|
|
16
|
+
* Levels: error, warn, info, http, verbose, debug, silly
|
|
17
|
+
*/
|
|
18
|
+
const LOG_LEVEL = process.env.EBAY_LOG_LEVEL || 'info';
|
|
19
|
+
/**
|
|
20
|
+
* Whether to enable file logging (disabled in production MCP mode by default)
|
|
21
|
+
*/
|
|
22
|
+
const ENABLE_FILE_LOGGING = process.env.EBAY_ENABLE_FILE_LOGGING === 'true';
|
|
23
|
+
/**
|
|
24
|
+
* Custom log format with timestamp and colored output
|
|
25
|
+
*/
|
|
26
|
+
const consoleFormat = winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.printf(({ level, message, timestamp, stack, ...meta }) => {
|
|
27
|
+
const metaStr = Object.keys(meta).length ? `\n${JSON.stringify(meta, null, 2)}` : '';
|
|
28
|
+
const stackStr = typeof stack === 'string' && stack ? `\n${stack}` : '';
|
|
29
|
+
return `[${timestamp}] [${level.toUpperCase()}] ${message}${metaStr}${stackStr}`;
|
|
30
|
+
}));
|
|
31
|
+
/**
|
|
32
|
+
* File format (no colors, JSON for easier parsing)
|
|
33
|
+
*/
|
|
34
|
+
const fileFormat = winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.json());
|
|
35
|
+
/**
|
|
36
|
+
* Create Winston logger transports
|
|
37
|
+
*/
|
|
38
|
+
const transports = [
|
|
39
|
+
// Console transport - always enabled for MCP stderr output
|
|
40
|
+
new winston.transports.Console({
|
|
41
|
+
format: consoleFormat,
|
|
42
|
+
stderrLevels: ['error', 'warn', 'info', 'http', 'verbose', 'debug', 'silly'],
|
|
43
|
+
}),
|
|
44
|
+
];
|
|
45
|
+
// Add file transports if enabled
|
|
46
|
+
if (ENABLE_FILE_LOGGING) {
|
|
47
|
+
transports.push(
|
|
48
|
+
// Error log - only errors
|
|
49
|
+
new winston.transports.File({
|
|
50
|
+
filename: join(LOG_DIR, 'error.log'),
|
|
51
|
+
level: 'error',
|
|
52
|
+
format: fileFormat,
|
|
53
|
+
maxsize: 5 * 1024 * 1024, // 5MB
|
|
54
|
+
maxFiles: 5,
|
|
55
|
+
tailable: true,
|
|
56
|
+
}),
|
|
57
|
+
// Combined log - all levels
|
|
58
|
+
new winston.transports.File({
|
|
59
|
+
filename: join(LOG_DIR, 'combined.log'),
|
|
60
|
+
format: fileFormat,
|
|
61
|
+
maxsize: 10 * 1024 * 1024, // 10MB
|
|
62
|
+
maxFiles: 5,
|
|
63
|
+
tailable: true,
|
|
64
|
+
}),
|
|
65
|
+
// Debug log - verbose and debug messages
|
|
66
|
+
new winston.transports.File({
|
|
67
|
+
filename: join(LOG_DIR, 'debug.log'),
|
|
68
|
+
level: 'debug',
|
|
69
|
+
format: fileFormat,
|
|
70
|
+
maxsize: 10 * 1024 * 1024, // 10MB
|
|
71
|
+
maxFiles: 3,
|
|
72
|
+
tailable: true,
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Main Winston logger instance
|
|
77
|
+
*/
|
|
78
|
+
const logger = winston.createLogger({
|
|
79
|
+
level: LOG_LEVEL,
|
|
80
|
+
transports,
|
|
81
|
+
exitOnError: false,
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Create a child logger for a specific component
|
|
85
|
+
*/
|
|
86
|
+
export function createLogger(component) {
|
|
87
|
+
return {
|
|
88
|
+
error: (message, meta) => {
|
|
89
|
+
logger.error(`[${component}] ${message}`, meta);
|
|
90
|
+
},
|
|
91
|
+
warn: (message, meta) => {
|
|
92
|
+
logger.warn(`[${component}] ${message}`, meta);
|
|
93
|
+
},
|
|
94
|
+
info: (message, meta) => {
|
|
95
|
+
logger.info(`[${component}] ${message}`, meta);
|
|
96
|
+
},
|
|
97
|
+
http: (message, meta) => {
|
|
98
|
+
logger.http(`[${component}] ${message}`, meta);
|
|
99
|
+
},
|
|
100
|
+
debug: (message, meta) => {
|
|
101
|
+
logger.debug(`[${component}] ${message}`, meta);
|
|
102
|
+
},
|
|
103
|
+
verbose: (message, meta) => {
|
|
104
|
+
logger.verbose(`[${component}] ${message}`, meta);
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Pre-configured loggers for different components
|
|
110
|
+
*/
|
|
111
|
+
export const serverLogger = createLogger('Server');
|
|
112
|
+
export const apiLogger = createLogger('API');
|
|
113
|
+
export const authLogger = createLogger('Auth');
|
|
114
|
+
export const toolLogger = createLogger('Tool');
|
|
115
|
+
export const setupLogger = createLogger('Setup');
|
|
116
|
+
/**
|
|
117
|
+
* Log HTTP request details
|
|
118
|
+
*/
|
|
119
|
+
export function logRequest(method, url, params, body) {
|
|
120
|
+
apiLogger.http(`Request: ${method.toUpperCase()} ${url}`, {
|
|
121
|
+
params: params && Object.keys(params).length > 0 ? params : undefined,
|
|
122
|
+
body: body ? truncateData(body) : undefined,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Log HTTP response details
|
|
127
|
+
*/
|
|
128
|
+
export function logResponse(status, statusText, data, rateLimitRemaining, rateLimitTotal) {
|
|
129
|
+
const meta = {};
|
|
130
|
+
if (rateLimitRemaining && rateLimitTotal) {
|
|
131
|
+
meta.rateLimit = `${rateLimitRemaining}/${rateLimitTotal}`;
|
|
132
|
+
}
|
|
133
|
+
if (data) {
|
|
134
|
+
meta.data = truncateData(data);
|
|
135
|
+
}
|
|
136
|
+
apiLogger.http(`Response: ${status} ${statusText}`, meta);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Log HTTP error response
|
|
140
|
+
*/
|
|
141
|
+
export function logErrorResponse(status, statusText, url, errorData) {
|
|
142
|
+
apiLogger.error(`Error Response: ${status || 'N/A'} ${statusText || 'No response'}`, {
|
|
143
|
+
url,
|
|
144
|
+
error: errorData ? truncateData(errorData) : undefined,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Truncate large data objects for logging
|
|
149
|
+
*/
|
|
150
|
+
function truncateData(data, maxLength = 1000) {
|
|
151
|
+
const str = JSON.stringify(data);
|
|
152
|
+
if (str.length <= maxLength) {
|
|
153
|
+
return data;
|
|
154
|
+
}
|
|
155
|
+
return `${str.substring(0, maxLength)}... [truncated]`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get log file paths for user reference
|
|
159
|
+
*/
|
|
160
|
+
export function getLogPaths() {
|
|
161
|
+
return {
|
|
162
|
+
logDir: LOG_DIR,
|
|
163
|
+
errorLog: join(LOG_DIR, 'error.log'),
|
|
164
|
+
combinedLog: join(LOG_DIR, 'combined.log'),
|
|
165
|
+
debugLog: join(LOG_DIR, 'debug.log'),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Enable or disable file logging at runtime
|
|
170
|
+
*/
|
|
171
|
+
export function setFileLogging(enabled) {
|
|
172
|
+
if (enabled && !ENABLE_FILE_LOGGING) {
|
|
173
|
+
logger.add(new winston.transports.File({
|
|
174
|
+
filename: join(LOG_DIR, 'error.log'),
|
|
175
|
+
level: 'error',
|
|
176
|
+
format: fileFormat,
|
|
177
|
+
maxsize: 5 * 1024 * 1024,
|
|
178
|
+
maxFiles: 5,
|
|
179
|
+
tailable: true,
|
|
180
|
+
}));
|
|
181
|
+
logger.add(new winston.transports.File({
|
|
182
|
+
filename: join(LOG_DIR, 'combined.log'),
|
|
183
|
+
format: fileFormat,
|
|
184
|
+
maxsize: 10 * 1024 * 1024,
|
|
185
|
+
maxFiles: 5,
|
|
186
|
+
tailable: true,
|
|
187
|
+
}));
|
|
188
|
+
logger.info('File logging enabled');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Set log level at runtime
|
|
193
|
+
*/
|
|
194
|
+
export function setLogLevel(level) {
|
|
195
|
+
logger.level = level;
|
|
196
|
+
logger.info(`Log level set to: ${level}`);
|
|
197
|
+
}
|
|
198
|
+
export default logger;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth Helper - Assists with eBay OAuth token acquisition
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { createServer } from 'http';
|
|
6
|
+
import { getOAuthAuthorizationUrl } from '../config/environment.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate terminal hyperlink (if supported)
|
|
9
|
+
*/
|
|
10
|
+
function hyperlink(text, url) {
|
|
11
|
+
return `\u001B]8;;${url}\u0007${text}\u001B]8;;\u0007`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate eBay OAuth authorization URL
|
|
15
|
+
*/
|
|
16
|
+
export function generateAuthUrl(clientId, redirectUri, environment, scopes) {
|
|
17
|
+
return getOAuthAuthorizationUrl(clientId, redirectUri, environment, scopes);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start a local server to capture OAuth callback
|
|
21
|
+
*/
|
|
22
|
+
export async function startCallbackServer(port = 3000, timeout = 300000 // 5 minutes
|
|
23
|
+
) {
|
|
24
|
+
return await new Promise((resolve) => {
|
|
25
|
+
let callbackResolver;
|
|
26
|
+
const codePromise = new Promise((res) => {
|
|
27
|
+
callbackResolver = res;
|
|
28
|
+
});
|
|
29
|
+
const server = createServer((req, res) => {
|
|
30
|
+
if (!req.url) {
|
|
31
|
+
res.writeHead(400);
|
|
32
|
+
res.end('Bad Request');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
36
|
+
// Handle OAuth callback
|
|
37
|
+
if (url.pathname === '/oauth/callback') {
|
|
38
|
+
const code = url.searchParams.get('code');
|
|
39
|
+
const error = url.searchParams.get('error');
|
|
40
|
+
const errorDescription = url.searchParams.get('error_description');
|
|
41
|
+
if (code) {
|
|
42
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
43
|
+
res.end(`
|
|
44
|
+
<!DOCTYPE html>
|
|
45
|
+
<html>
|
|
46
|
+
<head>
|
|
47
|
+
<title>eBay MCP - Authorization Successful</title>
|
|
48
|
+
<style>
|
|
49
|
+
body {
|
|
50
|
+
font-family: Arial, sans-serif;
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
align-items: center;
|
|
54
|
+
height: 100vh;
|
|
55
|
+
margin: 0;
|
|
56
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
57
|
+
}
|
|
58
|
+
.container {
|
|
59
|
+
background: white;
|
|
60
|
+
padding: 40px;
|
|
61
|
+
border-radius: 10px;
|
|
62
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
|
63
|
+
text-align: center;
|
|
64
|
+
max-width: 500px;
|
|
65
|
+
}
|
|
66
|
+
.success-icon {
|
|
67
|
+
font-size: 64px;
|
|
68
|
+
margin-bottom: 20px;
|
|
69
|
+
}
|
|
70
|
+
h1 {
|
|
71
|
+
color: #4CAF50;
|
|
72
|
+
margin-bottom: 10px;
|
|
73
|
+
}
|
|
74
|
+
p {
|
|
75
|
+
color: #666;
|
|
76
|
+
line-height: 1.6;
|
|
77
|
+
}
|
|
78
|
+
.code {
|
|
79
|
+
background: #f5f5f5;
|
|
80
|
+
padding: 10px;
|
|
81
|
+
border-radius: 5px;
|
|
82
|
+
font-family: monospace;
|
|
83
|
+
word-break: break-all;
|
|
84
|
+
margin: 20px 0;
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
87
|
+
</head>
|
|
88
|
+
<body>
|
|
89
|
+
<div class="container">
|
|
90
|
+
<div class="success-icon">ā
</div>
|
|
91
|
+
<h1>Authorization Successful!</h1>
|
|
92
|
+
<p>You have successfully authorized the eBay MCP server.</p>
|
|
93
|
+
<p>You can close this window and return to your terminal.</p>
|
|
94
|
+
<p class="code">Authorization code received</p>
|
|
95
|
+
</div>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
98
|
+
`);
|
|
99
|
+
callbackResolver({ code });
|
|
100
|
+
}
|
|
101
|
+
else if (error) {
|
|
102
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
103
|
+
res.end(`
|
|
104
|
+
<!DOCTYPE html>
|
|
105
|
+
<html>
|
|
106
|
+
<head>
|
|
107
|
+
<title>eBay MCP - Authorization Failed</title>
|
|
108
|
+
<style>
|
|
109
|
+
body {
|
|
110
|
+
font-family: Arial, sans-serif;
|
|
111
|
+
display: flex;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
align-items: center;
|
|
114
|
+
height: 100vh;
|
|
115
|
+
margin: 0;
|
|
116
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
117
|
+
}
|
|
118
|
+
.container {
|
|
119
|
+
background: white;
|
|
120
|
+
padding: 40px;
|
|
121
|
+
border-radius: 10px;
|
|
122
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
|
123
|
+
text-align: center;
|
|
124
|
+
max-width: 500px;
|
|
125
|
+
}
|
|
126
|
+
.error-icon {
|
|
127
|
+
font-size: 64px;
|
|
128
|
+
margin-bottom: 20px;
|
|
129
|
+
}
|
|
130
|
+
h1 {
|
|
131
|
+
color: #f44336;
|
|
132
|
+
margin-bottom: 10px; /* Fix: Changed color to red for error */
|
|
133
|
+
}
|
|
134
|
+
p {
|
|
135
|
+
color: #666;
|
|
136
|
+
line-height: 1.6;
|
|
137
|
+
}
|
|
138
|
+
.error {
|
|
139
|
+
background: #ffebee;
|
|
140
|
+
color: #c62828;
|
|
141
|
+
padding: 10px;
|
|
142
|
+
border-radius: 5px;
|
|
143
|
+
margin: 20px 0;
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
146
|
+
</head>
|
|
147
|
+
<body>
|
|
148
|
+
<div class="container">
|
|
149
|
+
<div class="error-icon">ā</div>
|
|
150
|
+
<h1>Authorization Failed</h1>
|
|
151
|
+
<p>There was an error during authorization.</p>
|
|
152
|
+
<div class="error">${errorDescription ?? error}</div>
|
|
153
|
+
<p>Please return to your terminal and try again.</p>
|
|
154
|
+
</div>
|
|
155
|
+
<script>
|
|
156
|
+
// Close the window after a short delay
|
|
157
|
+
setTimeout(() => window.close(), 5000);
|
|
158
|
+
</script>
|
|
159
|
+
</body>
|
|
160
|
+
</html>
|
|
161
|
+
`);
|
|
162
|
+
callbackResolver({ error, errorDescription: errorDescription ?? undefined });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
res.writeHead(404);
|
|
167
|
+
res.end('Not Found');
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
server.listen(port, () => {
|
|
171
|
+
console.log(chalk.gray(` OAuth callback server listening on http://localhost:${port}`));
|
|
172
|
+
resolve({ server, codePromise });
|
|
173
|
+
});
|
|
174
|
+
// Set timeout
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
callbackResolver({
|
|
177
|
+
error: 'timeout',
|
|
178
|
+
errorDescription: 'OAuth callback timeout - no response received',
|
|
179
|
+
});
|
|
180
|
+
}, timeout);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Interactive OAuth flow with local callback server
|
|
185
|
+
*/
|
|
186
|
+
export async function interactiveOAuthFlow(config, scopes) {
|
|
187
|
+
console.log(chalk.bold.cyan('\nš Interactive OAuth Flow\n'));
|
|
188
|
+
// Check if redirect URI is localhost
|
|
189
|
+
const redirectUri = config.redirectUri || 'http://localhost:3000/oauth/callback';
|
|
190
|
+
const isLocalhost = redirectUri.includes('localhost') || redirectUri.includes('127.0.0.1');
|
|
191
|
+
if (!isLocalhost) {
|
|
192
|
+
console.log(chalk.yellow('ā ļø Your redirect URI is not localhost. Interactive flow requires localhost callback.\n'));
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
// Extract port from redirect URI
|
|
196
|
+
const portMatch = /:(\d+)/.exec(redirectUri);
|
|
197
|
+
const port = portMatch ? parseInt(portMatch[1], 10) : 3000;
|
|
198
|
+
// Start callback server
|
|
199
|
+
console.log(chalk.cyan('Starting local OAuth callback server...\n'));
|
|
200
|
+
const { server, codePromise } = await startCallbackServer(port);
|
|
201
|
+
// Generate auth URL
|
|
202
|
+
const authUrl = generateAuthUrl(config.clientId, redirectUri, config.environment, scopes);
|
|
203
|
+
console.log(chalk.bold.white('š Step 1: Authorize the Application\n'));
|
|
204
|
+
console.log(chalk.gray('Open this URL in your browser:\n'));
|
|
205
|
+
console.log(chalk.blue.underline(hyperlink(authUrl.substring(0, 20) + '...', authUrl)));
|
|
206
|
+
console.log('');
|
|
207
|
+
console.log(chalk.gray('Waiting for authorization...'));
|
|
208
|
+
console.log(chalk.gray('(This window will update automatically after you authorize)\n'));
|
|
209
|
+
// Wait for callback
|
|
210
|
+
const result = await codePromise;
|
|
211
|
+
// Close server
|
|
212
|
+
server.close();
|
|
213
|
+
if (result.error) {
|
|
214
|
+
console.log(chalk.red(`\nā Authorization failed: ${result.errorDescription || result.error}\n`));
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
if (result.code) {
|
|
218
|
+
console.log(chalk.green('\nā Authorization successful!\n'));
|
|
219
|
+
return result.code;
|
|
220
|
+
}
|
|
221
|
+
console.log(chalk.yellow('\nā ļø No authorization code received.\n'));
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Display manual OAuth instructions
|
|
226
|
+
*/
|
|
227
|
+
export function displayManualOAuthInstructions(clientId, redirectUri, environment, scopes) {
|
|
228
|
+
const authUrl = generateAuthUrl(clientId, redirectUri, environment, scopes);
|
|
229
|
+
console.log(chalk.bold.cyan('\nš Manual OAuth Token Acquisition Guide\n'));
|
|
230
|
+
console.log(chalk.white('Step 1: Generate Authorization URL\n'));
|
|
231
|
+
console.log(chalk.gray('Copy this URL and open it in your browser:\n'));
|
|
232
|
+
console.log(chalk.blue.underline(authUrl));
|
|
233
|
+
console.log('');
|
|
234
|
+
console.log(chalk.white('\nStep 2: Authorize the Application\n'));
|
|
235
|
+
console.log(chalk.gray(' ⢠Log in to your eBay account'));
|
|
236
|
+
console.log(chalk.gray(' ⢠Review the permissions requested'));
|
|
237
|
+
console.log(chalk.gray(' ⢠Click "Agree" to authorize\n'));
|
|
238
|
+
console.log(chalk.white('Step 3: Get the Authorization Code\n'));
|
|
239
|
+
console.log(chalk.gray(' ⢠After authorization, you will be redirected to your redirect URI'));
|
|
240
|
+
console.log(chalk.gray(' ⢠The URL will contain a "code" parameter'));
|
|
241
|
+
console.log(chalk.gray(' ⢠Example: https://your-redirect-uri?code=v^1.1#i^1...\n'));
|
|
242
|
+
console.log(chalk.white('Step 4: Exchange Code for Tokens\n'));
|
|
243
|
+
console.log(chalk.gray(' ⢠Use the code to get your refresh token'));
|
|
244
|
+
console.log(chalk.gray(' ⢠This can be done through the MCP tool: ebay_exchange_auth_code'));
|
|
245
|
+
console.log(chalk.gray(' ⢠Or paste the code in the setup wizard when prompted\n'));
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Get help text for RuName (Redirect URI)
|
|
249
|
+
*/
|
|
250
|
+
export function getRuNameHelp() {
|
|
251
|
+
return `
|
|
252
|
+
${chalk.bold.cyan('What is a RuName (Redirect URI)?')}
|
|
253
|
+
|
|
254
|
+
A RuName (Redirect URL name) is a unique identifier for your OAuth redirect URI.
|
|
255
|
+
It's required for eBay's OAuth flow to know where to send users after authorization.
|
|
256
|
+
|
|
257
|
+
${chalk.bold.white('How to create a RuName:')}
|
|
258
|
+
|
|
259
|
+
1. Go to eBay Developer Portal:
|
|
260
|
+
${chalk.blue.underline('https://developer.ebay.com/my/keys')}
|
|
261
|
+
|
|
262
|
+
2. Select your application
|
|
263
|
+
|
|
264
|
+
3. Navigate to "User Tokens" section
|
|
265
|
+
|
|
266
|
+
4. Click "Add RuName"
|
|
267
|
+
|
|
268
|
+
5. Enter your redirect URI:
|
|
269
|
+
${chalk.gray('For local development: http://localhost:3000/oauth/callback')}
|
|
270
|
+
${chalk.gray('For production: https://your-domain.com/oauth/callback')}
|
|
271
|
+
|
|
272
|
+
6. Copy the generated RuName and use it in your configuration
|
|
273
|
+
|
|
274
|
+
${chalk.bold.white('Common RuName formats:')}
|
|
275
|
+
|
|
276
|
+
${chalk.gray('⢠For localhost:')} YourCompany-YourApp-LocalTest-RuName
|
|
277
|
+
${chalk.gray('⢠For production:')} YourCompany-YourApp-Production-RuName
|
|
278
|
+
|
|
279
|
+
${chalk.yellow('Note:')} The RuName is NOT the same as the redirect URI itself.
|
|
280
|
+
It's a reference name that eBay associates with your redirect URI.
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Display first-time developer guide
|
|
285
|
+
*/
|
|
286
|
+
export function displayFirstTimeDeveloperGuide() {
|
|
287
|
+
console.log(chalk.bold.cyan('\nš First-Time eBay Developer Guide\n'));
|
|
288
|
+
console.log(chalk.white("Welcome! Here's how to get started:\n"));
|
|
289
|
+
console.log(chalk.bold.yellow('Step 1: Create eBay Developer Account\n'));
|
|
290
|
+
console.log(chalk.gray(' 1. Visit: ') + chalk.blue.underline('https://developer.ebay.com/'));
|
|
291
|
+
console.log(chalk.gray(' 2. Click "Register" or "Join"'));
|
|
292
|
+
console.log(chalk.gray(' 3. Complete the registration form'));
|
|
293
|
+
console.log(chalk.gray(' 4. Verify your email address\n'));
|
|
294
|
+
console.log(chalk.bold.yellow('Step 2: Create an Application\n'));
|
|
295
|
+
console.log(chalk.gray(' 1. Go to: ') + chalk.blue.underline('https://developer.ebay.com/my/keys'));
|
|
296
|
+
console.log(chalk.gray(' 2. Click "Create Application"'));
|
|
297
|
+
console.log(chalk.gray(' 3. Fill in application details (name, description)'));
|
|
298
|
+
console.log(chalk.gray(' 4. Choose Sandbox environment to start\n'));
|
|
299
|
+
console.log(chalk.bold.yellow('Step 3: Get Your Credentials\n'));
|
|
300
|
+
console.log(chalk.gray(' After creating the app, you will see:'));
|
|
301
|
+
console.log(chalk.gray(' ⢠App ID (Client ID) - Copy this'));
|
|
302
|
+
console.log(chalk.gray(' ⢠Cert ID (Client Secret) - Copy this'));
|
|
303
|
+
console.log(chalk.gray(' ⢠These are needed for the setup wizard\n'));
|
|
304
|
+
console.log(chalk.bold.yellow('Step 4: Create RuName (Redirect URI)\n'));
|
|
305
|
+
console.log(chalk.gray(' 1. In your application settings'));
|
|
306
|
+
console.log(chalk.gray(' 2. Navigate to "User Tokens" section'));
|
|
307
|
+
console.log(chalk.gray(' 3. Click "Add RuName"'));
|
|
308
|
+
console.log(chalk.gray(' 4. Enter: http://localhost:3000/oauth/callback'));
|
|
309
|
+
console.log(chalk.gray(' 5. Save and copy the generated RuName\n'));
|
|
310
|
+
console.log(chalk.bold.yellow('Step 5: Get User Token\n'));
|
|
311
|
+
console.log(chalk.gray(' Option A: Use this setup wizard (recommended)'));
|
|
312
|
+
console.log(chalk.gray(' Option B: Manual OAuth flow through eBay Developer Portal\n'));
|
|
313
|
+
console.log(chalk.green.bold("ā
Once you have these, you're ready to continue!\n"));
|
|
314
|
+
console.log(chalk.gray('Press Enter to continue when you have your credentials ready...'));
|
|
315
|
+
}
|