Skip to main content
Glama
response-formatter.ts.hbs7.97 kB
import { APIResponse, ErrorResponse, MCPToolResponse } from './types.js'; /** * Configuration options for response formatting */ export interface ResponseFormatterConfig { /** Include response headers in formatted output */ includeHeaders?: boolean; /** Pretty print JSON responses */ prettyPrintJson?: boolean; /** Maximum response length in characters */ maxResponseLength?: number; /** Include response metadata */ includeMetadata?: boolean; /** Enable debug logging */ debug?: boolean; } /** * Response formatter for {{server.name}} * Formats API responses and errors for MCP protocol */ export class ResponseFormatter { private config: Required<ResponseFormatterConfig>; constructor(config: ResponseFormatterConfig = {}) { this.config = { includeHeaders: config.includeHeaders ?? true, prettyPrintJson: config.prettyPrintJson ?? true, maxResponseLength: config.maxResponseLength ?? {{configuration.maxResponseLength}}, includeMetadata: config.includeMetadata ?? true, debug: config.debug ?? false, }; this.log('ResponseFormatter initialized', this.config); } /** * Format successful API response for MCP protocol */ formatResponse(response: APIResponse): MCPToolResponse { try { this.log('Formatting successful response', { status: response.status, hasData: !!response.data, dataType: typeof response.data, }); let formattedText = ''; // Add status information if (this.config.includeMetadata) { formattedText += `HTTP ${response.status} ${response.statusText}\n\n`; } // Add headers if requested if (this.config.includeHeaders && response.headers) { formattedText += 'Headers:\n'; Object.entries(response.headers).forEach(([key, value]) => { formattedText += ` ${key}: ${value}\n`; }); formattedText += '\n'; } // Add response body if (response.data !== undefined && response.data !== null) { formattedText += 'Response:\n'; if (typeof response.data === 'string') { formattedText += response.data; } else { // Format JSON data try { const jsonString = this.config.prettyPrintJson ? JSON.stringify(response.data, null, 2) : JSON.stringify(response.data); formattedText += jsonString; } catch (error) { formattedText += `[Error formatting JSON: ${error instanceof Error ? error.message : 'Unknown error'}]`; } } } else { formattedText += 'Response: (empty)'; } // Truncate if too long const truncatedText = this.truncateResponse(formattedText); this.log('Response formatted successfully', { originalLength: formattedText.length, truncatedLength: truncatedText.length, wasTruncated: formattedText.length !== truncatedText.length, }); return { content: [ { type: 'text', text: truncatedText, }, ], isError: false, }; } catch (error) { this.log('Error formatting response', error); // Fallback formatting return { content: [ { type: 'text', text: `Error formatting response: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } } /** * Format error response for MCP protocol */ formatErrorResponse(errorResponse: ErrorResponse): MCPToolResponse { try { this.log('Formatting error response', { errorType: errorResponse.error.type, hasDetails: !!errorResponse.error.details, }); let formattedText = ''; // Add error type and message formattedText += `Error (${errorResponse.error.type}): ${errorResponse.error.message}\n`; // Add status code if available if (errorResponse.error.statusCode) { formattedText += `Status Code: ${errorResponse.error.statusCode}\n`; } // Add error details if available and metadata is enabled if (this.config.includeMetadata && errorResponse.error.details) { formattedText += '\nDetails:\n'; try { const detailsString = this.config.prettyPrintJson ? JSON.stringify(errorResponse.error.details, null, 2) : JSON.stringify(errorResponse.error.details); formattedText += detailsString; } catch (error) { formattedText += `[Error formatting details: ${error instanceof Error ? error.message : 'Unknown error'}]`; } } // Truncate if too long const truncatedText = this.truncateResponse(formattedText); this.log('Error response formatted successfully', { originalLength: formattedText.length, truncatedLength: truncatedText.length, wasTruncated: formattedText.length !== truncatedText.length, }); return { content: [ { type: 'text', text: truncatedText, }, ], isError: true, }; } catch (error) { this.log('Error formatting error response', error); // Fallback error formatting return { content: [ { type: 'text', text: `Failed to format error response: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], isError: true, }; } } /** * Truncate response text if it exceeds maximum length */ private truncateResponse(text: string): string { if (text.length <= this.config.maxResponseLength) { return text; } const truncated = text.substring(0, this.config.maxResponseLength - 100); const lastNewline = truncated.lastIndexOf('\n'); // Try to truncate at a newline for better formatting const cutPoint = lastNewline > truncated.length - 200 ? lastNewline : truncated.length; return truncated.substring(0, cutPoint) + `\n\n[Response truncated - showing first ${cutPoint} of ${text.length} characters]`; } /** * Format response headers as a readable string */ private formatHeaders(headers: Record<string, string>): string { return Object.entries(headers) .map(([key, value]) => ` ${key}: ${value}`) .join('\n'); } /** * Detect if data is JSON and format accordingly */ private formatData(data: any): string { if (typeof data === 'string') { // Try to parse as JSON for pretty printing try { const parsed = JSON.parse(data); return this.config.prettyPrintJson ? JSON.stringify(parsed, null, 2) : data; } catch { // Not JSON, return as-is return data; } } // Object or other type - stringify try { return this.config.prettyPrintJson ? JSON.stringify(data, null, 2) : JSON.stringify(data); } catch (error) { return `[Error serializing data: ${error instanceof Error ? error.message : 'Unknown error'}]`; } } /** * Update formatter configuration */ updateConfig(config: Partial<ResponseFormatterConfig>): void { Object.assign(this.config, config); this.log('ResponseFormatter configuration updated', this.config); } /** * Get current configuration */ getConfig(): Required<ResponseFormatterConfig> { return { ...this.config }; } /** * Log messages with optional debug filtering */ private log(message: string, data?: any): void { if (this.config.debug) { const timestamp = new Date().toISOString(); if (data !== undefined) { console.error(`[${timestamp}] ResponseFormatter: ${message}`, data); } else { console.error(`[${timestamp}] ResponseFormatter: ${message}`); } } } }

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/fikri2992/mcp0'

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