{
  "markdown": "# Axiom — Advanced Math MCP Server\n\n[![npm](https://img.shields.io/npm/v/axiom-math)](https://www.npmjs.com/package/axiom-math)\n[![License: GPL v3+](https://img.shields.io/badge/License-GPLv3+-blue.svg)](LICENSE)\n[![Node.js >=20](https://img.shields.io/badge/Node.js->=20-green.svg)](https://nodejs.org/)\n[![MCP](https://img.shields.io/badge/Model_Context_Protocol-blue)](https://modelcontextprotocol.io/)\n[![CI](https://github.com/tufantunc/axiom-advanced-math-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/tufantunc/axiom-advanced-math-mcp/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/tufantunc/axiom-advanced-math-mcp/graph/badge.svg)](https://codecov.io/gh/tufantunc/axiom-advanced-math-mcp)\n\nExact symbolic and numerical mathematics for LLMs — a real computer algebra\nsystem (Giac/Xcas) behind the Model Context Protocol, and behind a shell\ncommand. Published as **`axiom-math`**.\n\n<!-- Absolute raw URL on purpose. npm rewrites relative README paths to\n     github.com/.../blob/HEAD/..., which serves text/html for a .gif and would\n     render as a broken image on the package page. -->\n\n![Axiom catching a wrong derivative, then computing an exact integral](https://raw.githubusercontent.com/tufantunc/axiom-advanced-math-mcp/main/docs/demo.gif)\n\n## Quick start\n\nAs a CLI, straight away:\n\n```bash\nnpx -y axiom-math compute 'integrate(sin(x)^3,x)'   # -cos(x)+cos(x)^3/3\nnpx -y axiom-math verify 'diff(x^3,x) = 3*x^2'      # exit 0 — it holds\n```\n\nAs an MCP server, in any client's config:\n\n```json\n{ \"command\": \"npx\", \"args\": [\"-y\", \"axiom-math\"] }\n```\n\nAs an agent skill — drop in [skills/axiom-math/SKILL.md](skills/axiom-math/SKILL.md),\nwhich teaches an agent the three commands and their exit codes.\n\n## Why Axiom?\n\nLLMs often make calculation errors, especially with symbolic math, exact fractions, and multi-step problems. Axiom provides **verified, exact results** through two layers:\n\n- **math.js** — Fast numerical evaluation (arithmetic, trigonometry, matrices)\n- **Giac/Xcas WASM** — Symbolic computation (calculus, algebra, equation solving)\n\n### Benchmark Results (GLM-5.1, May 2026)\n\n| Dataset           | Baseline | +MCP    | Delta     |\n| ----------------- | -------- | ------- | --------- |\n| GSM8K (100)       | 96.0%    | 98.0%   | +2.0%     |\n| MATH L3 (50)      | 70.0%    | 80.0%   | +10.0%    |\n| MATH L4 (50)      | 50.0%    | 62.0%   | +12.0%    |\n| MATH L5 (50)      | 38.0%    | 52.0%   | +14.0%    |\n| CAS-quick (60)    | 55.0%    | 70.0%   | +15.0%    |\n| Omni-MATH ≥7 (50) | 0.0%     | 0–4%    | (ceiling) |\n\n**Key insights:**\n\n- Phase 0 grader (LaTeX/Unicode normalization + symbolic equivalence) is the dominant value driver across all datasets\n- CAS-quick lifted from 26.7% (April pre-grader) to 70% (post-grader) — the biggest single jump\n- Omni-MATH ≥7 is at ceiling for current LLM+CAS setups; needs fundamentally different approaches (Lean/Coq, fine-tuning, RAG)\n\nFull results: [`benchmark/results/`](benchmark/results/) and [`docs/superpowers/specs/`](docs/superpowers/specs/) (per-phase analysis)\n\n---\n\n## Features\n\nAxiom exposes **3 MCP tools**. Almost everything flows through `compute`, a single gateway that parses a CAS-style problem string and routes it to the right internal engine — so callers learn one tool, not dozens.\n\n| Tool      | Purpose                                                                                                                                |\n| --------- | ------------------------------------------------------------------------------------------------------------------------------------- |\n| `compute` | Solve any math problem. Pass a CAS-style string (`solve(...)`, `diff(...)`, `det([[...]])`, `C(10,3)`, `2+3*sin(pi/4)`) or any Giac/Xcas expression. |\n| `verify`  | Independently check a mathematical claim (identity, solution, or computation) via symbolic and/or numeric methods.                    |\n| `plot`    | Render a 2D function graph as an SVG image.                                                                                            |\n\n### What `compute` covers\n\n`compute` recognizes CAS-style verbs and dispatches across these domains. Anything it doesn't recognize falls through to raw Giac/Xcas evaluation.\n\n| Domain                  | Verbs / examples                                                                                                                                              |\n| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Arithmetic & units      | `2+3*sin(pi/4)`, `100 km/h to m/s`                                                                                                                             |\n| Equation solving        | `solve(x^2-4=0, x)`, `csolve(...)` (complex), `solve_system([x+y=5, x-y=1], [x,y])`                                                                            |\n| Calculus                | `diff`, `int`, `limit`, `taylor`, `desolve` (ODEs of any order, and linear constant-coefficient systems)                                                                                                              |\n| Multivariable calculus  | `gradient`, `hessian`, `jacobian`, `divergence`, `curl`, `partial`, `iint`/`iiint` (multiple integrals), `critical_points`, `lagrange`, `tangent_plane`, `directional_derivative` |\n| Algebra                 | `factor`, `simplify`, `expand`, `partfrac`                                                                                                                     |\n| Linear algebra          | `det`, `inv`, `eigenvals`, `eigenvects`, `rref`, `rank`, `tran`, `ker`, `qr`, `lu`, `cholesky`, `svd`, `norm`, `cond`                                          |\n| Number theory           | `ifactor`, `isprime`, `euler`, `analyze`                                                                                                                       |\n| Combinatorics           | `C(n,k)`, `P(n,k)`, `stirling`, `bell`, `catalan`, `derangements`, `multinomial`                                                                               |\n| Probability             | `binomial`, `normal`, `poisson`, `geometric`, `hypergeometric`, `chi_square`, `student_t`, `f_distribution`, `beta`, `exponential`                            |\n| Hypothesis testing      | `t_test` (one/two/paired), `anova`, `chi_square_test`                                                                                                          |\n| Numerical methods       | `newton`, `bisection`, `secant`, `romberg`, `simpson`                                                                                                          |\n| 2D geometry             | `distance`, `midpoint`, `slope`, `area_*`, `perimeter`, `circumference`, `line_intersection`, `point_line_distance`, `angle_between_lines`                     |\n| 3D geometry             | `distance3d`, `midpoint3d`, `dot`, `cross`, `vector_norm`, `angle_vectors`, `plane_from_points`, `point_plane_distance`, `line_plane_intersection`, `plane_plane_angle`, `line_line_distance`, `volume_tetrahedron`, `volume_sphere`, `volume_parallelepiped` |\n| Transforms & series     | `laplace`, `ilaplace`, `fourier`/`fft`/`ifft`, `sum`, `product`                                                                                                |\n| Exact values            | `to_exact`, `to_decimal`, `simplify_fraction`                                                                                                                  |\n| Regression & sequences  | `linear_regression`/`fit`, `polynomial_regression`, `sequence` (pattern identification)                                                                       |\n\n---\n\n## Installation\n\nThe package is [`axiom-math`](https://www.npmjs.com/package/axiom-math) on npm.\nNothing to install for normal use — `npx` fetches and caches it:\n\n```bash\nnpx -y axiom-math compute '2+2'\n```\n\nOr install it so the `axiom-math` command is on your PATH:\n\n```bash\nnpm install -g axiom-math\n```\n\n**Node.js >= 20 required.** The first run downloads about 3.8 MB (the CAS engine\ncompiled to WebAssembly) and takes a few seconds; later runs come from the npx\ncache.\n\n### From source\n\nFor contributors, or to run a modified build:\n\n```bash\ngit clone https://github.com/tufantunc/axiom-advanced-math-mcp.git\ncd axiom-advanced-math-mcp\nnpm install\nnpm run build\n```\n\n### Docker\n\n```bash\n# Build and run\ndocker-compose -f docker/docker-compose.yml up -d\n\n# Check logs\ndocker-compose -f docker/docker-compose.yml logs -f\n\n# Stop\ndocker-compose -f docker/docker-compose.yml down\n```\n\n---\n\n## Usage\n\n### CLI (STDIO Transport)\n\n```bash\n# Run with stdio transport (default)\nnpm start\n\n# Development mode\nnpm run dev\n```\n\n**Claude Desktop integration:**\n\n```json\n// ~/Library/Application Support/Claude/claude_desktop_config.json\n{\n  \"mcpServers\": [\n    {\n      \"name\": \"axiom-math\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"axiom-math\"]\n    }\n  ]\n}\n```\n\nRunning from a local checkout instead of npm — point `args` at the built entry\npoint:\n\n```json\n\"args\": [\"/path/to/axiom-advanced-math-mcp/dist/cli.js\"]\n```\n\n### Command line\n\nThe same binary works as a one-shot CLI, so agents can use it as a skill with no\nMCP configuration. With no arguments it is the MCP server; with a subcommand it\nruns one computation and exits.\n\n```bash\nnpx -y axiom-math compute 'integrate(sin(x)^3,x)'\nnpx -y axiom-math compute -q 'solve(x^2-4=0,x)'     # {-2, 2}\nnpx -y axiom-math verify 'sin(x)^2+cos(x)^2 = 1'    # exit 0 if true\nnpx -y axiom-math plot 'sin(x)' -o wave.svg\necho 'diff(x^3,x)' | npx -y axiom-math compute -q   # 3*x^2\n```\n\n| Flag | Meaning |\n| --- | --- |\n| `-q` | print one value only, for scripting |\n| `--json` | structured output |\n| `--latex` | LaTeX-focused text (`compute` only) |\n| `-h`, `--help` | usage, or usage for a subcommand |\n\nExit codes: `0` success · `1` tool or usage error · `2` `verify` checked the\nclaim and it is **false**.\n\n`2` is a mathematical verdict, so a claim that never got checked does not use\nit: one that fails to parse, or that the CAS cannot evaluate, exits `1` with\nnothing on stdout. `axiom-math verify '...' && ...` therefore never reads a\nsyntax error as a disproof.\n\nA ready-to-use agent skill is in [skills/axiom-math/SKILL.md](skills/axiom-math/SKILL.md).\n\n### HTTP Transport\n\n```bash\n# Start HTTP server (default: http://127.0.0.1:3000)\nnpm run start:http\n\n# Development HTTP\nnpm run dev:http\n```\n\nThe HTTP transport is **stateless**: every `POST /mcp` is handled independently,\nno `Mcp-Session-Id` is issued, and no session state is kept between requests.\nThis server sends no server-initiated notifications, so nothing is lost — and it\nscales horizontally with no shared state.\n\n| Method | Path      | Behaviour                                              |\n| ------ | --------- | ------------------------------------------------------ |\n| POST   | `/mcp`    | Handles a JSON-RPC message                             |\n| GET    | `/mcp`    | `405` — no SSE stream is offered                       |\n| DELETE | `/mcp`    | `405` — there are no sessions to terminate             |\n| GET    | `/health` | `200` when ready, `503` when the CAS engine is not     |\n\n> **Security:** there is no authentication and no rate limiting. The default\n> bind address is `127.0.0.1`, but `docker/docker-compose.yml` sets\n> `MCP_HOST=0.0.0.0`. If you expose the port, put it behind a reverse proxy that\n> authenticates and rate-limits — [`docker/reverse-proxy/`](docker/reverse-proxy/)\n> is a working, tested one (nginx + basic auth + per-client concurrency cap,\n> with the app publishing no port of its own).\n> [SECURITY.md](SECURITY.md) documents the full posture — what is protected,\n> what is not, and how to report a vulnerability.\n>\n> `POST /mcp` also validates the `Host` header against an allowlist\n> (`localhost`, `127.0.0.1`, `[::1]` by default) to block DNS rebinding — a\n> malicious page can make a victim's browser resolve an attacker domain to\n> `127.0.0.1` and reach this server through it. If you reach the server by a\n> LAN address, hostname, or reverse-proxy domain other than loopback, set\n> `MCP_ALLOWED_HOSTS` or every `POST /mcp` request will get a `403`. This\n> check is **not** authentication — it only constrains which host names may\n> reach the endpoint, nothing about who is asking.\n\n**Environment variables:**\n\n| Variable                 | Default     | Description                                        |\n| ------------------------ | ----------- | --------------------------------------------------- |\n| `MCP_PORT`               | `3000`      | HTTP server port                                    |\n| `MCP_HOST`               | `127.0.0.1` | HTTP server host                                    |\n| `MCP_ALLOWED_HOSTS`      | loopback only (`localhost`, `127.0.0.1`, `[::1]`) | Comma-separated `Host` header allowlist for `POST /mcp` (DNS-rebinding protection). An explicit value replaces the default rather than extending it. |\n| `AXIOM_EVAL_TIMEOUT_MS`  | `10000`     | Per-evaluation timeout, in milliseconds. Bounds one CAS call **and** one js-compute call (arbitrary-precision integer work, arithmetic, plot sampling), so lowering it tightens both. |\n| `AXIOM_INTEGRATION_BUDGET_MS` | `max(3 × AXIOM_EVAL_TIMEOUT_MS, 30000)` | Wall-clock budget for one multi-call numerical routine (integration, root finding). Bounds the SUM of CAS calls, where `AXIOM_EVAL_TIMEOUT_MS` bounds one. |\n| `AXIOM_JS_COMPUTE_HEAP_MB` | `512` | Heap ceiling for the child process that runs arbitrary-precision integer work and mathjs evaluation. Exceeding it fails the computation that caused it — calls queued behind it are re-sent to the replacement worker — and leaves the server up. |\n| `AXIOM_COMPUTE_HYGIENE`  | unset       | Set to `1` to enable compute output post-processing |\n\nOne bound is not configurable: a result over **100,000 characters** is refused\nrather than returned, so an expression like `1:2000000` reports its element count\ninstead of shipping 24 million characters into the caller's context.\n\nSome inputs are refused rather than answered, because any answer would be\nmeaningless. Arithmetic that evaluates to `NaN` (such as `0/0`) is an error; an\ninfinite result is returned with a warning, because a true infinity and a value\nthat overflowed the range of a double are indistinguishable once computed. A\nt-test needs variation in whatever it actually tests — `paired_t` compares the\ndifferences, so it is those that must vary, while Welch's `two_sample_t` needs\nonly one of the two samples to vary. A contingency table needs non-negative\ncounts, no all-zero row or column, rows of equal length, and more than one row\nand column. A one-way ANOVA needs some within-group variation and more\nobservations than groups. And any of these is refused when the values are large\nenough that the statistic itself overflows to infinity, because an overflowed\nstatistic is no longer the statistic. A numerical method is refused when its\nexpression does not depend on the variable it is solved or integrated over, or\nwhen the CAS answers symbolically rather than with a number — previously the\nleading term of that symbolic answer was reported as the result.\n\nA system of differential equations written as a list — `desolve([y'=z, z'=-y],\nx)` — is rewritten into the matrix form the CAS solves and returns a solution for\nevery function. The components come back in the order the equations were written,\nand the JSON envelope names them in a `components` field, because\n`[[cos(x),-sin(x)]]` is not interpretable without it.\n\nInitial conditions must be given for every function, at the same point, or not at\nall — a partial set is refused rather than ignored. Also refused, each with its\nown reason: a system that is not linear in the unknown functions; coefficients\nthat depend on the independent variable; a derivative of order above one (rewrite\n`y''=z` as `y'=w, w'=z`); more than nine equations; and a system the CAS cannot\nfinish.\n\nThe infinite-result rule covers arithmetic evaluation. A symbolic `+infinity`\nfrom the CAS routes — a limit, a divergent integral — is a normal answer and\ncarries no warning.\n\n### MCP Inspector\n\n```bash\nnpm run inspect\n```\n\n---\n\n## Tool Reference\n\n### compute\n\nThe single gateway for all math. Pass a CAS-style problem string; the router parses it and dispatches to the right engine.\n\n| Parameter   | Type                                       | Description                                                                                                   |\n| ----------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |\n| `problem`   | string (**required**)                      | CAS-style problem, e.g. `solve(x^2-4=0, x)`, `diff(x^3, x)`, `det([[1,2],[3,4]])`, `gradient(x^2+y^2, [x,y])`. |\n| `domain`    | `real` \\| `complex` \\| `numeric` \\| `exact` | Domain hint (default `real`). `complex` → complex solutions; `numeric` → force numerical methods; `exact` → exact symbolic form. |\n| `precision` | integer 1–50                               | Decimal places (default 10).                                                                                  |\n| `format`    | `text` \\| `latex` \\| `json`                | Output format (default `text`). `json` returns a structured envelope.                                         |\n\n**Examples:**\n\n```json\n{ \"problem\": \"solve(x^2 - 5*x + 6 = 0, x)\" }\n{ \"problem\": \"int(x^2*sin(x), x)\", \"format\": \"latex\" }\n{ \"problem\": \"lagrange(x*y, x+y, 1, [x, y])\" }\n{ \"problem\": \"volume_tetrahedron([0,0,0],[1,0,0],[0,1,0],[0,0,1])\" }\n{ \"problem\": \"binomial cdf n=10 k=3 p=0.5\", \"format\": \"json\" }\n```\n\n### verify\n\nIndependently check a mathematical claim. Useful as a second, tool-grounded opinion on a result the model produced.\n\n| Parameter | Type                               | Description                                                                                                          |\n| --------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- |\n| `claim`   | string (**required**)              | The claim, e.g. `\"sin(x)^2 + cos(x)^2 = 1\"` (identity), `\"x=2 satisfies x^2-4=0\"` (solution), `\"diff(x^3, x) = 3*x^2\"` (computation). |\n| `method`  | `numeric` \\| `symbolic` \\| `both`  | Verification method (default `both`).                                                                                |\n\nReturns four fields: `verified`, `evaluated`, `confidence`, and `checks_performed`.\n\n`evaluated` is the one to read first. It is `false` when no check produced a\nusable answer — the claim did not parse, or the CAS could not evaluate it — in\nwhich case `verified: false` means \"unknown\", not \"refuted\". Treating the two as\nthe same turns a syntax error into a disproof.\n\n### plot\n\nRender a 2D function as an SVG image.\n\n| Parameter        | Type                  | Description                                  |\n| ---------------- | --------------------- | -------------------------------------------- |\n| `expression`     | string (**required**) | Function to plot, e.g. `\"sin(x)\"`, `\"x^2 - 3*x + 1\"`. |\n| `variable`       | string                | Variable name (default `x`).                 |\n| `x_min`, `x_max` | number                | X range (default −10 … 10).                  |\n| `y_min`, `y_max` | number                | Y range (auto-detected if omitted).          |\n| `width`, `height`| number                | Image size in px (default 600 × 400).        |\n| `title`          | string                | Optional chart title.                        |\n\nReturns a base64-encoded SVG image (axes, grid, labels, asymptote detection) plus a text caption.\n\n### Prompts\n\nThe server also registers guided MCP **prompts** that chain `compute`/`verify` for multi-step workflows: `solve-step-by-step`, `analyze-function`, `verify-identity`, `convert-units`, `analyze-dataset`, `solve-ode-system`, and `regression-workflow`.\n\n---\n\n## Run Benchmarks\n\nDefault production recipe (grader-v2 included automatically):\n\n```bash\ncd benchmark\nnpm install\n\n# Set provider API key (one of):\nexport ZAI_API_KEY=...\nexport ANTHROPIC_API_KEY=...\nexport OPENROUTER_API_KEY=...\n\n# Run benchmarks (provider defaults from --zai/--anthropic/--openrouter flags)\nnpm run cas:quick:zai      # CAS-quick (60 problems, ~30 min)\nnpm run gsm8k:quick:zai    # GSM8K-quick (100 problems, ~30 min)\nnpm run math:quick:zai     # MATH L3-L5 quick (150 problems, ~75 min)\n```\n\n### Optional ablation features (off by default)\n\n- `--features=output-hygiene` — tool output post-processing (Unicode normalize, optional simplify, silent-failure warning). Marginal +1pp on CAS in live measurement.\n- `--features=grader-v3` — equation-RHS extraction + bare-comma-list set match. Marginal +1pp on CAS.\n- `--features=self-consistency` — N=3 majority voting (variance reduction; 3× cost; no accuracy gain on CAS).\n\nExample:\n\n```bash\nnpm run cas:quick:zai -- --features=output-hygiene,grader-v3\n```\n\nSee `docs/superpowers/specs/2026-05-*-results.md` for live ablation analysis of every flag.\n\n### What we tried that didn't work\n\nThis project went through extensive ablation across five phases (Phase 0–4). The following experimental approaches were tested live and rejected:\n\n- **Phase 1: Structured JSON output with `\\boxed{}` trailers** — model paraphrased boxed content into LaTeX style, breaking answer extraction. Net regression on CAS.\n- **Phase 2: 8K token budget (`tokens-8k`)** — gave the model more room to wander rather than recovering from truncation. Net regression −6.7pp on CAS.\n- **Phase 3: Self-consistency for accuracy** — N=3 voting did not lift accuracy (Wang et al. literature gain not reproducible on CAS); kept as a methodology tool for variance reduction only.\n- **Phase 4: Olympiad-specific scaffolding prompt** — engagement improved (no-tool-call rate 84% → 74%) but accuracy stayed at 0%. Olympiad-tier problems are out of scope for prompt-engineering interventions.\n\nEach phase's per-problem analysis is in `docs/superpowers/specs/2026-05-*-results.md`. The honest documentation of failures is preserved as a project archive.\n\n---\n\n## Architecture\n\n### Compute gateway → router → domain handlers\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│              MCP Protocol Layer (stdio / HTTP)               │\n└─────────────────────────────────────────────────────────────┘\n                              │\n        ┌─────────────────────┼─────────────────────┐\n        ▼                     ▼                     ▼\n   ┌─────────┐          ┌──────────┐          ┌─────────┐\n   │ compute │          │  verify  │          │  plot   │\n   └────┬────┘          └──────────┘          └─────────┘\n        │  route() → extract args → dispatch\n        ▼\n┌─────────────────────────────────────────────────────────────┐\n│  Domain handlers: calculus, algebra, matrix, multivariable,  │\n│  geometry / geometry3d, combinatorics, probability,          │\n│  hypothesis testing, number theory, numerical methods, …     │\n└─────────────────────────────────────────────────────────────┘\n        │                     │                     │\n        ▼                     ▼                     ▼\n┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│   math.js    │     │  Giac/Xcas   │     │ Exact engine │\n│ (numerical)  │     │  (symbolic)  │     │ (fractions)  │\n└──────────────┘     └──────────────┘     └──────────────┘\n```\n\n`compute` never asks the caller to pick a handler. The router matches the problem string against ordered rules, the matching extractor parses arguments, and the dispatcher calls the corresponding domain handler. Unmatched input falls through to raw Giac/Xcas.\n\n### Response Format\n\nText-format responses are line-structured so LLMs (and the benchmark grader) can extract answers reliably:\n\n```json\n{\n  \"content\": [\n    { \"type\": \"text\", \"text\": \"Result: 400/11\" },\n    { \"type\": \"text\", \"text\": \"Decimal: 36.3636363636\" },\n    { \"type\": \"text\", \"text\": \"LaTeX: \\\\frac{400}{11}\" },\n    { \"type\": \"text\", \"text\": \"\" },\n    { \"type\": \"text\", \"text\": \"The answer is 400/11 (≈ 36.36)\" }\n  ],\n  \"isError\": false\n}\n```\n\n---\n\n## Benchmark Results\n\n### Datasets\n\n| Dataset      | Problems | Difficulty                     |\n| ------------ | -------- | ------------------------------ |\n| GSM8K        | 100      | Grade school math (arithmetic) |\n| MATH L3      | 50       | High school math               |\n| MATH L4      | 50       | Advanced high school math      |\n| MATH L5      | 50       | Olympiad-level math            |\n| Omni-MATH ≥7 | 50       | Expert-level math              |\n\n### How to Run\n\nSee [Run Benchmarks](#run-benchmarks) above for the commands. In short, from\nthe repository root:\n\n```bash\nnpm run benchmark:zai         # quick sample, GLM-5.1\nnpm run benchmark:full:zai    # all datasets\nnpm run benchmark:l5:zai      # one difficulty tier\n```\n\nSwap `:zai` for `:openrouter` to change provider. The `benchmark/` directory is\na separate npm project with finer-grained scripts (`cas:quick:zai`,\n`gsm8k:quick:zai`, …); `npm run benchmark:*` from the root delegates to them.\n\n**Environment variables:**\n\n| Variable             | Required for        | Description             |\n| -------------------- | ------------------- | ----------------------- |\n| `ZAI_API_KEY`        | zai provider        | Your z.ai API key       |\n| `OPENROUTER_API_KEY` | openrouter provider | Your OpenRouter API key |\n\n---\n\n## Development\n\n### Scripts\n\n| Command                    | Description                                          |\n| -------------------------- | ---------------------------------------------------- |\n| `npm run build`            | Compile TypeScript to `dist/` and copy the WASM asset |\n| `npm start`                | Run STDIO server                                     |\n| `npm run dev`              | Run in development mode (tsx)                        |\n| `npm run start:http`       | Run HTTP server                                      |\n| `npm run dev:http`         | Run HTTP server in dev mode                          |\n| `npm test`                 | Unit tests — no build required                        |\n| `npm run test:integration` | Integration tests — builds first, exercises `dist/`   |\n| `npm run test:watch`       | Unit tests in watch mode                             |\n| `npm run test:coverage`    | Unit tests with coverage report                      |\n| `npm run typecheck`        | Type-check without emitting                          |\n| `npm run lint`             | Lint with oxlint                                     |\n| `npm run lint:fix`         | Auto-fix linting issues                              |\n| `npm run format`           | Format with Prettier                                 |\n| `npm run format:check`     | Check formatting without writing                     |\n| `npm run inspect`          | Open the MCP Inspector against the stdio server      |\n\n### Testing\n\nThe suites are split. `npm test` runs the unit tests and needs no build;\n`npm run test:integration` builds first and exercises the packaged `dist/`\noutput, so it catches things the unit suite cannot — the shipped binary's\nargument dispatch, the MCP handshake, exit codes.\n\n```bash\nnpm test                  # unit\nnpm run test:integration  # integration (runs npm run build first)\nnpm run test:watch        # unit, watch mode\nnpm run test:coverage     # unit, with coverage\n```\n\n**Test coverage:** unit + integration suite, 100% pass rate. Run `npm test` for the current count — it changes too often to keep a number here in sync.\n\n### WASM Build (Giac)\n\n```bash\nnpm run build:giac:wasm\n\n# Build a specific upstream ref instead of master\nGIAC_REF=v1.9.x npm run build:giac:wasm\n```\n\nThis runs `scripts/build-giac-wasm.sh`, which builds\n`docker/build-giac-wasm/Dockerfile` with `docker build` (no Compose file\ninvolved) and writes `giac.wasm.js` straight into `src/server/giac/` — no\nmanual copy step needed. Requires Docker Desktop (or another Docker daemon)\nrunning locally. Per-task build logs land under `logs/giac-build/`.\n\n---\n\n## Contributing\n\nBug reports and pull requests are welcome — see\n[CONTRIBUTING.md](CONTRIBUTING.md) for the setup, the checks CI runs, and the\nfew things about this codebase that are not obvious from reading it.\n\n---\n\n## License\n\n**GNU General Public License v3.0 or later** — see [LICENSE](LICENSE).\n\nAxiom embeds [Giac/Xcas](https://xcas.univ-grenoble-alpes.fr/), which is\nGPL-3.0-or-later, so the combined work carries the same license. Details and\nattribution: [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).\n\n### Does the GPL affect my agent?\n\n**No.** Your agent talks to Axiom over the Model Context Protocol — a separate\nprocess, over stdio or HTTP. Separate programs communicating at arm's length\nare not a combined work, so running Axiom alongside your own agent puts no\nlicense obligation on your code, whatever license it uses. Running the software\nis unrestricted under the GPL, including running it as a service.\n\nThe copyleft terms apply when you **redistribute** Axiom itself — shipping it\n(modified or not) inside a product you hand to someone else. In that case, pass\nalong the source under GPL-3.0 and keep the notices intact.\n",
  "bytes": 29512,
  "sha": "8c877db853f447b5e6ac0d59968b97ee3f909d30a68fbfd1df7f1dfcf2b24f1e",
  "repo_slug": "tufantunc/axiom-advanced-math-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_tufantunc_axiom_math_000f2e52/readme"
}