Skip to main content
Glama

OpenAPI MCP Server

by aaker
http-client.js10.9 kB
import axios from 'axios'; export class HttpClient { constructor(baseURL = '', bearerToken = null, timeout = 30000) { console.error(`[HTTP CLIENT] === INITIALIZING HTTP CLIENT ===`); console.error(`[HTTP CLIENT] Base URL: ${baseURL || 'NONE'}`); console.error(`[HTTP CLIENT] Bearer Token: ${bearerToken ? 'PROVIDED' : 'NONE'}`); console.error(`[HTTP CLIENT] Timeout: ${timeout}ms`); this.baseURL = baseURL; this.bearerToken = bearerToken; this.timeout = timeout; this.client = axios.create({ baseURL: this.baseURL, timeout: this.timeout, headers: { 'Content-Type': 'application/json', 'User-Agent': 'netsapiens-mcp/1.0.0' } }); // Add request interceptor for authentication and logging this.client.interceptors.request.use( (config) => { // Log every outgoing request console.error(`[HTTP INTERCEPT] === OUTGOING REQUEST ===`); console.error(`[HTTP INTERCEPT] ${config.method?.toUpperCase()} ${config.baseURL}${config.url}`); console.error(`[HTTP INTERCEPT] Headers:`, JSON.stringify(config.headers, null, 2)); console.error(`[HTTP INTERCEPT] Query Params:`, config.params); console.error(`[HTTP INTERCEPT] Request Body:`, config.data); console.error(`[HTTP INTERCEPT] Timeout:`, config.timeout); if (this.bearerToken) { config.headers.Authorization = `Bearer ${this.bearerToken}`; console.error(`[HTTP INTERCEPT] Bearer token added to Authorization header`); } else { console.error(`[HTTP INTERCEPT] No bearer token available`); } console.error(`[HTTP INTERCEPT] Final headers:`, JSON.stringify(config.headers, null, 2)); return config; }, (error) => { console.error(`[HTTP INTERCEPT] Request interceptor error:`, error.message); return Promise.reject(error); } ); // Add response interceptor for logging and error handling this.client.interceptors.response.use( (response) => { // Log every incoming response console.error(`[HTTP INTERCEPT] === INCOMING RESPONSE ===`); console.error(`[HTTP INTERCEPT] Status: ${response.status} ${response.statusText}`); console.error(`[HTTP INTERCEPT] URL: ${response.config.url}`); console.error(`[HTTP INTERCEPT] Response Headers:`, JSON.stringify(response.headers, null, 2)); console.error(`[HTTP INTERCEPT] Response Data Type:`, typeof response.data); console.error(`[HTTP INTERCEPT] Response Data Length:`, Array.isArray(response.data) ? response.data.length : 'N/A'); console.error(`[HTTP INTERCEPT] Response Data:`, JSON.stringify(response.data, null, 2)); return response; }, (error) => { // Log every error response console.error(`[HTTP INTERCEPT] === ERROR RESPONSE ===`); console.error(`[HTTP INTERCEPT] Error Message:`, error.message); console.error(`[HTTP INTERCEPT] Error Code:`, error.code); if (error.response) { console.error(`[HTTP INTERCEPT] Error Status: ${error.response.status} ${error.response.statusText}`); console.error(`[HTTP INTERCEPT] Error URL: ${error.response.config?.url}`); console.error(`[HTTP INTERCEPT] Error Headers:`, JSON.stringify(error.response.headers, null, 2)); console.error(`[HTTP INTERCEPT] Error Data:`, JSON.stringify(error.response.data, null, 2)); } else if (error.request) { console.error(`[HTTP INTERCEPT] No response received`); console.error(`[HTTP INTERCEPT] Request was:`, error.request); } return Promise.reject(this.processError(error)); } ); } async executeRequest(method, path, parameters = {}) { console.error(`[HTTP DEBUG] Starting HTTP request`); console.error(`[HTTP DEBUG] Method: ${method.toUpperCase()}`); console.error(`[HTTP DEBUG] Path: ${path}`); console.error(`[HTTP DEBUG] Parameters:`, JSON.stringify(parameters, null, 2)); console.error(`[HTTP DEBUG] Base URL: ${this.baseURL}`); console.error(`[HTTP DEBUG] Bearer Token: ${this.bearerToken ? 'PROVIDED' : 'NONE'}`); try { const requestConfig = this.buildRequestConfig(method, path, parameters); console.error(`[HTTP DEBUG] Final request config:`, { method: requestConfig.method, url: requestConfig.url, params: requestConfig.params, headers: Object.keys(requestConfig.headers || {}), hasData: !!requestConfig.data, dataType: requestConfig.data ? typeof requestConfig.data : 'none' }); console.error(`[HTTP DEBUG] Full URL: ${this.baseURL}${requestConfig.url}`); const response = await this.client.request(requestConfig); console.error(`[HTTP DEBUG] Response received:`, { status: response.status, statusText: response.statusText, hasData: !!response.data, dataType: response.data ? typeof response.data : 'none', dataLength: Array.isArray(response.data) ? response.data.length : 'N/A' }); return { success: true, status: response.status, statusText: response.statusText, headers: response.headers, data: response.data }; } catch (error) { console.error(`[HTTP DEBUG] Request failed:`, { message: error.message, status: error.response?.status, statusText: error.response?.statusText, url: error.config?.url, method: error.config?.method }); if (error.response?.data) { console.error(`[HTTP DEBUG] Error response data:`, error.response.data); } return { success: false, error: error.message, status: error.response?.status, statusText: error.response?.statusText, data: error.response?.data }; } } buildRequestConfig(method, path, parameters) { const config = { method: method.toLowerCase(), url: this.interpolatePath(path, parameters), headers: {} }; // Add query parameters const queryParams = this.extractQueryParameters(parameters); if (Object.keys(queryParams).length > 0) { config.params = queryParams; } // Add custom headers const customHeaders = this.extractHeaderParameters(parameters); if (Object.keys(customHeaders).length > 0) { config.headers = { ...config.headers, ...customHeaders }; } // Add request body for methods that support it if (this.methodSupportsBody(method)) { const requestBody = this.buildRequestBody(parameters); if (requestBody !== null) { config.data = requestBody; } } return config; } interpolatePath(path, parameters) { let interpolatedPath = path; // Replace path parameters like {id} with actual values const pathParams = path.match(/{([^}]+)}/g) || []; pathParams.forEach(param => { const paramName = param.slice(1, -1); // Remove { } const value = parameters[paramName]; if (value !== undefined) { interpolatedPath = interpolatedPath.replace(param, encodeURIComponent(value)); } else { throw new Error(`Missing required path parameter: ${paramName}`); } }); return interpolatedPath; } extractQueryParameters(parameters) { const queryParams = {}; // Extract non-path, non-header, non-body parameters as query params Object.entries(parameters).forEach(([key, value]) => { if (value !== undefined && !key.startsWith('header_') && !this.isBodyParameter(key) && !this.isPathParameter(key, parameters)) { queryParams[key] = value; } }); return queryParams; } extractHeaderParameters(parameters) { const headers = {}; Object.entries(parameters).forEach(([key, value]) => { if (key.startsWith('header_') && value !== undefined) { const headerName = key.substring(7); // Remove 'header_' prefix headers[headerName] = value; } }); return headers; } buildRequestBody(parameters) { // Check if there's a dedicated requestBody parameter if (parameters.requestBody !== undefined) { return parameters.requestBody; } // Build object from non-query, non-header, non-path parameters const bodyParams = {}; let hasBodyParams = false; Object.entries(parameters).forEach(([key, value]) => { if (value !== undefined && !key.startsWith('header_') && !this.isPathParameter(key, parameters) && this.isBodyParameter(key)) { bodyParams[key] = value; hasBodyParams = true; } }); return hasBodyParams ? bodyParams : null; } isBodyParameter(key) { // Body parameters are those that are not query, header, or path parameters // This is a heuristic - in practice, we'd determine this from the OpenAPI spec return !key.startsWith('header_') && key !== 'requestBody'; } isPathParameter(key, parameters) { // This is simplified - in practice, we'd get this info from the OpenAPI spec // For now, assume path parameters are single values that appear in curly braces return false; // We handle path params separately in interpolatePath } methodSupportsBody(method) { const methodsWithBody = ['post', 'put', 'patch']; return methodsWithBody.includes(method.toLowerCase()); } processError(error) { const processed = { message: error.message, status: null, statusText: null, data: null }; if (error.response) { // Server responded with error status processed.status = error.response.status; processed.statusText = error.response.statusText; processed.data = error.response.data; if (error.response.data) { if (typeof error.response.data === 'string') { processed.message = error.response.data; } else if (error.response.data.message) { processed.message = error.response.data.message; } else if (error.response.data.error) { processed.message = error.response.data.error; } } } else if (error.request) { // Request was made but no response received processed.message = 'No response received from server'; } else { // Something else happened processed.message = error.message || 'An unknown error occurred'; } return processed; } updateBearerToken(token) { this.bearerToken = token; } updateBaseURL(baseURL) { this.baseURL = baseURL; this.client.defaults.baseURL = baseURL; } setTimeout(timeout) { this.timeout = timeout; this.client.defaults.timeout = timeout; } }

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/aaker/mini-openapi-mcp'

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