Skip to main content
Glama

OpenAI MCP Server

by bhjo0930
openai-client.ts6.65 kB
import OpenAI from 'openai'; import { config } from './config.js'; export interface OpenAIRequest { prompt: string; systemPrompt?: string; temperature?: number; maxTokens?: number; model?: string; reasoningEffort?: 'minimal' | 'low' | 'medium' | 'high'; verbosity?: 'low' | 'medium' | 'high'; } export interface OpenAIResponse { content: string; reasoning?: string; usage?: { promptTokens: number; completionTokens: number; totalTokens: number; reasoningTokens?: number; }; model: string; finishReason?: string; } export class OpenAIClient { private client: OpenAI; constructor() { this.client = new OpenAI({ apiKey: config.openai.apiKey, baseURL: config.openai.baseURL }); } async chat(request: OpenAIRequest): Promise<OpenAIResponse> { try { const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = []; if (request.systemPrompt) { messages.push({ role: 'system', content: request.systemPrompt }); } messages.push({ role: 'user', content: request.prompt }); const model = request.model || config.openai.model; const completionParams: any = { model, messages }; // Use appropriate parameters based on model if (model === 'gpt-5' || model.startsWith('gpt-5')) { completionParams.max_completion_tokens = request.maxTokens || 2000; // GPT-5 new parameters if (request.reasoningEffort) { completionParams.reasoning_effort = request.reasoningEffort; } else { completionParams.reasoning_effort = 'medium'; // Default for GPT-5 } if (request.verbosity) { completionParams.verbosity = request.verbosity; } // GPT-5 supports temperature but defaults to 1 if (request.temperature !== undefined) { completionParams.temperature = request.temperature; } } else { completionParams.max_tokens = request.maxTokens || 2000; completionParams.temperature = request.temperature || 0.7; } const response = await this.client.chat.completions.create(completionParams); const choice = response.choices[0]; if (!choice?.message) { throw new Error('No message in response from OpenAI'); } // Handle GPT-5 reasoning and content let content = choice.message.content || ''; let reasoning = ''; // Extract reasoning tokens count const reasoningTokens = response.usage?.completion_tokens_details?.reasoning_tokens || 0; // For GPT-5, if content is empty but reasoning tokens exist, fallback to GPT-4o if (!content && reasoningTokens > 0) { if (config.server.debug) { console.error('GPT-5 Reasoning Mode Detected - Falling back to GPT-4o:', { reasoningTokens, totalTokens: response.usage?.total_tokens, hasContent: false }); } // Automatic fallback to GPT-4o for actual content try { const fallbackParams = { ...completionParams, model: 'gpt-4o' }; // Remove GPT-5 specific parameters for GPT-4o delete fallbackParams.reasoning_effort; delete fallbackParams.verbosity; delete fallbackParams.max_completion_tokens; fallbackParams.max_tokens = request.maxTokens || 2000; fallbackParams.temperature = request.temperature || 0.7; const fallbackResponse = await this.client.chat.completions.create(fallbackParams); const fallbackContent = fallbackResponse.choices[0]?.message?.content || ''; if (fallbackContent) { content = `[GPT-5 reasoning: ${reasoningTokens} tokens] ${fallbackContent}`; // Update usage to include both models if (response.usage && fallbackResponse.usage) { response.usage.total_tokens += fallbackResponse.usage.total_tokens; response.usage.completion_tokens += fallbackResponse.usage.completion_tokens; } } else { content = `[GPT-5 used ${reasoningTokens} reasoning tokens but produced no content. GPT-4o fallback also failed.]`; } } catch (fallbackError) { content = `[GPT-5 used ${reasoningTokens} reasoning tokens but content unavailable. GPT-4o fallback error: ${fallbackError instanceof Error ? fallbackError.message : 'Unknown error'}]`; } } // Debug logging for development if (config.server.debug) { console.error('GPT-5 Response Analysis:', { hasContent: !!choice.message.content, contentLength: choice.message.content?.length || 0, reasoningTokens, finishReason: choice.finish_reason, model: response.model }); } return { content: content, reasoning: reasoning || undefined, usage: response.usage ? { promptTokens: response.usage.prompt_tokens, completionTokens: response.usage.completion_tokens, totalTokens: response.usage.total_tokens, reasoningTokens: reasoningTokens } : undefined, model: response.model, finishReason: choice.finish_reason || undefined }; } catch (error) { if (config.server.debug) { console.error('OpenAI API Error:', error); } if (error instanceof Error) { throw new Error(`OpenAI API Error: ${error.message}`); } throw new Error('Unknown OpenAI API Error'); } } async listModels(): Promise<any[]> { try { const response = await this.client.models.list(); return response.data; } catch (error) { if (config.server.debug) { console.error('List models error:', error); } throw new Error(`Failed to list models: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async testConnection(): Promise<boolean> { try { const response = await this.chat({ prompt: 'Test connection - respond with "OK"', systemPrompt: 'You are a test assistant. Respond only with "OK".', maxTokens: 10 }); if (config.server.debug) { console.error('Connection test successful:', response.content); } return true; } catch (error) { console.error('OpenAI connection test failed:', error); return false; } } }

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/bhjo0930/openai_mcp'

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