ask-chat-mcp
README.md
# ask-chat-mcp
An MCP server that lets Claude confer with **ChatGPT** directly — one specialist to another, grounded in the actual files, read-only, with no size limit in either direction.
Built for delegation, not review. When a problem is genuinely technical — the mathematics behind a model, whether a derivation holds, a design whose tradeoffs have to be argued out — the useful move is to put two capable models on it together and have them report what they concluded. Not to route every exchange through a person who must then adjudicate a subject neither of them is pitching at them.
So both sides talk at full technical depth. Nothing is explained down for a bystander, because there isn't one in the loop: the person delegated the question precisely so they would not have to sit in the middle of it.
```mermaid
flowchart TD
You([You]) -->|"'Ask Chat'"| Claude[Claude]
Claude -->|"the problem + file PATHS"| MCP["ask-chat MCP server"]
MCP -->|"codex exec --sandbox read-only"| Codex[Codex CLI]
Codex -->|"opens the files itself"| Repo[("your repo, read-only")]
Codex <-->|"one thread, kept open"| GPT["ChatGPT (your subscription)"]
GPT -->|"answer + what context it still needs"| Codex
Codex -->|"full answer, nothing truncated"| MCP
MCP -->|"arrives as if YOU wrote it"| Claude
Claude -->|"what Claude makes of it"| You
```
Three things that diagram is meant to make obvious:
- **Paths cross the boundary, never file contents.** ChatGPT opens the files itself, so there is no payload to budget and nothing to truncate.
- **Every reply says what context it still needed.** Supplying that and asking again is the normal path, not an error case — a confident answer resting on a silent assumption is the failure this prevents.
- **The reply returns as your turn**, not as a report. Claude answers it the way it would answer you.
## Table of Contents
- [Why not automate the ChatGPT desktop app](#why-not-automate-the-chatgpt-desktop-app)
- [Requirements](#requirements)
- [Install](#install)
- [Tools](#tools)
- [Configuration](#configuration)
- [Design notes](#design-notes)
- [Limitations](#limitations)
## Why not automate the ChatGPT desktop app
The obvious approach — drive the desktop app's window, paste a prompt, scrape the reply — is what the well-known MCP servers in this space do. It is a dead end for this use case, and it is worth being explicit about why, because the reasons are not obvious until you have built it:
- **The prompt has a practical ceiling.** It arrives by clipboard paste into the composer, and large pastes are silently truncated. Roughly 12k characters is the safe budget. That is not enough for a real question plus the documents it depends on.
- **The reply is truncated too, and worse, invisibly.** It has to be read back out of the app's accessibility tree, and a virtualized scroll container does not keep offscreen content there. A long answer comes back partial with no indication that it did.
- **It takes over your screen.** The window must be focused and keystrokes sent to it. You cannot type while it runs, and one call at a time is the hard limit.
- **It breaks on UI changes**, because the rendered accessibility tree is not an interface anyone promised to keep stable.
Driving the **Codex CLI** instead removes all four. It runs headless, reads files directly off disk, and returns its answer on stdout. Crucially it authenticates with a **ChatGPT subscription**, so this is not the OpenAI API with per-token billing — it is the plan you already pay for.
## Requirements
- Node.js 18+
- [Codex CLI](https://developers.openai.com/codex), signed in with your ChatGPT account:
```powershell
npm install -g @openai/codex
codex login # choose "Sign in with ChatGPT"
```
## Install
```powershell
git clone https://github.com/spe-investigator/ask-chat-mcp.git c:\src\ask-chat-mcp
cd c:\src\ask-chat-mcp
.\install.ps1 -DefaultCwd c:\src\YourProject
```
`install.ps1` verifies prerequisites, builds, reports whether Codex is installed and signed in, and registers the server with Claude Code. Idempotent — re-run after a pull.
Restart Claude Code and confirm with `/mcp`.
## Tools
### `ask_chatgpt`
| Parameter | Required | Meaning |
|---|---|---|
| `question` | yes | The problem, framed to stand alone for someone who has not seen this codebase. Write at full technical depth — the reader is another specialist |
| `files` | no | Paths relative to `cwd` to point ChatGPT at. Reference whole files freely — they are read, not pasted |
| `cwd` | no | Directory it reads from. File access is confined to this tree |
| `session` | no | Thread control — see below. Omit for the normal case |
| `model` | no | e.g. `gpt-5.5`. Omit for the Codex default |
| `timeout_seconds` | no | Defaults to 300 |
**Pass paths, not contents.** That is the whole point: there is no payload budget to spend, so send the actual files.
`files` is a pointer, not a whitelist. It says *start here*; ChatGPT can and does open anything else it needs within `cwd`, and will tell you when it did. So an incomplete list degrades gracefully rather than producing a wrong answer — `cwd` is the real boundary.
#### Threads
By default the first call in a session starts a Codex thread and **every later call continues it**, so ChatGPT keeps the context of what you already discussed rather than meeting each question cold.
The session boundary is the server process. An MCP client spawns a stdio server per session, so the thread is held in memory and needs no registry keyed by repo or client: a new session starts clean, and two concurrent sessions get independent threads instead of trampling a shared one.
| `session` | Effect |
|---|---|
| omitted | Continue this session's thread, starting one if there is none |
| `new` | Deliberately start a clean thread |
| `last` | Pick up the most recent thread **in this directory** from an earlier session |
| a thread id | Resume that specific thread |
`last` is directory-scoped because Codex filters recorded sessions by working directory unless told otherwise.
### `chatgpt_status`
Reports whether Codex is installed and signed in, and which thread this session is on. Check it before relying on `ask_chatgpt`, and to explain a failure without guessing.
## Configuration
| Variable | Default | Purpose |
|---|---|---|
| `ASK_CHAT_DEFAULT_CWD` | server's cwd | Directory used when a call does not name one |
| `ASK_CHAT_TIMEOUT_SECONDS` | `300` | Default timeout |
| `ASK_CHAT_MODEL` | Codex default | Default model |
| `ASK_CHAT_CODEX_BIN` | `codex` | Path to the Codex binary |
| `CODEX_HOME` | `~/.codex` | Where Codex keeps credentials |
## Design notes
**Read-only.** Codex is a coding agent that can edit files. A consulting specialist that can rewrite your working tree is a liability, not a feature. `codex exec` already defaults to a read-only sandbox, and on a fresh thread an explicit `--sandbox read-only` is passed as well, so the guarantee does not rest on a default staying put. On a resumed thread the flag is unavailable — see below.
**Every reply reports its own sufficiency.** The prompt asks ChatGPT to state explicitly whether the context it received was enough, to name precisely what it still wanted — a file, a definition, a measurement, a constraint — and to flag which parts of its answer rest on an assumption it had to make. This matters more than it sounds: the failure mode of a well-briefed model is not refusing to answer, it is answering confidently around a gap nobody knew was there. Naming the gap makes the next call trivial, since supplying a file costs a path.
**No flag is passed on faith.** The installed build is probed once, and optional flags are used only if it advertises them. Codex is moving quickly; guessing at its interface would make this brittle for no benefit.
**`exec` and `exec resume` are probed separately**, because they do not accept the same options — `resume` rejects `--sandbox` and `--cd` outright. Assuming one flag set for both produces a call that dies in argument parsing instead of doing anything, which is how this was found. On a resumed thread the read-only guarantee therefore rests on `codex exec`'s default plus the policy the thread was created under, rather than on a second explicit flag; the working directory comes from the spawned process either way.
**Neither direction has a length limit.** The prompt goes in on stdin using `codex exec -`, so it never touches a command line and cannot hit the ~32k argument ceiling. The answer comes back through `--output-last-message`, read from a file rather than parsed out of a stream that also carries progress output. Progress goes to stderr and is kept for diagnostics.
**Windows shim handling.** npm installs `codex` as a `.cmd` shim, which Node refuses to spawn directly since the 2024 argument-injection fix. A failed direct spawn is retried through the shell. Because the prompt travels on stdin rather than argv, that retry is not a quoting hazard for the one input that is arbitrary text.
## Limitations
- **Codex must be signed in.** `codex login` is an interactive browser flow; it cannot be automated, and `chatgpt_status` will tell you when it has lapsed.
- **File access is confined to `cwd`.** Deliberate. Point it at the repo root you want reviewed.
- **It is not fast.** A substantive answer over real files takes tens of seconds. The default timeout is five minutes.
- **A thread lives and dies with the session.** Restarting the client starts a fresh thread. `session: "last"` picks the previous one back up, but there is no listing of prior threads to choose from.
- **Threads are not visible in ChatGPT.** Codex records them under `~/.codex/sessions/` as JSONL; they do not appear in the ChatGPT sidebar or Projects. Nothing about this design can change that ([openai/codex#21079](https://github.com/openai/codex/issues/21079)).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing