chatgpt-codex-tools-mcp
by Kerberos255
README.md
[简体中文](./README.zh.md) | English
# chatgpt-codex-tools-mcp
A local MCP server that gives ChatGPT a constrained, Codex-style toolbox for
working with your own projects.
ChatGPT does the reasoning. This server provides workspace-scoped file reading,
search, Git inspection, preview-before-confirm edits, structured process
execution without a shell, and optional web and SQLite tools.
> Community project; not affiliated with OpenAI or Codex.
>
> The MCP endpoint has no application-layer authentication. Keep it bound to
> `127.0.0.1` and place a trusted ingress in front of it. With Tailscale Funnel,
> expose only the OAuth gateway on `127.0.0.1:3334`, never MCP port `3333` directly.
## Highlights
- Local HTTP MCP endpoint: `http://127.0.0.1:3333/mcp`
- Workspace boundary through `CTM_ALLOWED_ROOTS`
- Built-in deny rules for common private files and sensitive paths
- Preview-then-confirm file and SQLite writes
- Structured `command` + `args[]` execution; no shell syntax or shell tool
- Foreground and managed background processes with time/output limits
- Best-effort secret redaction on tool output
- Optional SearXNG search and public HTTP fetch, disabled by default
- Optional allowlisted SQLite reads and bounded structured writes, disabled by default
- Windows initializer for OpenAI Secure MCP Tunnel, Tailscale Funnel, or both
## Requirements
- Node.js 20 or newer for the core server; Node.js 24 is recommended
- npm
- ChatGPT access that supports custom MCP apps / connectors in Developer Mode (availability depends on plan and workspace policy)
- OpenAI `tunnel-client` for the OpenAI Secure MCP Tunnel path, or Tailscale for the Funnel path
- SQLite tools require a runtime with `node:sqlite` support (Node.js 22.5+;
Node.js 24+ recommended)
On Windows, `scripts/start-mcp.ps1` resolves Node from explicit PowerShell parameters first, then environment overrides, then `config.json`. If none of those select a runtime, it falls back to the Codex bundled runtime under `%LOCALAPPDATA%\OpenAI\Codex\runtimes\cua_node`, then `node` on `PATH`. Relevant settings are `runtime.codexRuntimeRoot` / `CTM_CODEX_RUNTIME_ROOT` and `runtime.fallbackNodeBin` / `OPENCLAW_NODE_BIN`.
## Windows quick start
### 1. Get the project
Download the ZIP attached to the latest GitHub Release and extract it, or clone:
```powershell
git clone https://github.com/Kerberos255/chatgpt-codex-tools-mcp.git
cd chatgpt-codex-tools-mcp
```
### 2. Initialize once
Run:
```text
init-windows.cmd
```
The initializer:
- asks for narrow allowed workspace roots, such as `D:\Projects`
- installs npm dependencies and builds `dist/server.js`
- lets you choose **OpenAI Secure MCP Tunnel**, **Tailscale Funnel**, or **Both**
- creates an ignored local `config.json` on first setup and preserves an existing one unless explicitly forced
- creates `tunnel\openai` and/or `tunnel\tailscale` for tunnel-specific binaries, profiles, and local state
- reuses an existing tunnel runtime when possible; otherwise downloads the selected runtime from its official distribution source
- verifies the downloaded OpenAI `tunnel-client` ZIP against the release `SHA256SUMS.txt`
- generates only the selected one-click launcher(s)
Depending on your selection, the project root gains:
```text
start-openai-mcp.cmd
start-tailscale-mcp.cmd
```
You can run `init-windows.cmd` again later and configure the other tunnel too; the existing launcher is kept, so both can coexist.
OpenAI-specific local files live under `tunnel\openai`. The launcher reads `CONTROL_PLANE_API_KEY` from the environment, then `tunnel\openai\control-plane-api-key.txt` when present, or asks for it with a hidden prompt.
First-time OpenAI setup also needs the OpenAI Tunnel ID used by ChatGPT and `tunnel-client`; `init-windows.cmd` asks for it when no matching local profile exists. The runtime API key should have Tunnels **Read + Use** permission for that tunnel; do not substitute a tunnel-admin key for the long-running runtime.
Tailscale-specific local files live under `tunnel\tailscale`. The initializer creates `owner-password.txt` for the local OAuth approval page and keeps OAuth state in the same directory.
### 3. Start MCP and your tunnel
For OpenAI Secure MCP Tunnel:
```text
start-openai-mcp.cmd
```
For Tailscale Funnel:
```text
start-tailscale-mcp.cmd
```
Each launcher starts the MCP server when needed, then starts only its own tunnel path. The Tailscale launcher exposes MCP as `HTTPS 443 -> OAuth gateway 3334 -> MCP 3333`.
On a normal cold start, the main visible console windows are:
- OpenAI mode: **Codex MCP Server** + **OpenAI MCP Tunnel** + **OpenAI MCP Tunnel Watchdog**.
- Tailscale mode: **Codex MCP Server** + **Tailscale OAuth Gateway** + **Tailscale Funnel** + **Tailscale MCP Watchdog**.
The Tailscale Funnel deliberately runs in the foreground. Keep its window open while using the Tailscale connection; closing it or pressing `Ctrl+C` stops the Funnel mapping on HTTPS 443. The watchdog monitors the MCP server, OAuth gateway, and Funnel route and can relaunch a missing foreground Funnel window. Components that are already healthy are reused instead of duplicated.
### 4. Configure ChatGPT
Create a custom MCP app in ChatGPT Developer Mode / Apps and provide the endpoint for the tunnel path you selected. Product availability and exact UI labels can vary by plan and workspace policy; see [OpenAI's current Developer Mode / MCP apps documentation](https://help.openai.com/en/articles/12584461).
For OpenAI Secure MCP Tunnel, choose **Connection: Tunnel** in ChatGPT and select the tunnel or paste the same Tunnel ID used during initialization. Because this MCP server itself has no application-layer authentication, choose **No Authentication** if the UI asks for MCP authentication.
For Tailscale Funnel, use:
```text
https://<your-machine>.<your-tailnet>.ts.net/mcp
```
Use OAuth discovery. When the approval page opens, enter the local Owner Password from `tunnel\tailscale\owner-password.txt`.
Tailscale Funnel is public internet ingress. First-time Funnel use can require tailnet permission plus MagicDNS/HTTPS enablement; see [Tailscale's Funnel requirements](https://tailscale.com/docs/features/tailscale-funnel).
The MCP server itself remains bound to `127.0.0.1` in both modes.
## Manual installation (Windows, macOS, Linux)
```bash
git clone https://github.com/Kerberos255/chatgpt-codex-tools-mcp.git
cd chatgpt-codex-tools-mcp
npm ci
npm run build
```
Create your local configuration from the public template:
```bash
cp config.example.json config.json
```
On Windows PowerShell:
```powershell
Copy-Item config.example.json config.json
```
Edit `config.json`, then start:
```bash
npm start
```
Core server settings are read from `config.json` and environment variables. Windows launcher-only settings under `runtime`, `proxy`, and `environment` are applied by `scripts/start-mcp.ps1`. Environment variables and explicit PowerShell parameters take precedence over matching `config.json` values. Without a config file, conservative defaults are used.
## Connection path
OpenAI path:
```text
ChatGPT -> OpenAI Secure MCP Tunnel -> tunnel\openai\tunnel-client.exe
-> http://127.0.0.1:3333/mcp -> allowed local workspaces
```
Tailscale path:
```text
ChatGPT -> Tailscale Funnel HTTPS 443 -> OAuth gateway 127.0.0.1:3334
-> MCP 127.0.0.1:3333 -> allowed local workspaces
```
Health endpoint:
```text
http://127.0.0.1:3333/healthz
```
The Streamable HTTP endpoint is stateless: each request gets a fresh transport and the server does not rely on an in-memory `Mcp-Session-Id` registry. This means older ChatGPT windows can resume after the MCP process restarts instead of getting stranded on an unknown server-side session.
`mcp.maxSessions` / `CTM_MAX_SESSIONS` are still accepted for backward-compatible configuration parsing, but the stateless HTTP transport does not use that limit.
## Tools
| Group | Tool | Actions / purpose |
| --- | --- | --- |
| Meta | `local_status` | Show version, access mode, roots, limits, and Web/SQLite feature status. |
| Workspace | `open_workspace` | Open a directory under `CTM_ALLOWED_ROOTS` and return a `workspaceId`. |
| Files | `files` | `list`, `read`, `search`, `find`; recursive `list` with `depth` replaces the old project-tree tool. |
| Git | `git` | Local `status` and `diff` only. Use GitHub/`gh` tooling for remote operations. |
| Edit | `edit` | `preview` and `confirm` bounded multi-file edits. |
| Exec | `exec` | `run`, `start`, `read`, `stop` structured executables without a shell. |
| SQLite | `sqlite` | Optional allowlisted `schema`, `select`, `preview`, `confirm`. |
| Web | `web` | Optional `search` and public HTTP `fetch`. |
| Capture | `screenshot` | Windows `desktop`, `monitor`, `window`, or `region` capture; returns PNG image content directly. |
The public MCP surface is intentionally kept to these nine tools. Web and SQLite
actions report a clear disabled error when their feature is off; `local_status`
shows the current configuration.
## Recommended workflow
```text
open_workspace
-> files / git
-> edit(action="preview")
-> review the diff
-> edit(action="confirm", actionId=...)
```
For processes, pass an action, a real executable, and an argv array:
```json
{
"action": "run",
"workspaceId": "...",
"command": "npm",
"args": ["run", "build"]
}
```
Pipes, redirects, command chaining, shell expansion, and shell builtins are not
supported.
## Access modes
```text
CTM_ACCESS_MODE=review # default
CTM_ACCESS_MODE=full
```
- `review` permits a small inspection/test process allowlist.
- `full` permits broader structured executables.
- Both modes still block direct shells (`cmd`, PowerShell, `sh`, `bash`) and
dangerous process patterns.
- Specialized read, Git, edit, web, and SQLite tools should be preferred over
generic process execution.
## Configuration
`config.example.json` is the public template. `config.json` is local, generated
or copied by the user, and ignored by Git.
```json
{
"mcp": {
"host": "127.0.0.1",
"port": 3333,
"allowedRoots": ["D:\\Projects"],
"accessMode": "review",
"maxReadBytes": 200000,
"maxOutputBytes": 200000,
"maxSessions": 128
},
"runtime": {
"codexRuntimeRoot": "",
"fallbackNodeBin": "",
"npmCache": ""
},
"proxy": {
"url": "",
"noProxy": "127.0.0.1,localhost,::1",
"nodeUseEnvProxy": false
},
"web": {
"enabled": false,
"searchProvider": "none",
"searxngUrl": "",
"maxBytes": 200000,
"timeoutMs": 15000
},
"sqlite": {
"enabled": false,
"allowedDbs": [],
"maxRows": 100
},
"environment": {}
}
```
Common environment overrides:
| Setting | Environment variable | Default |
| --- | --- | --- |
| Host / port | `HOST`, `PORT` | `127.0.0.1`, `3333` |
| Allowed roots | `CTM_ALLOWED_ROOTS` | current project directory |
| Access mode | `CTM_ACCESS_MODE` | `review` |
| Deny rules override | `CTM_DENY_GLOBS` | built-in deny list |
| Read/output caps | `CTM_MAX_READ_BYTES`, `CTM_MAX_OUTPUT_BYTES` | `200000` |
| MCP session cap | `CTM_MAX_SESSIONS` | `128` |
| Web tools | `CTM_WEB_TOOLS` | disabled |
| Search provider | `CTM_SEARCH_PROVIDER`, `CTM_SEARXNG_URL` | `none` |
| Web limits | `CTM_WEB_MAX_BYTES`, `CTM_WEB_TIMEOUT_MS` | `200000`, `15000` |
| SQLite tools | `CTM_SQLITE_TOOLS` | disabled |
| SQLite allowlist | `CTM_SQLITE_ALLOWED_DBS` | empty |
| SQLite row cap | `CTM_SQLITE_MAX_ROWS` | `100` |
| Config path | `CTM_CONFIG_PATH` | `<project>/config.json` |
See `env.example` for advanced runtime and proxy overrides.
`mcp.denyGlobs` and `CTM_DENY_GLOBS` **replace** the built-in deny list; they do not append to it. If you override them, include every default pattern you still want protected plus your additional rules.
Do not put tunnel runtime keys in `config.json`. For OpenAI Tunnel, keep
`CONTROL_PLANE_API_KEY` in the current environment or the Git-ignored local
`tunnel\openai\control-plane-api-key.txt` file.
## Optional web tools
Enable in `config.json`:
```json
{
"web": {
"enabled": true,
"searchProvider": "searxng",
"searxngUrl": "http://127.0.0.1:8888"
}
}
```
- `web` with `action="search"` queries only the configured SearXNG instance.
- `web` with `action="fetch"` accepts public HTTP(S) URLs and blocks localhost,
private network targets, embedded credentials, and unsafe redirects.
- No cookies, browser login state, authorization headers, or client certificates
are forwarded.
## Optional SQLite tools
Enable SQLite and list exact database paths:
```json
{
"sqlite": {
"enabled": true,
"allowedDbs": ["D:\\Data\\app.sqlite"],
"maxRows": 100
}
}
```
- `sqlite` with `action="schema"` reads schema metadata.
- `sqlite` with `action="select"` accepts one read-only `SELECT`/`WITH` or safe `PRAGMA`.
- Writes use `sqlite` with `action="preview"`, followed by `action="confirm"` with the returned `actionId`.
- Insert, bounded update/delete, expected-field revalidation, and `jsonSet`
dot paths such as `job_json.enabled` are supported.
- Raw write SQL and subqueries are not exposed.
## File edit operations
`edit` with `action="preview"` accepts multi-file batches with these operation types:
```text
replace_text replace_range insert_before insert_after
append create overwrite rename delete
```
The preview returns an action id and per-file diffs. `edit` with `action="confirm"`
rechecks workspace and deny boundaries before applying the batch. File batches are not
transactional, so keep related edits small and review the entire preview.
## Screenshot tool
`screenshot` is available on Windows and returns PNG pixels directly as MCP image content. By default it does not write a file.
- `mode="window"` accepts a case-insensitive `windowTitle` substring or a `windowHandle`; it uses Windows `PrintWindow`, so it can capture a window even when it is obscured.
- `mode="desktop"`, `monitor`, and `region` capture the interactive desktop. Windows may deny screen-surface access while the desktop is locked or switched away; the tool reports that condition instead of returning a blank image.
- Optional `savePath` is workspace-relative, requires `workspaceId`, and still passes the normal workspace and deny-path checks.
## Security rules
- Keep `HOST=127.0.0.1`.
- Use narrow allowed roots; never use an entire system drive or `/`.
- Keep `review` mode unless broader process execution is required.
- Do not expose the endpoint directly to the internet.
- Tailscale Funnel is public internet ingress; keep Funnel pointed at the OAuth gateway on `127.0.0.1:3334`, never directly at MCP port `3333`.
- Keep web and SQLite tools disabled unless needed.
- Treat redaction as a final safety net, not the primary boundary.
- Review every edit and SQLite preview before confirming.
See [`SECURITY.md`](SECURITY.md) for the full policy.
## Development
```bash
npm ci
npm run typecheck
npm run build
npm test
npm run check
```
The test suite covers configuration precedence, stateless MCP transport behavior, glob
matching, secret redaction, optional SQLite loading, repository/version
consistency, and CI/CD gates.
## CI and releases
Pull requests run CI on Node.js 20 and 24, smoke-test the HTTP server, parse all
PowerShell scripts on Windows, and perform a release-package dry run.
Pushing a tag that exactly matches `package.json`, such as `v0.6.0`, triggers
the Release workflow. It verifies that the tagged commit belongs to `main`,
runs the full checks, builds a ZIP containing source plus compiled `dist`,
generates `SHA256SUMS.txt`, and creates the GitHub Release.
## Troubleshooting
### Authentication behavior is unexpected
For OpenAI Secure MCP Tunnel, create or recreate the MCP app with **No Authentication**. For Tailscale Funnel, an OAuth authorization prompt is expected: use OAuth discovery and enter the Owner Password from `tunnel\tailscale\owner-password.txt`. Old app settings may retain a previous authentication choice.
### Path is outside allowed roots
Add the project parent directory to `mcp.allowedRoots` or
`CTM_ALLOWED_ROOTS`, then restart the server.
### Process command is blocked
Use specialized tools first. In `review` mode, only the small process allowlist
is accepted. Shell executables and shell syntax are blocked in every mode.
### SQLite tools are unavailable
Enable SQLite, add an exact database path, and use a Node runtime with
`node:sqlite` support. `local_status` reports whether SQLite is enabled and
which databases are allowlisted.
### `dist/server.js` is missing
```bash
npm ci
npm run build
```
### Tunnel runtime is missing
Rerun `init-windows.cmd` and select the affected tunnel. The initializer reuses
an installed runtime when possible. Otherwise it downloads OpenAI
`tunnel-client` from the official GitHub Release and verifies its SHA256, or
downloads the current stable Tailscale Windows installer from Tailscale.
## Repository boundaries
The repository and Release package do not include:
- `node_modules`
- local `config.json`
- the local `tunnel/` directory (binaries, profiles, OAuth state, and runtime keys)
- generated `start-openai-mcp.cmd` / `start-tailscale-mcp.cmd` launchers
- logs or workspace data
## License
MIT. See [`LICENSE`](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues