Skip to main content
Glama
README.md
# Yevgeny

An MCP server that lets a frontier coding agent hand work to a local LLM.

Claude Code (or any MCP client) calls Yevgeny to offload research, cataloguing,
and long-running computation onto a model running on your own GPU — work that
would otherwise burn context and tokens on grunt labour.

The interesting part is not the Ollama call. It is that the local model gets
real tools — filesystem reads, web fetch, Python execution — on a host with no
OS-level sandbox, and the boundaries that make that survivable are the bulk of
the code.

**[Why it's built this way → docs/DESIGN.md](docs/DESIGN.md)**

## What it looks like in use

```
> Claude, have Yevgeny catalogue every dependency in this monorepo
  and tell me which ones are unmaintained.

  → delegate_start({ task: "...", root: "D:/projects/app" })
  ← job_id: 20260901-49eb1c51, state: running

  → delegate_status({ job_id: "20260901-49eb1c51" })
  ← steps: 12/40
    step 9:  fetch_url {"url":"https://registry.npmjs.org/..."}
    step 11: write_scratch {"name":"deps.json"}

  → delegate_result({ job_id: "20260901-49eb1c51" })
  ← [report + deps.json, 41 packages, 6 flagged]
```

Claude stays in charge of judgement. Yevgeny does the legwork.

## Tools

| Tool | Blocking | Use for |
|---|---|---|
| `ask` | yes, seconds | one-shot text work: summarise, extract, classify, reformat |
| `delegate_start` | no, returns a job id | multi-step research, cataloguing, simulations |
| `delegate_status` | no | progress, tool calls, background process liveness, log tail |
| `delegate_result` | no | final report plus a listing of everything written |
| `delegate_cancel` | no | abort a job; optionally kill its background processes |
| `yevgeny_health` | no | is Ollama up, which models are pulled, which Python was found |

`ask` is a single model turn with no tools. `delegate_start` runs a real agent
loop and returns immediately — poll it rather than waiting, because a job can
run for hours.

Why both shapes exist, rather than one: [DESIGN.md → Two call shapes](docs/DESIGN.md#two-call-shapes).

## What the agent can do

Yevgeny's own tools are `glob`, `grep`, `read_file`, `write_scratch`,
`fetch_url`, `exec_python`, `exec_python_bg`, `exec_poll`.

The boundaries, all enforced in [`src/tools.js`](src/tools.js):

- **Reads** are confined to the `root` passed to `delegate_start`. Omit `root`
  and the agent has no filesystem read access at all. Escapes via `..` *and*
  via symlinks are both rejected — a lexical check alone is not enough, so the
  realpath of the nearest existing ancestor is checked too.
- **Writes** only ever land in that job's own scratch directory,
  `jobs/<job-id>/`. The agent cannot modify your files.
- **Execution** is Python only, through an interpreter resolved and version-
  checked at startup, with `shell: false` and cwd forced to the job scratch
  dir. No shell, no `cmd`, no arbitrary binaries.
- **Network** is HTTP/HTTPS only. Loopback and private ranges are refused, so
  the model cannot probe services on your machine or your LAN.

The threat model these come from is written up in
[DESIGN.md → What the boundaries are actually for](docs/DESIGN.md#what-the-boundaries-are-actually-for).

## Long-running work

`exec_python` is wall-clock capped and meant for quick computation and for
validating a script before committing to a real run. `exec_python_bg` spawns
detached and returns at once — that is the path for multi-hour jobs, and the
child survives the agent loop finishing.

So a job can complete while its simulation is still going. `delegate_status`
reports every background process the job launched and whether that pid is
still alive, because **a finished job is not the same as finished work**.

Scripts should write results to files and checkpoint as they go. Nothing
retries them if the machine reboots.

## Requirements

- **Node 22+** (uses `fs.promises.glob`, native `fetch`)
- **Python 3.11+** — discovered automatically; `YEVGENY_PYTHON` pins one
- **[Ollama](https://ollama.com)** with a tool-capable model pulled

Developed and tested on **Windows 11**. The code makes no Windows-specific
assumptions and should run on macOS and Linux, but that is untested — the
helper scripts `status.ps1` and `yevgeny.cmd` are Windows-only, and neither is
needed to run the server.

## Setup

```bash
git clone https://github.com/pSuarezFrancisco/yevgeny-mcp
cd yevgeny-mcp
npm install
ollama pull gemma4:12b       # or any tool-capable model
node scripts/smoke.js        # should print 27 passed
```

Register it with Claude Code:

```bash
claude mcp add yevgeny --scope user -- node /absolute/path/to/yevgeny-mcp/src/index.js
```

Full walkthrough, model choice, and troubleshooting: **[docs/SETUP.md](docs/SETUP.md)**.
Calling it from another machine on your LAN: **[docs/REMOTE.md](docs/REMOTE.md)**.

## Configuration

Everything has a working default. Override with environment variables:

| Variable | Default | Notes |
|---|---|---|
| `OLLAMA_URL` | `http://127.0.0.1:11434` | |
| `YEVGENY_MODEL` | `gemma4:12b` | must support tool calling |
| `YEVGENY_PYTHON` | auto-discovered | pin if discovery picks the wrong one |
| `YEVGENY_ALLOW_PRIVATE_NET` | unset | `1` lets `fetch_url` reach LAN/loopback |
| `YEVGENY_NODE` | — | Windows only; for `yevgeny.cmd` when node isn't on PATH |

Limits — step budget, context window, byte caps, timeouts — live in
[`src/config.js`](src/config.js) under `LIMITS`.

## Tests

```bash
node scripts/smoke.js        # 27 assertions: path scoping, exec, fetch guards
node scripts/mcp-smoke.js    #  8 assertions: MCP protocol over real stdio
node scripts/e2e.js          # a real job against the real model (minutes)
```

`smoke.js` attacks the security boundaries directly without involving the
model, because those are the parts a confused agent leans on hardest.
`mcp-smoke.js` speaks real newline-delimited JSON-RPC to a spawned server.
Neither needs a model pulled.

`e2e.js` is the only one that exercises Yevgeny's own judgement: a real job
fetches two pages, structures them to JSON, verifies that with Python, and
reports a cited table. Passing it means the plumbing works — **it does not mean
the research is right.** Spot-check output against a source you trust.

## Monitoring (Windows)

```powershell
powershell -File status.ps1
```

Prints Ollama's state, which model is resident and what fraction is on GPU,
recent jobs colour-coded by state, live background pids, and a GPU line from
`nvidia-smi`. Written so you can answer "is it running, and is it melting
anything" without asking the agent.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: direct one-turn ask, async delegated job lifecycle (start, status, result, cancel), and health check. delegate_status and delegate_result are separated by live progress versus final output, so there is no real ambiguity.

Naming Consistency4/5

The delegate_* tools follow a consistent and predictable prefix pattern. ask and yevgeny_health deviate slightly from that convention, but they are readable and clearly labeled, so the overall naming remains coherent.

Tool Count5/5

Six tools is a well-scoped set for a local-agent delegation server. Each tool maps to a necessary operation: direct ask, job start, status polling, result collection, cancellation, and health checking, with no redundant entries.

Completeness5/5

The tool set covers the full delegated-job lifecycle: start, monitor, collect, and cancel, plus a direct quick-ask path and a health check. Background process handling is also addressed through cancel and status. There are no obvious dead ends for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues