Skip to main content
Glama

OpenRouter MCP Multimodal Server

by hoangdn3
chat-completion.js6.02 kB
// Maximum context tokens const MAX_CONTEXT_TOKENS = 200000; // Utility function to estimate token count (simplified) function estimateTokenCount(text) { // Rough approximation: 4 characters per token return Math.ceil(text.length / 4); } // Truncate messages to fit within the context window function truncateMessagesToFit(messages, maxTokens) { const truncated = []; let currentTokenCount = 0; // Always include system message first if present if (messages[0]?.role === 'system') { truncated.push(messages[0]); currentTokenCount += estimateTokenCount(messages[0].content); } // Add messages from the end, respecting the token limit for (let i = messages.length - 1; i >= 0; i--) { const message = messages[i]; // Skip if it's the system message we've already added if (i === 0 && message.role === 'system') continue; // For string content, estimate tokens directly if (typeof message.content === 'string') { const messageTokens = estimateTokenCount(message.content); if (currentTokenCount + messageTokens > maxTokens) break; truncated.unshift(message); currentTokenCount += messageTokens; } // For multimodal content (array), estimate tokens for text content else if (Array.isArray(message.content)) { let messageTokens = 0; for (const part of message.content) { if (part.type === 'text' && part.text) { messageTokens += estimateTokenCount(part.text); } else if (part.type === 'image_url') { // Add a token cost estimate for images - this is a simplification // Actual image token costs depend on resolution and model messageTokens += 1000; } } if (currentTokenCount + messageTokens > maxTokens) break; truncated.unshift(message); currentTokenCount += messageTokens; } } return truncated; } // Find a suitable free model with the largest context window async function findSuitableFreeModel(openai) { try { // Query available models with 'free' in their name const modelsResponse = await openai.models.list(); if (!modelsResponse || !modelsResponse.data || modelsResponse.data.length === 0) { return 'deepseek/deepseek-chat-v3-0324:free'; // Fallback to a known model } // Filter models with 'free' in ID const freeModels = modelsResponse.data .filter(model => model.id.includes('free')) .map(model => { // Try to extract context length from the model object let contextLength = 0; try { const modelAny = model; // Cast to any to access non-standard properties if (typeof modelAny.context_length === 'number') { contextLength = modelAny.context_length; } else if (modelAny.context_window) { contextLength = parseInt(modelAny.context_window, 10); } } catch (e) { console.error(`Error parsing context length for model ${model.id}:`, e); } return { id: model.id, contextLength: contextLength || 0 }; }); if (freeModels.length === 0) { return 'deepseek/deepseek-chat-v3-0324:free'; // Fallback if no free models found } // Sort by context length and pick the one with the largest context window freeModels.sort((a, b) => b.contextLength - a.contextLength); console.error(`Selected free model: ${freeModels[0].id} with context length: ${freeModels[0].contextLength}`); return freeModels[0].id; } catch (error) { console.error('Error finding suitable free model:', error); return 'deepseek/deepseek-chat-v3-0324:free'; // Fallback to a known model } } export async function handleChatCompletion(request, openai, defaultModel) { const args = request.params.arguments; // Validate message array if (args.messages.length === 0) { return { content: [ { type: 'text', text: 'Messages array cannot be empty. At least one message is required.', }, ], isError: true, }; } try { // Select model with priority: // 1. User-specified model // 2. Default model from environment // 3. Free model with the largest context window (selected automatically) let model = args.model || defaultModel; if (!model) { model = await findSuitableFreeModel(openai); console.error(`Using auto-selected model: ${model}`); } // Truncate messages to fit within context window const truncatedMessages = truncateMessagesToFit(args.messages, MAX_CONTEXT_TOKENS); console.error(`Making API call with model: ${model}`); const completion = await openai.chat.completions.create({ model, messages: truncatedMessages, temperature: args.temperature ?? 1, }); return { content: [ { type: 'text', text: completion.choices[0].message.content || '', }, ], }; } catch (error) { if (error instanceof Error) { return { content: [ { type: 'text', text: `OpenRouter API error: ${error.message}`, }, ], isError: true, }; } throw error; } } //# sourceMappingURL=chat-completion.js.map

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/hoangdn3/mcp-ocr-fallback'

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