api.request
Send live HTTP requests to APIs with optional auth tokens, specified endpoints, and customizable methods, headers, and query parameters for streamlined API testing and integration.
Instructions
Execute a live HTTP request to API_BASE_URL; optionally include an Authorization bearer token retrieved from configured browser storage. Use after 'api.searchEndpoints' or for known endpoints.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| endpoint | Yes | The API endpoint path (e.g., '/api/users', '/auth/profile'). Will be combined with API_BASE_URL from environment. | |
| includeAuthToken | No | Whether to include auth token | |
| method | No | HTTP method for the API call | GET |
| queryParams | No | Query parameters as key-value pairs | |
| requestBody | No | Request body for POST/PUT/PATCH requests (will be JSON stringified) |
Implementation Reference
- browser-tools-mcp/mcp-server.ts:1018-1208 (registration)Registration of the 'api.request' MCP tool, including description, Zod input schema (endpoint, method, body, query, auth flag), and inline asynchronous handler function that performs the HTTP request.server.tool( "api.request", "Execute a live HTTP request to API_BASE_URL; optionally include an Authorization bearer token retrieved from configured browser storage. Use after 'api.searchEndpoints' or for known endpoints.", { endpoint: z .string() .describe( "The API endpoint path (e.g., '/api/users', '/auth/profile'). Will be combined with API_BASE_URL from environment." ), method: z .enum(["GET", "POST", "PUT", "PATCH", "DELETE"]) .optional() .default("GET") .describe("HTTP method for the API call"), requestBody: z .any() .optional() .describe( "Request body for POST/PUT/PATCH requests (will be JSON stringified)" ), queryParams: z .record(z.string()) .optional() .describe("Query parameters as key-value pairs"), includeAuthToken: z .boolean() .optional() .describe("Whether to include auth token"), }, async (params) => { console.log(`[api.request] - Making request to: ${params.endpoint}`); try { const { endpoint, method = "GET", requestBody, queryParams, includeAuthToken, } = params; // Check required environment variables or config const apiBaseUrl = getConfigValue("API_BASE_URL"); const authTokenResolved = await resolveAuthToken(includeAuthToken); console.log(`[api.request] - API base URL: ${apiBaseUrl} ${endpoint}`); // Validate/resolve auth token if requested if (includeAuthToken === true) { if (typeof (authTokenResolved as any)?.error === "string") { return { content: [ { type: "text", text: (authTokenResolved as any).error, }, ], isError: true, }; } } if (!apiBaseUrl) { return { content: [ { type: "text", text: "Missing required environment variable. Please set API_BASE_URL in projects.json or as environment variable.", }, ], isError: true, }; } // Build the full URL let fullUrl = `${apiBaseUrl}${endpoint}`; // Add query parameters if provided if (queryParams && Object.keys(queryParams).length > 0) { const urlParams = new URLSearchParams(); for (const [key, value] of Object.entries(queryParams)) { urlParams.append(key, value); } fullUrl += `?${urlParams.toString()}`; } // Prepare headers const headers: Record<string, string> = { "Content-Type": "application/json", }; // Add Authorization header if auth token is provided if (includeAuthToken === true) { const tokenString = typeof authTokenResolved === "string" ? authTokenResolved : undefined; if (!tokenString) { return { content: [ { type: "text", text: "Auth token requested but could not be resolved.", }, ], isError: true, }; } headers["Authorization"] = `Bearer ${tokenString}`; } // Prepare fetch options const fetchOptions: RequestInit = { method: method, headers: headers, }; // Add request body for POST/PUT/PATCH if ( requestBody && ["POST", "PUT", "PATCH"].includes(method.toUpperCase()) ) { fetchOptions.body = JSON.stringify(requestBody); } console.log(`[api.request] - Making ${method} request to ${fullUrl}`); // Make the API call const startTime = Date.now(); const response = await fetch(fullUrl, fetchOptions); const endTime = Date.now(); console.log(`[api.request] - Response status: ${response.status}`); // Parse response let responseData; const contentType = response.headers.get("content-type"); if (contentType && contentType.includes("application/json")) { responseData = await response.json(); } else { responseData = await response.text(); } // Build response object const result: any = { data: responseData, details: { status: response.status, statusText: response.statusText, headers: Object.fromEntries(response.headers.entries()), timing: { requestDuration: endTime - startTime, timestamp: new Date().toISOString(), }, url: fullUrl, method: method, }, }; return { content: [ { type: "text", text: JSON.stringify( { success: response.ok, method, url: fullUrl, responseDetails: result.details, data: result.data, }, null, 2 ), }, ], }; } catch (error) { console.error("[api.request] - Error:", error); return { content: [ { type: "text", text: `Error executing API call: ${ error instanceof Error ? error.message : String(error) }`, }, ], isError: true, }; } } );
- Inline handler function for 'api.request': extracts params, gets API_BASE_URL from config, resolves optional auth token, builds full URL with query params, sets JSON headers and optional Bearer auth, performs fetch request, parses response (JSON/text), returns structured result with data, status, headers, timing.async (params) => { console.log(`[api.request] - Making request to: ${params.endpoint}`); try { const { endpoint, method = "GET", requestBody, queryParams, includeAuthToken, } = params; // Check required environment variables or config const apiBaseUrl = getConfigValue("API_BASE_URL"); const authTokenResolved = await resolveAuthToken(includeAuthToken); console.log(`[api.request] - API base URL: ${apiBaseUrl} ${endpoint}`); // Validate/resolve auth token if requested if (includeAuthToken === true) { if (typeof (authTokenResolved as any)?.error === "string") { return { content: [ { type: "text", text: (authTokenResolved as any).error, }, ], isError: true, }; } } if (!apiBaseUrl) { return { content: [ { type: "text", text: "Missing required environment variable. Please set API_BASE_URL in projects.json or as environment variable.", }, ], isError: true, }; } // Build the full URL let fullUrl = `${apiBaseUrl}${endpoint}`; // Add query parameters if provided if (queryParams && Object.keys(queryParams).length > 0) { const urlParams = new URLSearchParams(); for (const [key, value] of Object.entries(queryParams)) { urlParams.append(key, value); } fullUrl += `?${urlParams.toString()}`; } // Prepare headers const headers: Record<string, string> = { "Content-Type": "application/json", }; // Add Authorization header if auth token is provided if (includeAuthToken === true) { const tokenString = typeof authTokenResolved === "string" ? authTokenResolved : undefined; if (!tokenString) { return { content: [ { type: "text", text: "Auth token requested but could not be resolved.", }, ], isError: true, }; } headers["Authorization"] = `Bearer ${tokenString}`; } // Prepare fetch options const fetchOptions: RequestInit = { method: method, headers: headers, }; // Add request body for POST/PUT/PATCH if ( requestBody && ["POST", "PUT", "PATCH"].includes(method.toUpperCase()) ) { fetchOptions.body = JSON.stringify(requestBody); } console.log(`[api.request] - Making ${method} request to ${fullUrl}`); // Make the API call const startTime = Date.now(); const response = await fetch(fullUrl, fetchOptions); const endTime = Date.now(); console.log(`[api.request] - Response status: ${response.status}`); // Parse response let responseData; const contentType = response.headers.get("content-type"); if (contentType && contentType.includes("application/json")) { responseData = await response.json(); } else { responseData = await response.text(); } // Build response object const result: any = { data: responseData, details: { status: response.status, statusText: response.statusText, headers: Object.fromEntries(response.headers.entries()), timing: { requestDuration: endTime - startTime, timestamp: new Date().toISOString(), }, url: fullUrl, method: method, }, }; return { content: [ { type: "text", text: JSON.stringify( { success: response.ok, method, url: fullUrl, responseDetails: result.details, data: result.data, }, null, 2 ), }, ], }; } catch (error) { console.error("[api.request] - Error:", error); return { content: [ { type: "text", text: `Error executing API call: ${ error instanceof Error ? error.message : String(error) }`, }, ], isError: true, }; } }
- Zod schema defining input parameters for the api.request tool: endpoint (required string), method (GET default), optional requestBody (any), queryParams (record<string>), includeAuthToken (boolean).endpoint: z .string() .describe( "The API endpoint path (e.g., '/api/users', '/auth/profile'). Will be combined with API_BASE_URL from environment." ), method: z .enum(["GET", "POST", "PUT", "PATCH", "DELETE"]) .optional() .default("GET") .describe("HTTP method for the API call"), requestBody: z .any() .optional() .describe( "Request body for POST/PUT/PATCH requests (will be JSON stringified)" ), queryParams: z .record(z.string()) .optional() .describe("Query parameters as key-value pairs"), includeAuthToken: z .boolean() .optional() .describe("Whether to include auth token"), },
- Helper function resolveAuthToken used by api.request handler to dynamically retrieve and cache authentication tokens from browser storage via extension, with TTL and JWT expiration handling.async function resolveAuthToken( includeAuthToken?: boolean ): Promise<string | undefined | { error: string }> { if (includeAuthToken !== true) return undefined; const projectName = getActiveProjectName() || "default-project"; // 1) Use cached token if valid const cached = getCachedToken(projectName); if (cached) return cached; // 2) Mandatory dynamic retrieval via extension (no fallback) const storageType = getConfigValue("AUTH_STORAGE_TYPE"); const tokenKey = getConfigValue("AUTH_TOKEN_KEY"); if (!storageType || !tokenKey) { return { error: "Auth token retrieval not configured. Set AUTH_STORAGE_TYPE, AUTH_TOKEN_KEY, and optional AUTH_ORIGIN in projects.json.", }; } const token = await retrieveTokenViaExtension(); if (!token) { return { error: "Failed to retrieve auth token from configured browser storage. Ensure the target app is open and DevTools extension connected.", }; } const ttlSecondsRaw = getConfigValue("API_AUTH_TOKEN_TTL_SECONDS"); let expiresAtMs: number | undefined; if (ttlSecondsRaw && !isNaN(Number(ttlSecondsRaw))) { expiresAtMs = Date.now() + Number(ttlSecondsRaw) * 1000; } else { expiresAtMs = decodeJwtExpirationMs(token) || Date.now() + 5 * 60 * 1000; } authTokenCacheByProject[projectName] = { token, expiresAtMs }; return token; }