duplex-bridge
This server exposes two MCP tools that let Claude request tasks from a ChatGPT agent working on the repository.
ask_chatgpt: read-only — ask for reviews, analysis, second opinions, or questions; it cannot modify files.ask_chatgpt_write: can modify files — fixes, refactors, or new code on disk.Both tools accept an optional
thread_idto continue a previous conversation; omit it to start a new thread.ChatGPT sees the repository on disk and cites files by path; conversation context is reconstructed automatically by the bridge.
The write capability is fixed per tool, so the model never decides whether it can write.
Bridges ChatGPT with Claude, enabling ChatGPT to send prompts to Claude and receive responses as part of a two-way conversation bridge.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@duplex-bridgeAsk ChatGPT to summarize the key points of this document."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Duplex Bridge
English. Italiano: README.it.md.
A two-way bridge between a Claude chat and a ChatGPT chat, built on the subscriptions you already pay for: no API keys, no cloud service.
By Sergio Di Salvo (@sergioDS-coder) · MIT licensed · not affiliated with Anthropic or OpenAI.
The bridge never talks to the Anthropic or OpenAI APIs. It drives the two local
CLIs you are already signed in to — codex and claude — and translates between
the two conversations.
How it works
One Node process, two transports, one shared ledger.
Direction | Transport | Backend | Plan required |
Claude → ChatGPT | MCP over stdio |
| Claude Free is enough |
ChatGPT → Claude | MCP over HTTP + SSE |
| ChatGPT Plus/Pro (Developer mode) |
The asymmetry is not a design choice. Claude Desktop speaks to local MCP servers
over stdio, on every plan including Free. ChatGPT only accepts custom MCP connectors
in Developer mode — which requires a paid plan — and only as remote HTTPS
servers, refusing localhost outright.
So the second direction needs an HTTPS tunnel in front of the local process. The
bridge itself stays bound to 127.0.0.1 and never opens a port to the outside.
Related MCP server: Herald
Requirements
Node 20 or later
codexCLI, signed in (codex)claudeCLI, signed in (claude)
Build
npm install
npm run buildClaude side
Claude Desktop and Claude Code keep separate registries of local MCP servers. Registering the bridge in one does not make it visible in the other, so pick the surface you actually want it in — or do both.
Either way Claude ends up with two tools:
ask_chatgpt— read-only,read-onlysandboxask_chatgpt_write— may edit files,workspace-writesandbox
Write permission is a property of the tool being called, never a decision left to the model.
Claude Desktop — chat and Cowork
The desktop app loads local servers as extensions, not from a config file. Build the bundle:
npm run pack:extensionThat writes build/duplex-bridge.mcpb. Install it from Settings → Extensions →
Install extension. The app asks for the workspace folder; leave the optional
codex path empty unless the bridge cannot find your install.
Claude Code
claude mcp add duplex --scope user -- node /absolute/path/to/duplex-bridge/dist/servers/claude-side.jsWith no DUPLEX_WORKSPACE set the bridge follows the session's working directory,
so the same registration serves every project. Pass -e DUPLEX_WORKSPACE=... to
pin it to one folder instead.
Note that --scope user means every folder within Claude Code — not the desktop
app's chat, which needs the extension above.
ChatGPT side
export DUPLEX_BEARER_TOKEN="$(openssl rand -hex 32)"
export DUPLEX_WORKSPACE="/path/to/your/project"
npm run start:chatgpt-sideThe server refuses to start without a token of at least 32 characters. Behind the tunnel this endpoint is reachable from the internet, and it can run Claude against your repository.
Expose it, then register the resulting https://.../mcp URL as a custom connector in
ChatGPT (Settings → Developer mode), with an Authorization: Bearer <token> header.
cloudflared tunnel --url http://127.0.0.1:8787Environment variables
Variable | Default | Effect |
| process cwd | Root the two agents work on. Fixed at startup: the MCP caller cannot change it. |
| — | Required by the HTTP server. Minimum 32 characters. |
|
| HTTP server port, always on |
|
| Conversation ledger and thread metadata. |
| auto-resolved | Absolute paths for non-standard installs. Rarely needed: see Resolving the CLIs below. |
| unset | Set to |
Resolving the CLIs
On macOS and Linux codex and claude are spawned by name and the OS resolves them.
Windows needs more care, because the bridge spawns with shell: false on purpose —
so that nothing in a prompt can ever be interpreted as a command. That rules out the
two things npm actually installs: an extension-less POSIX script, and a .cmd shim
that Node refuses to execute since CVE-2024-27980. For codex there is no .exe on
PATH at all: the native binary sits nested inside node_modules.
So on Windows the bridge resolves in two passes: first a real codex.exe / claude.exe
on PATH, then — failing that — it reads the .cmd shim, extracts the .js entry
point it points at, and runs that with the same Node executable already running the
bridge. The shell stays off in both cases.
DUPLEX_CODEX_BIN / DUPLEX_CLAUDE_BIN still win when set — but only if they point
at a file that exists. A dead override is logged and stepped over, so a stale path
left behind by an earlier install, or copied from another machine, cannot silently
defeat the resolution that would have found the CLI on its own.
Keeping the conversation coherent
Both headless CLIs start blank on every invocation, so conversational coherence is the middleware's job, not the providers'.
Every turn is recorded in an append-only JSONL ledger under DUPLEX_STATE_DIR, with
the canonical role (system / user / assistant) and the speaker (human /
claude / chatgpt / bridge) as separate fields — because two indistinguishable
assistant turns lead a model to believe it wrote the other one's text.
The bridge stores each provider's native session id (Codex's thread_id, Claude's
session_id) and reuses it: when the session is alive, only the new instruction is
sent. The transcript is replayed from the ledger only when there is no session to
resume, within a window of 24 messages and 60,000 characters.
One asymmetry is worth exploiting: claude --session-id <uuid> accepts an externally
supplied id, so the bridge's own thread id is the Claude session id — one fewer
identifier to keep in sync.
Security
The prompt goes in over stdin, never
argv: it stays out of the process list.spawnwith no shell: prompt contents can never be interpreted as a command.10-minute timeout, 2 MB output cap, 4 concurrent calls per provider.
Read-only is enforced on the process (
--safe-mode,--disallowedTools,read-onlysandbox), not requested of the model.The child process environment is stripped of the variables that would redirect authentication to an API key — otherwise the "no API keys" promise breaks silently in any shell that exports them.
The other model's transcript is presented as delimited material, with an explicit statement that no line inside it can change the task.
A
thread_idarriving from an MCP client is validated before it reaches a file path.
Known limitations
No recursion guard: a Claude → ChatGPT → Claude chain is possible and burns both subscriptions.
Rate limits are shared with normal use of both apps.
The ledger stores conversations in plaintext on disk, with no rotation.
The write path is not yet tested.
On Windows only the Claude side has been exercised, end to end, against a real
codexinstall; the ChatGPT side has not.No automated tests.
Author
Sergio Di Salvo — @sergioDS-coder
Credits
The design of this bridge comes out of studying noblehacks/frenemy (MIT, by Zakariya Syed) and the official openai/codex-plugin-cc plugin. No code was copied; what was taken are architectural decisions, listed one by one in NOTICE.md — along with the two places where this project deliberately departs from them.
Licence
MIT — see LICENSE. Free to distribute, modify and use commercially, as long as the copyright notice is kept.
Available Tools
2 toolsask_chatgptA
Interpella un agente ChatGPT su questo repository e restituisce la sua risposta. Non può modificare file. Adatto a revisioni, secondi pareri, analisi. ChatGPT vede questo repository su disco, quindi cita i file per percorso. Il contesto della conversazione viene ricostruito dal bridge: non serve incollarlo.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | No | Identificatore della conversazione. Omettilo per iniziare un thread nuovo; riusa quello restituito dalla chiamata precedente per continuare lo stesso discorso mantenendo il contesto. | |
| instruction | Yes | Istruzione completa e autosufficiente. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does it well: it states the tool cannot modify files, that ChatGPT sees the repository on disk, that file paths should be cited, and that conversation context is rebuilt by the bridge. This goes beyond a generic 'ask' tool and sets correct expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: the operation, the key limitation, suitable use cases, file-path guidance, and context behavior are all covered in four concise sentences. The most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with no output schema, the description is complete: it explains what to do, when to use it, what it cannot do, how to phrase instructions, and how conversation state works. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value by telling users to cite files by path when writing instructions, and by explaining that conversation context is reconstructed automatically, which directly informs how to use thread_id. This extra guidance justifies a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: interrogate a ChatGPT agent on the repository and return its response. It also differentiates from the sibling ask_chatgpt_write by explicitly noting that it cannot modify files. The scope and resource are both specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description names suitable use cases (reviews, second opinions, analysis) and explicitly excludes file modification, which implies the write sibling is for modification tasks. It does not explicitly name ask_chatgpt_write as the alternative, so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ask_chatgpt_writeA
Chiede a ChatGPT di modificare file in questo repository (fix, refactor, nuovo codice). PUÒ scrivere su disco. ChatGPT vede questo repository su disco, quindi cita i file per percorso. Il contesto della conversazione viene ricostruito dal bridge: non serve incollarlo.
| Name | Required | Description | Default |
|---|---|---|---|
| thread_id | No | Identificatore della conversazione. Omettilo per iniziare un thread nuovo; riusa quello restituito dalla chiamata precedente per continuare lo stesso discorso mantenendo il contesto. | |
| instruction | Yes | Istruzione completa e autosufficiente. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it does this well by explicitly warning 'PUÒ scrivere su disco' and noting that ChatGPT sees the repository on disk. It does not cover permissions, reversibility, or return behavior, but the critical write-side-effect is clearly disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: purpose first, then the critical write warning, then file-path guidance, then context-handling guidance. Every sentence adds a distinct, necessary fact and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with full schema coverage, the description covers purpose, side effects, and invocation guidance. The main gap is that it does not explicitly describe the return value, though the schema's thread_id hint implies a returned thread identifier. Overall it is complete enough for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds genuine value for the 'instruction' parameter by specifying that file paths should be cited and that conversation context should not be pasted. No extra thread_id semantics are needed because the schema already describes that parameter fully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Chiede a ChatGPT di modificare file in questo repository') and a clear resource (files in this repository), with examples (fix, refactor, new code). The explicit warning that it CAN write to disk and the '_write' suffix distinguish it from the sibling 'ask_chatgpt'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: when ChatGPT should modify files in the repo. It also provides practical invocation guidance—cite files by path, and do not paste conversation context because the bridge reconstructs it. It does not explicitly name 'ask_chatgpt' as the alternative, so exclusion guidance is absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
The two tools are clearly differentiated by capability: one is read-only for analysis and review, the other can write files. The names and descriptions explicitly state this distinction, leaving no ambiguity about which to invoke.
Both tools follow the exact same 'ask_chatgpt' prefix, with '_write' appended to denote the mutating variant. This is a clean, consistent naming pattern.
With only 2 tools, the surface is thin. For a specialized bridge between an agent and ChatGPT on a repository, the read/write pair is a minimal but functional set, yet it feels slightly under-scoped for a general-purpose bridge.
The core lifecycle of 'ask ChatGPT' and 'ask ChatGPT to modify files' is covered. There may be missing auxiliary operations (e.g., conversation history, tool configuration), but for the stated purpose the basic read/write coverage is sufficient with minor gaps.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Share one project context across ChatGPT, Claude, Telegram and any MCP client.
Real-time chat hub for AI agents — Claude Code, Cursor, Cline, Codex over MCP or REST.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables real-time communication and shared vector memory between Claude Code, OpenAI Codex CLI, and Google Gemini CLI. It allows different AI platforms to exchange messages, share context, and collaborate through a unified MCP interface.MIT
- AlicenseNot gradedqualityCmaintenanceThe self-hosted MCP bridge between Claude Chat and Claude Code.46AGPL 3.0
- AlicenseAqualityDmaintenanceBridges any MCP client (like Claude Code, Zed, VS Code) to any ACP coding agent, enabling multi-agent orchestration from a single chat interface.242109Apache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables interaction with Claude and Gemini command-line tools through the MCP protocol, allowing users to send prompts to either or both LLMs and receive responses.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/sergioDS-coder/duplex-bridge'
If you have feedback or need assistance with the MCP directory API, please join our Discord server