Skip to main content

macaulay2-mcp

Motivation

The goal for the Macaulay2-MCP project is to leverage large-language-models when working with Macaulay2. Especially, it should lower the entry point for newcomers or test a few lines of code. It is still under development; use it at your own risk and share your thoughts with me.

The current version is under testing. This early version is published on GitHub to test other components such as PyPI, LM Studio linking, and Binder.

Philosophy

  • Nearly all commands and programs below are non-invasive and reversible.
  • The program is not designed to make decisions but inform the users of options.
  • At some point, this MCP should work together with Lean-LSP.
  • It will be updated on an as-needed basis.

Acknowledgments

The project is largely developed under the author's guidance by Qwen 3.8 models hosted at National Research Platform. Also, the author thanks Dr. Mary Thomas and other leaders at the San Diego Supercomputer Center. The author learned a large portion of the skills used in this project from their CyberInfrastructure Professional Development Training Program.

Introduction

Use Macaulay2 from your AI coding assistant.

macaulay2-mcp is an MCP (Model Context Protocol) server that gives Claude Code, opencode, LM Studio, and any other MCP client a persistent Macaulay2 session: ask your assistant to compute Groebner bases, resolutions, Betti tables, primary decompositions, Hilbert polynomials — and it runs the computations in a real M2 kernel, with state (rings, ideals, your definitions) preserved across calls.

Three notations, one kernel — raw M2 syntax, plain English, LaTeX. Each ask is self-contained (paste any one into a fresh session), and the trailing memory line is genuine output (every m2_evaluate result ends with the kernel's resident/peak):

macaulay2-mcp in a real opencode v2 session — 40 s, three README examples run live

Note: When running the examples below, using Macaulay2 skill at https://github.com/youngsu-Kim/macaulay2-skills (skills/macaulay2/SKILL.md) would be helpful. That is, start running example with "First read Macaulay2-skills available at https://github.com/youngsu-Kim/macaulay2-skills. Then compute the Groebner basis of ideal(x^3 - y, x^4 - z) in QQ[x,y,z]"

Input

Compute the Groebner basis of ideal(x^3 - y, x^4 - z) in QQ[x,y,z]

Or Input

First read Macaulay2-skills available at https://github.com/youngsu-Kim/macaulay2-skills. Then compute the Groebner basis of ideal(x^3 - y, x^4 - z) in QQ[x,y,z]

Output Example

Response:   m2_evaluate: R = QQ[x,y,z]; I = ideal(x^3 - y, x^4 - z)
            m2_evaluate: print generators (gb I)
            The reduced Groebner basis is
            {xy - z, x^2 z - y^2, y^3 - x z^2, x^3 - y}.
            (M2 memory: 118.5 MB resident, peak 103.0 MB)

Input

In the polynomial ring in x, y, z over the rationals, let J be the ideal generated by x squared plus y squared minus z squared.
Use macaulay2-mcp to verify: is J prime? What are the dimension and degree of the quotient?

Output Example

Response:   m2_evaluate: S = QQ[x,y,z]; J = ideal(x^2 + y^2 - z^2)
            m2_evaluate: isPrime J; dim (S/J); degree (S/J)
            J is prime; S/J is a surface (dimension 2) of degree 2.
            (M2 memory: 119.3 MB resident, peak 103.0 MB)

Input

For the twisted cubic $C \subset \mathbb{P}^3$, whose ideal is $I_C = (xz - y^2, yw - z^2, xw - yz)$, compute a free resolution of $S/I_C$ with Betti table, and the Hilbert polynomial of $C$, in Macaulay2

Output Example

Response:   m2_evaluate: A = QQ[w,x,y,z]
                         C = ideal(x*z - y^2, y*w - z^2, x*w - y*z)
            m2_evaluate: betti res C
            m2_evaluate: hilbertPolynomial (A^1/C)
            Totals (1, 3, 2) — three quadrics, two linear syzygies — and the
            Hilbert polynomial 3T + 1.
            (M2 memory: 118.5 MB resident, peak 103.0 MB)

M2 syntax helps weak AI models, LaTeX/plain words usually suffice for strong ones — your assistant does the translating; verify its input lines.

Two design notes for local models: on multi-part asks, heavy-thinking models can spend minutes and many self-correcting tool calls — correct but slow (real transcripts: Case study 2 in examples/latex-decomposition-test.md); and a famous object invites answering from memory without calling the tool at all — hence ask 1 speaks M2's own syntax while asks 2 and 3 state it outright ("Use macaulay2-mcp to verify…", "…in Macaulay2"). And note that graded invariants (Betti tables, Hilbert polynomials) are asked only of a homogeneous ideal — where M2's table is minimal and unarguable.


Installation

Prerequisites (one line each):

You need macOS Ubuntu
Macaulay2 (latest stable, 1.26) brew install Macaulay2/tap/macaulay2 sudo add-apt-repository ppa:macaulay2/macaulay2 && sudo apt install macaulay2
uv (runs the server, no install) brew install uv curl -LsSf https://astral.sh/uv/install.sh | sh

Why a tap/PPA, how to undo it, the alternative uv installer, and the full list of environment settings: docs/installation.md.

Kernel from PyPI instead of a system install: uvx --with passagemath-macaulay2 macaulay2-mcp — official installs take precedence when present (details).

Add it to your AI client (harness):

  • Claude Code
    claude mcp add macaulay2 -- uvx macaulay2-mcp
    
  • opencode — add to your opencode.json (or project opencode.json):
    {
      "$schema": "https://opencode.ai/config.json",
      "mcp": {
        "macaulay2": {
          "type": "local",
          "command": ["uvx", "macaulay2-mcp"]
        }
      }
    }
    
  • LM Studio (GUI chat) — LM Studio (≥ 0.4.24) is itself an MCP host: Program tab → Install → Edit mcp.json → paste, then enable the server and pick a tool-calling-capable model (start it with the in-chat 1+1 check under Check the MCP below).
    {
      "mcpServers": {
        "macaulay2": {
          "command": "uvx",
          "args": ["macaulay2-mcp"],
          "env": { "MACAULAY2_MCP_JOURNAL": "~/.local/share/macaulay2-mcp/journals" }
        }
      }
    }
    

The env line just pins the history file to a known folder — see Reading the journal to relocate or turn it off. Setup details and fixes: Troubleshooting.

Check the MCP:

uvx macaulay2-mcp selftest
macaulay2-mcp 0.1.5 self-test

[OK] found Macaulay2: /opt/homebrew/bin/M2
[OK] supported version (1.26.x): 1.26.06
[OK] kernel source: official installation
[OK] started session: prompt received
[OK] evaluated 1 + 1: 1 + 1 / o1 = 2

Self-test passed. The MCP server is ready to use.

If anything above fails: M2 not on PATH → set M2_BIN=/path/to/M2 in the client's environment; both prereq commands add third-party repos (reversible — see docs/installation.md); more symptoms and fixes: Troubleshooting.

From inside the chat — checks that your model can reach the server (and wakes a lazily-started one). Paste as your first message:

Before any real math: use the Macaulay2 tool to evaluate 1 + 1, then report
the tool's last line verbatim. If you don't see a Macaulay2 tool, say so
plainly — don't invent an answer.

Examples

With the server connected, just ask (in Claude Code / opencode / ...). All of these are tested prompts:

For a model that struggles with M2's dialect, prepend one line to any prompt below: "Read the Macaulay2 skill at https://github.com/youngsu-Kim/macaulay2-skills (skills/macaulay2/SKILL.md) and follow it before executing." Agents that installed the skill via npx skills add youngsu-Kim/macaulay2-skills do this without being told — see its FINDINGS.md for the measured effect across five model families.

  • “Create R = QQ[x,y,z] and I = ideal(x^3 - y, x^4 - z). Compute the Groebner basis and a free resolution; show the Betti table, and the dimensions of R and R/I.” (→ basis xy - z, x^2 z - y^2, y^3 - x z^2, x^3 - y; M2 prints totals 1 4 4 1; dims 3 and 1 — the monomial curve is a curve)
  • “Use M2's own library: load the BoijSoederberg package and decompose the Betti diagram of res I into pure diagrams (decomposeBetti); also look up hilbertPolynomial and compute it for the twisted cubic (x*z - y^2, y*w - z^2, x*w - y*z).” (→ a positive sum of 3 pure diagrams; 3T + 1, printed - 2*P₀ + 3*P₁. Note the lowercase h: M2's CamelCase doc pointer HilbertPolynomial is an empty stub.)
  • “Compute the primary decomposition of ideal(x^2, x*y). Then work through Macaulay2's official Getting Started example — the rational quartic monomialCurveIdeal(R,{1,3,4}): dimension, degree, Hilbert polynomial, resolution, Betti table.” (→ (x) ∩ (x², y); quartic: degree 4, Hilbert 4T + 1, totals (1, 4, 4, 1) — straight from the tutorial itself; it works over MCP unchanged)
  • “For the family I_k = (x^(k+2) - y, x^(k+3) - z) in QQ[x,y,z], loop over k = 1..6 and tabulate the reduced Groebner basis sizes and the dimensions of R/I_k — then fan the same family out across several subagents as independent batch jobs and collect the results.” (→ sizes k+3, dim 1 throughout; the batch jobs are real parallel M2 processes)
  • “Here is my mycode.m2 file — import it into the session and call myFunction.” (state is kept between calls)

A full genuine transcript of the first prompt's Groebner/resolution ask: examples/groebner-demo.md. How the server itself handles long runs, stops, parallel batches, and errors: examples/example-prompts.md (§§2–5).

Want to benchmark your own model the way a real user types math? examples/latex-decomposition-test.md gives you two ready prompts, a rubric with known-true answers, and what we measured.

The companion macaulay2-skills repo ships machine-verified M2 1.26 know-how as an Agent Skill (npx skills add youngsu-Kim/macaulay2-skills) — it pairs with this server but is not bound to it, and installs into Claude Code, OpenCode, or LM Studio. Measured here on the three Introduction examples: a thinking-disabled model went from ~22 kernel calls with 8 error/retry events to 5 clean calls, and across all four thinking levels the skill held 3–8 calls with zero errors; its Benchmark at a glance table carries the dated, fully-versioned cross-deployment result (full protocol and transcripts in FINDINGS.md). The result generalized to five more model configurations (qwen3-small, DeepSeek-V4-Flash, GLM-5, Kimi, GPT-OSS): 3–5 clean calls each, 32 of 33 graded subanswers correct — the single miss (reading the Hilbert class form -2*P₀ + 3*P₁, by GPT-OSS) became the skill's trap #17 — and globally installed sessions discover the skill with no pointer at all.

From your own code (no LLM required)

The server is an ordinary MCP stdio process, so plain Python can drive the same persistent kernel: examples/drive_with_python.py (uv run python examples/drive_with_python.py) shows state surviving between separate tool calls, times each call client-side, and reports kernel memory two ways — the per-call resident/peak line and the on-demand m2_memory() tool, with a computation that visibly moves the peak.

What the server provides

Nine tools, one shared M2 session:

Tool What it does
m2_evaluate(code, timeout_s?, stop_on_error?, show_memory?) Evaluate M2 code in the persistent session. State carries over between calls; stop_on_error=True halts at the first error instead of running the rest. Results end with a kernel-memory line (resident + peak; swap when paging) unless show_memory=False.
m2_interrupt() Stop a running computation: M2 aborts at a safe checkpoint and keeps all earlier definitions (unlike a timeout, which restarts the kernel).
m2_memory() Report the kernel's resident memory (RSS), peak, swap, pid, and uptime — an unprivileged OS read of the server's own child process; works while a computation runs, so you can watch before deciding to interrupt.
m2_session_reset() Restart the kernel — a clean slate.
m2_help(topic) M2 documentation lookup (help "topic").
m2_run_script(path, timeout_s?) Run a .m2 file in a fresh, isolated M2 process (batch mode; use print for output).
m2_list_packages() List packages currently loaded in the session.
m2_load_package(name, reload?) Load a package (e.g. HilbertSchemes, CommutativeAlgebra).
m2_import_file(path) Import a local .m2 file into the session — newly defined or updated commands are picked up without a restart.

How it works (and the safety limits)

The server keeps one Macaulay2 kernel alive and sends your code to it, exactly like Emacs does. Results, M2 errors, and warnings all come back in the tool output, so your assistant can read and react to them.

  • Version pin. v0.1 supports Macaulay2 1.26.x (the current latest stable at release time) only. Other versions produce a clear error with the upgrade command.
  • Timeout guard. m2_evaluate and m2_run_script are guarded by an author-set default of 120 seconds (raise per call up to 3600) against runaway or infinite computations. A timeout is not an M2 error: the message says so, and explains how to retry with a larger timeout_s (self-contained code, since the session is restarted).
  • Stopping on demand. m2_interrupt sends a real software interrupt (SIGINT): M2 aborts the current computation at a safe checkpoint and the running call returns with error: interrupted — all earlier definitions survive. Only the timeout backstop (for computations that ignore the interrupt) restarts the kernel and loses state.
  • Parallelism. The shared session serializes evaluations by design (one kernel = consistent state; safe for concurrent requests from subagents). Genuine concurrency today: every m2_run_script spawns its own M2 process and multiple jobs run in parallel — e.g. one subagent per slice of an ideal family. First-class job submission (m2_submit_job, status/wait/cancel over a kernel pool) is planned.
  • Errors inform, they don't decide. M2 is a REPL: a runtime error does not stop the remaining lines from running, and there is no rollback. When that happens, the tool result appends an explicit menu — CONTINUE (fix and resend just the failing statement), RESTART (session reset — irreversible, all definitions lost), or INSPECT (see what survived) — and your assistant is instructed to put those choices to you. To prevent the cascade up front, run blocks with stop_on_error=True.
  • Unbalanced input (e.g. a missing }) is rejected up front instead of hanging, and syntax errors that desynchronize the session trigger an automatic restart.
  • OS-access gate. M2 functions that run programs, touch the filesystem, reach the network, or kill the kernel (runProgram, lines, openOut, makeDirectory, installPackage, quit, …) are refused before anything executes — the session stays untouched and the message explains how the user can enable a specific symbol (MACAULAY2_MCP_OS_ALLOW=lines,openOut in the server's environment). The gate is friction against accidents, not a sandbox: M2's value("...") string-evaluation is not blocked (blocking it breaks legitimate metaprogramming). For real isolation, run the server in a container/VM.
  • Audit journal. Every MCP↔M2 exchange is appended to a JSONL file at ./.m2-mcp/session-<UTC>-<pid>.jsonl in your project: the code, M2's output, timings, refused gate attempts, and the MCP client (LLM host) that connected. Relocate with MACAULAY2_MCP_JOURNAL=<dir>, disable with =off; for GUI clients a single central location is recommended, e.g. ~/.local/share/macaulay2-mcp/journals. Add .m2-mcp/ to your .gitignore (the server never reads it back in v0.1; checkpoint/replay is planned). Full guide: Reading the journal.
  • Long results are excerpted. A tool result past ~120 lines / 32 KB comes back as its first 100 and last 10 lines with a notice naming where the full text was saved (the journal); nothing is silently lost, and chats stay readable. Prefer narrowing in M2 (take, drop, smaller examples) over dumping huge results.
  • Memory reporting. Every m2_evaluate result ends with the kernel's resident memory and its peak — pass show_memory=False to omit that line — and m2_memory() answers on demand, including while a long computation is running (a cheap watchdog: watch, then decide whether m2_interrupt is worthwhile). When the kernel starts paging to swap, the line names the swap amount and a note lays out the options; nothing is ever killed automatically. The journal records rss_bytes, peak_rss_bytes and swap_bytes per evaluation regardless of the flag, and a kernel killed by a timeout is probed just before the restart, so its last measurement survives. Peak uses kernel-tracked counters (VmHWM on Linux; footprint's phys_footprint_peak on macOS), not sampling; swap is per-process on Linux, and the system-wide growth since the kernel started on macOS (Apple exposes no unprivileged per-process swap counter).
  • Security. This remains a local tool: your assistant can run arbitrary M2 computation on your machine. Both Claude Code and opencode ask for your approval per tool call by default — keep it that way.

Tested environments

Behaviour (including the golden outputs) is pinned against Macaulay2 1.26 on:

Environment Machine Memory relevant to the swap guidance
Development Apple-silicon Mac, macOS 27 —
CI GitHub Actions ubuntu-latest (24.04) 16 GB
Binder demo Container / hosted VM Low single-digit GB, host-dependent

The OS-access gate

Why some perfectly normal-looking code is blocked, and where this safeguard's honest limits are: the full rationale lives in docs/os-access-gate.md. In one line: M2 functions that run programs, touch the filesystem, reach the network, or kill the kernel are refused before anything executes — and since the check matches words rather than call positions, a plain variable named lines is refused too (rename it, or allowlist the symbol via MACAULAY2_MCP_OS_ALLOW). It is friction against accidents, not a sandbox.

Design principles

  1. Local-first. The server runs on your machine against your Macaulay2 installation. No accounts, no telemetry, no network calls.
  2. Messages inform, never direct. Every message states what it does and whether (and how) it is reversible; we explain decisions instead of telling you to click through them.
  3. Errors carry their own fix. "Not found" ships with install commands; "wrong version" ships with the exact upgrade line; timeouts explain the retry recipe.
  4. Safety limits are explicit. Timeouts are author-set, labeled as such, distinguishable from real errors, and adjustable per call.

Try it in your browser (no install)

Launch on Binder

The companion repo m2-mcp-binder launches a JupyterLab session (first launch ~2–4 min) where a plain Python notebook drives this very server over MCP — a zero-install way to see the tools in action.

Troubleshooting

Symptoms and fixes: docs/troubleshooting.md.

Todos/Plans

  • Remote/HTTP mode (Streamable HTTP + API key) so the server can be hosted and connected to services such as ChatGPT web; deployment recipes (Docker, Cloudflare Tunnel).
  • Multi-user sessions, support for older/newer M2 versions, MCP prompts for common workflows (e.g. "analyze an ideal"), a package availability search, and more — after community feedback.
  • Session-state persistence across restarts.
  • Dedicated dataset to train an LLM.

Feedback

Please file issues and PRs on GitHub. Once the software has stabilized, it is expected to be announced in the Macaulay2 Zulip first.

Sources

All material derives from publicly available sources, listed here for auditability:

  • Macaulay2 documentation and the official Getting Started tutorial — the rational-quartic example in the Examples section is worked straight from the tutorial.
  • Session transcripts — the genuine outputs in examples/ are published in this repo.
  • Benchmark measurements — collected with the companion macaulay2-skills repo; summaries are public there (FINDINGS.md), raw transcripts pending publication.
  • PyPI package macaulay2-mcp and the Binder companion repo — both public.

License

This program is free software under the GNU General Public License v3 or later: use it freely, including commercially — but if you distribute it, or a program built on top of it, the same freedoms must travel with your copy.

Metadata

Release files for macaulay2-mcp 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for macaulay2-mcp 0.1.5
File Size Uploaded Provenance Actions
macaulay2_mcp-0.1.5.tar.gz 646.2 kB With provenance Details for macaulay2_mcp-0.1.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for macaulay2-mcp 0.1.5
File Interpreter ABI Platform Actions
macaulay2_mcp-0.1.5-py3-none-any.whl Python 3 none any Details for macaulay2_mcp-0.1.5-py3-none-any.whl

Total release size: 706.2 kB

Release files / macaulay2_mcp-0.1.5.tar.gz

Download URL macaulay2_mcp-0.1.5.tar.gz
Size 646.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b895b4d5c0ae49b551744506c209ab4db52f19370a203c24e24c68485a6dd64e
BLAKE2b-256 checksum
How to use checksums
6df8ee0a96ec06efb21f6a74b2975a1d4be2a5c72eb6819e299116c0fef0b640
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / macaulay2_mcp-0.1.5-py3-none-any.whl

Download URL macaulay2_mcp-0.1.5-py3-none-any.whl
Size 60.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
84792811a1cc85f93d5253cefbea06f28dad29e15c9b807a0fc2526608bcffc9
BLAKE2b-256 checksum
How to use checksums
641f51af78cbe203ade54ae7cc88417f68fc456e9605c253aa883bad190ddfc4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Security for macaulay2-mcp 0.1.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for macaulay2_mcp-0.1.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page