Skip to main content
Glama
salman-frs

GPT Harness

by salman-frs

GPT Harness

A self-hosted MCP gateway that gives ChatGPT Web real command execution, file patching, and workspace management on a VPS you control.

WARNING

This is a personal experiment, not a product. It is built for a single owner, has no support channel, no stability guarantees, and no migration path between versions. In its most permissive configuration it hands whoever holds your ChatGPT session administrative control of your server. Readthe security model before you run it, and use it at your own risk.

Why this exists

ChatGPT Web is good at reasoning about code, but its built-in agentic tooling is usage constrained — you run out of agent capacity long before you run out of chat.

GPT Harness takes a different route. Instead of using ChatGPT's own agent, you connect it to a custom MCP server running on your machine. ChatGPT stays the reasoning layer and picks the tools; your VPS does the actual work. Because the interaction happens through ordinary chat turns, the ceiling is your ChatGPT message quota rather than a separate agent-tool allowance.

The execution side is not homegrown. Commands run through Codex app-server, which supplies the filesystem and network sandbox, so the gateway's job is authentication, workspace identity, tool surface, and process lifecycle — not inventing its own isolation.

NOTE

Custom MCP connectors in ChatGPT requiredeveloper mode, which OpenAI ships as a beta. Availability and write support have shifted between plans over time — this was set up and verified on a Plus account, but check Developer mode and MCP apps in ChatGPT for what your account can do today.

What it does

  • Persistent workspaces. Every direct child of your workspace root is a project with a durable generation ID. New chat sessions inherit a default workspace; existing ones keep their own selection.

  • Three execution modes. Sandboxed workspace commands, an opt-in network-enabled command, and — if you deliberately enable it — unsandboxed host commands.

  • Long-running processes. Commands that outlive their yield window return an opaque handle you can poll, write stdin to, and stop, with bounded output and retention.

  • Unified diff patching. apply_patch validates with git apply --check before touching the working tree, and rejects traversal, absolute paths, and .git mutation.

  • An admin portal. A separate service at /admin for creating and cloning workspaces, reviewing configuration changes before applying them, and inspecting activity — which stays up even when the gateway is down.

How it works

flowchart LR
    A[ChatGPT Web] -->|HTTPS + OAuth| B[Caddy]
    B -->|/mcp| C[Gateway]
    B -->|/admin| D[Admin portal]
    C -->|JSON-RPC| E[Codex app-server]
    E --> F[(Workspaces)]
    D -.->|control.sock| C
    D --> G[(SQLite state)]

The gateway validates every tool call against your Auth0 issuer, audience, JWKS signature, expiry, and exact OAuth subject — one account, pinned. It then maps the tool to a command/exec call on a single pinned Codex app-server connection.

The admin portal runs as its own systemd service with no health dependency on the gateway. It reads live runtime state over a private /run/gpt-harness/control.sock Unix socket that the reverse proxy never exposes, so when the gateway is down the portal degrades into a recovery mode you can still fix configuration from.

Requirements

  • A Linux VPS you control, with a domain and TLS

  • Node.js 24 and npm 11+

  • The pinned Codex CLI (currently 0.145.0 — see Upgrading the Codex pin)

  • An Auth0 tenant

  • A ChatGPT account with developer mode available

Getting started

Local first, so you can see the tool surface before wiring up a public host.

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

Edit .env and point HARNESS_WORKSPACE_ROOT and HARNESS_STATE_DIR at disposable local directories, then set the Auth0 values from the setup guide. Start the gateway:

npm run dev

/healthz is unauthenticated and answers immediately; MCP is served at /mcp. Tool discovery works anonymously for protocol compatibility, but no tool will execute without a valid token.

From there:

  1. Connect ChatGPT — create the Auth0 API and application, expose the gateway over HTTPS, and register the custom MCP connector.

  2. Deploy properly — dedicated service user, systemd units, reverse proxy, and versioned releases with rollback.

  3. Understand what you're accepting — the trust boundary and the risks that come with it.

Tools

Which tools appear depends on how you configure HARNESS_MODE and HARNESS_NETWORK at startup:

Configuration

Workspace command

Network command

Host command

default + on-request

exec.sandbox, network restricted

exec.network, one command

hidden

default + always

exec.sandbox, network enabled

hidden

hidden

full

exec.sandbox, network enabled

hidden

exec.full

Start with default + on-request. It keeps writes inside the active workspace and makes outbound network a per-command decision. Use full only if you actually want ChatGPT administering the host.

Every mode exposes:

  • workspace.list {} — projects, active workspace, mode, and effective network policy

  • workspace.use {"name":"project"} — create or resolve a project

  • workspace.delete {"name":"project","confirmation":"project"} — permanently delete an exact generation

  • exec.sandbox {"workspace":"project","command":"npm test"} — workspace-bounded command

  • exec.network {"workspace":"project","command":"npm ci"} — one network-enabled command, when exposed

  • exec.full {"workspace":"project","command":"sudo systemctl status example","cwd":"/"} — host command, when full mode is on

  • apply_patch {"workspace":"project","patch":"diff --git ..."} — validate and apply a unified diff

  • process.poll, process.write, process.stop — manage long-running command handles

Changing mode or network policy requires a service restart and a refresh or reconnect of the ChatGPT app, so the client rescans the tool list.

Every exec and patch call names its workspace explicitly. MCP clients may open a fresh transport for each tool call, so workspace.use cannot safely carry selection state into a later request. The persisted default is informational; commands never fall back to it.

Notes that will save you time

Codex workspace-write protects top-level .git, .agents, and .codex metadata. You can edit files and run git status or git diff, but git init, git add, and git commit need host provisioning or exec.full.

In default + on-request, sandboxed commands cannot create TCP or Unix listeners. To run a temporary dev server, start it with exec.network, bind it explicitly to 127.0.0.1, and probe it with another exec.network call. Never bind validation servers to 0.0.0.0.

Processes started through exec tools are temporary and die on timeout or gateway shutdown. Anything that needs to survive has to be handed to a real supervisor — sudo systemctl enable --now example.service or docker compose up -d.

Admin portal

The portal creates blank workspaces, clones credential-free GitHub SSH or HTTPS repositories through private staging directories, shows local-only Git status, performs explicit bounded git fetch --prune, changes the default workspace, and permanently deletes an exact name-and-generation identity. Clone and fetch progress streams over SSE.

Configuration changes are reviewed before they are applied: the portal shows a diff, stops active temporary processes only after you confirm, restarts the gateway, verifies the expected fingerprint, and automatically restores the previous backup if health checks fail.

Security

The hard boundaries are OAuth, startup configuration, the Codex per-command sandbox, and the Linux permissions of the dedicated service user. Everything else is a convention, not a control.

CAUTION

HARNESS_MODE=full exposes an unsandboxed host command tool. If the service user also has NOPASSWD: ALL, a compromised ChatGPT session is a compromised server. Enable full mode deliberately or not at all.

Two things are worth internalising before you connect anything real: the model can read any file in a workspace, including .env secrets, and command output is returned verbatim up to its cap — so a command that prints a secret hands that secret to ChatGPT. Prompt instructions are not a secret boundary. The full picture, including residual risks that are accepted rather than mitigated, is in docs/security.md.

Development

npm ci
npm run format
npm run check
npm test
npm run build

The default test run uses a fake transport. To exercise the real pinned Codex binary:

HARNESS_TEST_CODEX_BIN="$(command -v codex)" npm run test:acceptance
HARNESS_TEST_CODEX_BIN="$(command -v codex)" HARNESS_TEST_FULL=true npm run test:acceptance

These are deterministic and harmless. They cover multiple workspaces on one connection, restricted and enabled network policy, streamed stdin and output, patching in a non-Git workspace, process termination, and — with HARNESS_TEST_FULL — host and sudo access.

Browser tests for the admin portal run separately with npm run test:browser.

Upgrading the Codex pin

Codex app-server is a pinned external security boundary, so upgrades are gated:

  1. Choose the newest stable, non-prerelease release.

  2. Verify the artifact source, version, and SHA-256.

  3. Run codex app-server generate-ts --out src/codex/generated --prettier ./node_modules/.bin/prettier and review protocol changes. Only the stable command/exec family and sandboxPolicy are used in production.

  4. Run type checks, fake-transport tests, and the full real-backend acceptance suite.

  5. Smoke-test MCP locally.

  6. Update the version and hash only after every gate passes.

Project layout

src/auth/         OAuth resource-server validation
src/codex/        App-server JSON-RPC client, generated types, process registry
src/server/       HTTP and MCP SDK integration
src/tools/        Exec and unified-diff behavior
src/admin/        Admin portal server, APIs, and recovery mode
src/config/       Structured config review, apply, restart, and rollback
src/control/      Private gateway/admin Unix-socket control plane
src/metrics/      Redacted activity and aggregate metrics
src/storage/      SQLite state and migrations
src/workspace/    Generation-safe workspace lifecycle and Git helpers
admin-web/        React admin portal frontend
tests/            Unit, integration, and real-backend acceptance tests
deploy/           systemd units, sudoers, reverse proxy example, release scripts
docs/             Setup, deployment, and security documentation
-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/salman-frs/gpt-harness'

If you have feedback or need assistance with the MCP directory API, please join our Discord server