Skip to main content
Glama
laguchoritarik

Symbolic Algebra MCP Server

Symbolic Algebra MCP Server (lag-sympy-mcp)

This is a maintained fork of sdiehl/sympy-mcp, which is no longer maintained upstream (Apache License 2.0). It adds algebra and calculus tools (factor_expression, expand_expression, cancel_expression, apart_expression, limit_expression, series_expansion, solve_inequality) and a safe expression parser; see MODIFICATIONS.md.

Sympy-MCP is a Model Context Protocol server for allowing LLMs to autonomously perform symbolic mathematics and computer algebra. It exposes numerous tools from SymPy's core functionality to MCP clients for manipulating mathematical expressions and equations.

Why?

Language models are absolutely abysmal at symbolic manipulation. They hallucinate variables, make up random constants, permute terms and generally make a mess. But we have computer algebra systems specifically built for symbolic manipulation, so we can use tool-calling to orchestrate a sequence of transforms so that the symbolic kernel does all the heavy lifting.

While you can certainly have an LLM generate Mathematica or Python code, if you want to use the LLM as an agent or on-the-fly calculator, it's a better experience to use the MCP server and expose the symbolic tools directly.

The server exposes a subset of symbolic mathematics capabilities including algebraic equation solving, integration and differentiation, vector calculus, tensor calculus for general relativity, and both ordinary and partial differential equations.

For example, you can ask it in natural language to solve a differential equation:

Solve the damped harmonic oscillator with forcing term: the mass-spring-damper system described by the differential equation where m is mass, c is the damping coefficient, k is the spring constant, and F(t) is an external force.

$$ m\frac{d^2x}{dt^2} + c\frac{dx}{dt} + kx = F(t) $$

Or involving general relativity:

Compute the trace of the Ricci tensor $R_{\mu\nu}$ using the inverse metric $g^{\mu\nu}$ for Anti-de Sitter spacetime to determine its constant scalar curvature $R$.

Related MCP server: mcp-sympy

Usage

You need uv first.

  • Homebrew : brew install uv

  • Curl : curl -LsSf https://astral.sh/uv/install.sh | sh

Then you can install and run the server with the following commands:

# Setup the project
git clone https://github.com/laguchoritarik/lag-sympy-mcp.git
cd lag-sympy-mcp
uv sync

# Install the server to Claude Desktop
uv run mcp install server.py

# Run the server
uv run mcp run server.py

You should see the server available in the Claude Desktop app now. For other clients, see below.

Claude Code setup

claude mcp add --scope user sympy-mcp -- uv --directory /ABSOLUTE_PATH_TO/lag-sympy-mcp run mcp run server.py

Replace /ABSOLUTE_PATH_TO/lag-sympy-mcp with the absolute path of your clone, then check the connection with claude mcp list.

If you want to do general relativity calculations, you need to install the einsteinpy library.

uv sync --group relativity

Available Tools

The sympy-mcp server provides the following tools for symbolic mathematics:

Tool

Tool ID

Description

Variable Introduction

intro

Introduces a variable with specified assumptions and stores it

Multiple Variables

intro_many

Introduces multiple variables with specified assumptions simultaneously

Expression Parser

introduce_expression

Parses an expression string using available local variables and stores it

LaTeX Printer

print_latex_expression

Prints a stored expression in LaTeX format, along with variable assumptions

Algebraic Solver

solve_algebraically

Solves an equation algebraically for a given variable over a given domain

Linear Solver

solve_linear_system

Solves a system of linear equations

Nonlinear Solver

solve_nonlinear_system

Solves a system of nonlinear equations

Function Variable

introduce_function

Introduces a function variable for use in differential equations

ODE Solver

dsolve_ode

Solves an ordinary differential equation

PDE Solver

pdsolve_pde

Solves a partial differential equation

Standard Metric

create_predefined_metric

Creates a predefined spacetime metric (e.g. Schwarzschild, Kerr, Minkowski)

Metric Search

search_predefined_metrics

Searches available predefined metrics

Tensor Calculator

calculate_tensor

Calculates tensors from a metric (Ricci, Einstein, Weyl tensors)

Custom Metric

create_custom_metric

Creates a custom metric tensor from provided components and symbols

Tensor LaTeX

print_latex_tensor

Prints a stored tensor expression in LaTeX format

Simplifier

simplify_expression

Simplifies a mathematical expression using SymPy's canonicalize function

Substitution

substitute_expression

Substitutes a variable with an expression in another expression

Integration

integrate_expression

Integrates an expression with respect to a variable

Differentiation

differentiate_expression

Differentiates an expression with respect to a variable

Coordinates

create_coordinate_system

Creates a 3D coordinate system for vector calculus operations

Vector Field

create_vector_field

Creates a vector field in the specified coordinate system

Curl

calculate_curl

Calculates the curl of a vector field

Divergence

calculate_divergence

Calculates the divergence of a vector field

Gradient

calculate_gradient

Calculates the gradient of a scalar field

Unit Converter

convert_to_units

Converts a quantity to given target units

Unit Simplifier

quantity_simplify_units

Simplifies a quantity with units

Matrix Creator

create_matrix

Creates a SymPy matrix from the provided data

Determinant

matrix_determinant

Calculates the determinant of a matrix

Matrix Inverse

matrix_inverse

Calculates the inverse of a matrix

Eigenvalues

matrix_eigenvalues

Calculates the eigenvalues of a matrix

Eigenvectors

matrix_eigenvectors

Calculates the eigenvectors of a matrix

Factorization

factor_expression

Factors an expression over Q (optionally over Q(i) or GF(p))

Expansion

expand_expression

Expands products and integer powers of sums

Rational Cancellation

cancel_expression

Puts a rational expression in canonical form p/q with common factors cancelled

Partial Fractions

apart_expression

Computes the partial fraction decomposition of a rational expression

Limit

limit_expression

Computes a limit at a finite point or at ±∞ (two-sided or one-sided)

Series Expansion

series_expansion

Computes a Taylor/Laurent expansion with or without the O(...) remainder

Inequality Solver

solve_inequality

Solves an inequality (or And/Or of inequalities) in one real variable

By default variables are predefined with assumptions (similar to how the symbols() function works in SymPy). Unless otherwise specified the defaut assumptions is that a variable is complex, commutative, term over the complex field $\mathbb{C}$.

Property

Value

commutative

true

complex

true

finite

true

infinite

false

Algebra and Calculus Tools

These tools work on expressions already stored with introduce_expression and return a new expression key (print it with print_latex_expression), except solve_inequality, which returns the LaTeX of the solution set, like solve_algebraically. factor_expression, expand_expression, cancel_expression and apart_expression apply to both sides of an equation and to each entry of a matrix.

Tool

Parameters

Example input → output

factor_expression

expr_key, gaussian=false, modulus=null (prime)

x**6 - 1 → (x - 1)(x + 1)(x² - x + 1)(x² + x + 1); x**2 + 1 with gaussian=true → (x - i)(x + i)

expand_expression

expr_key

(x + 1)**3 → x³ + 3x² + 3x + 1

cancel_expression

expr_key

(x**2 - 1)/(x**2 - 2*x + 1) → (x + 1)/(x - 1) (formal cancellation)

apart_expression

expr_key, var_name (required if several variables)

1/(x**2 - 1) → 1/(2(x - 1)) - 1/(2(x + 1))

limit_expression

expr_key, var_name, point, direction = "+-" (default) / "+" / "-"

sin(x)/x, "0" → 1; (1 + 1/x)**x, "oo" → e; 1/x, "0" → error (one-sided limits differ)

series_expansion

expr_key, var_name, point="0", order=6 (1–50), remove_order_term=false

exp(x), order 4 → 1 + x + x²/2 + x³/6 + O(x⁴)

solve_inequality

expr_key, var_name

x**2 - 1 > 0 → (-∞, -1) ∪ (1, ∞); And(x > 0, x**2 < 4) → (0, 2)

Notes:

  • limit_expression reports an error, rather than a value, when the limit does not exist: one-sided limits that differ (1/x, Abs(x)/x at 0) or oscillation (sin(x) at oo).

  • Inequalities are solved over the reals. Write a double inequality a < f(x) < b as And(a < f(x), f(x) < b); Python's chained comparison is not supported by SymPy.

  • The point arguments of limit_expression and series_expansion are not passed to parse_expr. They are parsed with Python's ast module against an allow-list: numbers, introduced variables, oo/inf/infinity/zoo/pi/E/I, + - * / ** ^, and the functions sqrt, exp, log, sin, cos, tan, Rational. Anything else (attribute access, subscripts, strings, keyword arguments, other calls, very large exact powers, inputs over 256 characters) is rejected before evaluation.

Claude Desktop Setup

Normally the mcp install command will automatically add the server to the claude_desktop_config.json file. If it doesn't you need to find the config file and add the following:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add the following to the mcpServers object, replacing /ABSOLUTE_PATH_TO_SYMPY_MCP/server.py with the absolute path to the sympy-mcp server.py file.

{
  "mcpServers": {
    "sympy-mcp": {
      "command": "/opt/homebrew/bin/uv",
      "args": [
        "run",
        "--with",
        "einsteinpy",
        "--with",
        "mcp[cli]",
        "--with",
        "pydantic",
        "--with",
        "sympy",
        "mcp",
        "run",
        "/ABSOLUTE_PATH_TO_SYMPY_MCP/server.py"
      ]
    }
  }
}

Cursor Setup

In your ~/.cursor/mcp.json, add the following, where ABSOLUTE_PATH_TO_SYMPY_MCP is the path to the sympy-mcp server.py file.

{
  "mcpServers": {
    "sympy-mcp": {
      "command": "/opt/homebrew/bin/uv",
      "args": [
        "run",
        "--with",
        "einsteinpy",
        "--with",
        "mcp[cli]",
        "--with",
        "pydantic",
        "--with",
        "sympy",
        "mcp",
        "run",
        "/ABSOLUTE_PATH_TO_SYMPY_MCP/server.py"
      ]
    }
  }
}

VS Code Setup

VS Code and VS Code Insiders now support MCPs in agent mode. For VS Code, you may need to enable Chat > Agent: Enable in the settings.

  1. One-click Setup:

Install in VS Code

Install in VS Code Insiders

OR manually add the config to your settings.json (global):

{
  "mcp": {
    "servers": {
      "sympy-mcp": {
        "command": "uv",
        "args": [
          "run",
          "--with",
          "einsteinpy",
          "--with",
          "mcp[cli]",
          "--with",
          "pydantic",
          "--with",
          "sympy",
          "mcp",
          "run",
          "/ABSOLUTE_PATH_TO_SYMPY_MCP/server.py"
        ]
      }
    }
  }
}
  1. Click "Start" above the server config switch to agent mode in the chat, and try commands like "integrate x^2" or "solve x^2 = 1" to get started.

HTTP Transport (Streamable HTTP / SSE)

The server supports MCP over HTTP using the streamable-http transport introduced in MCP spec 2025-03-26. This replaces the legacy SSE transport and exposes a single /mcp endpoint that clients connect to over HTTP.

This is the recommended transport when running the server as a standalone process or in a container, because it allows any HTTP-capable MCP client to connect without needing to launch the server as a subprocess.

# Run locally with HTTP transport
uv run python server.py --transport streamable-http

# Override host/port
uv run python server.py --transport streamable-http --mcp-host 127.0.0.1 --mcp-port 9000

The legacy --transport sse flag is still supported for backward compatibility.

A /healthcheck endpoint is also exposed that runs a full MCP protocol round-trip (initialize → tools/list → session teardown) and returns {"status": "ok", "tool_count": N}.

Running in Container

You can build and run the server using Docker locally:

# Build the Docker image
docker build -t sympy-mcp .

# Run the Docker container
docker run -p 8081:8081 sympy-mcp

Or use Docker Compose from the docker/ directory:

cd docker
docker compose up -d --build

Alternatively, you can pull the pre-built image from GitHub Container Registry:

# Pull the latest image
docker pull ghcr.io/laguchoritarik/lag-sympy-mcp:main

# Run the container
docker run -p 8081:8081 --rm ghcr.io/laguchoritarik/lag-sympy-mcp:main

To configure Claude Desktop to launch the Docker container, edit your claude_desktop_config.json file:

{
  "mcpServers": {
    "sympy-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "-p",
        "8081:8081",
        "--rm",
        "sympy-mcp"
      ]
    }
  }
}

Or to use the pre-built container from GitHub:

{
  "mcpServers": {
    "sympy-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "-p",
        "8081:8081",
        "--rm",
        "ghcr.io/laguchoritarik/lag-sympy-mcp:main"
      ]
    }
  }
}

This configuration tells Claude Desktop to launch the Docker container when needed. Make sure to build the Docker image (docker build -t sympy-mcp .) before using Claude Desktop with this configuration.

The other installation methods can also be adapted to work with Docker if you change the uv command to use the docker run command instead.

Example Interaction 1 : Differential Equations

Here's an example of how the tool-calling works in a conversation with an AI assistant using this MCP server:

User: Solve the damped harmonic oscillator with forcing term: the mass-spring-damper system described by the differential equation where m is mass, c is the damping coefficient, k is the spring constant, and F(t) is an external force.

$$ m\frac{d^2x}{dt^2} + c\frac{dx}{dt} + kx = F(t) $$

Assistant: (Internal tool call) intro_many to introduce variables:

{
  "variables": [
    {"var_name": "t", "pos_assumptions": ["real"], "neg_assumptions": []},
    {"var_name": "m", "pos_assumptions": ["real", "positive"], "neg_assumptions": []},
    {"var_name": "c", "pos_assumptions": ["real", "positive"], "neg_assumptions": []},
    {"var_name": "k", "pos_assumptions": ["real", "positive"], "neg_assumptions": []}
  ]
}

Assistant: (Internal tool call) introduce_function to define x(t):

{
  "func_name": "x"
}

Assistant: (Internal tool call) introduce_expression to create the differential equation:

{
  "expr_str": "Eq(m*Derivative(x(t), t, t) + c*Derivative(x(t), t) + k*x(t), F(t))"
}

Assistant: (Internal tool call) print_latex_expression to display the equation nicely:

{
  "expr_key": "expr_12"
}

Result:

$$ c \frac{d}{d t} x{\left(t \right)} + k x{\left(t \right)} + m \frac{d^{2}}{d t^{2}} x{\left(t \right)} = F{\left(t \right)} $$

Assistant: (Internal tool call) introduce_function to define F(t):

{
  "func_name": "F"
}

Assistant: (Internal tool call) dsolve_ode to solve the differential equation:

{
  "expr_key": "expr_12",
  "func_name": "x"
}

Result:

$$ x{\left(t \right)} = C_{1} e^{\frac{t \left(- c + \sqrt{c^{2} - 4 k m}\right)}{2 m}} + C_{2} e^{- \frac{t \left(c + \sqrt{c^{2} - 4 k m}\right)}{2 m}} + \cdots $$

Example Interaction 2: General Relativity

User: Compute the trace of the Ricci tensor $R_{\mu\nu}$ using the inverse metric $g^{\mu\nu}$ for Anti-de Sitter spacetime to determine its constant scalar curvature $R$.

Assistant: (Internal tool call) create_predefined_metric to create the Anti-de Sitter metric:

{
  "metric_name": "AntiDeSitter"
}

Assistant: (Internal tool call) calculate_tensor to calculate the Ricci tensor:

{
  "metric_key": "metric_AntiDeSitter",
  "tensor_type": "RICCI_TENSOR",
  "simplify_result": true
}

Assistant: (Internal tool call) print_latex_tensor to display the Ricci tensor:

{
  "tensor_key": "riccitensor_metric_AntiDeSitter"
}

Result:

$$ \left[\begin{matrix}3 & 0 & 0 & 0\\0 & - 3 \cos^{2}{\left(t \right)} & 0 & 0\\0 & 0 & - 3 \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)} & 0\\0 & 0 & 0 & - 3 \sin^{2}{\left(\theta \right)} \cos^{2}{\left(t \right)} \sinh^{2}{\left(\chi \right)}\end{matrix}\right] $$

Assistant: (Internal tool call) calculate_tensor to calculate the Ricci scalar:

{
  "metric_key": "metric_AntiDeSitter",
  "tensor_type": "RICCI_SCALAR",
  "simplify_result": true
}

Assistant: (Internal tool call) print_latex_tensor to display the Ricci scalar:

{
  "tensor_key": "ricciscalar_metric_AntiDeSitter"
}

Result:

$$ -12 $$

Example Interaction 3: Coupled ODE System (Fluid Dynamics)

This example demonstrates solving a coupled system of ODEs and verifying the solution against an algebraic steady-state analysis, a task where LLMs typically hallucinate without a CAS to ground each step.

User:

Use the sympy-mcp tools to solve this symbolically. Do not compute by hand.

Two cylindrical tanks are connected by a pipe. Tank 1 has cross-sectional area A₁ = 2 m² and receives a constant inflow of Q = 0.5 m³/s. Water drains from Tank 1 into Tank 2 through a pipe with flow rate proportional to the height difference: q₁₂ = k·(h₁ - h₂) where k = 0.3 m²/s. Tank 2 has cross-sectional area A₂ = 1 m² and drains to the outside at rate q₂ = k·h₂ with the same k.

Set up and solve the coupled system of ODEs for the water heights h₁(t) and h₂(t), starting from empty tanks (h₁(0) = 0, h₂(0) = 0). Then find the steady-state heights as t → ∞ by solving the equilibrium equations algebraically, and verify they match the long-term solution of the ODEs.

Assistant: (Internal tool chain)

  1. intro_many: introduce t, k, A1, A2, Q with real/positive assumptions

  2. introduce_function × 2: introduce h1(t) and h2(t) as unknown functions

  3. introduce_expression × 2: encode the mass-balance ODEs:

$$A_1 \frac{dh_1}{dt} = Q - k(h_1 - h_2), \quad A_2 \frac{dh_2}{dt} = k(h_1 - h_2) - k h_2$$

  1. substitute_expression: substitute numeric values for k, A1, A2, Q

  2. dsolve_ode × 2: solve the coupled system; apply initial conditions via substitute_expression

  3. introduce_expression × 2: encode equilibrium equations (derivatives set to zero)

  4. solve_linear_system: solve the 2×2 algebraic system for h1*, h2*

  5. print_latex_expression: display both the time-domain solution and the steady-state values

Security Disclaimer

This server runs on your computer and gives the language model access to run Python logic. Notably it uses Sympy's parse_expr to parse mathematical expressions, which is uses eval under the hood, effectively allowing arbitrary code execution. By running the server, you are trusting the code that Claude generates. Running in the Docker image is slightly safer, but it's still a good idea to review the code before running it.

parse_expr call sites

The following tools pass client-supplied strings to parse_expr with SymPy's default global namespace (which includes Python builtins such as __import__, open, eval, exec):

  • introduce_expression (expr_str)

  • integrate_expression (lower_bound, upper_bound)

  • create_vector_field (component strings)

  • create_matrix (string entries)

  • convert_to_units (target unit strings)

  • create_custom_metric (component strings)

For example introduce_expression("__import__('os').getpid()") executes the call. Passing global_dict={} is not a mitigation: eval re-inserts the complete __builtins__ module into an empty globals dictionary, and object attribute traversal (obj.__class__.__mro__...) remains available regardless of the namespace. SymPy documents parse_expr/sympify as unsafe on untrusted input. Resource exhaustion is also possible (e.g. 10**10**10), and no time limit is applied to any tool. With the HTTP transports the server binds to 0.0.0.0 by default, which exposes these risks to the network; prefer --mcp-host 127.0.0.1 or the stdio transport.

The algebra/calculus tools added in this fork (factor_expression, expand_expression, cancel_expression, apart_expression, limit_expression, series_expansion, solve_inequality) never call parse_expr, sympify or eval themselves; their only string inputs are parsed by the allow-list parser described above. They still operate on expressions that were created through introduce_expression, so they do not remove the risk of that entry point.

License

Copyright 2025 Stephen Diehl.

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    C
    maintenance
    An MCP server that provides access to SymPy's symbolic mathematics library for advanced algebraic computations. It enables users to perform complex tasks such as symbolic simplification, calculus, equation solving, matrix operations, and number theory.
    100
    41 PyPI
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    MCP server for symbolic computation that enables AI agents to perform step-by-step derivations, transform formulas, and verify results with full provenance, combining natural language with formal mathematical operations.
    41
    71 PyPI
    12
    Apache 2.0