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

A small MCP server that turns a shared [Ollama](https://ollama.com) box into a team
resource for [Claude Code](https://claude.com/claude-code) or any MCP client. It
exposes typed grunt-work tools plus delegated, read-only repository exploration that
runs an agent loop on the box's own models, so bulk reading and first-pass analysis
cost zero frontier tokens.

## Why

Frontier tokens are precious, and spending them on bulk summaries or first-pass code
reading is a waste. The obvious fix (a proxy that reroutes your coding agent to a
local model) breaks subscription billing and swaps your good model for a weaker one on
everything. This takes the other route: your frontier agent keeps driving on your
subscription and calls this server as a tool for the cheap work.

- Reasoning, edits, and final judgement stay on the frontier model.
- Summaries, classification, and first-pass exploration go to the local box.
- The server never touches your agent's own API endpoint or auth.

It is not faster than a frontier model. It is free, so frontier time is spent only
where judgement matters.

## How it works: two channels

```
You  ·  Claude Code   (your subscription, untouched)
        │  MCP over HTTP  (:8434)
        ▼
bigmac-mcp:  this server on the Ollama box (run it as a service)
   ├─ ask · summarize · classify · models · usage   →  Ollama (localhost:11434)
   └─ explore_start / status / result   (delegated repo exploration)
            └─ OpenCode headless: read-only agent loop on the box,
               local model greps and reads, returns a cited synthesis
```

**Control channel (always on):** the MCP carries only the request and the result.
`ask` / `summarize` / `classify` send prompt text; nothing else moves.

**Data channel (only when delegating):** code ships out of band via the sync script
(`tar` over SSH), not through the MCP. Only tracked and unignored files are sent,
minus a secret deny-list and symlinks. It lands as a wipe-and-replace snapshot on the
box and is auto-purged after 7 days.

## Tools

| Tool | What it does |
|---|---|
| `ask(prompt, model?, think?, system?)` | One-shot generation on the local model |
| `summarize(text, style?)` | Summarise text locally |
| `classify(items[], labels[])` | Bulk classification, JSON-validated |
| `models()` | Live model inventory and Ollama version |
| `usage()` | Token accounting since daemon start (what stayed off your cloud budget) |
| `explore_start(workspace, question, model?, think?)` | Start a delegated exploration job, returns a job id |
| `explore_status(job_id)` / `explore_result(job_id)` | Poll, then fetch the cited synthesis |
| `workspaces()` | List synced workspaces |

## Requirements

- A box (macOS or Linux) with enough GPU/RAM for your chosen models. We run it on a
  Mac Studio (M3 Ultra, 96 GB).
- [Ollama](https://ollama.com) on that box.
- Python 3.12+ and [uv](https://docs.astral.sh/uv/) on that box.
- For delegation only: the [OpenCode](https://opencode.ai) CLI on the box, and SSH
  access from your workstation to the box.

## Setup

### 1. Ollama and models (on the box)

Install Ollama, then pull at least one tool-capable model (delegation needs tool
calling; the lightweight tools do not):

```bash
ollama pull qwen3.6:35b-a3b-nvfp4     # example; any tool-capable model works
ollama pull qwen2.5-coder:32b
```

Ollama listens on `11434`. Raise its context window, or agent loops forget their own
tool history:

```bash
export OLLAMA_CONTEXT_LENGTH=32768    # 16k minimum for agent loops; higher is better
```

### 2. Get the server (on the box)

```bash
git clone https://github.com/TrueNorthIT/bigmac-mcp
cd bigmac-mcp
uv sync
```

### 3. Run it (development)

```bash
uv run python -m bigmac_mcp.server    # streamable HTTP on 0.0.0.0:8434/mcp
```

### 4. Run it as a service (macOS LaunchDaemon)

Edit `deploy/com.bigmac.mcp.plist` (replace the `bigmac` user and the two paths for
your box), then:

```bash
sudo cp deploy/com.bigmac.mcp.plist /Library/LaunchDaemons/
sudo cp deploy/com.bigmac.mcp.conf  /etc/newsyslog.d/
sudo chown root:wheel /Library/LaunchDaemons/com.bigmac.mcp.plist
sudo mkdir -p /Library/Logs/bigmac && sudo chown "$USER:staff" /Library/Logs/bigmac
sudo launchctl bootstrap system /Library/LaunchDaemons/com.bigmac.mcp.plist
```

`KeepAlive` restarts the server on crash and at boot. After a code change, redeploy
and restart with `sudo launchctl kickstart -k system/com.bigmac.mcp`.

On Linux, run the same `uv run` command under systemd (or any process supervisor); an
equivalent unit file is a few lines.

### 5. OpenCode for delegation (on the box, optional)

Only needed for `explore_*`. Install the OpenCode CLI, then copy this repo's
`opencode.json` to `~/.config/opencode/opencode.json` and set the provider `baseURL`
to your Ollama endpoint. It defines a read-only `explore` agent (edit, bash, webfetch
and out-of-project reads denied) and an `explore-think` variant with reasoning on.

## Connect a client

Claude Code:

```bash
claude mcp add --transport http bigmac http://<box-host>:8434/mcp
```

Or add the same entry to a project `.mcp.json`. Any MCP client that speaks streamable
HTTP will work.

## Delegated exploration

From inside a git repo on your workstation, ship a snapshot to the box (this is a
deliberate, user-run step, because it sends source code to the shared box):

```bash
scripts/bigmac-sync.sh                # macOS/Linux
# or, on Windows:
scripts\bigmac-sync.ps1
```

Then, through the MCP tools: `explore_start(workspace, question)` returns a job id;
poll `explore_status`; fetch `explore_result`. Jobs run one at a time and take
minutes, not seconds. Pass `think=true` for hard architectural questions (reasoning
on, roughly six times slower, richer synthesis). Results cite `file:line`; verify a
few citations against the real repo before you trust the answer.

## Configuration

Environment variables read by the server:

| Variable | Default | Purpose |
|---|---|---|
| `OLLAMA_URL` | `http://localhost:11434` | Where Ollama lives |
| `MCP_HOST` | `0.0.0.0` | Bind address |
| `MCP_PORT` | `8434` | Bind port |
| `DELEGATE_ROOT` | `~/delegate` | Where synced workspaces and job files live |
| `OPENCODE_BIN` | `opencode` | OpenCode binary for delegation |
| `EXPLORE_WALL_SECONDS` | `900` | Hard wall-clock cap per exploration job |

The default model is resolved from the live `/api/tags` list (preference order in
`ollama.py`), so a repulled or renamed tag never breaks callers.

## Security model

**The server has no authentication and binds all interfaces.** It is built for a
trusted LAN or tailnet where everyone with network access is already trusted. Anyone
who can reach the port can run generations and read synced workspaces. Do not expose
it to untrusted networks; put a reverse proxy with authentication in front if you need
one.

Delegation is read-only by construction. The `explore` agent has edit, bash, webfetch
and out-of-project reads denied, and the server strips any workspace-level OpenCode
config (`opencode.json`, `.opencode`, `AGENTS.md`) before every run, because a synced
repo could otherwise carry a config that flips those permissions. Never sync secrets:
the sync script filters gitignored files, a secret deny-list (`.env*`, keys, and so
on) and symlinks.

## Tests

`test_client.py` exercises the lightweight tools; `test_explore.py` and
`test_think.py` exercise delegation. Run them on the box against the running server.

## License

MIT. See [LICENSE](LICENSE).

Maintenance

ActivityStale
ResponsivenessNo issues