Skip to main content
Glama

Git MCP Server

fetchWithTimeout.ts3.85 kB
/** * @fileoverview Provides a utility function to make fetch requests with a specified timeout. * @module src/utils/network/fetchWithTimeout */ // Adjusted import path import { JsonRpcErrorCode, McpError } from '@/types-global/errors.js'; import { logger } from '@/utils/internal/logger.js'; // Adjusted import path import type { RequestContext } from '@/utils/internal/requestContext.js'; /** * Options for the fetchWithTimeout utility. * Extends standard RequestInit but omits 'signal' as it's handled internally. */ export type FetchWithTimeoutOptions = Omit<RequestInit, 'signal'>; /** * Fetches a resource with a specified timeout. * * @param url - The URL to fetch. * @param timeoutMs - The timeout duration in milliseconds. * @param context - The request context for logging. * @param options - Optional fetch options (RequestInit), excluding 'signal'. * @returns A promise that resolves to the Response object. * @throws {McpError} If the request times out or another fetch-related error occurs. */ export async function fetchWithTimeout( url: string | URL, timeoutMs: number, context: RequestContext, options?: FetchWithTimeoutOptions, ): Promise<Response> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); const urlString = url.toString(); const operationDescription = `fetch ${options?.method || 'GET'} ${urlString}`; logger.debug( `Attempting ${operationDescription} with ${timeoutMs}ms timeout.`, context, ); try { const response = await fetch(url, { ...options, signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { const errorBody = await response .text() .catch(() => 'Could not read response body'); logger.error( `Fetch failed for ${urlString} with status ${response.status}.`, { ...context, statusCode: response.status, statusText: response.statusText, responseBody: errorBody, errorSource: 'FetchHttpError', }, ); throw new McpError( JsonRpcErrorCode.ServiceUnavailable, `Fetch failed for ${urlString}. Status: ${response.status}`, { ...context, statusCode: response.status, statusText: response.statusText, responseBody: errorBody, }, ); } logger.debug( `Successfully fetched ${urlString}. Status: ${response.status}`, context, ); return response; } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === 'AbortError') { logger.error(`${operationDescription} timed out after ${timeoutMs}ms.`, { ...context, errorSource: 'FetchTimeout', }); throw new McpError( JsonRpcErrorCode.Timeout, `${operationDescription} timed out.`, { ...context, errorSource: 'FetchTimeout' }, ); } // Log and re-throw other errors as McpError const errorMessage = error instanceof Error ? error.message : String(error); logger.error( `Network error during ${operationDescription}: ${errorMessage}`, { ...context, originalErrorName: error instanceof Error ? error.name : 'UnknownError', errorSource: 'FetchNetworkError', }, ); if (error instanceof McpError) { // If it's already an McpError, re-throw it throw error; } throw new McpError( JsonRpcErrorCode.ServiceUnavailable, // Generic error for network/service issues `Network error during ${operationDescription}: ${errorMessage}`, { ...context, originalErrorName: error instanceof Error ? error.name : 'UnknownError', errorSource: 'FetchNetworkErrorWrapper', }, ); } }

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/cyanheads/git-mcp-server'

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