Skip to main content
Glama

Node.js MCP Server

by WeiWeicode
calculatorTools.js9.35 kB
class CalculatorTools { getToolDefinitions() { return [ { name: 'calculate', description: '執行數學計算(支持基本四則運算和函數)', inputSchema: { type: 'object', properties: { expression: { type: 'string', description: '要計算的數學表達式,例如:2 + 3 * 4, sqrt(16), sin(30)', }, }, required: ['expression'], }, }, { name: 'convert_units', description: '單位轉換(長度、重量、溫度等)', inputSchema: { type: 'object', properties: { value: { type: 'number', description: '要轉換的數值', }, from_unit: { type: 'string', description: '原始單位(如:meter, kilogram, celsius)', }, to_unit: { type: 'string', description: '目標單位(如:foot, pound, fahrenheit)', }, }, required: ['value', 'from_unit', 'to_unit'], }, }, { name: 'statistics', description: '計算數組的統計信息(平均值、中位數、標準差等)', inputSchema: { type: 'object', properties: { numbers: { type: 'array', items: { type: 'number' }, description: '數字數組', }, }, required: ['numbers'], }, }, ]; } hasToolName(name) { return this.getToolDefinitions().some(tool => tool.name === name); } async handleToolCall(name, args) { switch (name) { case 'calculate': return await this.calculate(args.expression); case 'convert_units': return await this.convertUnits(args.value, args.from_unit, args.to_unit); case 'statistics': return await this.calculateStatistics(args.numbers); default: throw new Error(`Unknown calculator tool: ${name}`); } } async calculate(expression) { try { // 安全的數學表達式求值 const result = this.safeEval(expression); return { content: [ { type: 'text', text: `計算結果: ${expression} = ${result}`, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `計算錯誤: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } safeEval(expression) { // 移除空格 expression = expression.replace(/\s+/g, ''); // 只允許數字、基本運算符和數學函數 const allowedPattern = /^[0-9+\-*/().,\s]+$|sqrt|sin|cos|tan|log|exp|pow|abs|floor|ceil|round/; // 替換數學函數 expression = expression .replace(/sqrt\(([^)]+)\)/g, 'Math.sqrt($1)') .replace(/sin\(([^)]+)\)/g, 'Math.sin($1 * Math.PI / 180)') .replace(/cos\(([^)]+)\)/g, 'Math.cos($1 * Math.PI / 180)') .replace(/tan\(([^)]+)\)/g, 'Math.tan($1 * Math.PI / 180)') .replace(/log\(([^)]+)\)/g, 'Math.log($1)') .replace(/exp\(([^)]+)\)/g, 'Math.exp($1)') .replace(/pow\(([^,]+),([^)]+)\)/g, 'Math.pow($1,$2)') .replace(/abs\(([^)]+)\)/g, 'Math.abs($1)') .replace(/floor\(([^)]+)\)/g, 'Math.floor($1)') .replace(/ceil\(([^)]+)\)/g, 'Math.ceil($1)') .replace(/round\(([^)]+)\)/g, 'Math.round($1)'); // 檢查是否包含不安全的內容 if (expression.includes('eval') || expression.includes('function') || expression.includes('while') || expression.includes('for')) { throw new Error('不安全的表達式'); } try { return Function('"use strict"; return (' + expression + ')')(); } catch (error) { throw new Error('無效的數學表達式'); } } async convertUnits(value, fromUnit, toUnit) { try { const result = this.performUnitConversion(value, fromUnit.toLowerCase(), toUnit.toLowerCase()); return { content: [ { type: 'text', text: `單位轉換: ${value} ${fromUnit} = ${result} ${toUnit}`, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `單位轉換錯誤: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } performUnitConversion(value, fromUnit, toUnit) { // 長度轉換 const lengthConversions = { meter: 1, m: 1, kilometer: 1000, km: 1000, centimeter: 0.01, cm: 0.01, millimeter: 0.001, mm: 0.001, inch: 0.0254, foot: 0.3048, ft: 0.3048, yard: 0.9144, mile: 1609.34, }; // 重量轉換 const weightConversions = { kilogram: 1, kg: 1, gram: 0.001, g: 0.001, pound: 0.453592, lb: 0.453592, ounce: 0.0283495, oz: 0.0283495, ton: 1000, }; // 溫度轉換(需要特殊處理) if (fromUnit === 'celsius' && toUnit === 'fahrenheit') { return (value * 9 / 5) + 32; } if (fromUnit === 'fahrenheit' && toUnit === 'celsius') { return (value - 32) * 5 / 9; } if (fromUnit === 'celsius' && toUnit === 'kelvin') { return value + 273.15; } if (fromUnit === 'kelvin' && toUnit === 'celsius') { return value - 273.15; } // 檢查長度轉換 if (lengthConversions[fromUnit] && lengthConversions[toUnit]) { return (value * lengthConversions[fromUnit]) / lengthConversions[toUnit]; } // 檢查重量轉換 if (weightConversions[fromUnit] && weightConversions[toUnit]) { return (value * weightConversions[fromUnit]) / weightConversions[toUnit]; } throw new Error(`不支持的單位轉換: ${fromUnit} 到 ${toUnit}`); } async calculateStatistics(numbers) { try { if (!Array.isArray(numbers) || numbers.length === 0) { throw new Error('請提供有效的數字數組'); } const sorted = [...numbers].sort((a, b) => a - b); const sum = numbers.reduce((acc, num) => acc + num, 0); const mean = sum / numbers.length; const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)]; const variance = numbers.reduce((acc, num) => acc + Math.pow(num - mean, 2), 0) / numbers.length; const standardDeviation = Math.sqrt(variance); const min = Math.min(...numbers); const max = Math.max(...numbers); const result = { 數量: numbers.length, 總和: sum, 平均值: parseFloat(mean.toFixed(4)), 中位數: parseFloat(median.toFixed(4)), 最小值: min, 最大值: max, 方差: parseFloat(variance.toFixed(4)), 標準差: parseFloat(standardDeviation.toFixed(4)), }; return { content: [ { type: 'text', text: `統計結果:\n${JSON.stringify(result, null, 2)}`, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `統計計算錯誤: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } } export const calculatorTools = new CalculatorTools();

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/WeiWeicode/20250923MCPtest'

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