Skip to main content
Glama
README.md
# GPT Harness

A self-hosted MCP gateway that lets ChatGPT Web run shell commands on a server
you control.

> [!WARNING]
> This is a personal experiment, not a product. It hands whole shell commands
> to a language model and runs them on your server. Read
> [About the security model](docs/security.md) before you run it.

## Why this exists

ChatGPT Web reasons about code well. With the GitHub connector it reads and
edits a repository. What it cannot do is run anything, because its own
environment has no network access. It cannot install a dependency or execute a
test suite.

Codex can do both, but agentic usage is billed and capped separately from chat.
Chat runs out much later, or not at all.

The gateway closes that gap. ChatGPT decides what to do, and your server does
it. Your message quota becomes the limit instead of an agent allowance.

```
@gpt-harness work this ticket
  git clone, write code, npm ci, npm test, repeat until green

@gpt-harness review this PR <link>
  gh pr checkout, run its tests, report back
```

## What it exposes

Four tools: `bash`, `bash_output`, `bash_kill`, and `write_file`.
[Tool reference](docs/tools.md) documents the arguments, results, and limits.

There is no workspace tool and no workspace concept. Projects are directories
under `HARNESS_ROOT`, and ChatGPT uses `ls` and `mkdir` like anyone else.

Three of the four tools exist because of one constraint. A single tool call
cannot stay open for the several minutes `npm ci` takes, so `bash` returns a
handle once a command outlives its 20 second wait, `bash_output` reads from a
cursor, and `bash_kill` stops a command that will not finish.

Commands are not interactive. stdin reads end of file immediately, so ChatGPT
has to pass flags such as `npm ci` and `gh --yes`. Each command runs in its own
process group, so stopping one stops everything it started.

## Requirements

- A Linux server with systemd, a domain, and TLS
- Node.js 24
- An Auth0 tenant
- A ChatGPT account with developer mode available

## Run it locally

```bash
git clone https://github.com/salman-frs/gpt-harness.git
cd gpt-harness
npm ci
cp .env.example .env
```

Point `HARNESS_ROOT` at a directory you can throw away, fill in the Auth0
values from [Connect ChatGPT to the gateway](docs/chatgpt-setup.md), then start
it:

```bash
npm run dev
curl -fsS localhost:8787/healthz
```

`/healthz` needs no token. Every request to `/mcp` needs a valid token for the
configured owner, including `initialize`.

Running the gateway locally gives you no confinement. `ProtectSystem=strict`
and the rest come from the systemd unit, which only applies on the server.

## Prove it works

```bash
npm run build && npm run prove
```

`scripts/prove.mjs` starts `dist/main.js` as its own process from environment
variables alone. It serves a real HTTPS JWKS endpoint that the gateway fetches
over the network, mints a real RS256 token, and drives the result with the
ordinary MCP client. It writes a project, installs a dependency from the
registry, runs the tests, and checks that killing a command also kills the
processes that command started.

Nothing in the script imports `src/`.

## Documentation

- [Connect ChatGPT to the gateway](docs/chatgpt-setup.md) covers Auth0, the
  metadata endpoints, and the connector.
- [Deploy the gateway on a server](docs/deployment.md) covers the systemd unit,
  the reverse proxy, Git credentials, and updates.
- [Tool reference](docs/tools.md) covers arguments, results, limits, and error
  codes.
- [About the security model](docs/security.md) covers the boundaries and what
  you accept by running this.

## License

MIT