chatgpt-deepseek-bridge
by zzzjjack
README.md
# chatgpt-deepseek-bridge
[](https://github.com/zzzjjack/chatgpt-deepseek-bridge/actions/workflows/ci.yml)
Let ChatGPT (or any MCP client) delegate coding tasks to a **local
Hermes-backed coding agent**, with async job management so slow model runs
never block the MCP frontend.
This project is **not** an official OpenAI product and is not endorsed by
OpenAI. It uses the official [Secure MCP Tunnel](https://developers.openai.com/docs/guides/chatgpt-mcp)
and [tunnel-client](https://github.com/openai/tunnel-client) as the transport,
and [Hermes Agent](https://hermes-agent.nousresearch.com) as the local agent
runtime. It is tested with DeepSeek models served through OpenCode Go
(`opencode-go` provider), but the model/provider are Hermes configuration
values — other Hermes-supported providers work without code changes.
## What it does
```
ChatGPT (MCP client)
│ tools: deepseek_investigate / deepseek_execute / deepseek_continue
│ deepseek_job_status / deepseek_job_result / bridge_status
▼
OpenAI Secure MCP Tunnel (tunnel-client daemon)
▼
mcp_bridge_server.py (stdio MCP server)
▼
bridge_core.py (job queue, dedup, single-task lock, git verification)
▼
hermes chat -q -Q (local agent, one-shot invocation)
▼
DeepSeek / any Hermes-supported model
```
## Features
- **Async jobs**: `investigate` / `execute` / `continue` return a `job_id`
in ~1s; Hermes keeps working in the background (5–30 min is normal).
- **Job persistence**: job state and results are stored on disk
(`state/jobs/<job_id>.json`) — surviving MCP reconnects, tunnel restarts,
and bridge process restarts.
- **`deepseek_job_status` / `deepseek_job_result`**: local reads only, never
invoke the model again, zero extra token cost.
- **Idempotency**: identical requests (tool + normalized task + project root)
within a dedup window reuse the existing job — a retried `execute` never
runs a second writer agent.
- **Single-task lock** with TTL + dead-process detection; safe queueing.
- **Read-only verification**: `investigate` is checked with git
before/after snapshots; any change is reported as a `violation`.
- **Safety recovery**: on Hermes session-persistence failures the bridge
retries automatically — investigate only when verified read-only;
execute/continue only when no side effects were detected, otherwise it
spawns a fresh session that completes *only the remaining work*
(`partial_execution_possible` flag, original session id preserved).
- **Watchdog**: auto-restarts a dead tunnel daemon (~30s).
- **Windows notifications**: tray bubble on job completion/failure (fails
silently, never affects job results).
- **Environment hardening**: spawns Hermes with validated
TEMP/TMP/TMPDIR and verifies the Hermes home / session DB are writable.
## Requirements
- Windows (PowerShell 7+; scripts use `pwsh`)
- Python 3.11+
- [Hermes Agent](https://hermes-agent.nousresearch.com) CLI installed and
configured with a model provider (e.g. DeepSeek via `opencode-go`)
- An OpenAI account with Developer Mode and a Secure MCP Tunnel
(create at https://platform.openai.com/settings/organization/tunnels)
- A git repository you want the bridge to operate on
## Installation
```powershell
pwsh -NoProfile -ExecutionPolicy Bypass -File .\scripts\install-chatgpt-deepseek.ps1
```
This creates `.venv`, installs the pinned `mcp==1.28.1` SDK, locates
`hermes.exe` (config → `-HermesPath` → common install locations), and
downloads the official `tunnel-client` release from GitHub. Add
`-SkipTunnelClient` to skip the download (bridge-only setups).
## Configuration
Copy the templates and fill in your values:
```powershell
Copy-Item .env.example .env
Copy-Item config.example.json config.json
```
- `.env` → `CONTROL_PLANE_API_KEY=...` — your tunnel **runtime key**
(create in the OpenAI tunnels page; this is *not* the tunnel id).
**Never commit this file.**
- `config.json` →
- `project_root`: absolute path of the git project the bridge may operate on
- `hermes_command`: absolute path to `hermes.exe`
- `model` / `provider`: any Hermes-supported combination
(defaults are DeepSeek via `opencode-go`)
## Running the tests
Requires Python 3.11+ with only `requirements.txt` installed (see
Installation) and a local `config.json` (see Configuration) whose
`project_root` points at any directory. The stdio compat test
(`tests/test_server_discover_compat.py`) bootstraps a minimal config on a
clean checkout; the bridge_core tests (`test_recovery.py`,
`test_async_flow.py`, `tests/test_git_verification.py`) import
`bridge_core` at load time and need `config.json` to already exist.
`test_async_flow.py` spawns the configured `hermes_command` — point it at
a real agent CLI, or a stub that prints an answer and exits 0.
```powershell
\.venv\Scripts\python.exe tests est_server_discover_compat.py
\.venv\Scripts\python.exe tests est_git_verification.py
\.venv\Scripts\python.exe test_recovery.py
\.venv\Scripts\python.exe test_async_flow.py
```
Git must be available on PATH for verification; if it is not, jobs fail with
`error_type: git_verification_failed` instead of silently reporting a
verified run.
## Starting the bridge
```powershell
pwsh -NoProfile -File .\scripts\init-tunnel.ps1 -TunnelId tunnel_xxxxx
pwsh -NoProfile -File .\scripts\start-chatgpt-deepseek.ps1
pwsh -NoProfile -File .\scripts\status-chatgpt-deepseek.ps1
pwsh -NoProfile -File .\scripts\stop-chatgpt-deepseek.ps1
```
`start` launches tunnel-client (which spawns the bridge server) plus a
watchdog that auto-restarts the daemon if it dies. Then, in
ChatGPT → Developer Mode → Plugins, create a developer app and connect it to
your tunnel id. Use **Refresh Tools** after any tool description change.
## MCP tools
| Tool | Purpose |
|---|---|
| `deepseek_investigate(task)` | Starts a background **read-only** investigation job; returns `job_id` in ~1s |
| `deepseek_execute(task)` | Starts a background implementation job (serialized, deduped) |
| `deepseek_continue(session_id, task)` | New background job continuing a previous Hermes session's context |
| `deepseek_job_status(job_id)` | Local status read (`queued` / `running` / `completed` / `failed`) — never invokes the model |
| `deepseek_job_result(job_id)` | Returns the persisted full result (report, git verification, session id, duration) — never invokes the model |
| `bridge_status` | Bridge/tunnel health, lock state, recent jobs |
## Async job workflow (for MCP clients)
1. Call `deepseek_investigate` / `deepseek_execute` / `deepseek_continue` →
you get `{status: "accepted", job_id, mode}` almost immediately.
2. **Do not poll in a tight loop.** Jobs commonly take 5–30 minutes. Check
`deepseek_job_status` at most once every 5 minutes; if you cannot defer a
check that long, return control to the user and tell them the job is
running in the background. A Windows notification appears when it finishes.
3. Once status is `completed`, call `deepseek_job_result` **once** and stop
polling. It only reads saved data — no model quota is consumed.
4. `deepseek_continue` is for *new* work on an old session, not for fetching
a previous job's result.
## Security model / limitations
See [SECURITY.md](SECURITY.md) — read it before deploying.
- This bridge drives a local agent with **shell and filesystem access**.
- `investigate` read-only is enforced by git before/after verification, not
by an OS sandbox.
- Only point the bridge at projects you trust (agent reads AGENTS.md etc.).
- The tunnel credential in `.env` is high-value — protect it, rotate it,
never commit it.
## Troubleshooting
- **ChatGPT reports "connection timed out" on a tool call**: the model run
exceeded the MCP frontend's patience; the job keeps running in the
background. Wait for the local notification, then call
`deepseek_job_result` with the `job_id`. The watchdog restores a dead
daemon within ~30s.
- **`warning: Failed to set cwd to temp dir` in Hermes output**: emitted by
the uv trampoline when TEMP/TMP is invalid; non-fatal. The bridge now
sanitizes these variables before spawning Hermes.
- **`hermes_failed` with session persistence errors**: the bridge
auto-recovers (see Features). If jobs keep failing, run
`hermes sessions repair` while no Hermes process is running.
- **tunnel-client exits at startup**: make sure `CONTROL_PLANE_API_KEY` in
`.env` is the runtime key (starts with `sk-proj-`), not the tunnel id
(starts with `tunnel_`).
- **MSYS/git hangs**: the bridge isolates git through a helper process; if
you still see hangs, avoid running the bridge from an MSYS shell.
## License
MIT — see [LICENSE](LICENSE). The tunnel-client binary is distributed under
Apache-2.0 by OpenAI (downloaded at install time, not bundled here).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues