#
tokens: 4815/50000 8/8 files
lines: on (toggle) GitHub
raw markdown copy reset
# 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:
--------------------------------------------------------------------------------

```
1 | 3.11
2 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | __pycache__/
2 | *.pyc
3 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # MCP Calculate Server
 2 | 
 3 | [![smithery badge](https://smithery.ai/badge/@611711Dark/mcp_calculate_server)](https://smithery.ai/server/@611711Dark/mcp_calculate_server)
 4 | 
 5 | A mathematical calculation service based on MCP protocol and SymPy library, providing powerful symbolic computation capabilities.
 6 | 
 7 | ## Key Features
 8 | 
 9 | - **Basic Operations**: Addition, subtraction, multiplication, division, exponentiation
10 | - **Algebraic Operations**: Expression expansion, factorization, simplification
11 | - **Calculus**: Differentiation, integration (definite/indefinite), limit calculation
12 | - **Equation Solving**: Algebraic equations, systems of equations
13 | - **Matrix Operations**: Matrix inversion, eigenvalues/eigenvectors calculation
14 | - **Series Expansion**: Taylor series expansion
15 | - **Special Functions**: Trigonometric, logarithmic, exponential functions
16 | 
17 | ## Usage Examples
18 | 
19 | ```python
20 | # Basic operations
21 | "2 + 3*5" → 17
22 | 
23 | # Algebraic operations
24 | "expand((x + 1)**2)" → x² + 2x + 1
25 | "factor(x**2 - 2*x - 15)" → (x - 5)(x + 3)
26 | 
27 | # Calculus
28 | "diff(sin(x), x)" → cos(x)
29 | "integrate(exp(x), (x, 0, 1))" → E - 1
30 | "limit(tan(x)/x, x, 0)" → 1
31 | 
32 | # Equation solving
33 | "solve(x**2 - 4, x)" → [-2, 2]
34 | "solve([x**2 + y**2 - 1, x + y - 1], [x, y])" → [(0, 1), (1, 0)]
35 | 
36 | # Matrix operations
37 | "Matrix([[1, 2], [3, 4]]).inv()" → [[-2, 1], [3/2, -1/2]]
38 | "Matrix([[1, 2, 3], [4, 5, 6]]).eigenvals()" → {9/2 - sqrt(33)/2: 1, 9/2 + sqrt(33)/2: 1}
39 | ```
40 | 
41 | ## Installation
42 | 
43 | ### Installing via Smithery
44 | 
45 | To install Calculate Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@611711Dark/mcp_calculate_server):
46 | 
47 | ```bash
48 | npx -y @smithery/cli install @611711Dark/mcp_sympy_calculate_server --client claude
49 | ```
50 | 
51 | ### Local Installation
52 | 
53 | 1. Clone repository:
54 |    ```bash
55 |    git clone https://github.com/611711Dark/mcp-calculate-server.git
56 |    cd mcp-calculate-server
57 |    ```
58 | 
59 | 2. Create virtual environment and install dependencies:
60 |    ```bash
61 |    uv venv
62 |    source .venv/bin/activate
63 |    uv pip install -e .
64 |    ```
65 | 
66 | 3. Configuration:
67 |    ```json
68 |    "calculate_expression1": {
69 |       "isActive": false,
70 |       "command": "uv",
71 |       "args": [
72 |         "run",
73 |         "--directory",
74 |         "/path/to/mcp_calculate_server",
75 |         "server.py"
76 |       ],
77 |     }
78 |    ```
79 | 
80 | ## API Usage
81 | 
82 | Call `calculate_expression` tool via MCP protocol by passing mathematical expression string, returns computation result.
83 | 
84 | ## Dependencies
85 | 
86 | - mcp>=1.5.0
87 | - sympy>=1.13.3
88 | - fastapi>=0.95.0
89 | - uvicorn>=0.21.0
90 | 
91 | ## License
92 | 
93 | This project is licensed under MIT License. See [LICENSE](LICENSE) file.
94 | 
95 | [中文版本](README_CN.md)
96 | 
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "mcp-calcualte-server"
 3 | version = "0.1.0"
 4 | description = "Add your description here"
 5 | readme = "README.md"
 6 | requires-python = ">=3.11"
 7 | dependencies = [
 8 |     "mcp>=1.5.0",
 9 |     "sympy>=1.13.3",
10 | ]
11 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 |     # JSON Schema defining the configuration options for the MCP.
 7 |     {}
 8 |   commandFunction:
 9 |     # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
10 |     |-
11 |     (config) => ({ command: 'python', args: ['server.py'] })
12 |   exampleConfig: {}
13 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
 2 | FROM python:3.11-alpine
 3 | 
 4 | # Install build dependencies
 5 | RUN apk add --no-cache build-base
 6 | 
 7 | WORKDIR /app
 8 | 
 9 | # Copy project files into the container
10 | COPY . .
11 | 
12 | # Upgrade pip and install the project with its dependencies
13 | RUN pip install --upgrade pip \
14 |     && pip install .
15 | 
16 | # Expose port if needed (not required for mcp via stdio)
17 | 
18 | # Run the MCP server
19 | CMD ["python", "server.py"]
20 | 
```

--------------------------------------------------------------------------------
/test/test_server.py:
--------------------------------------------------------------------------------

```python
 1 | import unittest
 2 | import sys
 3 | import os
 4 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 5 | from server import calculate_expression
 6 | 
 7 | class TestCalculateExpression(unittest.TestCase):
 8 |     def test_basic_operations(self):
 9 |         """测试基础运算"""
10 |         self.assertEqual(calculate_expression("2 + 3*5"), "17")
11 |         self.assertEqual(calculate_expression("10 / 2"), "5.0")
12 |         self.assertEqual(calculate_expression("2**8"), "256")
13 | 
14 |     def test_algebraic_operations(self):
15 |         """测试代数运算"""
16 |         self.assertEqual(calculate_expression("expand((x + 1)**2)"), "x**2 + 2.0*x + 1.0")
17 |         self.assertEqual(calculate_expression("factor(x**2 - 2*x - 15)"), "(x - 5.0)*(x + 3.0)")
18 |         self.assertEqual(calculate_expression("simplify((x**2 - 1)/(x + 1))"), "x - 1.0")
19 | 
20 |     def test_calculus(self):
21 |         """测试微积分"""
22 |         self.assertEqual(calculate_expression("diff(sin(x), x)"), "cos(x)")
23 |         self.assertEqual(calculate_expression("integrate(exp(x), x)"), "exp(x)")
24 |         self.assertEqual(calculate_expression("limit(tan(x)/x, x, 0)"), "1.00000000000000")
25 | 
26 |     def test_equation_solving(self):
27 |         """测试方程求解"""
28 |         self.assertEqual(calculate_expression("solve(x**2 - 4, x)"), "[-2.00000000000000, 2.00000000000000]")
29 |         self.assertEqual(calculate_expression("solve([x + y - 1, x - y - 1], [x, y])"), "{x: 1, y: 0}")
30 | 
31 |     def test_matrix_operations(self):
32 |         """测试矩阵运算"""
33 |         self.assertEqual(calculate_expression("Matrix([[1, 2], [3, 4]]).inv()"), 
34 |                          "Matrix([[-2.00000000000000, 1.00000000000000], [1.50000000000000, -0.500000000000000]])")
35 |         self.assertEqual(calculate_expression("Matrix([[1, 2], [3, 4]]).det()"), "-2.00000000000000")
36 | 
37 |     def test_error_handling(self):
38 |         """测试错误处理"""
39 |         self.assertTrue(calculate_expression("1 / 0").startswith("Error:"))
40 |         self.assertTrue(calculate_expression("invalid expression").startswith("Error:"))
41 | 
42 | if __name__ == "__main__":
43 |     unittest.main()
44 | 
```

--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------

```python
  1 | from mcp.server.fastmcp import FastMCP
  2 | import sympy as sp
  3 | from sympy import symbols, Matrix, sympify
  4 | import re
  5 | 
  6 | # Create MCP server
  7 | mcp = FastMCP("MathTool")
  8 | 
  9 | # Add tool for calculating expressions
 10 | @mcp.tool()
 11 | def calculate_expression(expression: str) -> str:
 12 |     """
 13 | 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)
 14 | Parameters:
 15 |     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"
 16 | Example expressions:
 17 |     "2 + 3*5"                          # Basic arithmetic → 17
 18 |     "expand((x + 1)**2)"               # Expand → x² + 2x + 1
 19 |     "diff(sin(x), x)"                  # Derivative → cos(x)
 20 |     "integrate(exp(x), (x, 0, 1))"      # Definite integral → E - 1
 21 |     "solve(x**2 - 4, x)"               # Solve equation → [-2, 2]
 22 |     "limit(tan(x)/x, x, 0)"            # Limit → 1
 23 |     "Sum(k, (k, 1, 10)).doit()"        # Summation → 55
 24 |     "Matrix([[1, 2], [3, 4]]).inv()"   # Matrix inverse → [[-2, 1], [3/2, -1/2]]
 25 |     "simplify((x**2 - 1)/(x + 1))"     # Simplify → x - 1
 26 |     "factor(x**2 - 2*x - 15)"          # Factorize → (x - 5)(x + 3)
 27 |     "series(cos(x), x, 0, 4)"          # Taylor series → 1 - x²/2 + x⁴/24 + O(x⁴)
 28 |     "integrate(exp(-x**2)*sin(x), (x, -oo, oo))"  # Complex integral
 29 |     "solve([x**2 + y**2 - 1, x + y - 1], [x, y])"  # Solve system of equations
 30 |     "Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).eigenvals()"  # Matrix eigenvalues
 31 | Returns:
 32 |     str: Calculation result. If the expression cannot be parsed or computed, returns an error message (str).
 33 | """
 34 |     try:
 35 |         # Define common symbolic variables
 36 |         x, y, z = sp.symbols('x y z')
 37 | 
 38 |         # Create local namespace containing all sympy functions and symbolic variables
 39 |         locals_dict = {**sp.__dict__, 'x': x, 'y': y, 'z': z}
 40 | 
 41 |         # Special handling for various types of expressions
 42 | 
 43 |         # 1. Handle complex integral expressions
 44 |         if "integrate" in expression and ("oo" in expression or "-oo" in expression):
 45 |             return handle_complex_integration(expression, locals_dict)
 46 | 
 47 |         # 2. Handle system of equations solving expressions
 48 |         elif "solve(" in expression and "[" in expression and "]" in expression:
 49 |             return handle_equation_solving(expression, locals_dict)
 50 | 
 51 |         # 3. Handle matrix eigenvalue calculation expressions
 52 |         elif "eigenvals" in expression or "eigenvects" in expression:
 53 |             return handle_matrix_eigenvalues(expression, locals_dict)
 54 | 
 55 |         # 4. General expression calculation
 56 |         else:
 57 |             # First try to evaluate the expression directly
 58 |             result = eval(expression, globals(), locals_dict)
 59 | 
 60 |             # Process based on result type
 61 |             return format_result(result)
 62 | 
 63 |     except Exception as e:
 64 |         return f"Error: {e}"
 65 | 
 66 | def handle_complex_integration(expression, locals_dict):
 67 |     """Handle complex integral expressions"""
 68 |     try:
 69 |         # Check if it's an infinite integral
 70 |         if "-oo" in expression or "oo" in expression:
 71 |             # Try symbolic computation
 72 |             expr = eval(expression, globals(), locals_dict)
 73 | 
 74 |             # If it's an integral object but not computed
 75 |             if isinstance(expr, sp.Integral):
 76 |                 try:
 77 |                     # Try to perform the integral
 78 |                     result = expr.doit()
 79 | 
 80 |                     # Try to compute numerical result
 81 |                     try:
 82 |                         numerical = result.evalf()
 83 |                         return str(numerical)
 84 |                     except:
 85 |                         return str(result)
 86 |                 except Exception as e:
 87 |                     # If symbolic integration fails, try alternative methods
 88 |                     try:
 89 |                         # Extract integral expression information
 90 |                         match = re.search(r"integrate\((.*?), \((.*?), (.*?), (.*?)\)\)", expression)
 91 |                         if match:
 92 |                             integrand, var, lower, upper = match.groups()
 93 | 
 94 |                             # For infinite integrals, use finite approximation
 95 |                             if (lower == "-oo" or lower == "oo") or (upper == "oo" or upper == "-oo"):
 96 |                                 # Replace infinity with a large value
 97 |                                 if lower == "-oo":
 98 |                                     lower = "-100"
 99 |                                 elif lower == "oo":
100 |                                     lower = "100"
101 | 
102 |                                 if upper == "-oo":
103 |                                     upper = "-100"
104 |                                 elif upper == "oo":
105 |                                     upper = "100"
106 | 
107 |                                 # Build finite range integral expression
108 |                                 finite_expr = f"integrate({integrand}, ({var}, {lower}, {upper}))"
109 |                                 result = eval(finite_expr, globals(), locals_dict)
110 | 
111 |                                 try:
112 |                                     numerical = result.evalf()
113 |                                     return f"Approximate numerical result: {numerical} (using finite range integral)"
114 |                                 except:
115 |                                     return f"Approximate result: {result} (using finite range integral)"
116 |                     except Exception as e2:
117 |                         return f"Integration error: {e}, finite approximation failed: {e2}"
118 | 
119 |             # Try to compute result directly
120 |             try:
121 |                 numerical = expr.evalf()
122 |                 return str(numerical)
123 |             except:
124 |                 return str(expr)
125 | 
126 |         # Regular integral
127 |         result = eval(expression, globals(), locals_dict)
128 |         return format_result(result)
129 | 
130 |     except Exception as e:
131 |         return f"Integration error: {e}"
132 | 
133 | def handle_equation_solving(expression, locals_dict):
134 |     """Handle system of equations solving expressions"""
135 |     try:
136 |         # Compute result
137 |         result = eval(expression, globals(), locals_dict)
138 | 
139 |         # Format result
140 |         return format_result(result)
141 | 
142 |     except Exception as e:
143 |         return f"Equation solving error: {e}"
144 | 
145 | def handle_matrix_eigenvalues(expression, locals_dict):
146 |     """Handle matrix eigenvalue calculation expressions"""
147 |     try:
148 |         # Extract matrix expression
149 |         matrix_expr = expression.split(".eigen")[0]
150 |         operation = "eigenvals" if "eigenvals" in expression else "eigenvects"
151 | 
152 |         # Compute matrix
153 |         matrix = eval(matrix_expr, globals(), locals_dict)
154 | 
155 |         # Compute eigenvalues or eigenvectors
156 |         if operation == "eigenvals":
157 |             result = matrix.eigenvals()
158 |         else:
159 |             result = matrix.eigenvects()
160 | 
161 |         # Format result
162 |         return format_result(result)
163 | 
164 |     except Exception as e:
165 |         return f"Matrix eigenvalue calculation error: {e}"
166 | 
167 | def format_result(result):
168 |     """Format output based on result type"""
169 |     try:
170 |         # Handle dictionary type results (e.g., eigenvalues)
171 |         if isinstance(result, dict):
172 |             formatted = "{"
173 |             for key, value in result.items():
174 |                 # Try numerical computation
175 |                 try:
176 |                     key_eval = key.evalf()
177 |                 except:
178 |                     key_eval = key
179 | 
180 |                 formatted += f"{key_eval}: {value}, "
181 | 
182 |             if formatted.endswith(", "):
183 |                 formatted = formatted[:-2]
184 | 
185 |             formatted += "}"
186 |             return formatted
187 | 
188 |         # Handle list type results (e.g., solutions to equations)
189 |         elif isinstance(result, list):
190 |             formatted = "["
191 |             for item in result:
192 |                 # Check if it's a tuple (e.g., coordinate points)
193 |                 if isinstance(item, tuple):
194 |                     coords = []
195 |                     for val in item:
196 |                         # Try numerical computation
197 |                         try:
198 |                             val_eval = val.evalf()
199 |                             coords.append(str(val_eval))
200 |                         except:
201 |                             coords.append(str(val))
202 | 
203 |                     formatted += "(" + ", ".join(coords) + "), "
204 |                 else:
205 |                     # Try numerical computation
206 |                     try:
207 |                         item_eval = item.evalf()
208 |                         formatted += f"{item_eval}, "
209 |                     except:
210 |                         formatted += f"{item}, "
211 | 
212 |             if formatted.endswith(", "):
213 |                 formatted = formatted[:-2]
214 | 
215 |             formatted += "]"
216 |             return formatted
217 | 
218 |         # Other types of results
219 |         else:
220 |             # Try numerical computation
221 |             try:
222 |                 return str(result.evalf())
223 |             except:
224 |                 return str(result)
225 | 
226 |     except Exception as e:
227 |         return f"Result formatting error: {e}, original result: {result}"
228 | 
229 | if __name__ == "__main__":
230 |     mcp.run()
231 | 
```