api_call
Send HTTP requests to any external API and retrieve the response. Supports all methods, custom headers, and request bodies, enabling data fetching, webhook delivery, and API testing.
Instructions
Make an HTTP request to any external API endpoint and return the response.
Supported features:
All HTTP methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
Custom headers (including Authorization / Bearer tokens)
JSON and form-urlencoded request bodies
URL query parameters (via url or params)
Configurable timeout (default 15 seconds)
Response includes status code, headers, and body
Use cases:
Fetching data from REST APIs
Sending webhooks
Querying third-party services (weather, maps, etc.)
Testing and debugging API endpoints
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | The full URL to send the request to. | |
| method | No | HTTP method to use. | GET |
| headers | No | HTTP headers to include (key-value pairs). | |
| body | No | Request body. Can be a JSON object (sent as application/json) or a string. | |
| params | No | Query parameters to append to the URL (key-value pairs). | |
| timeout | No | Request timeout in milliseconds (1,000–60,000). |
Implementation Reference
- src/tools/api-call.ts:59-151 (handler)The async handler function that executes the api_call tool logic — builds URL with query params, makes the HTTP request via fetch, parses the response (JSON or text), truncates large bodies, and returns the result or an error.
async ({ url, method, headers, body, params, timeout }) => { try { // Build URL with query params let finalUrl = url; if (params && Object.keys(params).length > 0) { const u = new URL(url); for (const [key, value] of Object.entries(params)) { u.searchParams.set(key, value); } finalUrl = u.toString(); } // Build fetch options const fetchOptions: RequestInit = { method, headers: { "Content-Type": "application/json", "User-Agent": "mcp-toolkit-server/1.0", ...headers, }, signal: AbortSignal.timeout(timeout), }; // Attach body for methods that support it if (body !== undefined && !["GET", "HEAD", "OPTIONS"].includes(method)) { fetchOptions.body = typeof body === "string" ? body : JSON.stringify(body); } const startTime = Date.now(); const response = await fetch(finalUrl, fetchOptions); const elapsed = Date.now() - startTime; // Collect response headers const respHeaders: Record<string, string> = {}; response.headers.forEach((value, key) => { respHeaders[key] = value; }); // Parse response body let responseBody: string; const contentType = response.headers.get("content-type") || ""; if (contentType.includes("application/json")) { const json = await response.json(); responseBody = JSON.stringify(json, null, 2); } else { responseBody = await response.text(); } // Truncate very large responses to keep the MCP response manageable const MAX_BODY_LENGTH = 50_000; const truncated = responseBody.length > MAX_BODY_LENGTH ? responseBody.slice(0, MAX_BODY_LENGTH) + `\n\n... [truncated: original was ${responseBody.length} characters]` : responseBody; return { content: [ { type: "text" as const, text: JSON.stringify( { status: response.status, statusText: response.statusText, headers: respHeaders, body: truncated, timing: { elapsed_ms: elapsed }, }, null, 2 ), }, ], }; } catch (err: any) { const errorMessage = err.name === "AbortError" ? `Request timed out after ${timeout}ms` : err.message; return { content: [ { type: "text" as const, text: `API Error: ${errorMessage}`, }, ], isError: true, }; } } ); - src/tools/api-call.ts:29-58 (schema)Zod schema defining the input parameters for api_call: url (string.url), method (enum with default GET), headers (optional record), body (optional unknown), params (optional record), timeout (optional int, default 15000).
{ url: z.string().url().describe("The full URL to send the request to."), method: z .enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]) .default("GET") .describe("HTTP method to use."), headers: z .record(z.string()) .optional() .describe("HTTP headers to include (key-value pairs)."), body: z .unknown() .optional() .describe( "Request body. Can be a JSON object (sent as application/json) or a string." ), params: z .record(z.string()) .optional() .describe( "Query parameters to append to the URL (key-value pairs)." ), timeout: z .number() .int() .min(1000) .max(60000) .default(15000) .describe("Request timeout in milliseconds (1,000–60,000)."), }, - src/index.ts:44-44 (registration)Registration call: registerApiCallTool(this.server) invoked inside McpToolkitServer.registerTools().
registerApiCallTool(this.server); - src/tools/api-call.ts:11-152 (registration)The registerApiCallTool function that calls server.tool('api_call', ...) to register the tool.
export function registerApiCallTool(server: McpServer): void { server.tool( "api_call", `Make an HTTP request to any external API endpoint and return the response. Supported features: - All HTTP methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS - Custom headers (including Authorization / Bearer tokens) - JSON and form-urlencoded request bodies - URL query parameters (via url or params) - Configurable timeout (default 15 seconds) - Response includes status code, headers, and body Use cases: - Fetching data from REST APIs - Sending webhooks - Querying third-party services (weather, maps, etc.) - Testing and debugging API endpoints`, { url: z.string().url().describe("The full URL to send the request to."), method: z .enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]) .default("GET") .describe("HTTP method to use."), headers: z .record(z.string()) .optional() .describe("HTTP headers to include (key-value pairs)."), body: z .unknown() .optional() .describe( "Request body. Can be a JSON object (sent as application/json) or a string." ), params: z .record(z.string()) .optional() .describe( "Query parameters to append to the URL (key-value pairs)." ), timeout: z .number() .int() .min(1000) .max(60000) .default(15000) .describe("Request timeout in milliseconds (1,000–60,000)."), }, async ({ url, method, headers, body, params, timeout }) => { try { // Build URL with query params let finalUrl = url; if (params && Object.keys(params).length > 0) { const u = new URL(url); for (const [key, value] of Object.entries(params)) { u.searchParams.set(key, value); } finalUrl = u.toString(); } // Build fetch options const fetchOptions: RequestInit = { method, headers: { "Content-Type": "application/json", "User-Agent": "mcp-toolkit-server/1.0", ...headers, }, signal: AbortSignal.timeout(timeout), }; // Attach body for methods that support it if (body !== undefined && !["GET", "HEAD", "OPTIONS"].includes(method)) { fetchOptions.body = typeof body === "string" ? body : JSON.stringify(body); } const startTime = Date.now(); const response = await fetch(finalUrl, fetchOptions); const elapsed = Date.now() - startTime; // Collect response headers const respHeaders: Record<string, string> = {}; response.headers.forEach((value, key) => { respHeaders[key] = value; }); // Parse response body let responseBody: string; const contentType = response.headers.get("content-type") || ""; if (contentType.includes("application/json")) { const json = await response.json(); responseBody = JSON.stringify(json, null, 2); } else { responseBody = await response.text(); } // Truncate very large responses to keep the MCP response manageable const MAX_BODY_LENGTH = 50_000; const truncated = responseBody.length > MAX_BODY_LENGTH ? responseBody.slice(0, MAX_BODY_LENGTH) + `\n\n... [truncated: original was ${responseBody.length} characters]` : responseBody; return { content: [ { type: "text" as const, text: JSON.stringify( { status: response.status, statusText: response.statusText, headers: respHeaders, body: truncated, timing: { elapsed_ms: elapsed }, }, null, 2 ), }, ], }; } catch (err: any) { const errorMessage = err.name === "AbortError" ? `Request timed out after ${timeout}ms` : err.message; return { content: [ { type: "text" as const, text: `API Error: ${errorMessage}`, }, ], isError: true, }; } } ); } - src/utils/helpers.ts:1-34 (helper)Shared helper utilities (ToolResult, textResult, errorResult, jsonResult) used by the api_call handler for building responses.
/** * Shared utility types and helpers for MCP Toolkit Server tools. */ /** Standard success response shape returned by tool handlers. */ export interface ToolResult { content: Array<{ type: "text"; text: string }>; isError?: boolean; } /** Helper to build a success text response. */ export function textResult(text: string): ToolResult { return { content: [{ type: "text" as const, text }] }; } /** Helper to build an error text response. */ export function errorResult(message: string): ToolResult { return { content: [{ type: "text" as const, text: message }], isError: true, }; } /** Helper to JSON-stringify and wrap in a text result. */ export function jsonResult(data: unknown, pretty = true): ToolResult { return { content: [ { type: "text" as const, text: JSON.stringify(data, null, pretty ? 2 : 0), }, ], }; }