Skip to main content
Glama
util.js3.6 kB
/** * Utility Handlers * * Consolidated handlers for: ping, date_time, calc, list_tools, search_tools */ const { normalize } = require('../../core/normalize'); const { Schemas, safeValidate } = require('../../core/schemas'); const config = require('../../../config'); /** * Unified utility handler * * Routes to specific operation based on tool name or op parameter */ async function handleUtil(tool, params, context = {}) { const normalized = normalize(tool, params); switch (tool) { case 'ping': return handlePing(normalized); case 'date_time': return handleDateTime(normalized); case 'calc': return handleCalc(normalized); case 'list_tools': case 'search_tools': return handleTools(tool, normalized, context); default: return { error: `Unknown utility tool: ${tool}` }; } } /** * Health check */ function handlePing(params = {}) { const result = { pong: true, timestamp: new Date().toISOString() }; if (params.info) { result.version = config.version || '1.8.0'; result.mode = config.mode || 'ALL'; result.uptime = process.uptime(); } return result; } /** * Get current date/time */ function handleDateTime(params = {}) { const format = params.format || 'iso'; const now = new Date(); switch (format) { case 'epoch': return { timestamp: now.getTime(), format: 'epoch' }; case 'rfc': return { timestamp: now.toUTCString(), format: 'rfc' }; case 'iso': default: return { timestamp: now.toISOString(), format: 'iso' }; } } /** * Safe math expression evaluator */ function handleCalc(params) { const { expr, precision = 6 } = params; if (!expr || typeof expr !== 'string') { throw new Error('expr parameter is required'); } // Validate expression contains only safe characters const safePattern = /^[\d\s+\-*/().^%]+$/; if (!safePattern.test(expr)) { throw new Error('Invalid characters in expression. Allowed: digits, +, -, *, /, (, ), ^, %, .'); } try { // Replace ^ with ** for exponentiation const jsExpr = expr.replace(/\^/g, '**'); // Use Function constructor for safe evaluation (no access to global scope) const fn = new Function(`return (${jsExpr})`); const result = fn(); if (typeof result !== 'number' || !isFinite(result)) { throw new Error('Expression did not evaluate to a finite number'); } return { expression: expr, result: Number(result.toFixed(precision)), precision }; } catch (error) { throw new Error(`Calculation error: ${error.message}`); } } /** * List or search tools */ async function handleTools(tool, params, context = {}) { const { query, limit = 50, semantic = true } = params; const { toolRegistry } = context; // If no registry provided, return basic info if (!toolRegistry) { return { message: 'Tool registry not available in this context', hint: 'Use list_tools from MCP client to get full tool list' }; } // Filter tools if query provided let tools = Array.from(toolRegistry.values()); if (query) { const q = query.toLowerCase(); tools = tools.filter(t => t.name.toLowerCase().includes(q) || (t.description && t.description.toLowerCase().includes(q)) ); } // Limit results tools = tools.slice(0, limit); return { count: tools.length, tools: tools.map(t => ({ name: t.name, description: t.description || '' })) }; } module.exports = { handleUtil, handlePing, handleDateTime, handleCalc, handleTools };

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/wheattoast11/openrouter-deep-research-mcp'

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