Skip to main content
Glama

fetch

Execute HTTP requests with customizable methods, headers, body, and options to retrieve or send data to web resources.

Instructions

Perform HTTP requests with full control over method, headers, body, and other fetch options

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesThe URL to fetch from
methodNoThe HTTP method to use. Defaults to GETGET
headersNoHTTP headers to include in the request as key-value pairs
bodyNoThe request body. Can be a string, JSON, or form data
modeNoThe mode for the request (cors, no-cors, or same-origin)
credentialsNoWhether to include credentials with the request
cacheNoThe cache mode for the request
redirectNoHow to handle redirects. Defaults to followfollow
referrerNoThe referrer to send with the request
referrerPolicyNoThe referrer policy for the request
signalNoAn AbortSignal to abort the request
timeoutNoRequest timeout in milliseconds
followRedirectsNoWhether to follow redirects. Defaults to true

Implementation Reference

  • Main handler function for the 'fetch' tool. Performs HTTP requests using globalThis.fetch, validates inputs, handles timeouts, body content types, parses responses (JSON/text/binary), and returns structured results or errors.
    export default async function fetch(params: InferSchema<typeof schema>) { try { const { url, method, headers, body, timeout, followRedirects, signal, ...fetchOptions } = params // Validate URL if (!url || url.trim() === '') { throw new TypeError('Invalid URL: URL cannot be empty'); } try { new URL(url); } catch { throw new TypeError('Invalid URL: Not a valid URL format'); } // Build fetch options const options: RequestInit = { method, headers: headers || {}, ...fetchOptions, } // Handle followRedirects parameter if (followRedirects === false) { options.redirect = 'manual'; } // Add body if provided and method supports it if (body && ["POST", "PUT", "PATCH", "DELETE"].includes(method)) { options.body = body // Ensure headers is a proper object for type safety const requestHeaders = options.headers as Record<string, string> // Auto-detect content type if not provided if (!requestHeaders["Content-Type"] && !requestHeaders["content-type"]) { try { JSON.parse(body) requestHeaders["Content-Type"] = "application/json" } catch { // If not JSON, assume plain text requestHeaders["Content-Type"] = "text/plain" } } } // Create abort controller for timeout let abortController: AbortController | undefined let timeoutId: NodeJS.Timeout | undefined if (timeout) { abortController = new AbortController() options.signal = abortController.signal timeoutId = setTimeout(() => { abortController?.abort() }, timeout) } // Perform the fetch const startTime = Date.now() const response = await globalThis.fetch(url, options) const responseTime = Date.now() - startTime // Clear timeout if set if (timeoutId) { clearTimeout(timeoutId) } // Get response headers const responseHeaders: Record<string, string> = {} response.headers.forEach((value, key) => { responseHeaders[key] = value }) // Determine response content type const contentType = response.headers.get("content-type") || "" let responseBody: any try { if (contentType.includes("application/json")) { responseBody = await response.json() } else if (contentType.includes("text/") || contentType.includes("application/xml")) { responseBody = await response.text() } else { // For binary data, convert to base64 const buffer = await response.arrayBuffer() responseBody = { type: "binary", size: buffer.byteLength, base64: Buffer.from(buffer).toString("base64") } } } catch (error) { responseBody = { error: "Failed to parse response body", message: error instanceof Error ? error.message : "Unknown error" } } return JSON.stringify({ success: true, status: response.status, statusText: response.statusText, headers: responseHeaders, body: responseBody, url: response.url, redirected: response.redirected, responseTime: `${responseTime}ms`, request: { method, url: params.url, headers: headers || {} } }, null, 2) } catch (error) { // Handle different error types let errorMessage = "Unknown error occurred" let errorType = "UnknownError" if (error instanceof Error) { errorMessage = error.message if (error.name === "AbortError") { errorType = "TimeoutError" errorMessage = `Request timed out after ${params.timeout}ms` } else if (error.message.includes("Failed to fetch") || error.message.includes("ECONNREFUSED") || error.message.includes("ENOTFOUND")) { errorType = "NetworkError" errorMessage = "Network error - could not connect to the server" } else if (error.message.includes("Invalid URL") || error.message.includes("invalid URL")) { errorType = "InvalidURLError" } else if (error instanceof TypeError && (error.message.includes("fetch") || error.message.includes("URL"))) { errorType = "InvalidURLError" } } return JSON.stringify({ success: false, error: errorMessage, errorType, request: { method: params.method, url: params.url, headers: params.headers || {} } }, null, 2) } }
  • Input schema for the fetch tool using Zod, defining parameters like url, method, headers, body, and various fetch options.
    export const schema = { url: z.string().describe("The URL to fetch from"), method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]) .optional() .default("GET") .describe("The HTTP method to use. Defaults to GET"), headers: z.record(z.string()) .optional() .describe("HTTP headers to include in the request as key-value pairs"), body: z.string() .optional() .describe("The request body. Can be a string, JSON, or form data"), mode: z.enum(["cors", "no-cors", "same-origin"]) .optional() .describe("The mode for the request (cors, no-cors, or same-origin)"), credentials: z.enum(["omit", "same-origin", "include"]) .optional() .describe("Whether to include credentials with the request"), cache: z.enum(["default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached"]) .optional() .describe("The cache mode for the request"), redirect: z.enum(["follow", "error", "manual"]) .optional() .default("follow") .describe("How to handle redirects. Defaults to follow"), referrer: z.string() .optional() .describe("The referrer to send with the request"), referrerPolicy: z.enum([ "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url" ]) .optional() .describe("The referrer policy for the request"), signal: z.any() .optional() .describe("An AbortSignal to abort the request"), timeout: z.number() .optional() .describe("Request timeout in milliseconds"), followRedirects: z.boolean() .optional() .default(true) .describe("Whether to follow redirects. Defaults to true"), }
  • Tool metadata registration defining the name 'fetch', description, and annotations for the MCP tool.
    export const metadata: ToolMetadata = { name: "fetch", description: "Perform HTTP requests with full control over method, headers, body, and other fetch options", annotations: { title: "HTTP Fetch", readOnlyHint: false, destructiveHint: false, idempotentHint: false, }, }

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/matiasngf/mcp-fetch'

If you have feedback or need assistance with the MCP directory API, please join our Discord server