ebay-mcp-remote-edition 4.5.1 → 4.7.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/README.md +393 -576
- package/build/auth/multi-user-store.js +78 -13
- package/build/auth/oauth.js +26 -11
- package/build/captcha/captcha.js +302 -0
- package/build/config/environment.js +23 -1
- package/build/scripts/bootstrap-ebay-research-session.js +43 -2
- package/build/server-http.d.ts +2 -1
- package/build/server-http.js +425 -28
- package/build/tools/index.js +6 -8
- package/build/tools/schemas.js +8 -11
- package/build/validation/providers/ebay-research-session-alerts.js +28 -14
- package/build/validation/providers/ebay-research.js +414 -25
- package/build/validation/providers/ebay-sold.js +53 -11
- package/build/validation/providers/ebay.js +6 -6
- package/build/validation/providers/terapeak.js +146 -5
- package/build/validation/recommendation.js +22 -5
- package/build/validation/run-validation.js +32 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -16,23 +16,21 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server providi
|
|
|
16
16
|
|
|
17
17
|
## Overview
|
|
18
18
|
|
|
19
|
-
This project extends [Yosef Hayim's eBay MCP](https://github.com/YosefHayim/ebay-mcp) with
|
|
19
|
+
This project extends [Yosef Hayim's eBay MCP](https://github.com/YosefHayim/ebay-mcp) with hosted, multi-user deployment while preserving local STDIO mode. Key additions:
|
|
20
20
|
|
|
21
|
-
- **Hosted Streamable HTTP
|
|
22
|
-
- **MCP OAuth 2.1
|
|
23
|
-
- **Environment-scoped
|
|
24
|
-
- **Cloudflare KV / Upstash Redis** token and session storage
|
|
21
|
+
- **Hosted Streamable HTTP** — deploy anywhere, serve multiple users from one instance
|
|
22
|
+
- **MCP OAuth 2.1** — browser-based eBay login with automatic token management; OAuth-aware clients (Cline) connect without manual token pasting
|
|
23
|
+
- **Environment-scoped routes** — `/sandbox/mcp` and `/production/mcp` hard-bind their eBay environment
|
|
24
|
+
- **Cloudflare KV / Upstash Redis** — persistent multi-user token and session storage with TTL-aligned expiry
|
|
25
25
|
- **Admin session management** — inspect, revoke, or delete sessions via authenticated endpoints
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **QStash-triggered Telegram alerts for eBay Research session expiry** — bootstrap can schedule version-aware expiry callbacks that notify operators before first-party research auth silently degrades
|
|
29
|
-
- **Alert-safe scheduling guardrails** — expiry callbacks are only scheduled when the callback URL is externally reachable and the research session store supports shared alert locks (`upstash-redis` or `filesystem`)
|
|
26
|
+
- **eBay Research session persistence** — Playwright storage state to KV/Redis/filesystem via `EBAY_RESEARCH_SESSION_STORE`
|
|
27
|
+
- **QStash-triggered Telegram alerts** — expiry callbacks notify operators before research auth degrades
|
|
30
28
|
|
|
31
29
|
---
|
|
32
30
|
|
|
33
31
|
## ⚠️ Disclaimer
|
|
34
32
|
|
|
35
|
-
This is an open-source project provided "as is" without warranty of any kind.
|
|
33
|
+
This is an open-source project provided "as is" without warranty of any kind. Not affiliated with, endorsed by, or sponsored by eBay Inc. Test thoroughly in sandbox before production.
|
|
36
34
|
|
|
37
35
|
---
|
|
38
36
|
|
|
@@ -41,21 +39,8 @@ This is an open-source project provided "as is" without warranty of any kind. Th
|
|
|
41
39
|
- [Choose a runtime mode](#choose-a-runtime-mode)
|
|
42
40
|
- [Prerequisites](#prerequisites)
|
|
43
41
|
- [Local mode setup](#local-mode-setup)
|
|
44
|
-
- [Install](#install)
|
|
45
|
-
- [Configure credentials](#configure-credentials)
|
|
46
|
-
- [Run the setup wizard](#run-the-setup-wizard)
|
|
47
|
-
- [Local client configuration](#local-client-configuration)
|
|
48
42
|
- [Hosted mode setup](#hosted-mode-setup)
|
|
49
|
-
|
|
50
|
-
- [Secret file](#secret-file)
|
|
51
|
-
- [Deploy to Render](#deploy-to-render)
|
|
52
|
-
- [OAuth flows](#oauth-flows)
|
|
53
|
-
- [MCP endpoints](#mcp-endpoints)
|
|
54
|
-
- [Validation architecture](#validation-architecture)
|
|
55
|
-
- [Validation endpoints and auth model](#validation-endpoints-and-auth-model)
|
|
56
|
-
- [Diagnostics and health endpoints](#diagnostics-and-health-endpoints)
|
|
57
|
-
- [Validation provider behavior and limitations](#validation-provider-behavior-and-limitations)
|
|
58
|
-
- [Remote client configuration](#remote-client-configuration)
|
|
43
|
+
- [Tool discovery for agents](#tool-discovery-for-agents)
|
|
59
44
|
- [Available tools](#available-tools)
|
|
60
45
|
- [Development](#development)
|
|
61
46
|
- [Testing & validation](#testing--validation)
|
|
@@ -66,12 +51,12 @@ This is an open-source project provided "as is" without warranty of any kind. Th
|
|
|
66
51
|
|
|
67
52
|
## Choose a runtime mode
|
|
68
53
|
|
|
69
|
-
| Mode | Transport | Best for |
|
|
70
|
-
|
|
71
|
-
| **Local STDIO** | stdin/stdout | Single-user local AI client (Claude Desktop, Cline, Cursor, etc.) |
|
|
72
|
-
| **Hosted HTTP** | Streamable HTTP | Multi-user server deployment; remote MCP clients |
|
|
54
|
+
| Mode | Command | Transport | Best for | Authorization model |
|
|
55
|
+
|------|---------|-----------|----------|---------------------|
|
|
56
|
+
| **Local STDIO** | `pnpm start` / `pnpm run dev` | stdin/stdout | Single-user local AI client (Claude Desktop, Cline, Cursor, etc.) | The local process reads eBay credentials and optional `EBAY_USER_REFRESH_TOKEN` from environment variables. |
|
|
57
|
+
| **Hosted HTTP** | `pnpm run start:http` / `pnpm run dev:http` | Streamable HTTP | Multi-user server deployment; remote MCP clients | Users authorize through browser OAuth. Requests can use normal session Bearer auth or opt into server-request auth with `X-Ebay-Server-Request: true`. |
|
|
73
58
|
|
|
74
|
-
Both modes use the same eBay
|
|
59
|
+
Both modes use the same eBay tool registry. Local STDIO is best when one trusted local client owns the eBay credentials. Hosted HTTP runs an Express server with OAuth 2.1 discovery, environment-scoped route trees, server-side token/session storage, and admin-only operational endpoints.
|
|
75
60
|
|
|
76
61
|
---
|
|
77
62
|
|
|
@@ -82,16 +67,16 @@ Both modes use the same eBay tools. The local mode reads credentials from enviro
|
|
|
82
67
|
- [pnpm](https://pnpm.io/) (or npm — `npm install -g pnpm`)
|
|
83
68
|
- An [eBay Developer Account](https://developer.ebay.com/)
|
|
84
69
|
|
|
85
|
-
**Getting
|
|
86
|
-
1. Log in to
|
|
87
|
-
2. Create an application
|
|
88
|
-
3. Under **User Tokens → Add RuName**, register your OAuth callback URL and copy the generated **RuName** string
|
|
70
|
+
**Getting credentials:**
|
|
71
|
+
1. Log in to [eBay Developer Portal](https://developer.ebay.com/my/keys)
|
|
72
|
+
2. Create an application, copy **App ID (Client ID)** and **Cert ID (Client Secret)**
|
|
73
|
+
3. Under **User Tokens → Add RuName**, register your public HTTPS OAuth callback URL and copy the generated **RuName** string
|
|
89
74
|
|
|
90
|
-
> **`EBAY_RUNAME`
|
|
75
|
+
> **`EBAY_RUNAME` and the public Redirect URL are distinct.** `EBAY_RUNAME` is the eBay-generated RuName string used as eBay's OAuth `redirect_uri` identifier (for example, `YourApp-YourApp-SB-abcdefghi`). The public Redirect URL is the real browser callback URL you register in eBay, such as `https://your-server.com/oauth/callback` or `https://ebay-local.test:3000/oauth/callback`; it is derived from `PUBLIC_BASE_URL` in this project. Do not use either value as a fallback for the other.
|
|
91
76
|
|
|
92
77
|
### HTTPS callback URL (required by eBay)
|
|
93
78
|
|
|
94
|
-
eBay requires
|
|
79
|
+
eBay requires HTTPS for OAuth callbacks. For local dev, use [mkcert](https://github.com/FiloSottile/mkcert):
|
|
95
80
|
|
|
96
81
|
```bash
|
|
97
82
|
brew install mkcert nss
|
|
@@ -100,7 +85,7 @@ mkcert ebay-local.test
|
|
|
100
85
|
echo "127.0.0.1 ebay-local.test" | sudo tee -a /etc/hosts
|
|
101
86
|
```
|
|
102
87
|
|
|
103
|
-
Register `https://ebay-local.test:3000/oauth/callback` in the
|
|
88
|
+
Register `https://ebay-local.test:3000/oauth/callback` in the Developer Portal. Add to `.env`:
|
|
104
89
|
|
|
105
90
|
```bash
|
|
106
91
|
PUBLIC_BASE_URL=https://ebay-local.test:3000
|
|
@@ -108,17 +93,15 @@ EBAY_LOCAL_TLS_CERT_PATH=/path/to/ebay-local.test.pem
|
|
|
108
93
|
EBAY_LOCAL_TLS_KEY_PATH=/path/to/ebay-local.test-key.pem
|
|
109
94
|
```
|
|
110
95
|
|
|
111
|
-
####
|
|
96
|
+
#### Trust mkcert CA in Node.js
|
|
112
97
|
|
|
113
|
-
VS Code's extension host
|
|
114
|
-
|
|
115
|
-
**Fix — run these two commands once, then fully quit and reopen VS Code:**
|
|
98
|
+
VS Code's extension host uses Node.js, which doesn't read macOS system keychain by default. Trust the cert:
|
|
116
99
|
|
|
117
100
|
```bash
|
|
118
|
-
#
|
|
101
|
+
# Current session (Dock/Spotlight-launched apps):
|
|
119
102
|
launchctl setenv NODE_EXTRA_CA_CERTS "$(mkcert -CAROOT)/rootCA.pem"
|
|
120
103
|
|
|
121
|
-
#
|
|
104
|
+
# Persist across reboots:
|
|
122
105
|
cat > ~/Library/LaunchAgents/com.local.mkcert-node-trust.plist <<'EOF'
|
|
123
106
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
124
107
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -137,23 +120,13 @@ cat > ~/Library/LaunchAgents/com.local.mkcert-node-trust.plist <<'EOF'
|
|
|
137
120
|
EOF
|
|
138
121
|
launchctl load ~/Library/LaunchAgents/com.local.mkcert-node-trust.plist
|
|
139
122
|
|
|
140
|
-
#
|
|
123
|
+
# Terminal-launched apps — add to ~/.zshrc:
|
|
141
124
|
echo 'export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"' >> ~/.zshrc
|
|
142
125
|
```
|
|
143
126
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
After running these commands and **fully quitting VS Code (Cmd+Q on macOS)** and reopening it, Cline's extension host will trust the `ebay-local.test` certificate and the MCP OAuth flow will complete successfully.
|
|
127
|
+
Then fully quit and reopen VS Code.
|
|
147
128
|
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" node -e "
|
|
151
|
-
require('https').get('https://ebay-local.test:3000/health', r => console.log('TLS OK — status:', r.statusCode)).on('error', e => console.error('TLS FAIL:', e.message));
|
|
152
|
-
"
|
|
153
|
-
# Expected: TLS OK — status: 200
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
For hosted deployments, register your server's public HTTPS URL instead (e.g. `https://your-server.com/oauth/callback`).
|
|
129
|
+
For hosted deployments, register your server's public HTTPS URL instead.
|
|
157
130
|
|
|
158
131
|
---
|
|
159
132
|
|
|
@@ -161,64 +134,48 @@ For hosted deployments, register your server's public HTTPS URL instead (e.g. `h
|
|
|
161
134
|
|
|
162
135
|
### Install
|
|
163
136
|
|
|
164
|
-
**Option A — pnpm global install (no build step):**
|
|
165
|
-
|
|
166
137
|
```bash
|
|
138
|
+
# Option A — global install (no build step):
|
|
167
139
|
pnpm install -g ebay-mcp-remote-edition
|
|
168
|
-
```
|
|
169
140
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
```bash
|
|
141
|
+
# Option B — clone and build (contributors):
|
|
173
142
|
git clone https://github.com/mrnajiboy/ebay-mcp-remote-edition.git
|
|
174
143
|
cd ebay-mcp-remote-edition
|
|
175
|
-
pnpm install
|
|
176
|
-
pnpm run build
|
|
144
|
+
pnpm install && pnpm run build
|
|
177
145
|
```
|
|
178
146
|
|
|
179
147
|
### Configure credentials
|
|
180
148
|
|
|
181
|
-
Create
|
|
149
|
+
Create `.env` (see `.env.example`):
|
|
182
150
|
|
|
183
151
|
```bash
|
|
184
152
|
EBAY_CLIENT_ID=your_client_id
|
|
185
153
|
EBAY_CLIENT_SECRET=your_client_secret
|
|
186
|
-
EBAY_RUNAME=your_runame_string
|
|
154
|
+
EBAY_RUNAME=your_runame_string # eBay-generated RuName, not a URL
|
|
155
|
+
EBAY_REDIRECT_URI= # legacy env name; do not set to the public callback URL
|
|
187
156
|
EBAY_ENVIRONMENT=sandbox # or production
|
|
188
157
|
EBAY_MARKETPLACE_ID=EBAY_US # optional, defaults to EBAY_US
|
|
189
158
|
EBAY_CONTENT_LANGUAGE=en-US # optional, defaults to en-US
|
|
190
|
-
|
|
191
|
-
# Populated by the setup wizard:
|
|
192
|
-
EBAY_USER_REFRESH_TOKEN=
|
|
159
|
+
EBAY_USER_REFRESH_TOKEN= # populated by setup wizard
|
|
193
160
|
```
|
|
194
161
|
|
|
195
162
|
**Authentication tiers:**
|
|
196
163
|
|
|
197
164
|
| Method | Rate limit | How |
|
|
198
165
|
|--------|-----------|-----|
|
|
199
|
-
| Client credentials (default) | 1,000 req/day |
|
|
200
|
-
| User tokens (recommended) | 10,000–50,000 req/day | Run
|
|
166
|
+
| Client credentials (default) | 1,000 req/day | Set `EBAY_CLIENT_ID` + `EBAY_CLIENT_SECRET` |
|
|
167
|
+
| User tokens (recommended) | 10,000–50,000 req/day | Run `pnpm run setup` to complete OAuth |
|
|
201
168
|
|
|
202
169
|
### Run the setup wizard
|
|
203
170
|
|
|
204
|
-
The interactive wizard guides you through environment selection, credential entry, OAuth login, and MCP client configuration:
|
|
205
|
-
|
|
206
171
|
```bash
|
|
207
|
-
pnpm run setup
|
|
172
|
+
pnpm run setup # interactive: env selection, credentials, OAuth, client config
|
|
173
|
+
pnpm run setup --quick # skip optional steps
|
|
174
|
+
pnpm run setup --diagnose # connectivity and token checks only
|
|
208
175
|
```
|
|
209
176
|
|
|
210
|
-
Options:
|
|
211
|
-
- `--quick` — skip optional steps
|
|
212
|
-
- `--diagnose` — run connectivity and token checks only
|
|
213
|
-
|
|
214
|
-
After completing OAuth, the wizard writes `EBAY_USER_REFRESH_TOKEN` to `.env` and optionally configures Claude Desktop automatically.
|
|
215
|
-
|
|
216
177
|
### Local client configuration
|
|
217
178
|
|
|
218
|
-
For direct STDIO usage, configure your MCP client to launch the server as a subprocess. All clients use the same JSON pattern:
|
|
219
|
-
|
|
220
|
-
**Using npm (no clone needed):**
|
|
221
|
-
|
|
222
179
|
```json
|
|
223
180
|
{
|
|
224
181
|
"mcpServers": {
|
|
@@ -230,6 +187,7 @@ For direct STDIO usage, configure your MCP client to launch the server as a subp
|
|
|
230
187
|
"EBAY_CLIENT_SECRET": "YOUR_CLIENT_SECRET",
|
|
231
188
|
"EBAY_ENVIRONMENT": "sandbox",
|
|
232
189
|
"EBAY_RUNAME": "YOUR_RUNAME",
|
|
190
|
+
"EBAY_REDIRECT_URI": "",
|
|
233
191
|
"EBAY_USER_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN"
|
|
234
192
|
}
|
|
235
193
|
}
|
|
@@ -237,35 +195,14 @@ For direct STDIO usage, configure your MCP client to launch the server as a subp
|
|
|
237
195
|
}
|
|
238
196
|
```
|
|
239
197
|
|
|
240
|
-
**
|
|
241
|
-
|
|
242
|
-
```json
|
|
243
|
-
{
|
|
244
|
-
"mcpServers": {
|
|
245
|
-
"ebay": {
|
|
246
|
-
"command": "node",
|
|
247
|
-
"args": ["/absolute/path/to/ebay-mcp-remote-edition/build/index.js"],
|
|
248
|
-
"env": {
|
|
249
|
-
"EBAY_CLIENT_ID": "YOUR_CLIENT_ID",
|
|
250
|
-
"EBAY_CLIENT_SECRET": "YOUR_CLIENT_SECRET",
|
|
251
|
-
"EBAY_ENVIRONMENT": "sandbox",
|
|
252
|
-
"EBAY_RUNAME": "YOUR_RUNAME",
|
|
253
|
-
"EBAY_USER_REFRESH_TOKEN": "YOUR_REFRESH_TOKEN"
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
**Config file locations by client:**
|
|
198
|
+
**Config file locations:**
|
|
261
199
|
|
|
262
200
|
| Client | Config file |
|
|
263
201
|
|--------|-------------|
|
|
264
202
|
| Cline | `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` |
|
|
265
203
|
| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
266
204
|
| Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
267
|
-
| Cursor
|
|
268
|
-
| Cursor (project) | `.cursor/mcp.json` |
|
|
205
|
+
| Cursor | `~/.cursor/mcp.json` or `.cursor/mcp.json` |
|
|
269
206
|
|
|
270
207
|
Zed, Windsurf, Continue.dev, Roo Code, and Amazon Q follow the same `mcpServers` JSON shape.
|
|
271
208
|
|
|
@@ -273,543 +210,416 @@ Zed, Windsurf, Continue.dev, Roo Code, and Amazon Q follow the same `mcpServers`
|
|
|
273
210
|
|
|
274
211
|
## Hosted mode setup
|
|
275
212
|
|
|
276
|
-
|
|
213
|
+
### Environment variables
|
|
277
214
|
|
|
278
|
-
|
|
215
|
+
Hosted HTTP reads the same eBay credential variables as local STDIO plus the HTTP, storage, and security variables below. The start script is `pnpm run start:http`; development uses `pnpm run dev:http`.
|
|
279
216
|
|
|
280
217
|
```bash
|
|
281
|
-
#
|
|
282
|
-
PORT=3000
|
|
283
|
-
MCP_HOST=0.0.0.0
|
|
218
|
+
# Required for hosted OAuth URLs and eBay callback registration
|
|
284
219
|
PUBLIC_BASE_URL=https://your-server.com
|
|
285
220
|
|
|
286
|
-
# eBay credentials
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
#
|
|
302
|
-
#
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
#
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
221
|
+
# Required eBay credentials unless EBAY_CONFIG_FILE provides them
|
|
222
|
+
EBAY_CLIENT_ID=
|
|
223
|
+
EBAY_CLIENT_SECRET=
|
|
224
|
+
EBAY_RUNAME=
|
|
225
|
+
EBAY_REDIRECT_URI= # legacy env name; not the public callback URL
|
|
226
|
+
# Recommended when serving both environments from one host
|
|
227
|
+
EBAY_PRODUCTION_CLIENT_ID=
|
|
228
|
+
EBAY_PRODUCTION_CLIENT_SECRET=
|
|
229
|
+
EBAY_PRODUCTION_RUNAME=
|
|
230
|
+
EBAY_PRODUCTION_REDIRECT_URI=
|
|
231
|
+
EBAY_SANDBOX_CLIENT_ID=
|
|
232
|
+
EBAY_SANDBOX_CLIENT_SECRET=
|
|
233
|
+
EBAY_SANDBOX_RUNAME=
|
|
234
|
+
EBAY_SANDBOX_REDIRECT_URI=
|
|
235
|
+
|
|
236
|
+
# Required for hosted multi-user token/session persistence
|
|
237
|
+
EBAY_TOKEN_STORE_BACKEND=upstash-redis # cloudflare-kv | upstash-redis | memory
|
|
238
|
+
UPSTASH_REDIS_REST_URL= # required when backend is upstash-redis
|
|
239
|
+
UPSTASH_REDIS_REST_TOKEN= # required when backend is upstash-redis
|
|
240
|
+
CLOUDFLARE_ACCOUNT_ID= # required when backend is cloudflare-kv
|
|
241
|
+
CLOUDFLARE_KV_NAMESPACE_ID= # required when backend is cloudflare-kv
|
|
242
|
+
CLOUDFLARE_API_TOKEN= # required when backend is cloudflare-kv
|
|
243
|
+
|
|
244
|
+
# Required for admin/validation endpoints and privileged MCP bypass
|
|
245
|
+
ADMIN_API_KEY=
|
|
246
|
+
|
|
247
|
+
# Optional HTTP/server behavior
|
|
248
|
+
PORT=3000 # defaults to 3000; many hosts inject this
|
|
249
|
+
MCP_HOST=0.0.0.0 # defaults to 0.0.0.0
|
|
250
|
+
EBAY_ENVIRONMENT=production # root/legacy default selector
|
|
251
|
+
EBAY_DEFAULT_ENVIRONMENT=production # fallback when EBAY_ENVIRONMENT is unset
|
|
252
|
+
SESSION_TTL_SECONDS=2592000 # default: 30 days
|
|
253
|
+
OAUTH_START_KEY= # optional gate for /oauth/start
|
|
254
|
+
EBAY_CONFIG_FILE=/etc/secrets/ebay-config.json
|
|
255
|
+
EBAY_MARKETPLACE_ID=EBAY_US
|
|
256
|
+
EBAY_CONTENT_LANGUAGE=en-US
|
|
257
|
+
EBAY_LOG_LEVEL=info
|
|
322
258
|
|
|
323
|
-
#
|
|
324
|
-
# Reuses a stored refresh-token-backed user in the existing multi-user auth store.
|
|
325
|
-
# Use the env-specific values when sandbox and production need different runner users.
|
|
259
|
+
# Optional validation runner identity
|
|
326
260
|
VALIDATION_RUNNER_USER_ID=
|
|
327
261
|
VALIDATION_RUNNER_USER_ID_SANDBOX=
|
|
328
262
|
VALIDATION_RUNNER_USER_ID_PRODUCTION=
|
|
329
263
|
|
|
330
|
-
#
|
|
331
|
-
# This is an interim external abstraction and will be replaced by an internal
|
|
332
|
-
# sales-data implementation without changing the validation orchestration route.
|
|
264
|
+
# Optional validation/research providers and alerts
|
|
333
265
|
SOLD_ITEMS_API_URL=
|
|
334
266
|
SOLD_ITEMS_API_KEY=
|
|
335
|
-
|
|
336
|
-
# Future orchestration-side historical research provider.
|
|
337
|
-
# Currently only used to enable the placeholder research contract.
|
|
338
267
|
PERPLEXITY_API_KEY=
|
|
339
|
-
|
|
340
|
-
# Optional phase-1 social-signal providers used by hosted validation.
|
|
341
|
-
# These signals are supportive only and should not be treated as authoritative
|
|
342
|
-
# automated buy triggers on their own.
|
|
343
268
|
TWITTER_BEARER_TOKEN=
|
|
344
269
|
YOUTUBE_API_KEY=
|
|
345
270
|
REDDIT_CLIENT_ID=
|
|
346
271
|
REDDIT_CLIENT_SECRET=
|
|
347
272
|
REDDIT_USER_AGENT=
|
|
273
|
+
TELEGRAM_BOT_TOKEN=
|
|
274
|
+
TELEGRAM_CHAT_ID=
|
|
275
|
+
QSTASH_URL=
|
|
276
|
+
QSTASH_TOKEN=
|
|
277
|
+
QSTASH_CURRENT_SIGNING_KEY=
|
|
278
|
+
QSTASH_NEXT_SIGNING_KEY=
|
|
279
|
+
EBAY_RESEARCH_SESSION_ALERTS_ENABLED=true
|
|
280
|
+
EBAY_RESEARCH_SESSION_ALERT_CALLBACK_URL=
|
|
348
281
|
|
|
349
|
-
#
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
#
|
|
353
|
-
|
|
354
|
-
EBAY_MARKETPLACE_ID=EBAY_US
|
|
355
|
-
EBAY_CONTENT_LANGUAGE=en-US
|
|
356
|
-
|
|
357
|
-
# Path to secret file (see below)
|
|
358
|
-
EBAY_CONFIG_FILE=/etc/secrets/ebay-config.json
|
|
282
|
+
# eBay Research/Terapeak first-party session source.
|
|
283
|
+
# Set this explicitly in hosted deployments. If unset, research sessions default
|
|
284
|
+
# to Cloudflare KV even when EBAY_TOKEN_STORE_BACKEND=upstash-redis.
|
|
285
|
+
EBAY_RESEARCH_SESSION_STORE=upstash-redis # cloudflare_kv | upstash-redis | filesystem | none
|
|
286
|
+
EBAY_RESEARCH_SESSION_ALLOW_FILESYSTEM_FALLBACK=false
|
|
359
287
|
```
|
|
360
288
|
|
|
361
|
-
> Use `
|
|
289
|
+
> `EBAY_TOKEN_STORE_BACKEND` defaults to Cloudflare KV when unset or unrecognized. Use `memory` only for tests or throwaway local development because hosted sessions and tokens are lost on restart.
|
|
290
|
+
> `EBAY_RESEARCH_SESSION_STORE` is separate from OAuth token storage. Set it to `upstash-redis` when Terapeak/eBay Research cookies are stored in Upstash.
|
|
362
291
|
|
|
363
292
|
### Secret file
|
|
364
293
|
|
|
365
|
-
|
|
294
|
+
Mount a JSON file with credentials (e.g., Render Secret File at `/etc/secrets/ebay-config.json`):
|
|
366
295
|
|
|
367
296
|
```json
|
|
368
297
|
{
|
|
369
298
|
"production": {
|
|
370
299
|
"clientId": "PROD_CLIENT_ID",
|
|
371
300
|
"clientSecret": "PROD_CLIENT_SECRET",
|
|
372
|
-
"redirectUri": "YOUR_PRODUCTION_RUNAME"
|
|
301
|
+
"redirectUri": "YOUR_PRODUCTION_RUNAME",
|
|
302
|
+
"ruName": "YOUR_PRODUCTION_RUNAME"
|
|
373
303
|
},
|
|
374
304
|
"sandbox": {
|
|
375
305
|
"clientId": "SANDBOX_CLIENT_ID",
|
|
376
306
|
"clientSecret": "SANDBOX_CLIENT_SECRET",
|
|
377
|
-
"redirectUri": "YOUR_SANDBOX_RUNAME"
|
|
307
|
+
"redirectUri": "YOUR_SANDBOX_RUNAME",
|
|
308
|
+
"ruName": "YOUR_SANDBOX_RUNAME"
|
|
378
309
|
}
|
|
379
310
|
}
|
|
380
311
|
```
|
|
381
312
|
|
|
382
|
-
### Deploy to Render / Railway /
|
|
313
|
+
### Deploy to Render / Railway / Coolify
|
|
383
314
|
|
|
384
|
-
1. Connect your repo
|
|
385
|
-
2.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
```
|
|
389
|
-
3. Set **Start command:**
|
|
390
|
-
```bash
|
|
391
|
-
pnpm run start:http
|
|
392
|
-
```
|
|
393
|
-
4. Add the environment variables listed above
|
|
394
|
-
5. Add the `ebay-config.json` secret file
|
|
315
|
+
1. Connect your repo as a **Web Service**
|
|
316
|
+
2. **Build:** `pnpm install && pnpm run build`
|
|
317
|
+
3. **Start:** `pnpm run start:http`
|
|
318
|
+
4. Add environment variables + secret file
|
|
395
319
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
For Nixpacks-based platforms such as Railway and Coolify:
|
|
399
|
-
|
|
400
|
-
- The repository now includes `nixpacks.toml` so the generated image uses `pnpm install --frozen-lockfile`, runs `pnpm run build`, installs Chromium for the Playwright-backed validation paths, and starts with `pnpm run start:http`.
|
|
401
|
-
- Runtime secrets should be configured in the platform dashboard as runtime environment variables or mounted secret files. Do not bake secrets into Docker build arguments or `ENV` layers.
|
|
402
|
-
- Keep `pnpm-lock.yaml` committed and in sync with `package.json`; Nixpacks installs with a frozen lockfile.
|
|
320
|
+
For Nixpacks-based platforms (Railway, Coolify): `nixpacks.toml` handles `pnpm`, build, Chromium install, and start automatically.
|
|
403
321
|
|
|
404
322
|
### OAuth flows
|
|
405
323
|
|
|
406
|
-
eBay requires a single registered callback URL per application. The hosted server registers `/oauth/callback` at the root and recovers the environment from the stored OAuth state record.
|
|
407
|
-
|
|
408
|
-
**Start an OAuth flow (browser):**
|
|
409
|
-
|
|
410
324
|
```
|
|
411
|
-
GET /sandbox/oauth/start
|
|
412
|
-
GET /production/oauth/start
|
|
325
|
+
GET /sandbox/oauth/start # sandbox browser login
|
|
326
|
+
GET /production/oauth/start # production browser login
|
|
413
327
|
```
|
|
414
328
|
|
|
415
|
-
If `OAUTH_START_KEY` is set,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
# or header: X-OAuth-Start-Key: YOUR_OAUTH_START_KEY
|
|
419
|
-
```
|
|
329
|
+
If `OAUTH_START_KEY` is set, start URLs require either `?key=YOUR_KEY` or the `X-OAuth-Start-Key: YOUR_KEY` header. The server also includes this key as `key` in generated `authorization_url` values for unauthenticated MCP requests.
|
|
330
|
+
|
|
331
|
+
After login, the callback page shows three hosted auth options with copy buttons:
|
|
420
332
|
|
|
421
|
-
|
|
333
|
+
| Hosted auth mode | How to select it | Best for |
|
|
334
|
+
|------------------|------------------|----------|
|
|
335
|
+
| **User/session mode** | Send `Authorization: Bearer <session-token>` and omit `X-Ebay-Server-Request` | Normal OAuth-aware MCP clients and user-scoped desktop clients. |
|
|
336
|
+
| **Server request mode — identity headers** | Send `X-Ebay-Server-Request: true`, `X-Ebay-Client-Id`, `X-Ebay-User-Id`, and optional `X-Ebay-Environment` | Server/client setups that need to handle both regular user requests and backend server requests without copying a session token. |
|
|
337
|
+
| **Server request mode — bearer-capable clients** | Send `X-Ebay-Server-Request: true` plus `Authorization: Bearer <mcp-server-issued-bearer-token>` | MCP clients or automation platforms that can store an authorization header but should not use the admin key. |
|
|
422
338
|
|
|
423
|
-
|
|
339
|
+
Switching between modes is per request, not a server-wide environment toggle. The same hosted MCP server can handle user/session requests and server requests concurrently; the client chooses server mode by adding `X-Ebay-Server-Request: true`.
|
|
424
340
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
|
428
|
-
|
|
429
|
-
|
|
|
430
|
-
|
|
|
341
|
+
**Session TTL schedule:**
|
|
342
|
+
|
|
343
|
+
| Record | TTL |
|
|
344
|
+
|--------|-----|
|
|
345
|
+
| OAuth state | 15 minutes |
|
|
346
|
+
| MCP auth code | 10 minutes |
|
|
347
|
+
| Session | 30 days (configurable) |
|
|
348
|
+
| User token | eBay refresh token expiry (fallback: 18 months) |
|
|
431
349
|
|
|
432
350
|
### MCP endpoints
|
|
433
351
|
|
|
434
352
|
**Environment-scoped (recommended):**
|
|
435
|
-
|
|
436
353
|
```
|
|
437
354
|
POST/GET/DELETE /sandbox/mcp
|
|
438
355
|
POST/GET/DELETE /production/mcp
|
|
439
356
|
```
|
|
440
357
|
|
|
441
|
-
Each
|
|
442
|
-
```
|
|
443
|
-
GET /sandbox/.well-known/oauth-authorization-server
|
|
444
|
-
GET /production/.well-known/oauth-authorization-server
|
|
445
|
-
```
|
|
358
|
+
Each includes OAuth 2.1 discovery: `GET /sandbox/.well-known/oauth-authorization-server`
|
|
446
359
|
|
|
447
|
-
**Legacy auto-detect
|
|
360
|
+
**Legacy auto-detect:**
|
|
448
361
|
```
|
|
449
|
-
POST/GET/DELETE /mcp
|
|
362
|
+
POST/GET/DELETE /mcp # resolves from ?env= or EBAY_ENVIRONMENT/EBAY_DEFAULT_ENVIRONMENT
|
|
450
363
|
```
|
|
451
364
|
|
|
452
|
-
**
|
|
453
|
-
- `GET /mcp`
|
|
454
|
-
- `POST /mcp` without
|
|
455
|
-
-
|
|
365
|
+
**Auth behavior:**
|
|
366
|
+
- `GET /mcp` without token → redirects to `oauth/start`
|
|
367
|
+
- `POST /mcp` without token → `401` JSON with `authorization_url`, `resource_metadata`, and a `WWW-Authenticate` Bearer challenge
|
|
368
|
+
- Normal user requests: `Authorization: Bearer <session-token>`
|
|
369
|
+
- Server requests with identity headers: `X-Ebay-Server-Request: true`, `X-Ebay-Client-Id: <client-id>`, `X-Ebay-User-Id: <user-id>`, `X-Ebay-Environment: sandbox|production`
|
|
370
|
+
- Server requests with bearer-capable clients: `X-Ebay-Server-Request: true` plus `Authorization: Bearer <mcp-server-issued-bearer-token>`
|
|
371
|
+
- Privileged admin bypass: `Authorization: Bearer <ADMIN_API_KEY>` when `ADMIN_API_KEY` is configured
|
|
456
372
|
|
|
457
|
-
**
|
|
373
|
+
The `X-Ebay-Server-Request` header is intentionally client-side and per-request. Leave it off for normal user/session OAuth calls. Add it when the MCP client is making a server-style request and should resolve the stored Redis/KV user token record by headers or by the MCP server-issued bearer lookup token. This bearer lookup token is generated by this MCP server on the OAuth callback page; it is **not** an eBay user access token, eBay refresh token, eBay client-credentials/app token, legacy hosted session token, or `ADMIN_API_KEY`.
|
|
458
374
|
|
|
459
|
-
|
|
460
|
-
GET /health # Server health check (no auth required)
|
|
461
|
-
GET /whoami # Session identity; requires Bearer session token
|
|
462
|
-
GET /admin/session/:sessionToken # View session; requires X-Admin-API-Key
|
|
463
|
-
POST /admin/session/:sessionToken/revoke # Revoke session
|
|
464
|
-
DELETE /admin/session/:sessionToken # Delete session
|
|
465
|
-
```
|
|
375
|
+
#### Admin key bypass
|
|
466
376
|
|
|
467
|
-
|
|
468
|
-
```json
|
|
469
|
-
{
|
|
470
|
-
"userId": "...",
|
|
471
|
-
"environment": "sandbox",
|
|
472
|
-
"createdAt": "2026-03-23T08:00:00.000Z",
|
|
473
|
-
"expiresAt": "2026-04-22T08:00:00.000Z",
|
|
474
|
-
"lastUsedAt": "2026-03-23T09:30:00.000Z",
|
|
475
|
-
"revokedAt": null
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
`/whoami` is the quickest hosted-session debugging check when an MCP client appears authenticated but requests still fail. It confirms which stored user session is active, which environment it is bound to, and whether the session has expired or been revoked.
|
|
480
|
-
|
|
481
|
-
### Validation architecture
|
|
482
|
-
|
|
483
|
-
The hosted backend now includes a deployment-oriented validation pipeline for non-MCP server-side execution. The route handlers live in [`src/server-http.ts`](src/server-http.ts), while the validation module lives under [`src/validation/`](src/validation).
|
|
484
|
-
|
|
485
|
-
Current module layout:
|
|
486
|
-
|
|
487
|
-
- [`src/validation/types.ts`](src/validation/types.ts) — request/response contracts for validation runs, decision payloads, debug payloads, and provider signal types
|
|
488
|
-
- [`src/validation/effective-context.ts`](src/validation/effective-context.ts) — source-aware normalization layer that converts raw request payloads into a first-class effective validation context for item and event runs
|
|
489
|
-
- [`src/validation/run-validation.ts`](src/validation/run-validation.ts) — orchestration entrypoint that validates input, queries providers, merges signals, and returns writes/decision/debug output
|
|
490
|
-
- [`src/validation/recommendation.ts`](src/validation/recommendation.ts) — recommendation and automation decision logic
|
|
491
|
-
- [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts) — live eBay browse-market snapshot provider using the server's existing user-scoped eBay API client
|
|
492
|
-
- [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts) — temporary sold-data provider backed by an external API via `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`
|
|
493
|
-
- [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) — authenticated eBay Research provider orchestration for current-market and previous-POB metrics, including candidate scoring, fallback diagnostics, and sold-velocity bucketing
|
|
494
|
-
- [`src/validation/providers/ebay-research.ts`](src/validation/providers/ebay-research.ts) — low-level authenticated eBay Research fetcher with session-cookie sourcing, response parsing, and auth-aware cache invalidation
|
|
495
|
-
- [`src/validation/providers/query-utils.ts`](src/validation/providers/query-utils.ts) — shared multi-tier query candidate and fallback helpers used by browse and sold providers
|
|
496
|
-
- [`src/validation/providers/social.ts`](src/validation/providers/social.ts) — phase-1 social provider for recent Twitter/X activity, YouTube view-rate proxy data, and Reddit recent-post counts with graceful degradation
|
|
497
|
-
- [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts) — chart-signal stub reserved for later implementation
|
|
498
|
-
- [`src/validation/providers/research.ts`](src/validation/providers/research.ts) — stable previous-comeback research contract provider for orchestration-side historical inference; currently a placeholder contract with optional future `PERPLEXITY_API_KEY` support
|
|
499
|
-
|
|
500
|
-
Current provider domains called by [`runValidation()`](src/validation/run-validation.ts:106):
|
|
501
|
-
|
|
502
|
-
- **browse/current-market** via [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts)
|
|
503
|
-
- **sold enrichment** via [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts)
|
|
504
|
-
- **Terapeak / eBay research contract** via [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts)
|
|
505
|
-
- **social support signals** via [`src/validation/providers/social.ts`](src/validation/providers/social.ts)
|
|
506
|
-
- **chart support signals** via [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts)
|
|
507
|
-
- **previous comeback research inference** via [`src/validation/providers/research.ts`](src/validation/providers/research.ts)
|
|
508
|
-
|
|
509
|
-
Architecturally, the validation stack is split into two practical classes of providers:
|
|
510
|
-
|
|
511
|
-
- **Server-side authenticated providers** — these run with the hosted backend's stored eBay user context and are the right place for authenticated marketplace retrieval. Today that means the live browse/current-market provider in [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts), the sold enrichment layer in [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts), and the Terapeak/eBay research contract in [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts).
|
|
512
|
-
- **Orchestration-side research providers** — these run as supporting inference layers inside orchestration rather than as part of the user-scoped eBay API client surface. Today that means previous comeback resolution and external historical-research inference in [`src/validation/providers/research.ts`](src/validation/providers/research.ts), plus non-authoritative support providers such as [`src/validation/providers/social.ts`](src/validation/providers/social.ts) and [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts).
|
|
377
|
+
`ADMIN_API_KEY` is used in two distinct ways:
|
|
513
378
|
|
|
514
|
-
|
|
379
|
+
| Use | Exact implementation | Scope |
|
|
380
|
+
|-----|----------------------|-------|
|
|
381
|
+
| Admin/validation HTTP routes | `X-Admin-API-Key: <ADMIN_API_KEY>` header | Required for `/admin/session/:sessionToken`, `/admin/session/:sessionToken/revoke`, `/admin/session/:sessionToken`, `/sandbox/validation/*`, `/production/validation/*`, and legacy `/validation/*`. |
|
|
382
|
+
| MCP authorization bypass | `Authorization: Bearer <ADMIN_API_KEY>` header | Lets privileged server-to-server/admin tooling call `/sandbox/mcp`, `/production/mcp`, or `/mcp` without a hosted user session lookup. The request runs with `userId` set to `admin` and the requested environment. |
|
|
515
383
|
|
|
516
|
-
|
|
517
|
-
2. The server resolves the environment (`sandbox` or `production`) from the mounted route tree.
|
|
518
|
-
3. The route looks up the configured validation runner user ID for that environment.
|
|
519
|
-
4. The server loads that user's stored refresh-token-backed credentials from the existing hosted auth store.
|
|
520
|
-
5. The validation orchestrator calls all six provider domains and gathers browse/current-market, sold enrichment, Terapeak/research contract data, social support signals, chart stub output, and previous-comeback research output.
|
|
521
|
-
6. Before provider execution, [`runValidation()`](src/validation/run-validation.ts) builds a normalized `effectiveContext` so downstream logic consumes a source-aware model (`item` or `event`) instead of relying on empty item placeholders.
|
|
522
|
-
7. [`runValidation()`](src/validation/run-validation.ts) deterministically merges the provider outputs into normalized field writes.
|
|
523
|
-
8. The response returns those writes, a conservative buy/track decision block, and provider debug metadata for downstream systems.
|
|
384
|
+
The admin bypass does **not** use query parameters or request body fields. `ADMIN_API_KEY` must be configured on the server; if it is unset, admin HTTP routes return `500` and the MCP bypass is disabled.
|
|
524
385
|
|
|
525
|
-
|
|
386
|
+
Security caveats:
|
|
387
|
+
- Treat `ADMIN_API_KEY` as a privileged root credential for this MCP server.
|
|
388
|
+
- Generate a long, random value and store it only in your deployment secret manager.
|
|
389
|
+
- Use it only for server-to-server automation, operational checks, or admin tooling. Do not ship it to browsers, desktop clients, or regular users.
|
|
390
|
+
- OAuth browser authorization and hosted session tokens remain the normal path for user MCP access.
|
|
526
391
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
- **Item-scope runs** normalize to an item-oriented context with the resolved artist, album/item phrase, location, and resolved search query.
|
|
530
|
-
- **Event-scope runs** normalize to an event-oriented context with `searchArtist`, `searchEvent`, `searchItem`, `searchLocation`, timing metadata, and a derived `effectiveSearchQuery` when no direct resolved query is present.
|
|
531
|
-
- Providers and recommendation logic consume that normalized context rather than reasoning about blank `item.recordId` or `item.name` fields.
|
|
532
|
-
- Debug output now exposes `effectiveSourceType`, `effectiveContextMode`, `effectiveSearchQuery`, `hasItem`, and `hasEvent` so operators can confirm whether an event run was normalized correctly.
|
|
533
|
-
|
|
534
|
-
The request schema also now accepts source-aware query-context fields for hosted validation runs:
|
|
535
|
-
|
|
536
|
-
- `resolvedSearchArtist`
|
|
537
|
-
- `resolvedSearchItem`
|
|
538
|
-
- `resolvedSearchEvent`
|
|
539
|
-
- `resolvedSearchLocation`
|
|
540
|
-
- `resolvedSearchQuery`
|
|
541
|
-
|
|
542
|
-
The validation contract is intentionally split between stable route orchestration and swappable providers. That is why the current sold-data source can be replaced later without changing downstream orchestration or the hosted route contract implemented in [`src/validation/run-validation.ts`](src/validation/run-validation.ts).
|
|
543
|
-
|
|
544
|
-
#### Deterministic merge precedence
|
|
545
|
-
|
|
546
|
-
The current merge order is fixed in [`runValidation()`](src/validation/run-validation.ts:106) so downstream systems can treat the writes as predictable rather than provider-order dependent:
|
|
547
|
-
|
|
548
|
-
- **Watchers / preorder count / shipping / competition** prefer Terapeak contract output when available, then fall back to the browse/current-market provider.
|
|
549
|
-
- **Market price** prefers Terapeak contract output, then the sold provider's median sold price, then the browse/current-market provider.
|
|
550
|
-
- **Sold day buckets** (`day1Sold` through `day5Sold`, plus `daysTracked`) prefer the sold provider, then authenticated eBay Research sold-row bucketing, then the browse/current-market provider.
|
|
551
|
-
- **Previous POB metrics** (`previousPobAvgPriceUsd`, `previousPobSellThroughPct`) are written from the Terapeak contract output when available.
|
|
552
|
-
- **Previous comeback first-week sales** (`previousComebackFirstWeekSales`) is written from the orchestration-side research provider when available.
|
|
553
|
-
- **Supportive social fields** are only written when a value is actually resolved, so the pipeline avoids blanking previously stored downstream data.
|
|
554
|
-
|
|
555
|
-
The validation signal contracts in [`TerapeakValidationSignals`](src/validation/types.ts:142) and [`PreviousComebackResearchSignals`](src/validation/types.ts:164) also back the new write fields in [`ValidationWrites`](src/validation/types.ts:176): `previousPobAvgPriceUsd`, `previousPobSellThroughPct`, and `previousComebackFirstWeekSales`.
|
|
556
|
-
|
|
557
|
-
### Validation endpoints and auth model
|
|
558
|
-
|
|
559
|
-
Use the environment-scoped hosted routes for validation:
|
|
392
|
+
**Utility endpoints:**
|
|
560
393
|
|
|
561
394
|
```
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
395
|
+
GET /health # health check (no auth)
|
|
396
|
+
GET /whoami # session identity (Bearer token)
|
|
397
|
+
GET /admin/session/:sessionToken # view session (admin key)
|
|
398
|
+
POST /admin/session/:sessionToken/revoke # revoke session
|
|
399
|
+
DELETE /admin/session/:sessionToken # delete session
|
|
567
400
|
```
|
|
568
401
|
|
|
569
|
-
|
|
402
|
+
### Admin endpoints
|
|
403
|
+
|
|
404
|
+
All `/admin/*` routes accept authentication via either:
|
|
405
|
+
- Header: `X-Admin-API-Key: <ADMIN_API_KEY>`
|
|
406
|
+
- Query param: `?key=<ADMIN_API_KEY>` (useful for browser access)
|
|
570
407
|
|
|
571
408
|
```
|
|
572
|
-
|
|
409
|
+
GET /admin/token-status # OAuth + Playwright session health
|
|
410
|
+
POST /admin/oauth/start-for-validation # Start OAuth flow for validation runner
|
|
411
|
+
POST /admin/playwright-session # Store Playwright storage state JSON
|
|
412
|
+
GET /admin/playwright-capture # Browser UI to capture eBay Research cookies
|
|
573
413
|
```
|
|
574
414
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
- Validation routes are **hosted HTTP backend routes**, not MCP tool endpoints.
|
|
578
|
-
- They do **not** use MCP client auth for execution.
|
|
579
|
-
- They reuse the existing stored refresh-token-backed hosted user architecture.
|
|
580
|
-
- The caller authenticates with `X-Admin-API-Key`, and the server then impersonates the configured validation runner user for the target environment.
|
|
581
|
-
- Validation runner identity comes from `VALIDATION_RUNNER_USER_ID`, `VALIDATION_RUNNER_USER_ID_SANDBOX`, or `VALIDATION_RUNNER_USER_ID_PRODUCTION`.
|
|
582
|
-
- The validation runner must already have stored hosted tokens in the configured token store backend.
|
|
583
|
-
|
|
584
|
-
#### `POST /validation/run`
|
|
585
|
-
|
|
586
|
-
Runs the validation pipeline for the target environment.
|
|
587
|
-
|
|
588
|
-
- Uses the configured validation runner user ID for that environment
|
|
589
|
-
- Requires that stored refresh-token-backed eBay credentials already exist for that user
|
|
590
|
-
- Returns either:
|
|
591
|
-
- `status: "ok"` with `writes`, `decision`, and `debug`, or
|
|
592
|
-
- `status: "error"` with `errorCode`, `message`, `retryable`, and `nextCheckAt`
|
|
593
|
-
|
|
594
|
-
The request/response contract is defined in [`src/validation/types.ts`](src/validation/types.ts), and the orchestration behavior is implemented in [`src/validation/run-validation.ts`](src/validation/run-validation.ts).
|
|
595
|
-
|
|
596
|
-
The `writes` payload is intentionally non-destructive for supportive and optional fields: if a social, authenticated eBay Research, or previous-comeback research provider cannot resolve data, the orchestration omits those optional writes instead of overwriting existing downstream values with empty placeholders.
|
|
597
|
-
|
|
598
|
-
#### `GET /validation/health`
|
|
599
|
-
|
|
600
|
-
Checks whether the validation runner is operational in the target environment.
|
|
601
|
-
|
|
602
|
-
This endpoint is intended for deployment diagnostics and returns:
|
|
603
|
-
|
|
604
|
-
- configured environment
|
|
605
|
-
- configured validation runner user ID
|
|
606
|
-
- whether stored tokens are present
|
|
607
|
-
- whether token refresh/authentication succeeded
|
|
608
|
-
- token status from the user-scoped eBay API client
|
|
609
|
-
- `authDebug` diagnostics including token endpoint resolution and credential presence
|
|
610
|
-
- provider availability summary
|
|
611
|
-
|
|
612
|
-
The diagnostics are especially useful after the OAuth token endpoint fix in [`getOAuthTokenBaseUrl()`](src/config/environment.ts:373) and the debug additions in [`getAuthDebugInfo()`](src/auth/oauth.ts:282). If the validation runner cannot refresh tokens, `/validation/health` shows the resolved token endpoint and any captured upstream response status/body excerpt.
|
|
613
|
-
|
|
614
|
-
### Diagnostics and health endpoints
|
|
615
|
-
|
|
616
|
-
Use these endpoints together when validating a hosted deployment:
|
|
415
|
+
**`/admin/playwright-capture`** renders a self-service page for renewing the eBay Research Playwright session. Open it in a browser with the admin key as a query parameter:
|
|
617
416
|
|
|
618
417
|
```
|
|
619
|
-
|
|
620
|
-
GET /whoami
|
|
621
|
-
GET /sandbox/validation/health
|
|
622
|
-
GET /production/validation/health
|
|
623
|
-
POST /internal/ebay-research/check-session-expiry
|
|
418
|
+
https://your-server.com/admin/playwright-capture?key=YOUR_ADMIN_API_KEY
|
|
624
419
|
```
|
|
625
420
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
2. Call `/whoami` with a Bearer hosted session token to confirm the active hosted user session, bound environment, expiry, and revocation status.
|
|
630
|
-
3. Call the matching env-scoped `/validation/health` route with `X-Admin-API-Key` to confirm the validation runner user is configured, stored tokens exist, and token refresh succeeds.
|
|
631
|
-
4. The internal `POST /internal/ebay-research/check-session-expiry` route is reserved for signed QStash callbacks and should not be used as an unauthenticated public endpoint.
|
|
632
|
-
|
|
633
|
-
`/whoami` is especially useful when an operator wants to verify which hosted session is currently active before registering or troubleshooting the validation runner user. Validation routes themselves still authenticate with the admin key and a stored hosted runner identity, not with MCP auth.
|
|
634
|
-
|
|
635
|
-
The validation health response is also the main place to verify the OAuth token-endpoint derivation fix from [`getOAuthTokenBaseUrl()`](src/config/environment.ts:373). If a refresh fails, the `authDebug` block exposes the resolved endpoint, credential-presence flags, and captured upstream response excerpts.
|
|
636
|
-
|
|
637
|
-
### Validation provider behavior and limitations
|
|
638
|
-
|
|
639
|
-
Current backend status:
|
|
421
|
+
The page has two tabs:
|
|
422
|
+
1. **Auto-Capture** — loads eBay Research in an iframe (may be blocked by eBay's security policies)
|
|
423
|
+
2. **Manual Export** — provides step-by-step instructions to export cookies from Chrome DevTools, a bookmarklet for one-click cookie copying, and a text area to paste and submit the JSON
|
|
640
424
|
|
|
641
|
-
|
|
642
|
-
- Sold-data enrichment is implemented through a **temporary external provider** abstraction.
|
|
643
|
-
- Authenticated eBay Research is wired into orchestration for current-market and previous-POB retrieval, while previous-comeback research remains a separate placeholder contract.
|
|
644
|
-
- Social support signals are implemented in phase 1.
|
|
645
|
-
- Chart data remains a stub.
|
|
646
|
-
- Validation is currently an **admin-operated hosted backend workflow**, not an MCP tool surface.
|
|
647
|
-
- Event-scope validations are now handled as first-class normalized runs instead of as item-shaped requests with null item identity tolerated for compatibility.
|
|
425
|
+
Submitted cookies are validated against the authenticated eBay Research ACTIVE endpoint before persistence, stored in the configured session backend (Upstash Redis / Cloudflare KV / filesystem), and written with a long KV TTL. Cookie expiry is tracked in metadata so the runtime can report missing/expired Terapeak auth separately from provider parsing failures.
|
|
648
426
|
|
|
649
|
-
|
|
427
|
+
### Validation endpoints
|
|
650
428
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
- **Terapeak / eBay research provider:** [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) now evaluates authenticated eBay Research candidates for both current-market and previous-POB contexts, scores them against title alignment and subtype coverage, preserves per-candidate diagnostics in debug output, and derives sold-day buckets from sold-row timestamps when available.
|
|
655
|
-
- **Authenticated research session source:** [`src/validation/providers/ebay-research.ts`](src/validation/providers/ebay-research.ts) now prefers KV-backed Playwright storage state first, then environment-provided storage state / cookie fallbacks, then local storage-state/profile fallbacks for local development only. Parsed ACTIVE and SOLD tab responses are cached, automatically invalidated when the authenticated cookie fingerprint changes, and emit explicit auth-resolution debug fields including `sessionSource`, KV/env/filesystem attempt status, and fallback reasons.
|
|
656
|
-
- **Social provider:** [`src/validation/providers/social.ts`](src/validation/providers/social.ts) supports phase-1 Twitter/X recent activity, YouTube average-daily-views proxy data exposed through the `youtubeViews24hMillions` field, and Reddit recent post counts. These signals degrade gracefully on provider/API failure and are used as supportive indicators rather than authoritative demand truth.
|
|
657
|
-
- **Chart provider:** [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts) is still a stub and does not currently contribute chart-based metrics.
|
|
658
|
-
- **Previous comeback research provider:** [`src/validation/providers/research.ts`](src/validation/providers/research.ts) now performs Perplexity-backed historical research when `PERPLEXITY_API_KEY` is configured. It attempts to resolve the prior comeback, normalize previous first-week sales when support exists, assign a `perplexityHistoricalContextScore`, generate concise `historicalContextNotes`, and emit debug diagnostics covering the research query, citations/snippets, resolved prior release, confidence, and score reasoning.
|
|
659
|
-
|
|
660
|
-
Recommendation behavior:
|
|
661
|
-
|
|
662
|
-
- [`src/validation/recommendation.ts`](src/validation/recommendation.ts) now accepts Terapeak and research inputs alongside browse, sold, social, and chart signals.
|
|
663
|
-
- Recommendation generation also consumes the normalized effective context so event runs can carry source-aware monitoring notes and avoid item-only assumptions when no usable item identity exists.
|
|
664
|
-
- Automatic tracking now pauses when the validation is still nominally in a watch state but the required source context or a usable derived query is missing.
|
|
665
|
-
- The decisioning remains intentionally conservative: Terapeak and research data can improve monitoring notes and confidence context, but the system still avoids aggressive automatic buy-state changes from partial or proxy signals alone.
|
|
666
|
-
|
|
667
|
-
Known limitations in the current implementation:
|
|
668
|
-
|
|
669
|
-
- The sold-data provider depends on external configuration via `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`.
|
|
670
|
-
- If those sold-data variables are missing, validation still runs but sold enrichment degrades to an unavailable/error state rather than providing full historical-sales signals.
|
|
671
|
-
- The sold-data provider is temporary and intended to be replaced by an internal implementation later.
|
|
672
|
-
- Authenticated eBay Research requires a valid session source such as KV-backed Playwright storage state, `EBAY_RESEARCH_STORAGE_STATE_JSON`, `EBAY_RESEARCH_COOKIES_JSON`, a local Playwright storage-state file, or a local browser profile directory; without one, the provider degrades to diagnostic-only output with explicit structured auth-resolution debug.
|
|
673
|
-
|
|
674
|
-
#### eBay Research bootstrap and hosted runtime notes
|
|
429
|
+
```
|
|
430
|
+
POST /sandbox/validation/run # run validation pipeline
|
|
431
|
+
POST /production/validation/run
|
|
675
432
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
- Bootstrap a signed-in eBay Research storage state into KV with [`src/scripts/bootstrap-ebay-research-session.ts`](src/scripts/bootstrap-ebay-research-session.ts) via the packaged/runtime-safe [`package.json`](package.json) script `research:bootstrap` (`pnpm run build && pnpm run research:bootstrap`).
|
|
680
|
-
- Inspect canonical eBay Research session persistence and fresh-client readback diagnostics with [`src/scripts/inspect-ebay-research-session.ts`](src/scripts/inspect-ebay-research-session.ts) via the packaged/runtime-safe [`package.json`](package.json) script `research:inspect-session` (`pnpm run build && pnpm run research:inspect-session`).
|
|
681
|
-
- Verify headless Chromium launchability with [`src/scripts/check-playwright.ts`](src/scripts/check-playwright.ts) via the packaged/runtime-safe [`package.json`](package.json) script `research:check-browser` (`pnpm run build && pnpm run research:check-browser`).
|
|
682
|
-
- Runtime precedence is: KV storage state → `EBAY_RESEARCH_STORAGE_STATE_JSON` → `EBAY_RESEARCH_COOKIES_JSON` → local storage-state file → local Playwright profile → explicit auth-missing fallback.
|
|
683
|
-
- Every candidate session source is validated against the first-party ACTIVE endpoint before the provider reports `authState = loaded`; failed validation is surfaced through debug fields including `kvStorageStateBytes`, `authValidationAttempted`, and `authValidationSucceeded`.
|
|
684
|
-
- Once a validated session is loaded, ACTIVE and SOLD endpoint fetches automatically become the preferred first-party research source while legacy active/sold fallbacks remain intact when auth is missing or invalid.
|
|
685
|
-
- Successful bootstrap also schedules signed QStash callbacks for 24 hours before expiry, 6 hours before expiry, and at expiry. Those callbacks target `POST /internal/ebay-research/check-session-expiry`, which verifies QStash signatures, suppresses stale reminders by `sessionVersion`, and sends Telegram alerts to `TELEGRAM_CHAT_ID`.
|
|
686
|
-
- Alert scheduling is intentionally skipped when the callback URL resolves to localhost/loopback or when `EBAY_RESEARCH_SESSION_STORE` uses a backend without shared lock support, because those configurations cannot safely deliver or deduplicate hosted reminders.
|
|
687
|
-
- Session refresh is manual by design for now: rerun `pnpm run build && pnpm run research:bootstrap` whenever eBay expires the stored session, then redeploy or restart the hosted service if your platform does not hot-reload env/KV-backed state.
|
|
688
|
-
- The previous-comeback research provider depends on grounded external research and therefore degrades to low-confidence notes with a zero historical score when `PERPLEXITY_API_KEY` is missing, the response cannot be normalized, or reliable evidence is not found.
|
|
689
|
-
- The browse provider still relies on heuristic query selection and fallback matching.
|
|
690
|
-
- The YouTube-backed `youtubeViews24hMillions` field is currently an **average daily views proxy**, not a true trailing 24-hour delta.
|
|
691
|
-
- Social signals are supportive/proxy data only and should not be presented as decisive automated buy logic.
|
|
692
|
-
- eBay-derived metrics are intentionally practical rather than exhaustive, but authenticated ACTIVE research rows now populate watcher-derived metrics whenever watcher counts are present in the first-party response.
|
|
433
|
+
GET /sandbox/validation/health # check runner status
|
|
434
|
+
GET /production/validation/health
|
|
435
|
+
```
|
|
693
436
|
|
|
694
|
-
|
|
437
|
+
Both require `X-Admin-API-Key: <ADMIN_API_KEY>`. The server impersonates the configured validation runner user from `VALIDATION_RUNNER_USER_ID` env vars.
|
|
695
438
|
|
|
696
|
-
|
|
697
|
-
- The Terapeak/eBay research layer is intentionally isolated behind [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) so a future authenticated research integration can drop in without changing the route contract or downstream writes.
|
|
698
|
-
- The orchestration-side historical research layer is intentionally isolated behind [`src/validation/providers/research.ts`](src/validation/providers/research.ts) so future previous-comeback resolution or external inference providers can be added without rewriting the validation runner.
|
|
439
|
+
See [Validation architecture](#validation-architecture) below for provider details.
|
|
699
440
|
|
|
700
441
|
### Remote client configuration
|
|
701
442
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
443
|
+
**Cline (automatic OAuth):**
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"mcpServers": {
|
|
447
|
+
"ebay-sandbox": { "url": "https://your-server.com/sandbox/mcp" },
|
|
448
|
+
"ebay-production": { "url": "https://your-server.com/production/mcp" }
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
Cline auto-discovers OAuth, opens browser login, exchanges auth code, and stores session token.
|
|
707
453
|
|
|
454
|
+
**Claude Desktop / Cursor (Bearer token):**
|
|
455
|
+
1. Open `https://your-server.com/sandbox/oauth/start` → complete eBay login → copy session token
|
|
456
|
+
2. Configure client:
|
|
708
457
|
```json
|
|
709
458
|
{
|
|
710
459
|
"mcpServers": {
|
|
711
460
|
"ebay-sandbox": {
|
|
712
|
-
"url": "https://your-server.com/sandbox/mcp"
|
|
713
|
-
|
|
714
|
-
"ebay-production": {
|
|
715
|
-
"url": "https://your-server.com/production/mcp"
|
|
461
|
+
"url": "https://your-server.com/sandbox/mcp",
|
|
462
|
+
"headers": { "Authorization": "Bearer YOUR_SESSION_TOKEN" }
|
|
716
463
|
}
|
|
717
464
|
}
|
|
718
465
|
}
|
|
719
466
|
```
|
|
720
467
|
|
|
721
|
-
|
|
722
|
-
1.
|
|
723
|
-
2.
|
|
724
|
-
3.
|
|
725
|
-
4.
|
|
726
|
-
5. Cline exchanges the code at `POST /sandbox/token` for a session token and stores it
|
|
727
|
-
6. All subsequent `/sandbox/mcp` requests authenticate automatically
|
|
728
|
-
|
|
729
|
-
#### Claude Desktop and Cursor (Bearer token)
|
|
730
|
-
|
|
731
|
-
Claude Desktop and most other remote MCP clients require a pre-obtained session token. Complete the browser OAuth flow first:
|
|
732
|
-
|
|
733
|
-
1. Open `https://your-server.com/sandbox/oauth/start` (or `/production/oauth/start`) in a browser
|
|
734
|
-
2. Log in with your eBay account
|
|
735
|
-
3. Copy the session token from the confirmation page
|
|
736
|
-
|
|
737
|
-
Then configure your client:
|
|
738
|
-
|
|
468
|
+
**Server request mode (custom headers):**
|
|
469
|
+
1. Open `https://your-server.com/sandbox/oauth/start` or `https://your-server.com/production/oauth/start`
|
|
470
|
+
2. Complete eBay login
|
|
471
|
+
3. Copy the server request headers shown on the callback page
|
|
472
|
+
4. Configure the MCP client with those headers:
|
|
739
473
|
```json
|
|
740
474
|
{
|
|
741
475
|
"mcpServers": {
|
|
742
|
-
"ebay-
|
|
743
|
-
"url": "https://your-server.com/
|
|
476
|
+
"ebay-production-server": {
|
|
477
|
+
"url": "https://your-server.com/production/mcp",
|
|
744
478
|
"headers": {
|
|
745
|
-
"
|
|
479
|
+
"X-Ebay-Server-Request": "true",
|
|
480
|
+
"X-Ebay-Client-Id": "YOUR_EBAY_CLIENT_ID",
|
|
481
|
+
"X-Ebay-User-Id": "STORED_USER_ID_FROM_CALLBACK",
|
|
482
|
+
"X-Ebay-Environment": "production"
|
|
746
483
|
}
|
|
747
484
|
}
|
|
748
485
|
}
|
|
749
486
|
}
|
|
750
487
|
```
|
|
751
488
|
|
|
752
|
-
|
|
489
|
+
**Server request mode (bearer-capable clients):**
|
|
490
|
+
Use this when the MCP client can set `Authorization` but cannot easily send several custom identity headers:
|
|
491
|
+
```json
|
|
492
|
+
{
|
|
493
|
+
"mcpServers": {
|
|
494
|
+
"ebay-production-server": {
|
|
495
|
+
"url": "https://your-server.com/production/mcp",
|
|
496
|
+
"headers": {
|
|
497
|
+
"X-Ebay-Server-Request": "true",
|
|
498
|
+
"Authorization": "Bearer MCP_SERVER_ISSUED_BEARER_TOKEN_FROM_CALLBACK"
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
753
504
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
505
|
+
**Make / Zapier / other platforms:**
|
|
506
|
+
1. Complete OAuth via browser at `/oauth/start`
|
|
507
|
+
2. If the platform supports multiple headers, use server request mode identity headers
|
|
508
|
+
3. If the platform only supports one auth header, use server request mode with the MCP server-issued bearer lookup token from the callback page
|
|
509
|
+
4. Set MCP URL to `https://your-server.com/sandbox/mcp`
|
|
758
510
|
|
|
759
511
|
---
|
|
760
512
|
|
|
761
|
-
##
|
|
513
|
+
## Tool discovery for agents
|
|
514
|
+
|
|
515
|
+
AI agents discover tools through the MCP protocol's `tools/list` call. The eBay MCP server exposes 325+ tools with a predictable naming and description structure optimized for agent searchability.
|
|
516
|
+
|
|
517
|
+
### Tool naming convention
|
|
518
|
+
|
|
519
|
+
All tools follow the pattern `ebay_<action>_<resource>`:
|
|
520
|
+
|
|
521
|
+
| Action | Meaning | Examples |
|
|
522
|
+
|--------|---------|----------|
|
|
523
|
+
| `get` | Read/fetch | `ebay_get_inventory_item`, `ebay_get_offers` |
|
|
524
|
+
| `create` | Create new | `ebay_create_offer`, `ebay_create_fulfillment_policy` |
|
|
525
|
+
| `update` | Modify existing | `ebay_update_offer`, `ebay_update_inventory_item` |
|
|
526
|
+
| `delete` | Remove | `ebay_delete_offer`, `ebay_delete_inventory_item` |
|
|
527
|
+
| `publish` | Activate | `ebay_publish_offer` |
|
|
528
|
+
| `withdraw` | Deactivate | `ebay_withdraw_offer` |
|
|
529
|
+
| `revise` | Modify listing | `ebay_revise_listing` |
|
|
530
|
+
| `bulk_` | Batch operations | `ebay_bulk_create_offer`, `ebay_bulk_update_price_quantity` |
|
|
531
|
+
|
|
532
|
+
### Tool descriptions are self-documenting
|
|
533
|
+
|
|
534
|
+
Each tool description includes:
|
|
535
|
+
- **What it does** — concise action description
|
|
536
|
+
- **OAuth scope required** — the minimum scope needed
|
|
537
|
+
- **Minimum scope URL** — for fine-grained permission setup
|
|
538
|
+
|
|
539
|
+
Example:
|
|
540
|
+
```
|
|
541
|
+
Get a specific inventory item by SKU.
|
|
542
|
+
|
|
543
|
+
Required OAuth Scope: sell.inventory.readonly or sell.inventory
|
|
544
|
+
Minimum Scope: https://api.ebay.com/oauth/api_scope/sell.inventory.readonly
|
|
545
|
+
```
|
|
762
546
|
|
|
763
|
-
|
|
547
|
+
### Tools organized by category
|
|
764
548
|
|
|
765
|
-
|
|
766
|
-
- Inventory Management
|
|
767
|
-
- Order Fulfillment
|
|
768
|
-
- Marketing & Promotions
|
|
769
|
-
- Analytics & Reporting
|
|
770
|
-
- Communication (messages, feedback, notifications, negotiation)
|
|
771
|
-
- Metadata & Taxonomy
|
|
772
|
-
- Developer Tools (key management, analytics)
|
|
773
|
-
- Auth / Token helper tools
|
|
549
|
+
Tools are grouped into 13 category files in `src/tools/definitions/`:
|
|
774
550
|
|
|
775
|
-
|
|
551
|
+
| Category file | Tool prefix | Key operations |
|
|
552
|
+
|---------------|-------------|----------------|
|
|
553
|
+
| `inventory.ts` | `ebay_*inventory*`, `ebay_*offer*` | CRUD inventory items, offers, locations, bulk ops |
|
|
554
|
+
| `fulfillment.ts` | `ebay_*fulfillment*`, `ebay_*shipment*` | Shipments, fulfillment orders, shipping labels |
|
|
555
|
+
| `account.ts` | `ebay_*policy*` | Payment, return, fulfillment policies |
|
|
556
|
+
| `marketing.ts` | `ebay_*promotion*`, `ebay_*markdown*` | Promotions, markdown listings |
|
|
557
|
+
| `analytics.ts` | `ebay_*analytics*`, `ebay_*report*` | Analytics, reporting |
|
|
558
|
+
| `communication.ts` | `ebay_*message*`, `ebay_*feedback*` | Messages, feedback, notifications |
|
|
559
|
+
| `metadata.ts` | `ebay_*metadata*`, `ebay_*policies*` | Category policies, listing metadata |
|
|
560
|
+
| `taxonomy.ts` | `ebay_*category*` | Category tree, suggestions, item specifics |
|
|
561
|
+
| `browse.ts` | `ebay_*browse*`, `ebay_*product*` | Browse/search products |
|
|
562
|
+
| `trading.ts` | `ebay_*listing*`, `ebay_*create_listing*` | Trading API (XML/SOAP) operations |
|
|
563
|
+
| `developer.ts` | `ebay_*signing*`, `ebay_*vero*` | Key management, VERO reports |
|
|
564
|
+
| `other.ts` | Mixed | Misc/legacy endpoints |
|
|
565
|
+
| `token-management.ts` | `ebay_*oauth*`, `ebay_*token*` | OAuth helpers, token management |
|
|
566
|
+
|
|
567
|
+
### How agents find the right tool
|
|
568
|
+
|
|
569
|
+
1. **Search by name pattern** — `ebay_get_*` for reads, `ebay_create_*` for writes, `ebay_*offer*` for offers
|
|
570
|
+
2. **Search by description** — descriptions contain action keywords and resource names
|
|
571
|
+
3. **Search by OAuth scope** — `sell.inventory` for inventory, `sell.fulfillment` for shipping
|
|
572
|
+
4. **Use `tools/list`** — agents receive the full tool list with names and descriptions; filter programmatically
|
|
573
|
+
|
|
574
|
+
### Tool annotations
|
|
575
|
+
|
|
576
|
+
Tools carry MCP annotations that help agents understand behavior:
|
|
577
|
+
|
|
578
|
+
| Annotation | Meaning |
|
|
579
|
+
|-----------|---------|
|
|
580
|
+
| `readOnlyHint: true` | Safe to call; no side effects |
|
|
581
|
+
| `destructiveHint: true` | Irreversible; use caution |
|
|
582
|
+
| `idempotentHint: true` | Safe to retry |
|
|
583
|
+
| `openWorldHint: true` | May interact with external services |
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## Available tools
|
|
588
|
+
|
|
589
|
+
325+ tools across all eBay Sell API categories. Full source: [`src/tools/definitions/`](src/tools/definitions/)
|
|
776
590
|
|
|
777
591
|
---
|
|
778
592
|
|
|
779
593
|
## Development
|
|
780
594
|
|
|
781
|
-
### Commands
|
|
595
|
+
### Commands
|
|
782
596
|
|
|
783
597
|
| Command | Description |
|
|
784
598
|
|---------|-------------|
|
|
785
|
-
| `pnpm run build` | Compile TypeScript
|
|
786
|
-
| `pnpm start` | Run local STDIO
|
|
787
|
-
| `pnpm run start:http` | Run hosted HTTP
|
|
788
|
-
| `pnpm run dev` |
|
|
789
|
-
| `pnpm run dev:http` |
|
|
790
|
-
| `pnpm test` | Run
|
|
791
|
-
| `pnpm run setup` | Interactive
|
|
792
|
-
| `pnpm run sync` | Download
|
|
793
|
-
| `pnpm run diagnose` | Check
|
|
794
|
-
| `pnpm run typecheck` |
|
|
795
|
-
| `pnpm run check` | Typecheck + lint + format
|
|
796
|
-
| `pnpm run fix` | Auto-fix lint and format
|
|
599
|
+
| `pnpm run build` | Compile TypeScript |
|
|
600
|
+
| `pnpm start` | Run local STDIO server |
|
|
601
|
+
| `pnpm run start:http` | Run hosted HTTP server |
|
|
602
|
+
| `pnpm run dev` | STDIO with hot reload |
|
|
603
|
+
| `pnpm run dev:http` | HTTP with hot reload |
|
|
604
|
+
| `pnpm test` | Run tests |
|
|
605
|
+
| `pnpm run setup` | Interactive setup wizard |
|
|
606
|
+
| `pnpm run sync` | Download eBay OpenAPI specs, regenerate types |
|
|
607
|
+
| `pnpm run diagnose` | Check config and connectivity |
|
|
608
|
+
| `pnpm run typecheck` | TypeScript type checking |
|
|
609
|
+
| `pnpm run check` | Typecheck + lint + format |
|
|
610
|
+
| `pnpm run fix` | Auto-fix lint and format |
|
|
797
611
|
|
|
798
612
|
### `pnpm run sync`
|
|
799
613
|
|
|
800
|
-
|
|
614
|
+
Download latest eBay OpenAPI specs and regenerate types:
|
|
801
615
|
|
|
802
616
|
```bash
|
|
803
|
-
pnpm run sync
|
|
804
|
-
pnpm run typecheck
|
|
805
|
-
pnpm run build
|
|
617
|
+
pnpm run sync && pnpm run typecheck && pnpm run build
|
|
806
618
|
```
|
|
807
619
|
|
|
808
|
-
Review the diff, commit
|
|
809
|
-
|
|
810
|
-
### Local env management
|
|
620
|
+
Review the diff, commit changes you want to keep, and deploy.
|
|
811
621
|
|
|
812
|
-
|
|
622
|
+
### Env management
|
|
813
623
|
|
|
814
624
|
```bash
|
|
815
625
|
pnpm run env:encrypt # encrypt .env for safe sharing
|
|
@@ -825,40 +635,74 @@ EBAY_ENABLE_FILE_LOGGING=true # write logs to files
|
|
|
825
635
|
|
|
826
636
|
---
|
|
827
637
|
|
|
638
|
+
## Validation architecture
|
|
639
|
+
|
|
640
|
+
The hosted backend includes a validation pipeline for item evaluation. Routes live in [`src/server-http.ts`](src/server-http.ts), logic in [`src/validation/`](src/validation).
|
|
641
|
+
|
|
642
|
+
**Module layout:**
|
|
643
|
+
|
|
644
|
+
| File | Purpose |
|
|
645
|
+
|------|---------|
|
|
646
|
+
| `types.ts` | Request/response contracts |
|
|
647
|
+
| `effective-context.ts` | Source-aware normalization (item vs event runs) |
|
|
648
|
+
| `run-validation.ts` | Orchestration entrypoint |
|
|
649
|
+
| `recommendation.ts` | Buy/track decision logic |
|
|
650
|
+
| `providers/ebay.ts` | Live browse-market snapshot |
|
|
651
|
+
| `providers/ebay-sold.ts` | Sold-data enrichment (temporary external provider) |
|
|
652
|
+
| `providers/terapeak.ts` | Terapeak / eBay Research metrics |
|
|
653
|
+
| `providers/ebay-research.ts` | Authenticated eBay Research fetcher |
|
|
654
|
+
| `providers/social.ts` | Twitter/X, YouTube, Reddit signals |
|
|
655
|
+
| `providers/chart.ts` | Chart-signal stub |
|
|
656
|
+
| `providers/research.ts` | Historical comeback research (Perplexity) |
|
|
657
|
+
|
|
658
|
+
**Flow:** Admin calls `/validation/run` → server resolves runner user → orchestrator queries all providers → merges signals → returns writes + decision + debug metadata.
|
|
659
|
+
|
|
660
|
+
**Merge precedence:** Terapeak > sold provider > browse provider for overlapping fields. Optional providers (social, research) only write when data resolves — never blank existing values.
|
|
661
|
+
|
|
662
|
+
**Known limitations:**
|
|
663
|
+
- Sold-data provider is temporary (external API via `SOLD_ITEMS_API_URL`)
|
|
664
|
+
- Social signals are supportive only — not authoritative buy triggers
|
|
665
|
+
- Chart provider is a stub
|
|
666
|
+
- eBay Research requires valid Playwright session
|
|
667
|
+
|
|
668
|
+
**eBay Research session management:**
|
|
669
|
+
- Bootstrap: `pnpm run research:bootstrap`
|
|
670
|
+
- Inspect: `pnpm run research:inspect-session`
|
|
671
|
+
- Browser check: `pnpm run research:check-browser`
|
|
672
|
+
- Session source precedence: KV → env vars → local files → fallback
|
|
673
|
+
- QStash alerts: 24h before, 6h before, and at expiry → Telegram
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
828
677
|
## Testing & validation
|
|
829
678
|
|
|
830
679
|
```bash
|
|
831
|
-
# Build and
|
|
832
|
-
pnpm run build
|
|
833
|
-
pnpm run typecheck
|
|
680
|
+
# Build and test
|
|
681
|
+
pnpm run build && pnpm run typecheck && pnpm test
|
|
834
682
|
|
|
835
|
-
#
|
|
836
|
-
pnpm test
|
|
837
|
-
|
|
838
|
-
# Check connectivity and token status
|
|
683
|
+
# Connectivity check
|
|
839
684
|
pnpm run diagnose
|
|
840
685
|
|
|
841
|
-
#
|
|
686
|
+
# Hosted health
|
|
842
687
|
curl https://your-server.com/health
|
|
843
688
|
|
|
844
|
-
#
|
|
845
|
-
curl -H "Authorization: Bearer <
|
|
689
|
+
# Session check
|
|
690
|
+
curl -H "Authorization: Bearer <token>" https://your-server.com/whoami
|
|
846
691
|
|
|
847
|
-
#
|
|
692
|
+
# Validation runner health
|
|
848
693
|
curl https://your-server.com/sandbox/validation/health \
|
|
849
694
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
850
695
|
|
|
851
|
-
#
|
|
852
|
-
curl
|
|
853
|
-
-H "
|
|
854
|
-
-H "
|
|
855
|
-
-d '{"validationId":"example-123","runType":"manual","cadence":"Daily","timestamp":"2026-03-31T00:00:00.000Z","item":{"recordId":"1","name":"Example Item","variation":[],"itemType":[],"releaseType":[],"releaseDate":null,"releasePeriod":[],"availability":[],"wholesalePrice":null,"supplierNames":[],"canonicalArtists":[],"relatedAlbums":[]},"validation":{"validationType":"default","buyDecision":"Hold","automationStatus":"Manual","autoCheckEnabled":false,"dDay":null,"artistTier":"unknown","initialBudget":null,"reserveBudget":null,"currentMetrics":{"avgWatchersPerListing":null,"preOrderListingsCount":null,"twitterTrending":false,"youtubeViews24hMillions":null,"redditPostsCount7d":null,"marketPriceUsd":null,"avgShippingCostUsd":null,"competitionLevel":null,"marketPriceTrend":"Stable","day1Sold":null,"day2Sold":null,"day3Sold":null,"day4Sold":null,"day5Sold":null,"daysTracked":null}}}'
|
|
696
|
+
# Privileged MCP admin-key bypass check
|
|
697
|
+
curl https://your-server.com/sandbox/mcp \
|
|
698
|
+
-H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
|
|
699
|
+
-H "Accept: application/json, text/event-stream"
|
|
856
700
|
|
|
857
|
-
#
|
|
701
|
+
# MCP auth challenge test
|
|
858
702
|
curl -X POST https://your-server.com/sandbox/mcp \
|
|
859
703
|
-H "Content-Type: application/json" \
|
|
860
704
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
|
|
861
|
-
# →
|
|
705
|
+
# → 401 with authorization_url
|
|
862
706
|
```
|
|
863
707
|
|
|
864
708
|
---
|
|
@@ -867,59 +711,37 @@ curl -X POST https://your-server.com/sandbox/mcp \
|
|
|
867
711
|
|
|
868
712
|
### Hosted MCP returns 406
|
|
869
713
|
|
|
870
|
-
Include
|
|
871
|
-
```
|
|
872
|
-
Accept: application/json, text/event-stream
|
|
873
|
-
```
|
|
714
|
+
Include `Accept: application/json, text/event-stream` header.
|
|
874
715
|
|
|
875
716
|
### OAuth callback: "Invalid or expired OAuth state"
|
|
876
717
|
|
|
877
|
-
OAuth state
|
|
878
|
-
|
|
879
|
-
### Token verification fails on existing refresh token
|
|
718
|
+
OAuth state expires in 15 minutes. Restart the browser flow.
|
|
880
719
|
|
|
881
|
-
|
|
882
|
-
```bash
|
|
883
|
-
pnpm run setup
|
|
884
|
-
```
|
|
720
|
+
### Token verification fails on refresh token
|
|
885
721
|
|
|
886
|
-
|
|
722
|
+
Refresh tokens expire after ~18 months or can be revoked. Run `pnpm run setup` or start new browser OAuth at `/oauth/start`.
|
|
887
723
|
|
|
888
|
-
### Session token no longer works
|
|
724
|
+
### Session token no longer works
|
|
889
725
|
|
|
890
|
-
Check whether the session was revoked or expired:
|
|
891
726
|
```bash
|
|
727
|
+
# Check status:
|
|
892
728
|
curl -H "Authorization: Bearer <token>" https://your-server.com/whoami
|
|
893
|
-
```
|
|
894
729
|
|
|
895
|
-
Revoke exposed
|
|
896
|
-
```bash
|
|
730
|
+
# Revoke if exposed:
|
|
897
731
|
curl -X POST https://your-server.com/admin/session/<token>/revoke \
|
|
898
732
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
899
733
|
```
|
|
900
734
|
|
|
901
735
|
### Validation health is degraded
|
|
902
736
|
|
|
903
|
-
Start with the environment-scoped health endpoint:
|
|
904
|
-
|
|
905
737
|
```bash
|
|
906
738
|
curl https://your-server.com/sandbox/validation/health \
|
|
907
739
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
908
740
|
```
|
|
909
741
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
- `VALIDATION_RUNNER_USER_ID` or the env-specific override is missing
|
|
913
|
-
- the validation runner user has no stored refresh-token-backed credentials in the hosted token store
|
|
914
|
-
- the refresh token is expired or revoked upstream
|
|
915
|
-
- `SOLD_ITEMS_API_URL` or `SOLD_ITEMS_API_KEY` is missing, causing sold enrichment to degrade
|
|
916
|
-
- one or more social-provider credentials are absent, which causes the related supportive signal to degrade gracefully instead of failing the entire run
|
|
742
|
+
Check: `VALIDATION_RUNNER_USER_ID` set, runner has stored tokens, tokens not expired, `SOLD_ITEMS_API_URL` configured.
|
|
917
743
|
|
|
918
|
-
### eBay Research
|
|
919
|
-
|
|
920
|
-
This means the first-party research provider could not load a validated authenticated session and validation is intentionally falling back to browse and/or the temporary sold provider.
|
|
921
|
-
|
|
922
|
-
Run this checklist:
|
|
744
|
+
### eBay Research shows `authState = missing`
|
|
923
745
|
|
|
924
746
|
```bash
|
|
925
747
|
pnpm run playwright:install
|
|
@@ -928,28 +750,23 @@ pnpm run research:check-browser
|
|
|
928
750
|
pnpm run research:bootstrap
|
|
929
751
|
```
|
|
930
752
|
|
|
931
|
-
Expected
|
|
753
|
+
Expected after bootstrap: `authState = loaded`, `sessionStrategy = storage_state`, `sessionSource = kv`, `authValidationSucceeded = true`.
|
|
932
754
|
|
|
933
|
-
|
|
934
|
-
- `sessionStrategy = storage_state`
|
|
935
|
-
- `sessionSource = kv`
|
|
936
|
-
- `kvLoadAttempted = true`
|
|
937
|
-
- `kvLoadSucceeded = true`
|
|
938
|
-
- `authValidationAttempted = true`
|
|
939
|
-
- `authValidationSucceeded = true`
|
|
755
|
+
### Stale MCP sessions after deployment
|
|
940
756
|
|
|
941
|
-
|
|
757
|
+
After deploying new code, agents' MCP sessions may still point to old container code. **Agents must restart their MCP session** (`/reset` or reopen chat) to negotiate a fresh connection.
|
|
942
758
|
|
|
943
|
-
|
|
759
|
+
---
|
|
944
760
|
|
|
945
|
-
|
|
761
|
+
## Security checklist
|
|
946
762
|
|
|
947
|
-
- Do not commit `.env` or session tokens
|
|
948
|
-
- Protect `/oauth/start`
|
|
949
|
-
- Keep
|
|
950
|
-
- Keep `/
|
|
951
|
-
-
|
|
952
|
-
- Rotate exposed eBay
|
|
763
|
+
- Do not commit `.env` or session tokens
|
|
764
|
+
- Protect `/oauth/start` with `OAUTH_START_KEY`, `/admin/*` and `/validation/*` with `ADMIN_API_KEY`
|
|
765
|
+
- Keep `ADMIN_API_KEY` long, random, server-side only, and separate from user session tokens; it also works as a privileged MCP Bearer-token bypass
|
|
766
|
+
- Keep `/oauth/callback` publicly reachable (eBay redirects here)
|
|
767
|
+
- Keep `/health` reachable for deployment health checks
|
|
768
|
+
- Rotate exposed eBay credentials and update secret file
|
|
769
|
+
- For production isolation, consider Cloudflare Access on `/`, `/oauth/start`, `/admin/*`
|
|
953
770
|
|
|
954
771
|
---
|
|
955
772
|
|