call_endpoint
Execute API calls to the Swagger Petstore by specifying operation IDs and parameters, enabling interaction with endpoints discovered through list_endpoints.
Instructions
Call an endpoint in the Swagger Petstore - OpenAPI 3.0. Use list_endpoints first to discover available operationIds and their required parameters.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operationId | Yes | The operationId from list_endpoints, e.g. 'getPetById' or 'createUser' | |
| parameters | No | Path, query, and header parameters as key-value pairs | |
| body | No | Request body for POST/PUT/PATCH requests (object or string) |
Implementation Reference
- src/index.ts:82-112 (handler)The handler function for the `call_endpoint` tool. It validates the operationId, executes the request via `executeCall`, and formats the response.
async ({ operationId, parameters, body }) => { const endpoint = findEndpoint(spec, operationId); if (!endpoint) { const available = getAllEndpoints(spec) .map((e) => e.operationId) .join(", "); return { content: [ { type: "text" as const, text: `Unknown operationId: "${operationId}".\n\nAvailable operations: ${available}`, }, ], isError: true, }; } try { const result = await executeCall(spec, endpoint, parameters ?? {}, body); return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }], }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error calling ${operationId}: ${message}` }], isError: true, }; } } - src/index.ts:65-113 (registration)Tool registration for `call_endpoint` including input schema validation using Zod.
server.tool( "call_endpoint", `Call an endpoint in the ${apiTitle}. ` + "Use list_endpoints first to discover available operationIds and their required parameters.", { operationId: z .string() .describe("The operationId from list_endpoints, e.g. 'getPetById' or 'createUser'"), parameters: z .record(z.union([z.string(), z.number(), z.boolean()])) .optional() .describe("Path, query, and header parameters as key-value pairs"), body: z .unknown() .optional() .describe("Request body for POST/PUT/PATCH requests (object or string)"), }, async ({ operationId, parameters, body }) => { const endpoint = findEndpoint(spec, operationId); if (!endpoint) { const available = getAllEndpoints(spec) .map((e) => e.operationId) .join(", "); return { content: [ { type: "text" as const, text: `Unknown operationId: "${operationId}".\n\nAvailable operations: ${available}`, }, ], isError: true, }; } try { const result = await executeCall(spec, endpoint, parameters ?? {}, body); return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }], }; } catch (err) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: "text" as const, text: `Error calling ${operationId}: ${message}` }], isError: true, }; } } ); - src/executor.ts:35-123 (helper)The actual logic that prepares and executes the HTTP request for the API endpoint.
export async function executeCall( spec: OpenAPIV3.Document, endpoint: EndpointInfo, parameters: Record<string, string | number | boolean>, body: unknown ): Promise<ApiResponse> { const baseUrl = getBaseUrl(spec); let urlPath = endpoint.path; const queryParams: Record<string, string> = {}; const headers: Record<string, string> = { Accept: "application/json", ...buildAuthHeaders(), }; const params = (endpoint.operation.parameters ?? []) as OpenAPIV3.ParameterObject[]; for (const param of params) { const value = parameters[param.name]; if (value === undefined || value === null) { if (param.required) { throw new Error(`Missing required parameter: ${param.name} (${param.in})`); } continue; } const strValue = String(value); switch (param.in) { case "path": urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(strValue)); break; case "query": queryParams[param.name] = strValue; break; case "header": headers[param.name] = strValue; break; // cookie params are uncommon — skip for now } } let fullUrl = baseUrl + urlPath; if (Object.keys(queryParams).length > 0) { fullUrl += "?" + new URLSearchParams(queryParams).toString(); } const fetchOptions: RequestInit = { method: endpoint.method.toUpperCase(), headers, }; const methodHasBody = ["post", "put", "patch"].includes(endpoint.method.toLowerCase()); if (methodHasBody && body !== undefined && body !== null) { if (typeof body === "string") { fetchOptions.body = body; headers["Content-Type"] = "text/plain"; } else { fetchOptions.body = JSON.stringify(body); headers["Content-Type"] = "application/json"; } } const response = await fetch(fullUrl, fetchOptions); const responseText = await response.text(); let responseBody: unknown; const contentType = response.headers.get("content-type") ?? ""; if (contentType.includes("application/json") || contentType.includes("+json")) { try { responseBody = JSON.parse(responseText); } catch { responseBody = responseText; } } else { responseBody = responseText; } const responseHeaders: Record<string, string> = {}; response.headers.forEach((value, key) => { responseHeaders[key] = value; }); return { status: response.status, statusText: response.statusText, headers: responseHeaders, body: responseBody, }; }