Skip to main content
Glama
core.ts3.01 kB
import type { ServiceError, InternalError } from "./services/base.js"; import { debugHttp } from "./debug.js"; export interface HttpOptions extends globalThis.RequestInit { timeoutMs?: number; } export async function fetchJson<T>( url: string, options: HttpOptions = {}, ): Promise<T> { const { timeoutMs = 5000, ...fetchOptions } = options; const method = fetchOptions.method || "GET"; const startTime = Date.now(); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); try { const response = await fetch(url, { ...fetchOptions, signal: controller.signal, headers: { Accept: "application/json", ...fetchOptions.headers, }, }); const elapsed = Date.now() - startTime; debugHttp(method, url, response.status, elapsed); clearTimeout(timeoutId); if (!response.ok) { let errorMessage = `HTTP ${response.status}`; let errorCode: string | undefined; let rawError: unknown; try { const errorBody = await response.json(); if (errorBody.message) errorMessage = errorBody.message; if (errorBody.code) errorCode = errorBody.code; rawError = errorBody; } catch { // Ignore JSON parsing errors for error responses } throw { service: "unknown", status: response.status, code: errorCode, message: errorMessage, raw: rawError, } as ServiceError; } return await response.json(); } catch (error) { const elapsed = Date.now() - startTime; debugHttp(method, url, undefined, elapsed); clearTimeout(timeoutId); if (error && typeof error === "object" && "service" in error) { throw error; // Re-throw ServiceError } if (error instanceof Error && error.name === "AbortError") { throw { service: "unknown", status: 0, message: `Request timeout after ${timeoutMs}ms`, } as ServiceError; } throw { kind: "internal", message: error instanceof Error ? error.message : "Unknown error", cause: error, } as InternalError; } } export function createServiceError( service: string, status: number, message: string, code?: string, ): ServiceError { return { service, status, message, code }; } export function createInternalError( message: string, cause?: unknown, ): InternalError { return { kind: "internal", message, cause }; } export function handleError( error: unknown, serviceName: string, ): { ok: false; error: ServiceError | InternalError } { if (error && typeof error === "object") { if ("service" in error || "kind" in error) { return { ok: false, error: error as ServiceError | InternalError }; } } return { ok: false, error: createInternalError(`Unexpected error in ${serviceName}`, error), }; } export function buildUrl( baseUrl: string, path: string, params: Record<string, string | number> = {}, ): string { const url = new URL(path, baseUrl); for (const [key, value] of Object.entries(params)) { url.searchParams.set(key, String(value)); } return url.toString(); }

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/thesammykins/FlixBridge'

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