# Directory Structure ``` ├── .gitignore ├── .python-version ├── Dockerfile ├── LICENSE ├── pyproject.toml ├── README_CN.md ├── README.md ├── server.py ├── smithery.yaml └── test └── test_server.py ``` # Files -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- ``` 3.11 ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` __pycache__/ *.pyc ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # MCP Calculate Server [](https://smithery.ai/server/@611711Dark/mcp_calculate_server) A mathematical calculation service based on MCP protocol and SymPy library, providing powerful symbolic computation capabilities. ## Key Features - **Basic Operations**: Addition, subtraction, multiplication, division, exponentiation - **Algebraic Operations**: Expression expansion, factorization, simplification - **Calculus**: Differentiation, integration (definite/indefinite), limit calculation - **Equation Solving**: Algebraic equations, systems of equations - **Matrix Operations**: Matrix inversion, eigenvalues/eigenvectors calculation - **Series Expansion**: Taylor series expansion - **Special Functions**: Trigonometric, logarithmic, exponential functions ## Usage Examples ```python # Basic operations "2 + 3*5" → 17 # Algebraic operations "expand((x + 1)**2)" → x² + 2x + 1 "factor(x**2 - 2*x - 15)" → (x - 5)(x + 3) # Calculus "diff(sin(x), x)" → cos(x) "integrate(exp(x), (x, 0, 1))" → E - 1 "limit(tan(x)/x, x, 0)" → 1 # Equation solving "solve(x**2 - 4, x)" → [-2, 2] "solve([x**2 + y**2 - 1, x + y - 1], [x, y])" → [(0, 1), (1, 0)] # Matrix operations "Matrix([[1, 2], [3, 4]]).inv()" → [[-2, 1], [3/2, -1/2]] "Matrix([[1, 2, 3], [4, 5, 6]]).eigenvals()" → {9/2 - sqrt(33)/2: 1, 9/2 + sqrt(33)/2: 1} ``` ## Installation ### Installing via Smithery To install Calculate Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@611711Dark/mcp_calculate_server): ```bash npx -y @smithery/cli install @611711Dark/mcp_sympy_calculate_server --client claude ``` ### Local Installation 1. Clone repository: ```bash git clone https://github.com/611711Dark/mcp-calculate-server.git cd mcp-calculate-server ``` 2. Create virtual environment and install dependencies: ```bash uv venv source .venv/bin/activate uv pip install -e . ``` 3. Configuration: ```json "calculate_expression1": { "isActive": false, "command": "uv", "args": [ "run", "--directory", "/path/to/mcp_calculate_server", "server.py" ], } ``` ## API Usage Call `calculate_expression` tool via MCP protocol by passing mathematical expression string, returns computation result. ## Dependencies - mcp>=1.5.0 - sympy>=1.13.3 - fastapi>=0.95.0 - uvicorn>=0.21.0 ## License This project is licensed under MIT License. See [LICENSE](LICENSE) file. [中文版本](README_CN.md) ``` -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- ```toml [project] name = "mcp-calcualte-server" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.11" dependencies = [ "mcp>=1.5.0", "sympy>=1.13.3", ] ``` -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- ```yaml # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml startCommand: type: stdio configSchema: # JSON Schema defining the configuration options for the MCP. {} commandFunction: # A JS function that produces the CLI command based on the given config to start the MCP on stdio. |- (config) => ({ command: 'python', args: ['server.py'] }) exampleConfig: {} ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- ```dockerfile # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile FROM python:3.11-alpine # Install build dependencies RUN apk add --no-cache build-base WORKDIR /app # Copy project files into the container COPY . . # Upgrade pip and install the project with its dependencies RUN pip install --upgrade pip \ && pip install . # Expose port if needed (not required for mcp via stdio) # Run the MCP server CMD ["python", "server.py"] ``` -------------------------------------------------------------------------------- /test/test_server.py: -------------------------------------------------------------------------------- ```python import unittest import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from server import calculate_expression class TestCalculateExpression(unittest.TestCase): def test_basic_operations(self): """测试基础运算""" self.assertEqual(calculate_expression("2 + 3*5"), "17") self.assertEqual(calculate_expression("10 / 2"), "5.0") self.assertEqual(calculate_expression("2**8"), "256") def test_algebraic_operations(self): """测试代数运算""" self.assertEqual(calculate_expression("expand((x + 1)**2)"), "x**2 + 2.0*x + 1.0") self.assertEqual(calculate_expression("factor(x**2 - 2*x - 15)"), "(x - 5.0)*(x + 3.0)") self.assertEqual(calculate_expression("simplify((x**2 - 1)/(x + 1))"), "x - 1.0") def test_calculus(self): """测试微积分""" self.assertEqual(calculate_expression("diff(sin(x), x)"), "cos(x)") self.assertEqual(calculate_expression("integrate(exp(x), x)"), "exp(x)") self.assertEqual(calculate_expression("limit(tan(x)/x, x, 0)"), "1.00000000000000") def test_equation_solving(self): """测试方程求解""" self.assertEqual(calculate_expression("solve(x**2 - 4, x)"), "[-2.00000000000000, 2.00000000000000]") self.assertEqual(calculate_expression("solve([x + y - 1, x - y - 1], [x, y])"), "{x: 1, y: 0}") def test_matrix_operations(self): """测试矩阵运算""" self.assertEqual(calculate_expression("Matrix([[1, 2], [3, 4]]).inv()"), "Matrix([[-2.00000000000000, 1.00000000000000], [1.50000000000000, -0.500000000000000]])") self.assertEqual(calculate_expression("Matrix([[1, 2], [3, 4]]).det()"), "-2.00000000000000") def test_error_handling(self): """测试错误处理""" self.assertTrue(calculate_expression("1 / 0").startswith("Error:")) self.assertTrue(calculate_expression("invalid expression").startswith("Error:")) if __name__ == "__main__": unittest.main() ``` -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- ```python from mcp.server.fastmcp import FastMCP import sympy as sp from sympy import symbols, Matrix, sympify import re # Create MCP server mcp = FastMCP("MathTool") # Add tool for calculating expressions @mcp.tool() def calculate_expression(expression: str) -> str: """ calculate mathematical expressions using the `sympify` function from `sympy`, parse and compute the input mathematical expression string, supports direct calls to SymPy functions (automatically recognizes x, y, z as symbolic variables) Parameters: expression (str): Mathematical expression, e.g., "223 - 344 * 6" or "sin(pi/2) + log(10)".Replace special symbols with approximate values, e.g., pi → 3.1415" Example expressions: "2 + 3*5" # Basic arithmetic → 17 "expand((x + 1)**2)" # Expand → x² + 2x + 1 "diff(sin(x), x)" # Derivative → cos(x) "integrate(exp(x), (x, 0, 1))" # Definite integral → E - 1 "solve(x**2 - 4, x)" # Solve equation → [-2, 2] "limit(tan(x)/x, x, 0)" # Limit → 1 "Sum(k, (k, 1, 10)).doit()" # Summation → 55 "Matrix([[1, 2], [3, 4]]).inv()" # Matrix inverse → [[-2, 1], [3/2, -1/2]] "simplify((x**2 - 1)/(x + 1))" # Simplify → x - 1 "factor(x**2 - 2*x - 15)" # Factorize → (x - 5)(x + 3) "series(cos(x), x, 0, 4)" # Taylor series → 1 - x²/2 + x⁴/24 + O(x⁴) "integrate(exp(-x**2)*sin(x), (x, -oo, oo))" # Complex integral "solve([x**2 + y**2 - 1, x + y - 1], [x, y])" # Solve system of equations "Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).eigenvals()" # Matrix eigenvalues Returns: str: Calculation result. If the expression cannot be parsed or computed, returns an error message (str). """ try: # Define common symbolic variables x, y, z = sp.symbols('x y z') # Create local namespace containing all sympy functions and symbolic variables locals_dict = {**sp.__dict__, 'x': x, 'y': y, 'z': z} # Special handling for various types of expressions # 1. Handle complex integral expressions if "integrate" in expression and ("oo" in expression or "-oo" in expression): return handle_complex_integration(expression, locals_dict) # 2. Handle system of equations solving expressions elif "solve(" in expression and "[" in expression and "]" in expression: return handle_equation_solving(expression, locals_dict) # 3. Handle matrix eigenvalue calculation expressions elif "eigenvals" in expression or "eigenvects" in expression: return handle_matrix_eigenvalues(expression, locals_dict) # 4. General expression calculation else: # First try to evaluate the expression directly result = eval(expression, globals(), locals_dict) # Process based on result type return format_result(result) except Exception as e: return f"Error: {e}" def handle_complex_integration(expression, locals_dict): """Handle complex integral expressions""" try: # Check if it's an infinite integral if "-oo" in expression or "oo" in expression: # Try symbolic computation expr = eval(expression, globals(), locals_dict) # If it's an integral object but not computed if isinstance(expr, sp.Integral): try: # Try to perform the integral result = expr.doit() # Try to compute numerical result try: numerical = result.evalf() return str(numerical) except: return str(result) except Exception as e: # If symbolic integration fails, try alternative methods try: # Extract integral expression information match = re.search(r"integrate\((.*?), \((.*?), (.*?), (.*?)\)\)", expression) if match: integrand, var, lower, upper = match.groups() # For infinite integrals, use finite approximation if (lower == "-oo" or lower == "oo") or (upper == "oo" or upper == "-oo"): # Replace infinity with a large value if lower == "-oo": lower = "-100" elif lower == "oo": lower = "100" if upper == "-oo": upper = "-100" elif upper == "oo": upper = "100" # Build finite range integral expression finite_expr = f"integrate({integrand}, ({var}, {lower}, {upper}))" result = eval(finite_expr, globals(), locals_dict) try: numerical = result.evalf() return f"Approximate numerical result: {numerical} (using finite range integral)" except: return f"Approximate result: {result} (using finite range integral)" except Exception as e2: return f"Integration error: {e}, finite approximation failed: {e2}" # Try to compute result directly try: numerical = expr.evalf() return str(numerical) except: return str(expr) # Regular integral result = eval(expression, globals(), locals_dict) return format_result(result) except Exception as e: return f"Integration error: {e}" def handle_equation_solving(expression, locals_dict): """Handle system of equations solving expressions""" try: # Compute result result = eval(expression, globals(), locals_dict) # Format result return format_result(result) except Exception as e: return f"Equation solving error: {e}" def handle_matrix_eigenvalues(expression, locals_dict): """Handle matrix eigenvalue calculation expressions""" try: # Extract matrix expression matrix_expr = expression.split(".eigen")[0] operation = "eigenvals" if "eigenvals" in expression else "eigenvects" # Compute matrix matrix = eval(matrix_expr, globals(), locals_dict) # Compute eigenvalues or eigenvectors if operation == "eigenvals": result = matrix.eigenvals() else: result = matrix.eigenvects() # Format result return format_result(result) except Exception as e: return f"Matrix eigenvalue calculation error: {e}" def format_result(result): """Format output based on result type""" try: # Handle dictionary type results (e.g., eigenvalues) if isinstance(result, dict): formatted = "{" for key, value in result.items(): # Try numerical computation try: key_eval = key.evalf() except: key_eval = key formatted += f"{key_eval}: {value}, " if formatted.endswith(", "): formatted = formatted[:-2] formatted += "}" return formatted # Handle list type results (e.g., solutions to equations) elif isinstance(result, list): formatted = "[" for item in result: # Check if it's a tuple (e.g., coordinate points) if isinstance(item, tuple): coords = [] for val in item: # Try numerical computation try: val_eval = val.evalf() coords.append(str(val_eval)) except: coords.append(str(val)) formatted += "(" + ", ".join(coords) + "), " else: # Try numerical computation try: item_eval = item.evalf() formatted += f"{item_eval}, " except: formatted += f"{item}, " if formatted.endswith(", "): formatted = formatted[:-2] formatted += "]" return formatted # Other types of results else: # Try numerical computation try: return str(result.evalf()) except: return str(result) except Exception as e: return f"Result formatting error: {e}, original result: {result}" if __name__ == "__main__": mcp.run() ```