Skip to main content
Glama
Atomic-Germ

MCP Ollama Consult Server

mcpToolRegistrar.ts5.98 kB
import { registerTool } from './invoke'; import { listTools, callToolHandler } from './legacy-handlers'; import * as logger from './logger'; import { getAllowedTools } from './config'; function minimalForSchema(propSchema: any): any { if (!propSchema) return 'test'; const t = propSchema.type; if (!t) return 'test'; if (Array.isArray(t)) { if (t.includes('string')) return 'test'; if (t.includes('object')) return {}; return null; } switch (t) { case 'string': return 'test'; case 'number': return 0; case 'boolean': return true; case 'array': return []; case 'object': return {}; default: return 'test'; } } function mapArgsFromSchema(name: string, schema: any, invokeArgs: any): any { const props = (schema && schema.properties) || {}; const callArgs: any = {}; for (const propName of Object.keys(props)) { // Prefer explicit arg if provided if (invokeArgs && Object.prototype.hasOwnProperty.call(invokeArgs, propName)) { callArgs[propName] = invokeArgs[propName]; continue; } // Common mappings if (['prompt', 'text', 'message', 'query'].includes(propName)) { if (invokeArgs && invokeArgs.prompt) callArgs[propName] = invokeArgs.prompt; continue; } if (['response', 'value', 'content'].includes(propName)) { if (invokeArgs && invokeArgs.response) callArgs[propName] = invokeArgs.response; else if (invokeArgs && invokeArgs.result) callArgs[propName] = invokeArgs.result; else if (invokeArgs && invokeArgs.prompt) callArgs[propName] = invokeArgs.prompt; continue; } if (propName === 'resource') { callArgs.resource = invokeArgs && invokeArgs.resource ? invokeArgs.resource : { uri: `mcp-consult://runtime/${name}`, text: invokeArgs && invokeArgs.prompt ? invokeArgs.prompt : '', }; continue; } if (propName === 'key') { callArgs.key = invokeArgs && invokeArgs.key ? invokeArgs.key : invokeArgs && invokeArgs.prompt ? invokeArgs.prompt : undefined; continue; } // fallback: check memory or variables if ( invokeArgs && invokeArgs.memory && Object.prototype.hasOwnProperty.call(invokeArgs.memory, propName) ) { callArgs[propName] = invokeArgs.memory[propName]; continue; } // last resort: default sample based on schema callArgs[propName] = minimalForSchema(props[propName]); } return callArgs; } /** * Register MCP tools exposed by local handlers into the runtime tool registry. * If `healthCheck` is true, attempts a minimal invocation of each tool using required schema keys. */ export async function registerMcpTools( healthCheck = false, allowedTools?: string[] ): Promise<string[]> { const res = listTools(); const tools = res.tools || []; const names: string[] = []; const registered = new Set<string>(); // Determine allowed tools: function argument takes precedence, then env/file config let allowedSet: Set<string> | undefined; if (Array.isArray(allowedTools) && allowedTools.length > 0) { allowedSet = new Set(allowedTools.map((s) => String(s))); } else { const cfg = getAllowedTools(); if (Array.isArray(cfg) && cfg.length > 0) allowedSet = new Set(cfg.map((s) => String(s))); } for (const t of tools) { const name = t.name; if (!name || typeof name !== 'string') { logger.warn('Skipping tool with invalid name', name); continue; } // If a server-side whitelist is configured, only register allowed tools if (allowedSet && !allowedSet.has(name)) { logger.warn(`Skipping tool not in allowed list: ${name}`); continue; } if (registered.has(name)) { logger.warn('Duplicate tool registration skipped:', name); continue; } const inputSchema = t.inputSchema || {}; // Basic descriptor validation try { if (inputSchema && typeof inputSchema === 'object') { // ok } else if (inputSchema && inputSchema !== undefined) { logger.warn(`Tool ${name} has non-object inputSchema; skipping`); continue; } // Register safe wrapper registerTool(name, async (args: any) => { try { const callArgs = mapArgsFromSchema(name, inputSchema, args || {}); const resp = await callToolHandler({ name, arguments: callArgs }); return resp; } catch (_e) { const e = _e; logger.error( `Tool invocation failed: ${name}`, e instanceof Error ? e.message : String(e) ); // Standardized error object return { isError: true, error: e instanceof Error ? e.message : String(e) }; } }); names.push(name); registered.add(name); logger.info(`Registered tool: ${name}`); logger.info(`Processing tool: ${name}`); if (healthCheck) { try { const required: string[] = (inputSchema && inputSchema.required) || []; const sampleArgs: any = {}; for (const r of required) { const propSchema = ((inputSchema.properties || {}) as any)[r]; sampleArgs[r] = minimalForSchema(propSchema); } // Try call with sample args; ignore result but log errors await callToolHandler({ name, arguments: sampleArgs }).catch((e) => { logger.warn(`Health check failed for ${name}: ${(e as Error).message}`); }); } catch (_e) { const e = _e; logger.warn(`Health check exception for ${name}: ${(e as Error).message}`); } } } catch (_e) { const e = _e; logger.error(`Failed to register tool ${name}:`, e instanceof Error ? e.message : String(e)); continue; } } return names; } export default { registerMcpTools };

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/Atomic-Germ/mcp-consult'

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