ebay-mcp 1.12.0 → 1.13.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 +13 -0
- package/build/config/environment.js +6 -0
- package/build/config/tool-families.js +79 -0
- package/build/mcp/runtime.js +38 -4
- package/build/mcp/tool-gating.js +198 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -205,8 +205,21 @@ EBAY_MARKETPLACE_ID=EBAY_US # default marketplace (overridable per tool)
|
|
|
205
205
|
EBAY_CONTENT_LANGUAGE=en-US # default request content language
|
|
206
206
|
EBAY_USER_REFRESH_TOKEN=your_token # for higher rate limits
|
|
207
207
|
EBAY_MCP_UI=on # interactive MCP Apps views (beta); "off" forces plain JSON
|
|
208
|
+
EBAY_MCP_TOOLS=all # tool exposure: "all", "dynamic", or a family list (see below)
|
|
208
209
|
```
|
|
209
210
|
|
|
211
|
+
### Tool exposure (`EBAY_MCP_TOOLS`)
|
|
212
|
+
|
|
213
|
+
By default all tools are advertised to the agent at once. On a long conversation that catalogue is a meaningful slice of the context window, so two opt-in modes let you shrink it:
|
|
214
|
+
|
|
215
|
+
| Value | Behavior | Works on |
|
|
216
|
+
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
|
217
|
+
| `all` _(default, or unset)_ | Every tool advertised at startup. | every host |
|
|
218
|
+
| `dynamic` | Only three discovery tools are visible (`list_ebay_tools`, `enable_ebay_tools`, `disable_ebay_tools`). The agent searches the catalogue and loads only the tools it needs; they then appear natively. | hosts that honor `tools/listChanged` (e.g. Claude) |
|
|
219
|
+
| `inventory,fulfillment,…` | Registers **only** the named families (listed below), frozen for the session. | every host (incl. ChatGPT, Cursor) |
|
|
220
|
+
|
|
221
|
+
The family list is literal — you get exactly what you name. ChatGPT connectors need the `connector` family (its `search`/`fetch` tools); add it explicitly, e.g. `EBAY_MCP_TOOLS=connector,inventory`. An unknown family name fails fast at startup with the valid list. Valid families: `connector`, `token-management`, `account`, `inventory`, `fulfillment`, `marketing`, `analytics`, `metadata`, `taxonomy`, `communication`, `other`, `developer`, `trading`.
|
|
222
|
+
|
|
210
223
|
### Authentication & rate limits
|
|
211
224
|
|
|
212
225
|
| Mode | Daily limit | Best for | Setup |
|
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
5
|
import { LocaleEnum } from '../types/ebay-enums.js';
|
|
6
|
+
import { getToolGatingConfigError } from '../config/tool-families.js';
|
|
6
7
|
import { getVersion } from '../utils/version.js';
|
|
7
8
|
import { getErrorMessage } from '../utils/errors.js';
|
|
8
9
|
// Get the current directory for loading scope files and .env
|
|
@@ -126,6 +127,11 @@ export function validateEnvironmentConfig() {
|
|
|
126
127
|
if (!process.env.EBAY_REDIRECT_URI) {
|
|
127
128
|
warnings.push('EBAY_REDIRECT_URI is not set. User OAuth flow will not work. Set this to enable user token generation.');
|
|
128
129
|
}
|
|
130
|
+
// Validate EBAY_MCP_TOOLS (all | dynamic | comma-separated family list)
|
|
131
|
+
const toolGatingError = getToolGatingConfigError();
|
|
132
|
+
if (toolGatingError) {
|
|
133
|
+
errors.push(toolGatingError);
|
|
134
|
+
}
|
|
129
135
|
// Validate that scope files exist
|
|
130
136
|
try {
|
|
131
137
|
getProductionScopes();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-family contract for the `EBAY_MCP_TOOLS` env var.
|
|
3
|
+
*
|
|
4
|
+
* This module is deliberately free of any import from the tool tree
|
|
5
|
+
* (`@/tools/*`). `config/environment.ts` validates `EBAY_MCP_TOOLS` and is itself
|
|
6
|
+
* imported by tool handlers (e.g. `tools/categories/token-management.ts`), so
|
|
7
|
+
* pulling the registry in here would create an import cycle. The heavier pieces
|
|
8
|
+
* that genuinely need the registry — the discovery catalogue and the meta-tools —
|
|
9
|
+
* live in `@/mcp/tool-gating.ts`, which imports these primitives.
|
|
10
|
+
*
|
|
11
|
+
* The family keys below must stay in lock-step with `toolCategories`; a unit test
|
|
12
|
+
* asserts the two agree so adding a category without updating this list fails CI.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Canonical tool-family keys, mirroring `toolCategories[].key`. These are the
|
|
16
|
+
* accepted tokens in a static `EBAY_MCP_TOOLS` list (e.g. `inventory,fulfillment`).
|
|
17
|
+
*/
|
|
18
|
+
export const TOOL_FAMILY_KEYS = [
|
|
19
|
+
'connector',
|
|
20
|
+
'token-management',
|
|
21
|
+
'account',
|
|
22
|
+
'inventory',
|
|
23
|
+
'fulfillment',
|
|
24
|
+
'marketing',
|
|
25
|
+
'analytics',
|
|
26
|
+
'metadata',
|
|
27
|
+
'taxonomy',
|
|
28
|
+
'communication',
|
|
29
|
+
'other',
|
|
30
|
+
'developer',
|
|
31
|
+
'trading',
|
|
32
|
+
];
|
|
33
|
+
const FAMILY_KEY_SET = new Set(TOOL_FAMILY_KEYS);
|
|
34
|
+
/** Splits a raw `EBAY_MCP_TOOLS` list into trimmed, lowercased, non-empty tokens. */
|
|
35
|
+
function parseFamilyTokens(raw) {
|
|
36
|
+
return raw
|
|
37
|
+
.split(',')
|
|
38
|
+
.map((token) => token.trim().toLowerCase())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolves `EBAY_MCP_TOOLS` into a {@link ToolGatingMode}.
|
|
43
|
+
*
|
|
44
|
+
* Parsing is lenient by design — unknown family tokens are kept in the returned
|
|
45
|
+
* `static` mode so the dedicated validator ({@link getToolGatingConfigError}) can
|
|
46
|
+
* report them precisely. Callers that act on the mode should treat only
|
|
47
|
+
* {@link TOOL_FAMILY_KEYS} members as registerable.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveToolGatingMode(env = process.env) {
|
|
50
|
+
const raw = env.EBAY_MCP_TOOLS?.trim();
|
|
51
|
+
if (!raw || raw.toLowerCase() === 'all') {
|
|
52
|
+
return { kind: 'all' };
|
|
53
|
+
}
|
|
54
|
+
if (raw.toLowerCase() === 'dynamic') {
|
|
55
|
+
return { kind: 'dynamic' };
|
|
56
|
+
}
|
|
57
|
+
return { kind: 'static', families: parseFamilyTokens(raw) };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validates `EBAY_MCP_TOOLS` and returns a human-readable error string, or
|
|
61
|
+
* `undefined` when the value is valid. Surfaced through
|
|
62
|
+
* `validateEnvironmentConfig` so a typo fails loudly at startup (server exits)
|
|
63
|
+
* rather than silently leaving the agent with fewer tools than intended.
|
|
64
|
+
*/
|
|
65
|
+
export function getToolGatingConfigError(env = process.env) {
|
|
66
|
+
const mode = resolveToolGatingMode(env);
|
|
67
|
+
if (mode.kind !== 'static') {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
if (mode.families.length === 0) {
|
|
71
|
+
return `EBAY_MCP_TOOLS is set but lists no tool families. Use "all", "dynamic", or a comma-separated list of: ${TOOL_FAMILY_KEYS.join(', ')}.`;
|
|
72
|
+
}
|
|
73
|
+
const unknown = mode.families.filter((family) => !FAMILY_KEY_SET.has(family));
|
|
74
|
+
if (unknown.length === 0) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const noun = unknown.length === 1 ? 'family' : 'families';
|
|
78
|
+
return `EBAY_MCP_TOOLS contains unknown tool ${noun}: ${unknown.join(', ')}. Valid families: ${TOOL_FAMILY_KEYS.join(', ')}.`;
|
|
79
|
+
}
|
package/build/mcp/runtime.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { EbaySellerApi } from '../api/index.js';
|
|
3
3
|
import { getEbayConfig, mcpConfig } from '../config/environment.js';
|
|
4
|
+
import { resolveToolGatingMode } from '../config/tool-families.js';
|
|
5
|
+
import { createToolGatingController, DYNAMIC_MODE_INSTRUCTIONS, registerMetaTools, toolNamesInFamilies, } from '../mcp/tool-gating.js';
|
|
4
6
|
import { buildUiToolResult, createUiBridge } from '../mcp/ui-bridge.js';
|
|
5
7
|
import { getToolEntries } from '../tools/registry.js';
|
|
6
8
|
import { getErrorMessage } from '../utils/errors.js';
|
|
@@ -56,18 +58,50 @@ function registerTool(server, api, entry, logToolExecution, ui) {
|
|
|
56
58
|
}
|
|
57
59
|
});
|
|
58
60
|
ui.register(entry, registered);
|
|
61
|
+
return registered;
|
|
59
62
|
}
|
|
60
63
|
/**
|
|
61
64
|
* Create an MCP server runtime and register all eBay tool handlers.
|
|
62
65
|
*/
|
|
63
66
|
export function createEbayMcpRuntime(options = {}) {
|
|
64
67
|
const api = options.api ?? new EbaySellerApi(getEbayConfig());
|
|
65
|
-
const
|
|
66
|
-
const
|
|
68
|
+
const serverInfo = options.serverConfig ?? mcpConfig;
|
|
69
|
+
const mode = resolveToolGatingMode();
|
|
70
|
+
// Instructions are set only in dynamic mode so the agent knows the catalogue is
|
|
71
|
+
// hidden behind the discovery tools; default/static modes keep the handshake
|
|
72
|
+
// byte-for-byte unchanged (a bare single-arg construction).
|
|
73
|
+
const server = mode.kind === 'dynamic'
|
|
74
|
+
? new McpServer(serverInfo, { instructions: DYNAMIC_MODE_INSTRUCTIONS })
|
|
75
|
+
: new McpServer(serverInfo);
|
|
67
76
|
const ui = createUiBridge(server, import.meta.url);
|
|
68
|
-
|
|
77
|
+
// Static mode registers only the named families; all and dynamic register the
|
|
78
|
+
// full catalogue (dynamic then disables it below, before the transport connects).
|
|
79
|
+
const allEntries = getToolEntries();
|
|
80
|
+
const entries = mode.kind === 'static'
|
|
81
|
+
? (() => {
|
|
82
|
+
const names = toolNamesInFamilies(mode.families);
|
|
83
|
+
return allEntries.filter((entry) => names.has(entry.definition.name));
|
|
84
|
+
})()
|
|
85
|
+
: allEntries;
|
|
86
|
+
const handles = new Map();
|
|
69
87
|
for (const entry of entries) {
|
|
70
|
-
registerTool(server, api, entry, options.logToolExecution ?? false, ui);
|
|
88
|
+
handles.set(entry.definition.name, registerTool(server, api, entry, options.logToolExecution ?? false, ui));
|
|
89
|
+
}
|
|
90
|
+
if (mode.kind === 'dynamic') {
|
|
91
|
+
// Disable before `connect`: the SDK only emits `tools/listChanged` once the
|
|
92
|
+
// transport is connected, so these flips are silent. The agent re-enables the
|
|
93
|
+
// tools it needs via the meta-tools, which fire `listChanged` post-connect.
|
|
94
|
+
for (const handle of handles.values()) {
|
|
95
|
+
handle.disable();
|
|
96
|
+
}
|
|
97
|
+
registerMetaTools(server, createToolGatingController(handles));
|
|
98
|
+
serverLogger.info(`Dynamic tool mode: ${handles.size} eBay tools hidden behind 3 discovery tools`);
|
|
99
|
+
}
|
|
100
|
+
else if (mode.kind === 'static') {
|
|
101
|
+
serverLogger.info(`Static tool mode: registered ${handles.size} tools from families: ${mode.families.join(', ')}`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
serverLogger.info(`Registering ${handles.size} tools`);
|
|
71
105
|
}
|
|
72
106
|
// Install after registration so every UI-eligible tool is captured before the
|
|
73
107
|
// gate can flip their metadata on a UI-capable client's `initialize`.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TOOL_FAMILY_KEYS } from '../config/tool-families.js';
|
|
3
|
+
import { toolCategories } from '../tools/categories/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Tool gating: the runtime half of the `EBAY_MCP_TOOLS=dynamic` feature.
|
|
6
|
+
*
|
|
7
|
+
* In dynamic mode the server registers every eBay tool but boots with them
|
|
8
|
+
* disabled, advertising only the three discovery meta-tools defined here. The
|
|
9
|
+
* agent browses the catalogue and enables just the tools it needs; the MCP SDK
|
|
10
|
+
* emits `tools/listChanged` automatically when a tool's `enabled` flag flips, so
|
|
11
|
+
* the host re-fetches and the freshly enabled tools appear natively, with their
|
|
12
|
+
* real input schemas and validation. This keeps advertised context proportional
|
|
13
|
+
* to what the agent actually uses instead of the full ~187-tool catalogue.
|
|
14
|
+
*
|
|
15
|
+
* The pure env parsing/validation lives in `@/config/tool-families.ts`; this
|
|
16
|
+
* module owns everything that needs the live tool registry.
|
|
17
|
+
*/
|
|
18
|
+
/** Default page size for {@link ToolGatingController.list} when `limit` is omitted. */
|
|
19
|
+
const DEFAULT_LIST_LIMIT = 25;
|
|
20
|
+
/** Upper bound on a single discovery page, mirrored by the `list_ebay_tools` schema. */
|
|
21
|
+
const MAX_LIST_LIMIT = 100;
|
|
22
|
+
/**
|
|
23
|
+
* Initialize-time guidance shown to the agent in dynamic mode so it knows the
|
|
24
|
+
* catalogue is hidden behind the discovery tools. Set only when dynamic mode is
|
|
25
|
+
* active; the default and static modes leave the handshake untouched.
|
|
26
|
+
*/
|
|
27
|
+
export const DYNAMIC_MODE_INSTRUCTIONS = 'This eBay server keeps its full tool catalogue hidden to save context. Only the discovery tools are visible right now. ' +
|
|
28
|
+
'Call `list_ebay_tools` (no arguments) to see the tool families, then `list_ebay_tools` with a `family` or `query` to find specific tools, ' +
|
|
29
|
+
'then `enable_ebay_tools` with the tool names you need — they will appear as normal tools you can call. ' +
|
|
30
|
+
'Call `disable_ebay_tools` to remove tools you no longer need and reclaim context.';
|
|
31
|
+
/** Condenses a tool description to a single sentence for the discovery listing. */
|
|
32
|
+
function toSummary(description) {
|
|
33
|
+
const firstLine = description.split('\n', 1)[0].trim();
|
|
34
|
+
const sentenceEnd = firstLine.indexOf('. ');
|
|
35
|
+
const sentence = sentenceEnd === -1 ? firstLine : firstLine.slice(0, sentenceEnd + 1);
|
|
36
|
+
return sentence.length > 160 ? `${sentence.slice(0, 157)}...` : sentence;
|
|
37
|
+
}
|
|
38
|
+
/** Builds the discovery catalogue (tool rows, family overview, name→family index). */
|
|
39
|
+
function buildCatalog() {
|
|
40
|
+
const rows = [];
|
|
41
|
+
const families = [];
|
|
42
|
+
const familyByToolName = new Map();
|
|
43
|
+
for (const category of toolCategories) {
|
|
44
|
+
families.push({ key: category.key, title: category.title, count: category.entries.length });
|
|
45
|
+
for (const entry of category.entries) {
|
|
46
|
+
const { name, description } = entry.definition;
|
|
47
|
+
rows.push({ name, family: category.key, summary: toSummary(description) });
|
|
48
|
+
familyByToolName.set(name, category.key);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { rows, families, familyByToolName };
|
|
52
|
+
}
|
|
53
|
+
const CATALOG = buildCatalog();
|
|
54
|
+
/**
|
|
55
|
+
* Resolves the tool names belonging to the given families, preserving the caller's
|
|
56
|
+
* ability to filter registry entries for static mode. Unknown family keys
|
|
57
|
+
* contribute nothing (they are rejected earlier by env validation).
|
|
58
|
+
*/
|
|
59
|
+
export function toolNamesInFamilies(families) {
|
|
60
|
+
const wanted = new Set(families);
|
|
61
|
+
const names = new Set();
|
|
62
|
+
for (const [name, family] of CATALOG.familyByToolName) {
|
|
63
|
+
if (wanted.has(family)) {
|
|
64
|
+
names.add(name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return names;
|
|
68
|
+
}
|
|
69
|
+
/** Parses an opaque list cursor (a stringified offset) back into a non-negative offset. */
|
|
70
|
+
function parseCursor(cursor) {
|
|
71
|
+
if (!cursor) {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
const offset = Number.parseInt(cursor, 10);
|
|
75
|
+
return Number.isInteger(offset) && offset > 0 ? offset : 0;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates the controller backing the discovery meta-tools.
|
|
79
|
+
*
|
|
80
|
+
* @param handles - Map of eBay tool name → its registered handle. Only these tools
|
|
81
|
+
* are gateable; the meta-tools themselves are intentionally absent so they can
|
|
82
|
+
* never be disabled and are excluded from `activeCount`.
|
|
83
|
+
*/
|
|
84
|
+
export function createToolGatingController(handles) {
|
|
85
|
+
const activeCount = () => [...handles.values()].filter((handle) => handle.enabled).length;
|
|
86
|
+
const mutate = (names, enable) => {
|
|
87
|
+
const changed = [];
|
|
88
|
+
const unknown = [];
|
|
89
|
+
for (const name of names) {
|
|
90
|
+
const handle = handles.get(name);
|
|
91
|
+
if (!handle) {
|
|
92
|
+
unknown.push(name);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (handle.enabled !== enable) {
|
|
96
|
+
if (enable) {
|
|
97
|
+
handle.enable();
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
handle.disable();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
changed.push(name);
|
|
104
|
+
}
|
|
105
|
+
return enable
|
|
106
|
+
? { enabled: changed, unknown, activeCount: activeCount() }
|
|
107
|
+
: { disabled: changed, unknown, activeCount: activeCount() };
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
list({ family, query, cursor, limit }) {
|
|
111
|
+
if (!family && !query) {
|
|
112
|
+
return {
|
|
113
|
+
families: CATALOG.families.map((row) => ({
|
|
114
|
+
...row,
|
|
115
|
+
enabledCount: [...handles.entries()].filter(([name, handle]) => CATALOG.familyByToolName.get(name) === row.key && handle.enabled).length,
|
|
116
|
+
})),
|
|
117
|
+
hint: 'Call list_ebay_tools with { family } or { query } to list tools, then enable_ebay_tools.',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (family && !CATALOG.families.some((row) => row.key === family)) {
|
|
121
|
+
return {
|
|
122
|
+
error: `Unknown tool family "${family}".`,
|
|
123
|
+
validFamilies: TOOL_FAMILY_KEYS,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const needle = query?.toLowerCase();
|
|
127
|
+
const matches = CATALOG.rows.filter((row) => {
|
|
128
|
+
if (family && row.family !== family) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (needle) {
|
|
132
|
+
return (row.name.toLowerCase().includes(needle) ||
|
|
133
|
+
row.summary.toLowerCase().includes(needle) ||
|
|
134
|
+
row.family.includes(needle));
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
});
|
|
138
|
+
const offset = parseCursor(cursor);
|
|
139
|
+
const size = Math.min(limit ?? DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT);
|
|
140
|
+
const page = matches.slice(offset, offset + size);
|
|
141
|
+
const nextOffset = offset + size;
|
|
142
|
+
return {
|
|
143
|
+
tools: page.map((row) => ({ ...row, enabled: handles.get(row.name)?.enabled ?? false })),
|
|
144
|
+
total: matches.length,
|
|
145
|
+
nextCursor: nextOffset < matches.length ? String(nextOffset) : undefined,
|
|
146
|
+
};
|
|
147
|
+
},
|
|
148
|
+
enable: (names) => mutate(names, true),
|
|
149
|
+
disable: (names) => mutate(names, false),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** Wraps controller output as a standard text tool result. */
|
|
153
|
+
function toToolResult(data) {
|
|
154
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Registers the three discovery meta-tools on the server. Called only in dynamic
|
|
158
|
+
* mode, after the eBay tools are registered and disabled, so the controller sees
|
|
159
|
+
* every gateable handle.
|
|
160
|
+
*/
|
|
161
|
+
export function registerMetaTools(server, controller) {
|
|
162
|
+
server.registerTool('list_ebay_tools', {
|
|
163
|
+
description: "Discover eBay tools without loading them into context. Call with no arguments to list the tool families; pass `family` to list a family's tools, or `query` to keyword-search across all tools. Returns lightweight rows (name, family, summary) — enable a tool with enable_ebay_tools to get its full schema and call it.",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
family: z
|
|
166
|
+
.string()
|
|
167
|
+
.optional()
|
|
168
|
+
.describe('Restrict results to one family key (e.g. "inventory").'),
|
|
169
|
+
query: z
|
|
170
|
+
.string()
|
|
171
|
+
.optional()
|
|
172
|
+
.describe('Case-insensitive keyword matched against tool name, summary, and family.'),
|
|
173
|
+
cursor: z.string().optional().describe('Pagination cursor from a prior call.'),
|
|
174
|
+
limit: z
|
|
175
|
+
.number()
|
|
176
|
+
.int()
|
|
177
|
+
.positive()
|
|
178
|
+
.max(MAX_LIST_LIMIT)
|
|
179
|
+
.optional()
|
|
180
|
+
.describe(`Max rows per page (default ${DEFAULT_LIST_LIMIT}, max ${MAX_LIST_LIMIT}).`),
|
|
181
|
+
},
|
|
182
|
+
}, (args) => toToolResult(controller.list(args)));
|
|
183
|
+
server.registerTool('enable_ebay_tools', {
|
|
184
|
+
description: 'Load specific eBay tools into context so they can be called. Pass the exact tool names from list_ebay_tools. Returns the names enabled, any unknown names, and the active tool count.',
|
|
185
|
+
inputSchema: {
|
|
186
|
+
names: z
|
|
187
|
+
.array(z.string())
|
|
188
|
+
.min(1)
|
|
189
|
+
.describe('Exact tool names to enable, as returned by list_ebay_tools.'),
|
|
190
|
+
},
|
|
191
|
+
}, ({ names }) => toToolResult(controller.enable(names)));
|
|
192
|
+
server.registerTool('disable_ebay_tools', {
|
|
193
|
+
description: 'Unload eBay tools previously enabled, reclaiming their context. Pass the exact tool names. Returns the names disabled, any unknown names, and the active tool count.',
|
|
194
|
+
inputSchema: {
|
|
195
|
+
names: z.array(z.string()).min(1).describe('Exact tool names to disable.'),
|
|
196
|
+
},
|
|
197
|
+
}, ({ names }) => toToolResult(controller.disable(names)));
|
|
198
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ebay-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server that exposes 100% of eBay's Sell APIs (322 tools across 270 endpoints) to AI assistants like Claude, Cursor, and Cline, covering inventory, order fulfillment, marketing, analytics, and developer tools with OAuth authentication and refresh-token support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|