ebay-mcp-remote-edition 4.4.0 → 4.6.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 +322 -587
- package/build/api/media/media.js +88 -73
- package/build/config/environment.js +22 -0
- package/build/index.js +0 -0
- package/build/scripts/update-api-status-doc.js +19 -1
- package/build/server-http.d.ts +2 -1
- package/build/server-http.js +40 -6
- package/build/tools/index.js +135 -6
- package/build/tools/schemas.js +8 -11
- package/build/utils/api-status-feed.js +4 -1
- package/package.json +27 -37
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 normally authorize through the browser OAuth flow and then call MCP with `Authorization: Bearer <session-token>`. |
|
|
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.
|
|
147
|
-
|
|
148
|
-
**Verify the fix works (without restarting VS Code):**
|
|
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
|
-
```
|
|
127
|
+
Then fully quit and reopen VS Code.
|
|
155
128
|
|
|
156
|
-
For hosted deployments, register your server's public HTTPS URL instead
|
|
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
|
-
|
|
170
|
-
**Option B — clone and build (for contributors or self-hosting):**
|
|
171
140
|
|
|
172
|
-
|
|
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,334 @@ 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=
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
# Path to secret file (see below)
|
|
358
|
-
EBAY_CONFIG_FILE=/etc/secrets/ebay-config.json
|
|
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=
|
|
359
281
|
```
|
|
360
282
|
|
|
361
|
-
> Use `
|
|
283
|
+
> `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.
|
|
362
284
|
|
|
363
285
|
### Secret file
|
|
364
286
|
|
|
365
|
-
|
|
287
|
+
Mount a JSON file with credentials (e.g., Render Secret File at `/etc/secrets/ebay-config.json`):
|
|
366
288
|
|
|
367
289
|
```json
|
|
368
290
|
{
|
|
369
291
|
"production": {
|
|
370
292
|
"clientId": "PROD_CLIENT_ID",
|
|
371
293
|
"clientSecret": "PROD_CLIENT_SECRET",
|
|
372
|
-
"redirectUri": "YOUR_PRODUCTION_RUNAME"
|
|
294
|
+
"redirectUri": "YOUR_PRODUCTION_RUNAME",
|
|
295
|
+
"ruName": "YOUR_PRODUCTION_RUNAME"
|
|
373
296
|
},
|
|
374
297
|
"sandbox": {
|
|
375
298
|
"clientId": "SANDBOX_CLIENT_ID",
|
|
376
299
|
"clientSecret": "SANDBOX_CLIENT_SECRET",
|
|
377
|
-
"redirectUri": "YOUR_SANDBOX_RUNAME"
|
|
300
|
+
"redirectUri": "YOUR_SANDBOX_RUNAME",
|
|
301
|
+
"ruName": "YOUR_SANDBOX_RUNAME"
|
|
378
302
|
}
|
|
379
303
|
}
|
|
380
304
|
```
|
|
381
305
|
|
|
382
|
-
### Deploy to Render / Railway /
|
|
306
|
+
### Deploy to Render / Railway / Coolify
|
|
383
307
|
|
|
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
|
|
308
|
+
1. Connect your repo as a **Web Service**
|
|
309
|
+
2. **Build:** `pnpm install && pnpm run build`
|
|
310
|
+
3. **Start:** `pnpm run start:http`
|
|
311
|
+
4. Add environment variables + secret file
|
|
395
312
|
|
|
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.
|
|
313
|
+
For Nixpacks-based platforms (Railway, Coolify): `nixpacks.toml` handles `pnpm`, build, Chromium install, and start automatically.
|
|
403
314
|
|
|
404
315
|
### OAuth flows
|
|
405
316
|
|
|
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
317
|
```
|
|
411
|
-
GET /sandbox/oauth/start
|
|
412
|
-
GET /production/oauth/start
|
|
318
|
+
GET /sandbox/oauth/start # sandbox browser login
|
|
319
|
+
GET /production/oauth/start # production browser login
|
|
413
320
|
```
|
|
414
321
|
|
|
415
|
-
If `OAUTH_START_KEY` is set,
|
|
416
|
-
```
|
|
417
|
-
GET /sandbox/oauth/start?key=YOUR_OAUTH_START_KEY
|
|
418
|
-
# or header: X-OAuth-Start-Key: YOUR_OAUTH_START_KEY
|
|
419
|
-
```
|
|
322
|
+
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.
|
|
420
323
|
|
|
421
|
-
After
|
|
324
|
+
After login, the callback page shows your **session token** with copy buttons.
|
|
422
325
|
|
|
423
|
-
**Session
|
|
326
|
+
**Session TTL schedule:**
|
|
424
327
|
|
|
425
|
-
| Record |
|
|
426
|
-
|
|
427
|
-
| OAuth state | 15 minutes |
|
|
428
|
-
| MCP auth code | 10 minutes |
|
|
429
|
-
| Session | 30 days (configurable) |
|
|
430
|
-
| User token
|
|
328
|
+
| Record | TTL |
|
|
329
|
+
|--------|-----|
|
|
330
|
+
| OAuth state | 15 minutes |
|
|
331
|
+
| MCP auth code | 10 minutes |
|
|
332
|
+
| Session | 30 days (configurable) |
|
|
333
|
+
| User token | eBay refresh token expiry (fallback: 18 months) |
|
|
431
334
|
|
|
432
335
|
### MCP endpoints
|
|
433
336
|
|
|
434
337
|
**Environment-scoped (recommended):**
|
|
435
|
-
|
|
436
338
|
```
|
|
437
339
|
POST/GET/DELETE /sandbox/mcp
|
|
438
340
|
POST/GET/DELETE /production/mcp
|
|
439
341
|
```
|
|
440
342
|
|
|
441
|
-
Each
|
|
442
|
-
```
|
|
443
|
-
GET /sandbox/.well-known/oauth-authorization-server
|
|
444
|
-
GET /production/.well-known/oauth-authorization-server
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
**Legacy auto-detect (backward-compatible):**
|
|
448
|
-
```
|
|
449
|
-
POST/GET/DELETE /mcp # resolves environment from ?env= or EBAY_DEFAULT_ENVIRONMENT
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
**Authentication behavior:**
|
|
453
|
-
- `GET /mcp` (or scoped variant) without a valid Bearer token redirects the browser to the matching `oauth/start` URL
|
|
454
|
-
- `POST /mcp` without a valid Bearer token returns a structured `401` JSON with an `authorization_url` field
|
|
455
|
-
- All requests supply a session token via `Authorization: Bearer <session-token>`
|
|
456
|
-
|
|
457
|
-
**Other utility endpoints:**
|
|
343
|
+
Each includes OAuth 2.1 discovery: `GET /sandbox/.well-known/oauth-authorization-server`
|
|
458
344
|
|
|
345
|
+
**Legacy auto-detect:**
|
|
459
346
|
```
|
|
460
|
-
GET
|
|
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
|
-
```
|
|
466
|
-
|
|
467
|
-
`/whoami` response:
|
|
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
|
-
}
|
|
347
|
+
POST/GET/DELETE /mcp # resolves from ?env= or EBAY_ENVIRONMENT/EBAY_DEFAULT_ENVIRONMENT
|
|
477
348
|
```
|
|
478
349
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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).
|
|
513
|
-
|
|
514
|
-
Operationally, validation works like this:
|
|
515
|
-
|
|
516
|
-
1. An admin caller invokes an environment-scoped validation route.
|
|
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.
|
|
524
|
-
|
|
525
|
-
#### Effective validation context
|
|
350
|
+
**Auth behavior:**
|
|
351
|
+
- `GET /mcp` without token → redirects to `oauth/start`
|
|
352
|
+
- `POST /mcp` without token → `401` JSON with `authorization_url`, `resource_metadata`, and a `WWW-Authenticate` Bearer challenge
|
|
353
|
+
- Normal user requests: `Authorization: Bearer <session-token>`
|
|
354
|
+
- Privileged admin bypass: `Authorization: Bearer <ADMIN_API_KEY>` when `ADMIN_API_KEY` is configured
|
|
526
355
|
|
|
527
|
-
|
|
356
|
+
#### Admin key bypass
|
|
528
357
|
|
|
529
|
-
|
|
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.
|
|
358
|
+
`ADMIN_API_KEY` is used in two distinct ways:
|
|
533
359
|
|
|
534
|
-
|
|
360
|
+
| Use | Exact implementation | Scope |
|
|
361
|
+
|-----|----------------------|-------|
|
|
362
|
+
| 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/*`. |
|
|
363
|
+
| 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. |
|
|
535
364
|
|
|
536
|
-
|
|
537
|
-
- `resolvedSearchItem`
|
|
538
|
-
- `resolvedSearchEvent`
|
|
539
|
-
- `resolvedSearchLocation`
|
|
540
|
-
- `resolvedSearchQuery`
|
|
365
|
+
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.
|
|
541
366
|
|
|
542
|
-
|
|
367
|
+
Security caveats:
|
|
368
|
+
- Treat `ADMIN_API_KEY` as a privileged root credential for this MCP server.
|
|
369
|
+
- Generate a long, random value and store it only in your deployment secret manager.
|
|
370
|
+
- Use it only for server-to-server automation, operational checks, or admin tooling. Do not ship it to browsers, desktop clients, or regular users.
|
|
371
|
+
- OAuth browser authorization and hosted session tokens remain the normal path for user MCP access.
|
|
543
372
|
|
|
544
|
-
|
|
373
|
+
**Utility endpoints:**
|
|
545
374
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
|
375
|
+
```
|
|
376
|
+
GET /health # health check (no auth)
|
|
377
|
+
GET /whoami # session identity (Bearer token)
|
|
378
|
+
GET /admin/session/:sessionToken # view session (admin key)
|
|
379
|
+
POST /admin/session/:sessionToken/revoke # revoke session
|
|
380
|
+
DELETE /admin/session/:sessionToken # delete session
|
|
381
|
+
```
|
|
558
382
|
|
|
559
|
-
|
|
383
|
+
### Validation endpoints
|
|
560
384
|
|
|
561
385
|
```
|
|
562
|
-
POST /sandbox/validation/run
|
|
386
|
+
POST /sandbox/validation/run # run validation pipeline
|
|
563
387
|
POST /production/validation/run
|
|
564
388
|
|
|
565
|
-
GET /sandbox/validation/health
|
|
389
|
+
GET /sandbox/validation/health # check runner status
|
|
566
390
|
GET /production/validation/health
|
|
567
391
|
```
|
|
568
392
|
|
|
569
|
-
Both
|
|
570
|
-
|
|
571
|
-
```
|
|
572
|
-
X-Admin-API-Key: YOUR_ADMIN_API_KEY
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
Auth model summary:
|
|
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.
|
|
393
|
+
Both require `X-Admin-API-Key: <ADMIN_API_KEY>`. The server impersonates the configured validation runner user from `VALIDATION_RUNNER_USER_ID` env vars.
|
|
587
394
|
|
|
588
|
-
|
|
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`
|
|
395
|
+
See [Validation architecture](#validation-architecture) below for provider details.
|
|
593
396
|
|
|
594
|
-
|
|
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:
|
|
397
|
+
### Remote client configuration
|
|
617
398
|
|
|
399
|
+
**Cline (automatic OAuth):**
|
|
400
|
+
```json
|
|
401
|
+
{
|
|
402
|
+
"mcpServers": {
|
|
403
|
+
"ebay-sandbox": { "url": "https://your-server.com/sandbox/mcp" },
|
|
404
|
+
"ebay-production": { "url": "https://your-server.com/production/mcp" }
|
|
405
|
+
}
|
|
406
|
+
}
|
|
618
407
|
```
|
|
619
|
-
|
|
620
|
-
GET /whoami
|
|
621
|
-
GET /sandbox/validation/health
|
|
622
|
-
GET /production/validation/health
|
|
623
|
-
POST /internal/ebay-research/check-session-expiry
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
Recommended debugging flow:
|
|
627
|
-
|
|
628
|
-
1. Call `/health` to confirm the HTTP service is up.
|
|
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:
|
|
640
|
-
|
|
641
|
-
- eBay live market snapshot support is implemented and wired into orchestration.
|
|
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.
|
|
648
|
-
|
|
649
|
-
Provider behavior:
|
|
650
|
-
|
|
651
|
-
- **Browse/eBay provider:** [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts) uses the eBay Browse API plus shared query fallback logic from [`src/validation/providers/query-utils.ts`](src/validation/providers/query-utils.ts). It walks multiple query candidates, records the selected query and tier in debug output, and uses heuristic matching rather than a strict catalog identity join. Event-driven runs now build those fallback queries from normalized event context instead of raw item title assumptions.
|
|
652
|
-
- **Browse debug semantics:** validation debug now keeps browse candidate generation, selected query/tier, browse-specific sample size, and per-candidate result counts separate from sold-provider result counts so operators can tell whether the browse layer contributed a field, fell back to a weaker query, or returned no usable match.
|
|
653
|
-
- **Sold provider:** [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts) uses a temporary external sold-data source configured by `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`. It uses the same query-fallback strategy as the browse provider and returns sold-price ranges, sample sold items, and recent sold-velocity buckets when available.
|
|
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.
|
|
408
|
+
Cline auto-discovers OAuth, opens browser login, exchanges auth code, and stores session token.
|
|
659
409
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
410
|
+
**Claude Desktop / Cursor (Bearer token):**
|
|
411
|
+
1. Open `https://your-server.com/sandbox/oauth/start` → complete eBay login → copy session token
|
|
412
|
+
2. Configure client:
|
|
413
|
+
```json
|
|
414
|
+
{
|
|
415
|
+
"mcpServers": {
|
|
416
|
+
"ebay-sandbox": {
|
|
417
|
+
"url": "https://your-server.com/sandbox/mcp",
|
|
418
|
+
"headers": { "Authorization": "Bearer YOUR_SESSION_TOKEN" }
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
666
423
|
|
|
667
|
-
|
|
424
|
+
**Make / Zapier / other platforms:**
|
|
425
|
+
1. Complete OAuth via browser at `/oauth/start`
|
|
426
|
+
2. Paste session token as API Key / Bearer token in connector settings
|
|
427
|
+
3. Set MCP URL to `https://your-server.com/sandbox/mcp`
|
|
668
428
|
|
|
669
|
-
|
|
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.
|
|
429
|
+
---
|
|
673
430
|
|
|
674
|
-
|
|
431
|
+
## Tool discovery for agents
|
|
675
432
|
|
|
676
|
-
|
|
677
|
-
- The Docker deployment path now provisions Chromium during image build in [`Dockerfile`](Dockerfile).
|
|
678
|
-
- Canonical production session source of truth is KV-backed Playwright storage-state JSON stored under `ebay_research_storage_state_json` with companion metadata in `ebay_research_storage_state_meta`, including `updatedAt`, `expiresAt`, `ttlSeconds`, `marketplace`, `sessionStore`, and `sessionVersion`.
|
|
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
|
+
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.
|
|
693
434
|
|
|
694
|
-
###
|
|
435
|
+
### Tool naming convention
|
|
695
436
|
|
|
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.
|
|
437
|
+
All tools follow the pattern `ebay_<action>_<resource>`:
|
|
699
438
|
|
|
700
|
-
|
|
439
|
+
| Action | Meaning | Examples |
|
|
440
|
+
|--------|---------|----------|
|
|
441
|
+
| `get` | Read/fetch | `ebay_get_inventory_item`, `ebay_get_offers` |
|
|
442
|
+
| `create` | Create new | `ebay_create_offer`, `ebay_create_fulfillment_policy` |
|
|
443
|
+
| `update` | Modify existing | `ebay_update_offer`, `ebay_update_inventory_item` |
|
|
444
|
+
| `delete` | Remove | `ebay_delete_offer`, `ebay_delete_inventory_item` |
|
|
445
|
+
| `publish` | Activate | `ebay_publish_offer` |
|
|
446
|
+
| `withdraw` | Deactivate | `ebay_withdraw_offer` |
|
|
447
|
+
| `revise` | Modify listing | `ebay_revise_listing` |
|
|
448
|
+
| `bulk_` | Batch operations | `ebay_bulk_create_offer`, `ebay_bulk_update_price_quantity` |
|
|
701
449
|
|
|
702
|
-
|
|
450
|
+
### Tool descriptions are self-documenting
|
|
703
451
|
|
|
704
|
-
|
|
452
|
+
Each tool description includes:
|
|
453
|
+
- **What it does** — concise action description
|
|
454
|
+
- **OAuth scope required** — the minimum scope needed
|
|
455
|
+
- **Minimum scope URL** — for fine-grained permission setup
|
|
705
456
|
|
|
706
|
-
|
|
457
|
+
Example:
|
|
458
|
+
```
|
|
459
|
+
Get a specific inventory item by SKU.
|
|
707
460
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
"mcpServers": {
|
|
711
|
-
"ebay-sandbox": {
|
|
712
|
-
"url": "https://your-server.com/sandbox/mcp"
|
|
713
|
-
},
|
|
714
|
-
"ebay-production": {
|
|
715
|
-
"url": "https://your-server.com/production/mcp"
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
461
|
+
Required OAuth Scope: sell.inventory.readonly or sell.inventory
|
|
462
|
+
Minimum Scope: https://api.ebay.com/oauth/api_scope/sell.inventory.readonly
|
|
719
463
|
```
|
|
720
464
|
|
|
721
|
-
|
|
722
|
-
1. Fetches `/.well-known/oauth-authorization-server` for the scoped path
|
|
723
|
-
2. Registers at `POST /sandbox/register` (or `/production/register`)
|
|
724
|
-
3. Your browser opens `GET /sandbox/authorize`, which redirects to eBay login
|
|
725
|
-
4. After you grant access, eBay redirects to `/oauth/callback`, which issues an auth code
|
|
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
|
|
465
|
+
### Tools organized by category
|
|
728
466
|
|
|
729
|
-
|
|
467
|
+
Tools are grouped into 13 category files in `src/tools/definitions/`:
|
|
730
468
|
|
|
731
|
-
|
|
469
|
+
| Category file | Tool prefix | Key operations |
|
|
470
|
+
|---------------|-------------|----------------|
|
|
471
|
+
| `inventory.ts` | `ebay_*inventory*`, `ebay_*offer*` | CRUD inventory items, offers, locations, bulk ops |
|
|
472
|
+
| `fulfillment.ts` | `ebay_*fulfillment*`, `ebay_*shipment*` | Shipments, fulfillment orders, shipping labels |
|
|
473
|
+
| `account.ts` | `ebay_*policy*` | Payment, return, fulfillment policies |
|
|
474
|
+
| `marketing.ts` | `ebay_*promotion*`, `ebay_*markdown*` | Promotions, markdown listings |
|
|
475
|
+
| `analytics.ts` | `ebay_*analytics*`, `ebay_*report*` | Analytics, reporting |
|
|
476
|
+
| `communication.ts` | `ebay_*message*`, `ebay_*feedback*` | Messages, feedback, notifications |
|
|
477
|
+
| `metadata.ts` | `ebay_*metadata*`, `ebay_*policies*` | Category policies, listing metadata |
|
|
478
|
+
| `taxonomy.ts` | `ebay_*category*` | Category tree, suggestions, item specifics |
|
|
479
|
+
| `browse.ts` | `ebay_*browse*`, `ebay_*product*` | Browse/search products |
|
|
480
|
+
| `trading.ts` | `ebay_*listing*`, `ebay_*create_listing*` | Trading API (XML/SOAP) operations |
|
|
481
|
+
| `developer.ts` | `ebay_*signing*`, `ebay_*vero*` | Key management, VERO reports |
|
|
482
|
+
| `other.ts` | Mixed | Misc/legacy endpoints |
|
|
483
|
+
| `token-management.ts` | `ebay_*oauth*`, `ebay_*token*` | OAuth helpers, token management |
|
|
732
484
|
|
|
733
|
-
|
|
734
|
-
2. Log in with your eBay account
|
|
735
|
-
3. Copy the session token from the confirmation page
|
|
485
|
+
### How agents find the right tool
|
|
736
486
|
|
|
737
|
-
|
|
487
|
+
1. **Search by name pattern** — `ebay_get_*` for reads, `ebay_create_*` for writes, `ebay_*offer*` for offers
|
|
488
|
+
2. **Search by description** — descriptions contain action keywords and resource names
|
|
489
|
+
3. **Search by OAuth scope** — `sell.inventory` for inventory, `sell.fulfillment` for shipping
|
|
490
|
+
4. **Use `tools/list`** — agents receive the full tool list with names and descriptions; filter programmatically
|
|
738
491
|
|
|
739
|
-
|
|
740
|
-
{
|
|
741
|
-
"mcpServers": {
|
|
742
|
-
"ebay-sandbox": {
|
|
743
|
-
"url": "https://your-server.com/sandbox/mcp",
|
|
744
|
-
"headers": {
|
|
745
|
-
"Authorization": "Bearer YOUR_SESSION_TOKEN"
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
```
|
|
492
|
+
### Tool annotations
|
|
751
493
|
|
|
752
|
-
|
|
494
|
+
Tools carry MCP annotations that help agents understand behavior:
|
|
753
495
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
496
|
+
| Annotation | Meaning |
|
|
497
|
+
|-----------|---------|
|
|
498
|
+
| `readOnlyHint: true` | Safe to call; no side effects |
|
|
499
|
+
| `destructiveHint: true` | Irreversible; use caution |
|
|
500
|
+
| `idempotentHint: true` | Safe to retry |
|
|
501
|
+
| `openWorldHint: true` | May interact with external services |
|
|
758
502
|
|
|
759
503
|
---
|
|
760
504
|
|
|
761
505
|
## Available tools
|
|
762
506
|
|
|
763
|
-
325+ tools across all eBay Sell API categories:
|
|
764
|
-
|
|
765
|
-
- Account Management
|
|
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
|
|
774
|
-
|
|
775
|
-
Full tool source: [`src/tools/definitions/`](src/tools/definitions/)
|
|
507
|
+
325+ tools across all eBay Sell API categories. Full source: [`src/tools/definitions/`](src/tools/definitions/)
|
|
776
508
|
|
|
777
509
|
---
|
|
778
510
|
|
|
779
511
|
## Development
|
|
780
512
|
|
|
781
|
-
### Commands
|
|
513
|
+
### Commands
|
|
782
514
|
|
|
783
515
|
| Command | Description |
|
|
784
516
|
|---------|-------------|
|
|
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
|
|
517
|
+
| `pnpm run build` | Compile TypeScript |
|
|
518
|
+
| `pnpm start` | Run local STDIO server |
|
|
519
|
+
| `pnpm run start:http` | Run hosted HTTP server |
|
|
520
|
+
| `pnpm run dev` | STDIO with hot reload |
|
|
521
|
+
| `pnpm run dev:http` | HTTP with hot reload |
|
|
522
|
+
| `pnpm test` | Run tests |
|
|
523
|
+
| `pnpm run setup` | Interactive setup wizard |
|
|
524
|
+
| `pnpm run sync` | Download eBay OpenAPI specs, regenerate types |
|
|
525
|
+
| `pnpm run diagnose` | Check config and connectivity |
|
|
526
|
+
| `pnpm run typecheck` | TypeScript type checking |
|
|
527
|
+
| `pnpm run check` | Typecheck + lint + format |
|
|
528
|
+
| `pnpm run fix` | Auto-fix lint and format |
|
|
797
529
|
|
|
798
530
|
### `pnpm run sync`
|
|
799
531
|
|
|
800
|
-
|
|
532
|
+
Download latest eBay OpenAPI specs and regenerate types:
|
|
801
533
|
|
|
802
534
|
```bash
|
|
803
|
-
pnpm run sync
|
|
804
|
-
pnpm run typecheck
|
|
805
|
-
pnpm run build
|
|
535
|
+
pnpm run sync && pnpm run typecheck && pnpm run build
|
|
806
536
|
```
|
|
807
537
|
|
|
808
|
-
Review the diff, commit
|
|
538
|
+
Review the diff, commit changes you want to keep, and deploy.
|
|
809
539
|
|
|
810
|
-
###
|
|
811
|
-
|
|
812
|
-
For local development, standard runtime scripts load `.env` via dotenvx only when a real local [`.env`](.env) file is present. Hosted platforms should provide environment variables directly — the server skips dotenvx for hosted/runtime environments (including Nixpacks-style deployments, which set [`DISABLE_DOTENVX`](nixpacks.toml:26)) and whenever no local [`.env`](.env) file exists.
|
|
540
|
+
### Env management
|
|
813
541
|
|
|
814
542
|
```bash
|
|
815
543
|
pnpm run env:encrypt # encrypt .env for safe sharing
|
|
@@ -825,40 +553,74 @@ EBAY_ENABLE_FILE_LOGGING=true # write logs to files
|
|
|
825
553
|
|
|
826
554
|
---
|
|
827
555
|
|
|
556
|
+
## Validation architecture
|
|
557
|
+
|
|
558
|
+
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).
|
|
559
|
+
|
|
560
|
+
**Module layout:**
|
|
561
|
+
|
|
562
|
+
| File | Purpose |
|
|
563
|
+
|------|---------|
|
|
564
|
+
| `types.ts` | Request/response contracts |
|
|
565
|
+
| `effective-context.ts` | Source-aware normalization (item vs event runs) |
|
|
566
|
+
| `run-validation.ts` | Orchestration entrypoint |
|
|
567
|
+
| `recommendation.ts` | Buy/track decision logic |
|
|
568
|
+
| `providers/ebay.ts` | Live browse-market snapshot |
|
|
569
|
+
| `providers/ebay-sold.ts` | Sold-data enrichment (temporary external provider) |
|
|
570
|
+
| `providers/terapeak.ts` | Terapeak / eBay Research metrics |
|
|
571
|
+
| `providers/ebay-research.ts` | Authenticated eBay Research fetcher |
|
|
572
|
+
| `providers/social.ts` | Twitter/X, YouTube, Reddit signals |
|
|
573
|
+
| `providers/chart.ts` | Chart-signal stub |
|
|
574
|
+
| `providers/research.ts` | Historical comeback research (Perplexity) |
|
|
575
|
+
|
|
576
|
+
**Flow:** Admin calls `/validation/run` → server resolves runner user → orchestrator queries all providers → merges signals → returns writes + decision + debug metadata.
|
|
577
|
+
|
|
578
|
+
**Merge precedence:** Terapeak > sold provider > browse provider for overlapping fields. Optional providers (social, research) only write when data resolves — never blank existing values.
|
|
579
|
+
|
|
580
|
+
**Known limitations:**
|
|
581
|
+
- Sold-data provider is temporary (external API via `SOLD_ITEMS_API_URL`)
|
|
582
|
+
- Social signals are supportive only — not authoritative buy triggers
|
|
583
|
+
- Chart provider is a stub
|
|
584
|
+
- eBay Research requires valid Playwright session
|
|
585
|
+
|
|
586
|
+
**eBay Research session management:**
|
|
587
|
+
- Bootstrap: `pnpm run research:bootstrap`
|
|
588
|
+
- Inspect: `pnpm run research:inspect-session`
|
|
589
|
+
- Browser check: `pnpm run research:check-browser`
|
|
590
|
+
- Session source precedence: KV → env vars → local files → fallback
|
|
591
|
+
- QStash alerts: 24h before, 6h before, and at expiry → Telegram
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
828
595
|
## Testing & validation
|
|
829
596
|
|
|
830
597
|
```bash
|
|
831
|
-
# Build and
|
|
832
|
-
pnpm run build
|
|
833
|
-
pnpm run typecheck
|
|
598
|
+
# Build and test
|
|
599
|
+
pnpm run build && pnpm run typecheck && pnpm test
|
|
834
600
|
|
|
835
|
-
#
|
|
836
|
-
pnpm test
|
|
837
|
-
|
|
838
|
-
# Check connectivity and token status
|
|
601
|
+
# Connectivity check
|
|
839
602
|
pnpm run diagnose
|
|
840
603
|
|
|
841
|
-
#
|
|
604
|
+
# Hosted health
|
|
842
605
|
curl https://your-server.com/health
|
|
843
606
|
|
|
844
|
-
#
|
|
845
|
-
curl -H "Authorization: Bearer <
|
|
607
|
+
# Session check
|
|
608
|
+
curl -H "Authorization: Bearer <token>" https://your-server.com/whoami
|
|
846
609
|
|
|
847
|
-
#
|
|
610
|
+
# Validation runner health
|
|
848
611
|
curl https://your-server.com/sandbox/validation/health \
|
|
849
612
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
850
613
|
|
|
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}}}'
|
|
614
|
+
# Privileged MCP admin-key bypass check
|
|
615
|
+
curl https://your-server.com/sandbox/mcp \
|
|
616
|
+
-H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
|
|
617
|
+
-H "Accept: application/json, text/event-stream"
|
|
856
618
|
|
|
857
|
-
#
|
|
619
|
+
# MCP auth challenge test
|
|
858
620
|
curl -X POST https://your-server.com/sandbox/mcp \
|
|
859
621
|
-H "Content-Type: application/json" \
|
|
860
622
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
|
|
861
|
-
# →
|
|
623
|
+
# → 401 with authorization_url
|
|
862
624
|
```
|
|
863
625
|
|
|
864
626
|
---
|
|
@@ -867,59 +629,37 @@ curl -X POST https://your-server.com/sandbox/mcp \
|
|
|
867
629
|
|
|
868
630
|
### Hosted MCP returns 406
|
|
869
631
|
|
|
870
|
-
Include
|
|
871
|
-
```
|
|
872
|
-
Accept: application/json, text/event-stream
|
|
873
|
-
```
|
|
632
|
+
Include `Accept: application/json, text/event-stream` header.
|
|
874
633
|
|
|
875
634
|
### OAuth callback: "Invalid or expired OAuth state"
|
|
876
635
|
|
|
877
|
-
OAuth state
|
|
878
|
-
|
|
879
|
-
### Token verification fails on existing refresh token
|
|
636
|
+
OAuth state expires in 15 minutes. Restart the browser flow.
|
|
880
637
|
|
|
881
|
-
|
|
882
|
-
```bash
|
|
883
|
-
pnpm run setup
|
|
884
|
-
```
|
|
638
|
+
### Token verification fails on refresh token
|
|
885
639
|
|
|
886
|
-
|
|
640
|
+
Refresh tokens expire after ~18 months or can be revoked. Run `pnpm run setup` or start new browser OAuth at `/oauth/start`.
|
|
887
641
|
|
|
888
|
-
### Session token no longer works
|
|
642
|
+
### Session token no longer works
|
|
889
643
|
|
|
890
|
-
Check whether the session was revoked or expired:
|
|
891
644
|
```bash
|
|
645
|
+
# Check status:
|
|
892
646
|
curl -H "Authorization: Bearer <token>" https://your-server.com/whoami
|
|
893
|
-
```
|
|
894
647
|
|
|
895
|
-
Revoke exposed
|
|
896
|
-
```bash
|
|
648
|
+
# Revoke if exposed:
|
|
897
649
|
curl -X POST https://your-server.com/admin/session/<token>/revoke \
|
|
898
650
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
899
651
|
```
|
|
900
652
|
|
|
901
653
|
### Validation health is degraded
|
|
902
654
|
|
|
903
|
-
Start with the environment-scoped health endpoint:
|
|
904
|
-
|
|
905
655
|
```bash
|
|
906
656
|
curl https://your-server.com/sandbox/validation/health \
|
|
907
657
|
-H "X-Admin-API-Key: YOUR_ADMIN_API_KEY"
|
|
908
658
|
```
|
|
909
659
|
|
|
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
|
|
660
|
+
Check: `VALIDATION_RUNNER_USER_ID` set, runner has stored tokens, tokens not expired, `SOLD_ITEMS_API_URL` configured.
|
|
917
661
|
|
|
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:
|
|
662
|
+
### eBay Research shows `authState = missing`
|
|
923
663
|
|
|
924
664
|
```bash
|
|
925
665
|
pnpm run playwright:install
|
|
@@ -928,28 +668,23 @@ pnpm run research:check-browser
|
|
|
928
668
|
pnpm run research:bootstrap
|
|
929
669
|
```
|
|
930
670
|
|
|
931
|
-
Expected
|
|
671
|
+
Expected after bootstrap: `authState = loaded`, `sessionStrategy = storage_state`, `sessionSource = kv`, `authValidationSucceeded = true`.
|
|
932
672
|
|
|
933
|
-
|
|
934
|
-
- `sessionStrategy = storage_state`
|
|
935
|
-
- `sessionSource = kv`
|
|
936
|
-
- `kvLoadAttempted = true`
|
|
937
|
-
- `kvLoadSucceeded = true`
|
|
938
|
-
- `authValidationAttempted = true`
|
|
939
|
-
- `authValidationSucceeded = true`
|
|
673
|
+
### Stale MCP sessions after deployment
|
|
940
674
|
|
|
941
|
-
|
|
675
|
+
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
676
|
|
|
943
|
-
|
|
677
|
+
---
|
|
944
678
|
|
|
945
|
-
|
|
679
|
+
## Security checklist
|
|
946
680
|
|
|
947
|
-
- Do not commit `.env` or session tokens
|
|
948
|
-
- Protect `/oauth/start`
|
|
949
|
-
- Keep
|
|
950
|
-
- Keep `/
|
|
951
|
-
-
|
|
952
|
-
- Rotate exposed eBay
|
|
681
|
+
- Do not commit `.env` or session tokens
|
|
682
|
+
- Protect `/oauth/start` with `OAUTH_START_KEY`, `/admin/*` and `/validation/*` with `ADMIN_API_KEY`
|
|
683
|
+
- 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
|
|
684
|
+
- Keep `/oauth/callback` publicly reachable (eBay redirects here)
|
|
685
|
+
- Keep `/health` reachable for deployment health checks
|
|
686
|
+
- Rotate exposed eBay credentials and update secret file
|
|
687
|
+
- For production isolation, consider Cloudflare Access on `/`, `/oauth/start`, `/admin/*`
|
|
953
688
|
|
|
954
689
|
---
|
|
955
690
|
|