Skip to main content
Glama
README.md
# gauss-mcp

[![Licence](https://img.shields.io/badge/licence-MIT-2c5f9e)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10+-2c5f9e)](https://www.python.org/)
[![Platform](https://img.shields.io/badge/platform-Windows-2c5f9e)](https://github.com/merwanroudane/mcp_gauss)
[![GAUSS](https://img.shields.io/badge/GAUSS-26-c05621)](https://www.aptech.com/)

Drive **GAUSS** from Python, and expose it to LLM clients over the Model
Context Protocol.

Author: Dr Merwan Roudane

Built and tested against **GAUSS 26.1.1** on Windows.

## Why this exists

Aptech publishes a [reference for AI assistants](https://github.com/aptech/gauss-llm-reference)
so they write better GAUSS, but writing is not running: an assistant that cannot
execute the code never learns whether it worked or what the numbers were. This
connects an assistant to a real GAUSS installation, so the results come from
GAUSS rather than from the model.

## How it drives GAUSS

Through `tgauss`, the terminal build that ships with an ordinary GAUSS
installation — not the GAUSS Engine, which is richer but needs a separate
licence key from Aptech.

Each call is its own `tgauss` process, so nothing would normally carry over.
The workspace is saved on the way out and restored on the way in, which makes a
run of calls behave like one continuous session: a matrix built in one call is
still there in the next.

## Install

The distribution is **`gauss-lang-mcp`** on PyPI: plain `gauss-mcp` was already
taken by an unrelated package about import workflows, nothing to do with the
Aptech language. The import name stays `gauss_mcp`.

```bash
pip install "gauss-lang-mcp[pandas]"
```

GAUSS is found automatically under `C:\gauss*` and `C:\Program Files\gauss*`.
Set `GAUSS_HOME` to choose between installations.

## Library use

```python
from gauss_mcp import Gauss

with Gauss() as g:
    g.run("""
        rndseed 90210;
        n = 400;
        x = rndn(n, 1);
        y = 1.25 + 0.8*x + 0.3*rndn(n, 1);
        des = ones(n,1)~x;
        bhat = invpd(des'des)*des'y;
    """)
    print(g.get_matrix("bhat"))     # [[1.2489...], [0.8043...]]
```

Values cross as CSV rather than as printed text, so they keep full double
precision instead of GAUSS's display rounding:

```python
g.run("pi_like = 3.14159265358979;")
g.get_scalar("pi_like")          # 3.14159265358979, every digit
```

pandas both ways:

```python
frame = g.to_dataframe(["x", "y"])
g.from_dataframe(frame)
```

## MCP server use

```json
{
  "mcpServers": {
    "gauss": { "command": "gauss-lang-mcp" }
  }
}
```

### Tools

| Tool | Purpose |
|---|---|
| `gauss_status` | Where GAUSS is, its version, what the workspace holds |
| `run_gauss_code` | **Main tool.** Run GAUSS code and return what it printed |
| `list_symbols` | Every symbol with its type and dimensions |
| `describe_symbol` | Type and shape of one symbol |
| `get_matrix` | Read a matrix out at full precision |
| `put_matrix` | Create a matrix from numbers given in the conversation |
| `read_csv` / `write_csv` | Move data between files and the workspace |
| `clear_workspace` | Start again from empty |

## Errors

GAUSS reports its own code, message and line, and those are passed through:

```text
GaussError: G0025: Undefined symbol: 'no_such_thing' on line 2
```

The line refers to **your** code. The workspace restore is prepended to every
generated program, which shifts GAUSS's own numbering by a line; that offset is
corrected before you see it.

## Behaviour worth knowing

Characteristics of GAUSS and of `tgauss` that this package handles for you,
each confirmed against a live installation rather than assumed.

- **The exit code is always 0**, whether the program succeeded or died. It
  carries nothing, so errors are read from stderr instead.
- **stdout is clean.** The banner and job header go to stderr, so the program's
  own output needs no filtering.
- **GAUSS compiles before it runs.** An undefined symbol anywhere means nothing
  executed and no output appears. A runtime error leaves the output produced up
  to that point, followed by "Program execute failed".
- **Symbol names ignore case.** `X` and `x` are the same symbol, so assigning to
  one overwrites the other. This surprises people arriving from R or Python.
- **The child must not inherit stdin.** Under MCP, the server's stdin is the
  JSON-RPC stream; a `tgauss` that inherited it would read the protocol itself.
  Every subprocess call detaches stdin.
- **Restoring a workspace uses `use`, not `loadall`.** `saveall` writes a `.gcg`
  and `use <name>;` must be the first statement of the program that reads it.

## Tests

```bash
python tests/test_offline.py   # 10 tests, no GAUSS needed
python tests/test_live.py      # 24 tests, drives a real installation
```

## Licence

MIT. Copyright (c) 2026 Merwan Roudane.

TDQS

A3.7/5.0

Scored across 9 tools

Disambiguation4/5

Most tools are clearly distinct: listing, describing, getting, putting, reading, writing, status, clearing, and executing. The main overlap is between gauss_status reporting what the workspace holds and list_symbols listing every symbol, but the descriptions are clear enough to prevent serious confusion.

Naming Consistency4/5

The overwhelming majority of tools follow a consistent verb_noun pattern such as list_symbols, put_matrix, read_csv, and run_gauss_code. The one outlier is gauss_status, which lacks a verb and breaks the otherwise predictable pattern.

Tool Count5/5

With nine tools, the server is well-scoped for a GAUSS workspace MCP. Each tool covers a distinct need—inspection, data exchange, file I/O, status, reset, and arbitrary code execution—without feeling bloated or thin.

Completeness4/5

The server covers the core GAUSS workflow well: list and describe symbols, get and put matrices, import/export CSV, check status, clear the workspace, and run arbitrary GAUSS code. There is no dedicated delete-symbol or rename tool, but run_gauss_code can handle those cases, so the gap is minor.

Maintenance

ActivityMaintained
ResponsivenessNo issues