system-one-mcp
# system-one-mcp
MCP server for any System One backend (Ollama nimble/tev/clef, TypeSafe jev, Kev, Laya).
Exposes two stdio tools:
- `systemone_evaluate` — answer typed `choice` / `score` / `noul` questions with a System One model
- `systemone_list_models` — list available System One models on the configured backend
Thin Zod-validated passthrough: MCP tools -> `fetch({baseUrl}/v1/systemone)` with optional Bearer key. `model` is a free-form non-empty string (never a hard-coded enum).
## Env
| Variable | Default | Notes |
|---|---|---|
| `SYSTEMONE_BASE_URL` | `http://localhost:11434` | Must start with `http://` or `https://`. Ollama default `http://localhost:11434`. |
| `SYSTEMONE_API_KEY` | (unset) | Optional. TypeSafe cloud / Kev with key / Laya with `LAYA_API_KEY`. Sent as `Authorization: Bearer <key>`. |
| `SYSTEMONE_MODEL` | `nimble` | Default model when the tool call omits `model`. Any of `nimble` / `tev` / `clef` / `jev` / `kev` / `laya`. |
See `.env.example` for a copy-paste starting point.
## Run
```bash
npm install
npm run build
SYSTEMONE_BASE_URL=http://localhost:11434 node dist/index.js
```
Windows PowerShell:
```powershell
npm install
npm run build
$env:SYSTEMONE_BASE_URL="http://localhost:11434"; node dist/index.js
```
## Claude Code
Add to your Claude Code MCP config:
```json
{
"mcpServers": {
"system-one": {
"command": "node",
"args": ["<path-to-system-one-mcp>/dist/index.js"],
"env": {
"SYSTEMONE_BASE_URL": "http://localhost:11434",
"SYSTEMONE_MODEL": "nimble"
}
}
}
}
```
For TypeSafe cloud / Kev / Laya, add `"SYSTEMONE_API_KEY": "<key>"` to `env` and point `SYSTEMONE_BASE_URL` at that backend.
## Manual parity
Direct HTTP check against an Ollama backend running `nimble` (bypasses MCP, same endpoint the server calls):
```bash
curl http://localhost:11434/v1/systemone \
-H 'Content-Type: application/json' \
-d '{"model":"nimble","state":"Our checkout has returned 500 errors since 9am.","questions":{"label":{"type":"choice","instructions":"Which label fits?","criteria":{"billing":"Payments","bug":"Errors","account":"Login"}}}}'
```
Expected: JSON with `model`, `answers.label`, and `usage` (`input_tokens` / `output_tokens`).
TDQS
Scored across 2 tools
The two tools serve clearly distinct purposes: one enumerates available models and the other runs an evaluation with a chosen model. There is no overlap in resource or action, so an agent cannot realistically confuse them.
Both names share the 'systemone_' snake_case prefix, which is predictable and readable. The minor deviation is that 'evaluate' is a bare verb without a noun object unlike 'list_models', but the set still feels coherent.
Two tools is thin even for a narrow evaluation-model domain; there is no separate model-detail, configuration, or result-retrieval tool. It is borderline rather than mismatched, since the core discover-then-evaluate flow is present.
The surface covers the minimal loop of listing models and evaluating a question, but lacks supporting operations such as fetching model metadata, setting backend configuration, or retrieving/batching prior evaluations. Agents can work around this only by relying on external configuration.