ebay-api-mcp-server-node-local 1.0.1 → 1.0.9

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.
@@ -0,0 +1,119 @@
1
+ /**
2
+ * OpenAPI helper functions, including loading OpenAPI documents,
3
+ * parsing OpenAPI specs, building schemas, and converting to Zod schemas.
4
+ */
5
+ import SwaggerParser from "@apidevtools/swagger-parser";
6
+ import { type OpenAPIV3 } from "openapi-types";
7
+ import * as fs from "fs";
8
+ import axios from "axios";
9
+ import * as yaml from "js-yaml";
10
+ import util from "util";
11
+ import { z, type ZodTypeAny } from "zod";
12
+ import { buildHeadersFromInput } from "../helper/http-helper.js";
13
+
14
+
15
+
16
+ const SCHEMA_REQUEST_BODY = "requestBody";
17
+
18
+ /**
19
+ * Get OpenAPI docs from user config file, which contains urls or paths of OpenAPI specs.
20
+ */
21
+ export async function getOpenApiDocumentsFromConfigFile(): Promise<OpenAPIV3.Document[]> {
22
+ const docs: OpenAPIV3.Document[] = [];
23
+ const urlFile = process.env.EBAY_API_DOC_URL_FILE;
24
+ let urls: string[] = [];
25
+ if (urlFile && fs.existsSync(urlFile)) {
26
+ // url or path each line in the file
27
+ urls = fs.readFileSync(urlFile, "utf-8").split(/\r?\n/)
28
+ .map(line => line.trim())
29
+ .filter(line => line.length > 0 && !line.startsWith("#"));
30
+ }
31
+ console.error("Loading OpenAPI specifications from:", urls);
32
+ // parse opebapi doc from url/path
33
+ for (const specPath of urls) {
34
+ try {
35
+ const doc = await SwaggerParser.dereference(specPath) as OpenAPIV3.Document;
36
+ docs.push(doc);
37
+ } catch (e) {
38
+ console.error(`getOpenApiDocumentsFromConfigFile#[Failed to load OpenAPI doc from the specPath : ${specPath}]`);
39
+ }
40
+ }
41
+ return docs;
42
+ }
43
+
44
+ // Helper: remove ignored keys recursively
45
+ export function readSchema2Map(obj: unknown): unknown {
46
+ const SCHEMA_IGNORE_KEYS = ["style", "explode", "exampleSetFlag", "types", "in", "required"];
47
+ if (Array.isArray(obj)) {
48
+ return obj.map(readSchema2Map);
49
+ } else if (obj && typeof obj === "object") {
50
+ const out: Record<string, unknown> = {};
51
+ for (const [k, v] of Object.entries(obj as Record<string, unknown>)) {
52
+ if (!SCHEMA_IGNORE_KEYS.includes(k)) {
53
+ out[k] = readSchema2Map(v);
54
+ }
55
+ }
56
+ return out;
57
+ }
58
+ return obj;
59
+ }
60
+
61
+ /**
62
+ * Query api spec and parse to OpenAPI document (supports both JSON and YAML)
63
+ */
64
+ export async function queryAndParseOpenApiDoc(specTitle: string, operationId : string, specUrl: string): Promise<OpenAPIV3.Document> {
65
+ const url = util.format(specUrl, specTitle, operationId);
66
+ const apiSpecRes = await axios.get<string>(url, {
67
+ headers: buildHeadersFromInput(undefined, false),
68
+ httpsAgent: new (await import("https")).Agent({
69
+ rejectUnauthorized: false,
70
+ })});
71
+ const docString = apiSpecRes.data;
72
+ try {
73
+ // Try parsing as JSON first
74
+ return JSON.parse(docString) as OpenAPIV3.Document;
75
+ } catch (jsonError) {
76
+ try {
77
+ // If JSON fails, try parsing as YAML
78
+ return yaml.load(docString) as OpenAPIV3.Document;
79
+ } catch (yamlError) {
80
+ const _jsonMsg = jsonError instanceof Error ? jsonError.message : String(jsonError);
81
+ const _yamlMsg = yamlError instanceof Error ? yamlError.message : String(yamlError);
82
+ console.error("failed to parse OpenAPI document !!!");
83
+ return {} as OpenAPIV3.Document;
84
+ }
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Build schema for an operation's input parameters
90
+ */
91
+ export function buildOperationSchema(operation: OpenAPIV3.OperationObject): { properties: Record<string, unknown> } {
92
+ const properties: Record<string, unknown> = {};
93
+ // handle request param
94
+ (operation.parameters || []).forEach(param => {
95
+ if ("$ref" in param) {return;}
96
+ const paramSchema = readSchema2Map(param);
97
+ properties[param.name] = paramSchema;
98
+ });
99
+ // handle request body
100
+ if (operation.requestBody && "content" in operation.requestBody &&
101
+ operation.requestBody.content?.["application/json"]?.schema) {
102
+ const requestBodySchema = readSchema2Map(operation.requestBody.content["application/json"].schema);
103
+ properties[SCHEMA_REQUEST_BODY] = requestBodySchema;
104
+ }
105
+ return { properties };
106
+ }
107
+
108
+ /**
109
+ * Build Zod validation schema
110
+ */
111
+ export function buildZodSchema(properties: Record<string, unknown>): Record<string, ZodTypeAny> {
112
+ const zodProperties: Record<string, ZodTypeAny> = {};
113
+
114
+ Object.keys(properties).forEach(key => {
115
+ zodProperties[key] = z.any();
116
+ });
117
+
118
+ return zodProperties;
119
+ }
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Validation helper functions for OpenAPI validation
3
+ */
4
+ import { type OpenAPIV3 } from "openapi-types";
5
+ import AjvLib from "ajv";
6
+ import { SUPPORTED_CALLING_METHODS, USER_ENVIRONMENT } from "../constant/constants.js";
7
+ const Ajv = AjvLib.default || AjvLib;
8
+
9
+ /**
10
+ * Validate request parameters against OpenAPI specification
11
+ */
12
+ export function validateRequestParameters(
13
+ url: string,
14
+ openApiDoc: OpenAPIV3.Document,
15
+ method: string,
16
+ input: {
17
+ urlVariables?: Record<string, unknown>;
18
+ urlQueryParams?: Record<string, unknown>;
19
+ headers?: Record<string, string>;
20
+ requestBody?: Record<string, unknown>;
21
+ },
22
+ ): { isValid: boolean; errors: string[] } {
23
+ const errors: string[] = [];
24
+
25
+ // validate method
26
+ if (!SUPPORTED_CALLING_METHODS[USER_ENVIRONMENT].includes(method.toLowerCase())) {
27
+ errors.push(`Method ${method} is not supported in ${USER_ENVIRONMENT} environment`);
28
+ return { isValid: false, errors };
29
+ }
30
+
31
+ // validate path
32
+ const {pathValidateRes, apiPath, specPath, specPathItem} = validatePath(openApiDoc, url);
33
+ if (!pathValidateRes || !specPathItem) {
34
+ errors.push(`API path ${apiPath} is not valid or not found in OpenAPI specification`);
35
+ return { isValid: false, errors };
36
+ }
37
+
38
+ // Check if the method exists for the path
39
+ const operation = specPathItem[method.toLowerCase() as keyof typeof specPathItem] as OpenAPIV3.OperationObject;
40
+ if (!operation) {
41
+ errors.push(`Method ${method} not found for path ${specPath} in OpenAPI specification`);
42
+ return { isValid: false, errors };
43
+ }
44
+
45
+ // Initialize AJV for schema validation
46
+ const _ajv = new Ajv({ allErrors: true });
47
+
48
+ validateUrlPathParam(input.urlVariables, operation.parameters, errors);
49
+
50
+ validateUrlQueryParam(input.urlQueryParams, operation.parameters, errors);
51
+
52
+ validateUrlHeaders(input.headers, operation.parameters, errors);
53
+
54
+ validateUrlRequestBody(input.requestBody, operation.requestBody, errors);
55
+
56
+ return { isValid: errors.length === 0, errors };
57
+ }
58
+
59
+ /**
60
+ * Validate the API path against the OpenAPI document
61
+ */
62
+ export function validatePath(openApiDoc: OpenAPIV3.Document, inputUrl: string): {
63
+ pathValidateRes : boolean,
64
+ apiPath : string,
65
+ specPath : string,
66
+ specPathItem?: OpenAPIV3.PathItemObject
67
+ } {
68
+ // Extract the path from the URL (remove base URL part)
69
+ const apiPath : string = parseApiPathFromUrl(inputUrl);
70
+ if (!apiPath) {
71
+ console.error(`input url ${inputUrl} is not valid, please check it.`);
72
+ return {pathValidateRes : false, apiPath:"", specPath: "", specPathItem: undefined};
73
+ }
74
+ // bathPath validation
75
+ const serverObj = openApiDoc.servers?.[0] || { url: "" };
76
+ let basePath : string = "";
77
+ if (serverObj?.variables) {
78
+ for (const [key, value] of Object.entries(serverObj.variables)) {
79
+ if (key === "basePath") {
80
+ basePath = value.default;
81
+ }
82
+ }
83
+ }
84
+ const basePathRegex = new RegExp(`${basePath.replace(/\{[^}]+\}/g, "[^/]+") }$`);
85
+ if (basePath && !basePathRegex.test(apiPath)) {
86
+ console.error(`API path ${apiPath} does not match the base path ${basePath} in OpenAPI specification.`);
87
+ return {pathValidateRes : false, apiPath, specPath: "", specPathItem: undefined};
88
+ }
89
+
90
+ // specPath validation
91
+ for (const specPath of Object.keys(openApiDoc.paths || {})) {
92
+ const specPathRegex = new RegExp(`${specPath.replace(/\{[^}]+\}/g, "[^/]+") }$`);
93
+ if (specPathRegex.test(apiPath) && openApiDoc.paths?.[specPath]) {
94
+ const specPathItem = openApiDoc.paths[specPath];
95
+ return { pathValidateRes: true, apiPath, specPath, specPathItem};
96
+ }
97
+ }
98
+
99
+ return {pathValidateRes : false, apiPath, specPath: "", specPathItem: undefined};
100
+ }
101
+
102
+ /**
103
+ * parse path from the given url by llm
104
+ */
105
+ export function parseApiPathFromUrl(inputUrl: string): string {
106
+ try {
107
+ const urlObj = new URL(inputUrl);
108
+ return decodeURIComponent(urlObj.pathname); // Decode URL path
109
+ } catch (urlError) {
110
+ // If URL parsing fails, try to extract path manually
111
+ const pathMatch = inputUrl.match(/https?:\/\/[^/]+(.*)$/);
112
+ if (pathMatch) {
113
+ return pathMatch[1];
114
+ }
115
+ console.error(`Failed to parse API path from URL: ${inputUrl}`);
116
+ return "";
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Validate URL path parameters against OpenAPI specification
122
+ */
123
+ export function validateUrlPathParam(
124
+ urlVariables: Record<string, unknown> | undefined,
125
+ parameters: (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[] | undefined,
126
+ errors: string[],
127
+ ): void {
128
+ // Initialize AJV for schema validation
129
+ const ajv = new Ajv({ allErrors: true });
130
+ if (urlVariables) {
131
+ const pathParams = (parameters || []).filter(
132
+ (param): param is OpenAPIV3.ParameterObject =>
133
+ !("$ref" in param) && param.in === "path",
134
+ );
135
+
136
+ for (const param of pathParams) {
137
+ const value = urlVariables[param.name];
138
+
139
+ if (param.required && (value === undefined || value === null)) {
140
+ errors.push(`Missing required path parameter: ${param.name}`);
141
+ continue;
142
+ }
143
+
144
+ if (value !== undefined && param.schema) {
145
+ const validate = ajv.compile(param.schema);
146
+ if (!validate(value)) {
147
+ errors.push(`Invalid path parameter ${param.name}: ${ajv.errorsText(validate.errors)}`);
148
+ }
149
+ }
150
+ }
151
+
152
+ // Check for extra path parameters not defined in spec
153
+ const definedPathParams = pathParams.map(p => p.name);
154
+ const extraParams = Object.keys(urlVariables).filter(key => !definedPathParams.includes(key));
155
+ if (extraParams.length > 0) {
156
+ errors.push(`Unknown path parameters: ${extraParams.join(", ")}`);
157
+ }
158
+
159
+ // Check for required path parameters that might be missing from urlVariables
160
+ const requiredPathParams = (parameters || [])
161
+ .filter((param): param is OpenAPIV3.ParameterObject =>
162
+ !("$ref" in param) && param.in === "path" && (param.required === true),
163
+ )
164
+ .map(param => param.name);
165
+ const providedPathParams = Object.keys(urlVariables || {});
166
+ const missingPathParams = requiredPathParams.filter(param => !providedPathParams.includes(param));
167
+ if (missingPathParams.length > 0) {
168
+ errors.push(`Missing required path parameters: ${missingPathParams.join(", ")}`);
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Validate URL query parameters against OpenAPI specification
175
+ */
176
+ export function validateUrlQueryParam(
177
+ urlQueryParams: Record<string, unknown> | undefined,
178
+ parameters: (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[] | undefined,
179
+ errors: string[],
180
+ ): void {
181
+ const ajv = new Ajv({ allErrors: true });
182
+ if (urlQueryParams) {
183
+ const queryParams = (parameters || []).filter(
184
+ (param): param is OpenAPIV3.ParameterObject =>
185
+ !("$ref" in param) && param.in === "query",
186
+ );
187
+
188
+ for (const param of queryParams) {
189
+ const value = urlQueryParams[param.name];
190
+
191
+ if (param.required && (value === undefined || value === null || value === "")) {
192
+ errors.push(`Missing required query parameter: ${param.name}`);
193
+ continue;
194
+ }
195
+
196
+ if (value !== undefined && param.schema) {
197
+ const validate = ajv.compile(param.schema);
198
+ // Convert string values to appropriate types for validation
199
+ let validationValue = value;
200
+ if (typeof value === "string" && param.schema && !("$ref" in param.schema) && (param.schema).type) {
201
+ const schemaObj = param.schema;
202
+ switch (schemaObj.type) {
203
+ case "integer":
204
+ case "number":
205
+ validationValue = Number(value);
206
+ break;
207
+ case "boolean":
208
+ validationValue = value.toLowerCase() === "true";
209
+ break;
210
+ case "array":
211
+ // Handle comma-separated values for arrays
212
+ if (param.style === "form" && !param.explode) {
213
+ validationValue = value.split(",");
214
+ }
215
+ break;
216
+ }
217
+ }
218
+
219
+ if (!validate(validationValue)) {
220
+ errors.push(`Invalid query parameter ${param.name}: ${ajv.errorsText(validate.errors)}`);
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Validate URL headers against OpenAPI specification
229
+ */
230
+ export function validateUrlHeaders(
231
+ headers: Record<string, string> | undefined,
232
+ parameters: (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[] | undefined,
233
+ errors: string[],
234
+ ): void {
235
+ const ajv = new Ajv({ allErrors: true });
236
+ if (headers) {
237
+ const headerParams = (parameters || []).filter(
238
+ (param): param is OpenAPIV3.ParameterObject =>
239
+ !("$ref" in param) && param.in === "header",
240
+ );
241
+
242
+ for (const param of headerParams) {
243
+ const headerName = param.name.toLowerCase();
244
+ const value = headers[headerName] || headers[param.name];
245
+
246
+ if (param.required && (value === undefined || value === null || value === "")) {
247
+ errors.push(`Missing required header parameter: ${param.name}`);
248
+ continue;
249
+ }
250
+
251
+ if (value !== undefined && param.schema) {
252
+ const validate = ajv.compile(param.schema);
253
+ if (!validate(value)) {
254
+ errors.push(`Invalid header parameter ${param.name}: ${ajv.errorsText(validate.errors)}`);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Validate URL request body against OpenAPI specification
263
+ */
264
+ export function validateUrlRequestBody(
265
+ inputBody: Record<string, unknown> | undefined,
266
+ operationBody: OpenAPIV3.ReferenceObject | OpenAPIV3.RequestBodyObject | undefined,
267
+ errors: string[],
268
+ ): void {
269
+ const ajv = new Ajv({ allErrors: true, strict: false });
270
+ if (operationBody && !("$ref" in operationBody)) {
271
+ const requestBody = operationBody;
272
+ const isRequired = requestBody.required || false;
273
+
274
+ if (isRequired && (!inputBody || Object.keys(inputBody).length === 0)) {
275
+ errors.push("Missing required request body");
276
+ } else if (inputBody && Object.keys(inputBody).length > 0) {
277
+ // Find the appropriate content type schema
278
+ const contentTypes = ["application/json", "application/x-www-form-urlencoded", "multipart/form-data"];
279
+ let schema: OpenAPIV3.SchemaObject | undefined;
280
+
281
+ for (const contentType of contentTypes) {
282
+ if (requestBody.content?.[contentType]?.schema) {
283
+ schema = requestBody.content[contentType].schema as OpenAPIV3.SchemaObject;
284
+ break;
285
+ }
286
+ }
287
+
288
+ if (schema) {
289
+ const validate = ajv.compile(schema);
290
+ if (!validate(inputBody)) {
291
+ errors.push(`Invalid request body: ${ajv.errorsText(validate.errors)}`);
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
package/src/index.ts ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ // Load environment variables from .env file
3
+ import * as dotenv from "dotenv";
4
+ dotenv.config();
5
+
6
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+ import { registerOpenApiTools } from "./service/openapi-service.js";
9
+ import * as constants from "./constant/constants.js";
10
+
11
+ /**
12
+ * Check if required environment variables are set for eBay API authentication
13
+ */
14
+ function checkEnvironmentVariables(): void {
15
+
16
+ // environment vals check
17
+ const missingVars = constants.REQUIRED_ENV_VARS.filter(varName => !process.env[varName]);
18
+
19
+ if (missingVars.length > 0) {
20
+ console.error(`Missing required environment variables: ${missingVars.join(", ")}`);
21
+ process.exit(1);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Main function to initialize and run the eBay API MCP Server
27
+ * This server exposes eBay API endpoints as MCP tools for access via AI models
28
+ */
29
+ async function main(): Promise<void> {
30
+ console.error("Starting eBay API MCP Server...");
31
+ // Check for required environment variables
32
+ checkEnvironmentVariables();
33
+ const server = initServer();
34
+
35
+ try {
36
+ // Register the OpenAPI tools with the server
37
+ await registerOpenApiTools(server);
38
+ console.error("Successfully registered OpenAPI tools");
39
+
40
+ // Create and connect server transport
41
+ const transport = new StdioServerTransport();
42
+ await server.connect(transport);
43
+ console.error("eBay API MCP Server running on stdio transport");
44
+
45
+ } catch (error) {
46
+ console.error("Error starting MCP server:", error instanceof Error ? error.message : String(error));
47
+ console.error("Stack trace:", error instanceof Error ? error.stack : "No stack trace available");
48
+ process.exit(1);
49
+ }
50
+ }
51
+
52
+ // Run the server
53
+ main().catch((error) => {
54
+ console.error("Fatal error:", error instanceof Error ? error.message : String(error));
55
+ console.error("Stack trace:", error instanceof Error ? error.stack : "No stack trace available");
56
+ process.exit(1);
57
+ });
58
+
59
+
60
+ // Create MCP server instance
61
+ function initServer(): McpServer {
62
+ return new McpServer({
63
+ name: "ebay-api-mcp-server",
64
+ version: "1.0.0",
65
+ capabilities: {
66
+ resources: {},
67
+ tools: {},
68
+ },
69
+ });
70
+ }
@@ -0,0 +1,140 @@
1
+ import {afterAll, beforeAll, describe, expect, it} from "vitest";
2
+ import {Client} from "@modelcontextprotocol/sdk/client/index.js";
3
+ import {StdioClientTransport} from "@modelcontextprotocol/sdk/client/stdio.js";
4
+ import * as path from "path";
5
+ import * as fs from "fs";
6
+
7
+ // Define interfaces for type safety
8
+ interface ContentPart {
9
+ type: string;
10
+ text: string;
11
+ }
12
+
13
+ interface CallToolResponse {
14
+ content: ContentPart[];
15
+ isError?: boolean;
16
+ }
17
+
18
+ describe("MCP Server Integration Tests", () => {
19
+ let client: Client;
20
+ let transport: StdioClientTransport;
21
+
22
+ // Only setup the test environment if we're not skipping tests
23
+ beforeAll(async () => {
24
+ try {
25
+ console.log("Setting up test client...");
26
+
27
+ // Use the correct path to your server script
28
+ // Make sure we're using node with the compiled JS file instead of ts-node
29
+ const serverScriptPath = path.join(process.cwd(), "src", "index.ts");
30
+
31
+ // Check if the file exists
32
+ if (!fs.existsSync(serverScriptPath)) {
33
+ throw new Error(`Server script not found at: ${serverScriptPath}`);
34
+ }
35
+
36
+ console.log(`Server script found at: ${serverScriptPath}`);
37
+
38
+ // Create the transport with the correct path to the server
39
+ transport = new StdioClientTransport({
40
+ command: "node",
41
+ args: [
42
+ "--loader", "ts-node/esm",
43
+ "--experimental-specifier-resolution=node",
44
+ serverScriptPath,
45
+ ],
46
+ });
47
+
48
+ // Initialize the client
49
+ client = new Client({
50
+ name: "test-client",
51
+ version: "1.0.0",
52
+ });
53
+
54
+ console.log("Connecting to MCP server...");
55
+
56
+ // Add a timeout to the connection attempt
57
+ const connectionPromise = client.connect(transport);
58
+ const timeoutPromise = new Promise((_, reject) => {
59
+ setTimeout(() => reject(new Error("Connection timed out after 15 seconds")), 15000);
60
+ });
61
+
62
+ await Promise.race([connectionPromise, timeoutPromise]);
63
+ console.log("✅ Client connected successfully");
64
+
65
+ } catch (error) {
66
+ console.error("❌ Error during test setup:", error);
67
+ // Explicitly failing the test setup
68
+ throw error;
69
+ }
70
+ });
71
+
72
+ afterAll(async () => {
73
+ try {
74
+ if (client) {
75
+ console.log("Closing client connection...");
76
+ await client.close();
77
+ console.log("✅ Client closed successfully");
78
+ }
79
+ } catch (error) {
80
+ console.error("❌ Error during test cleanup:", error);
81
+ }
82
+ });
83
+
84
+
85
+ it("test list tools", async () => {
86
+ const result = await client.listTools();
87
+ console.log("Available tools:", result.tools.map(tool => tool.name));
88
+ expect(result.tools.length).toBeGreaterThan(1);
89
+ });
90
+
91
+ it("test query api", async () => {
92
+ const response = await client.callTool({
93
+ name: "queryAPI",
94
+ arguments: {
95
+ prompt : "i wanna order api",
96
+ },
97
+ }) as CallToolResponse;
98
+
99
+ expect(response).toBeDefined();
100
+ expect(response.content).toBeDefined();
101
+ expect(response.content.length).toBeGreaterThan(0);
102
+ });
103
+
104
+ it("test invoke api", async () => {
105
+ const response = await client.callTool({
106
+ name: "invokeAPI",
107
+ arguments: {
108
+ url: "https://api.sandbox.ebay.com/commerce/notification/v1/topic/MARKETPLACE_ACCOUNT_DELETION",
109
+ method: "GET",
110
+ headers: {},
111
+ urlVariables: {},
112
+ requestBody: {},
113
+ token : process.env.EBAY_CLIENT_TOKEN
114
+ },
115
+ }) as CallToolResponse;
116
+
117
+ expect(response).toBeDefined();
118
+ expect(response.content).toBeDefined();
119
+ expect(response.content.length).toBeGreaterThan(0);
120
+ });
121
+
122
+ it("test invoke api with pathVals", async () => {
123
+ const response = await client.callTool({
124
+ name: "invokeAPI",
125
+ arguments: {
126
+ url: "https://api.sandbox.ebay.com/commerce/notification/v1/subscription/{subscription_id}/test",
127
+ method: "POST",
128
+ headers: {},
129
+ urlVariables: {"subscription_id":"1000"},
130
+ requestBody: {},
131
+ token: process.env.EBAY_CLIENT_TOKEN
132
+ },
133
+ }) as CallToolResponse;
134
+
135
+ expect(response).toBeDefined();
136
+ expect(response.content).toBeDefined();
137
+ expect(response.content.length).toBeGreaterThan(0);
138
+ });
139
+
140
+ });