#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
/**
* Math & Calculator MCP Server
* A Model Context Protocol server providing advanced mathematical utilities
*
* @author Jefferson Rosas Chambilla
* @repository https://github.com/Ankluna72/Math-Calculator-MCP-Server-
*/
// Define available tools
const TOOLS = [
{
name: "calculate",
description: "Perform basic arithmetic operations (add, subtract, multiply, divide, power, sqrt, modulo)",
inputSchema: {
type: "object",
properties: {
operation: {
type: "string",
enum: ["add", "subtract", "multiply", "divide", "power", "sqrt", "modulo"],
description: "The mathematical operation to perform"
},
a: {
type: "number",
description: "First number"
},
b: {
type: "number",
description: "Second number (not required for sqrt)"
}
},
required: ["operation", "a"]
}
},
{
name: "statistics",
description: "Calculate statistical measures (mean, median, mode, standard deviation, variance) from a list of numbers",
inputSchema: {
type: "object",
properties: {
numbers: {
type: "array",
items: { type: "number" },
description: "Array of numbers to analyze"
},
operation: {
type: "string",
enum: ["mean", "median", "mode", "stddev", "variance", "all"],
description: "Statistical operation to perform"
}
},
required: ["numbers", "operation"]
}
},
{
name: "convert_units",
description: "Convert between different units (length, weight, temperature)",
inputSchema: {
type: "object",
properties: {
value: {
type: "number",
description: "Value to convert"
},
from: {
type: "string",
description: "Source unit (e.g., 'meters', 'kilometers', 'celsius', 'fahrenheit', 'kg', 'pounds')"
},
to: {
type: "string",
description: "Target unit"
}
},
required: ["value", "from", "to"]
}
},
{
name: "solve_equation",
description: "Solve quadratic equations (ax² + bx + c = 0)",
inputSchema: {
type: "object",
properties: {
a: {
type: "number",
description: "Coefficient of x²"
},
b: {
type: "number",
description: "Coefficient of x"
},
c: {
type: "number",
description: "Constant term"
}
},
required: ["a", "b", "c"]
}
},
{
name: "percentage",
description: "Calculate percentages (percentage of a number, percentage increase/decrease, what percentage X is of Y)",
inputSchema: {
type: "object",
properties: {
operation: {
type: "string",
enum: ["of", "increase", "decrease", "what_percent"],
description: "Type of percentage calculation"
},
value1: {
type: "number",
description: "First value"
},
value2: {
type: "number",
description: "Second value"
}
},
required: ["operation", "value1", "value2"]
}
},
{
name: "trigonometry",
description: "Calculate trigonometric functions (sin, cos, tan, asin, acos, atan) in degrees",
inputSchema: {
type: "object",
properties: {
function: {
type: "string",
enum: ["sin", "cos", "tan", "asin", "acos", "atan"],
description: "Trigonometric function"
},
angle: {
type: "number",
description: "Angle in degrees"
}
},
required: ["function", "angle"]
}
}
];
// Calculator implementation
function calculate(operation: string, a: number, b?: number): number {
switch (operation) {
case "add": return a + (b || 0);
case "subtract": return a - (b || 0);
case "multiply": return a * (b || 1);
case "divide":
if (b === 0) throw new Error("Division by zero");
return a / (b || 1);
case "power": return Math.pow(a, b || 2);
case "sqrt": return Math.sqrt(a);
case "modulo": return a % (b || 1);
default: throw new Error("Unknown operation");
}
}
// Statistics implementation
function statistics(numbers: number[], operation: string): any {
const sorted = [...numbers].sort((a, b) => a - b);
const sum = numbers.reduce((acc, val) => acc + val, 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 frequency: Record<number, number> = {};
numbers.forEach(num => frequency[num] = (frequency[num] || 0) + 1);
const mode = Object.entries(frequency).reduce((a, b) => a[1] > b[1] ? a : b)[0];
const variance = numbers.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / numbers.length;
const stddev = Math.sqrt(variance);
const results: Record<string, any> = {
mean,
median,
mode: parseFloat(mode),
variance,
stddev
};
return operation === "all" ? results : { [operation]: results[operation] };
}
// Unit conversion implementation
function convertUnits(value: number, from: string, to: string): number {
const conversions: Record<string, Record<string, number>> = {
// Length (base: meters)
meters: { meters: 1, kilometers: 0.001, miles: 0.000621371, feet: 3.28084, inches: 39.3701 },
kilometers: { meters: 1000, kilometers: 1, miles: 0.621371, feet: 3280.84, inches: 39370.1 },
miles: { meters: 1609.34, kilometers: 1.60934, miles: 1, feet: 5280, inches: 63360 },
feet: { meters: 0.3048, kilometers: 0.0003048, miles: 0.000189394, feet: 1, inches: 12 },
inches: { meters: 0.0254, kilometers: 0.0000254, miles: 0.000015783, feet: 0.0833333, inches: 1 },
// Weight (base: kg)
kg: { kg: 1, grams: 1000, pounds: 2.20462, ounces: 35.274 },
grams: { kg: 0.001, grams: 1, pounds: 0.00220462, ounces: 0.035274 },
pounds: { kg: 0.453592, grams: 453.592, pounds: 1, ounces: 16 },
ounces: { kg: 0.0283495, grams: 28.3495, pounds: 0.0625, ounces: 1 }
};
// Temperature conversion
if (from === "celsius" && to === "fahrenheit") return (value * 9/5) + 32;
if (from === "fahrenheit" && to === "celsius") return (value - 32) * 5/9;
if (from === "celsius" && to === "kelvin") return value + 273.15;
if (from === "kelvin" && to === "celsius") return value - 273.15;
if (from === "fahrenheit" && to === "kelvin") return ((value - 32) * 5/9) + 273.15;
if (from === "kelvin" && to === "fahrenheit") return ((value - 273.15) * 9/5) + 32;
if (conversions[from] && conversions[from][to]) {
return value * conversions[from][to];
}
throw new Error(`Conversion from ${from} to ${to} not supported`);
}
// Quadratic equation solver
function solveQuadratic(a: number, b: number, c: number): any {
if (a === 0) throw new Error("Coefficient 'a' cannot be zero for quadratic equation");
const discriminant = b * b - 4 * a * c;
if (discriminant > 0) {
const x1 = (-b + Math.sqrt(discriminant)) / (2 * a);
const x2 = (-b - Math.sqrt(discriminant)) / (2 * a);
return { solutions: [x1, x2], type: "two real solutions" };
} else if (discriminant === 0) {
const x = -b / (2 * a);
return { solutions: [x], type: "one real solution" };
} else {
const realPart = -b / (2 * a);
const imagPart = Math.sqrt(-discriminant) / (2 * a);
return {
solutions: [`${realPart} + ${imagPart}i`, `${realPart} - ${imagPart}i`],
type: "two complex solutions"
};
}
}
// Percentage calculations
function calculatePercentage(operation: string, value1: number, value2: number): any {
switch (operation) {
case "of":
return { result: (value1 / 100) * value2, description: `${value1}% of ${value2}` };
case "increase":
return { result: value1 + (value1 * value2 / 100), description: `${value1} increased by ${value2}%` };
case "decrease":
return { result: value1 - (value1 * value2 / 100), description: `${value1} decreased by ${value2}%` };
case "what_percent":
return { result: (value1 / value2) * 100, description: `${value1} is ${((value1 / value2) * 100).toFixed(2)}% of ${value2}` };
default:
throw new Error("Unknown percentage operation");
}
}
// Trigonometry functions
function trigonometry(func: string, angle: number): number {
const radians = (angle * Math.PI) / 180;
switch (func) {
case "sin": return Math.sin(radians);
case "cos": return Math.cos(radians);
case "tan": return Math.tan(radians);
case "asin": return (Math.asin(angle) * 180) / Math.PI;
case "acos": return (Math.acos(angle) * 180) / Math.PI;
case "atan": return (Math.atan(angle) * 180) / Math.PI;
default: throw new Error("Unknown trigonometric function");
}
}
// Create and configure the server
const server = new Server(
{
name: "math-calculator-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Handle tool listing
server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools: TOOLS };
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
const { name, arguments: args } = request.params;
if (!args) {
throw new Error("No arguments provided");
}
let result: any;
switch (name) {
case "calculate":
result = calculate(args.operation as string, args.a as number, args.b as number);
return {
content: [
{
type: "text",
text: JSON.stringify({ operation: args.operation, result }, null, 2)
}
]
};
case "statistics":
result = statistics(args.numbers as number[], args.operation as string);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2)
}
]
};
case "convert_units":
result = convertUnits(args.value as number, args.from as string, args.to as string);
return {
content: [
{
type: "text",
text: JSON.stringify({
original: `${args.value} ${args.from}`,
converted: `${result} ${args.to}`,
value: result
}, null, 2)
}
]
};
case "solve_equation":
result = solveQuadratic(args.a as number, args.b as number, args.c as number);
return {
content: [
{
type: "text",
text: JSON.stringify({
equation: `${args.a}x² + ${args.b}x + ${args.c} = 0`,
...result
}, null, 2)
}
]
};
case "percentage":
result = calculatePercentage(args.operation as string, args.value1 as number, args.value2 as number);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2)
}
]
};
case "trigonometry":
result = trigonometry(args.function as string, args.angle as number);
return {
content: [
{
type: "text",
text: JSON.stringify({
function: args.function,
angle: `${args.angle}°`,
result
}, null, 2)
}
]
};
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: JSON.stringify({ error: errorMessage }, null, 2)
}
],
isError: true,
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Math & Calculator MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});