你在 ChatGPT 网页里说“检查一下本地项目的首页”,电脑上的 Codex 开始读文件;接着说“把这个问题修掉”,它修改代码、运行检查,再把结果带回网页。要做到这件事,需要给网页和本地执行器接上一条能传递任务的通道。MCP 负责描述可用工具,本地服务负责接收任务,Codex 负责执行。
这篇教程按 Windows 环境写,先用一个只有两个文本文件的测试目录把流程走通,再考虑接入真正的代码库。文中附了可下载的服务示例、PowerShell 命令、网页接入步骤和故障检查方法。需要先说明:本地协议检查与 ChatGPT 账户中的隧道接入是两次验证。本文不会把前者写成已经完成后者。核对日期为 2026 年 10 月 4 日。
1. 先确定你要控制的是哪一部分
这里的目标是让 ChatGPT 网页调用电脑上的开发工具。它适合读代码、分析问题、修改指定项目、运行检查和继续上一项任务。浏览器截图、点击桌面窗口、操控一个已经打开的 Codex 窗口,都需要另外的工具。把本地项目接成 MCP,并不会顺带修复电脑控制插件的窗口识别问题。
数据经过的顺序是:ChatGPT 网页 → 隧道 → 本地 MCP 服务 → Codex → 项目目录。结果沿同一条链路返回。你的电脑仍然保存代码,提交给模型的提示、被读取的代码片段和返回结果会进入相关服务的数据处理流程。“服务没有公网端口”不等于“代码片段不会离开电脑”。
第一次先做一件能当场核对的小事:读取 demo 项目的 hello.txt,返回里面的一行文字。文件内容你已经知道,模型有没有实际访问本地文件,很容易判断。等这一步成立,再谈自动修复项目。
2. 准备环境:网页账号、本地 Codex、隧道权限
准备一台保持在线的 Windows 电脑、Node.js、一个能使用开发者模式的 ChatGPT 网页账号,以及已登录的 Codex。本次示例在 Node.js 24 环境准备,依赖版本写进了 package-lock.json。下载后用 npm ci 安装,避免不同机器安装到不同的 SDK 版本。
node --version
codex --version
codex login status
最后一条显示 Logged in using ChatGPT,说明本地 Codex 已使用 ChatGPT 登录。网页登录状态和本地执行器认证应分别检查。需要登录时运行 codex login,按它给出的方式完成认证。订阅登录与 API 密钥登录是两条使用路径,选择与自己账户相符的方式。认证方式的官方说明。
再打开 Platform 的 Tunnels 设置,确认你能创建和使用隧道。创建或编辑需要 Tunnels Read + Manage;运行和选择需要 Read + Use。开发者模式的权限另行管理。没有这个入口时,先解决账户和组织权限,后面的命令不能替你获得权限。隧道的权限与前提。
费用也分开看:ChatGPT 订阅、本地 Codex 的使用方式、隧道要求的运行密钥,以及你额外使用的主机或服务。不要把 Pro 网页能聊天当成所有接口都有无限额度。这篇教程不要求先租服务器。
3. 为什么先用 SDK,什么时候再换 app-server
正式做一个长期使用的控制台,我会选择 Codex app-server。它能处理会话、执行事件和审批交互。但第一次学习还要同时掌握双向 JSON-RPC、请求编号和事件流,很容易把注意力花在通信细节上。本文的可运行示例先用 Codex SDK,把这些能力收在几个任务工具后面。SDK 的用途和用法。
示例包括六个工具:list_projects、start_task、get_task_status、get_task_result、continue_task 和 cancel_task。它会把任务记录写入本机 data/jobs.json;启动任务时立即返回 job_id,后续用同一编号查状态和结果。继续任务只接受本服务已经完成的任务编号,不接受网页随意指定外部 Codex 会话。
这种版本适合单人实验。完整服务还应补上 SQLite、跨进程项目锁、结果分页和审批处理。官方已经移除旧的 codex mcp-server 命令;新教程不应再把它作为接入前提。app-server 也需要经过你写的 MCP 服务转换,不能直接把它的 WebSocket 地址填进插件目录。app-server 协议说明。
4. 下载示例,在一个独立目录安装
下载 Local Codex MCP 示例源码(ZIP)。解压后把里面的文件放到 D:\CodexWebBridge。目录里应有 server.mjs、package.json、package-lock.json、smoke-test.mjs、projects.example.json 和 demo-project 文件夹。压缩包不含 node_modules、账户认证、真实项目配置或任务日志。
Set-Location 'D:\CodexWebBridge'
npm ci --ignore-scripts
Copy-Item -LiteralPath 'projects.example.json' -Destination 'projects.json'
node --check server.mjs
node smoke-test.mjs
最后一个命令只检查 MCP 初始化、工具发现、项目名单、未知任务拒绝和写入关闭,不会调用模型。正常结束应输出 passed: true、modelRun: false。node –check 没有输出也可能是正常的,重点看退出状态;不要因为屏幕上没有一句“成功”就重复安装。
示例固定使用 @openai/codex-sdk 0.135.0、@modelcontextprotocol/sdk 1.32.0 和 Zod 3.25.76。MCP SDK 的主分支现已采用另一套 v2 包名;本文按压缩包里的版本运行,不要把 v2 的 import 写法混进这份示例。以后升级时,依赖、导入和测试一起更新。MCP TypeScript SDK 版本说明。
5. 登记项目,先保持写入关闭
打开 projects.json,初始内容如下。demo 是网页调用工具时使用的名称,path 指向本地目录。相对路径以 server.mjs 所在目录为起点解析。
{
"demo": {
"path": "./demo-project",
"writeEnabled": false
}
}
不要第一步就把全部 D 盘登记进去。先让服务只知道 demo。它不会向网页返回绝对目录,也没有“执行任意命令”或“打开任意路径”工具;start_task 只能选择已经登记的名称。配置在启动时加载,修改后需要重启服务。
项目名单控制任务落到哪里,Codex 沙箱控制本地操作权限。两者都要有。尤其要记住,read-only 主要限制写入,不能据此认定进程只看得见这一个项目。示例也会使用本地 Codex 的配置和指令;已有的 MCP、插件和凭据都应该纳入检查。接入重要项目之前,最好使用独立的普通 Windows 账户,只给它访问必要目录的权限。Windows 沙箱说明。
如果想把这次实验的 Codex 配置单独放一份,可以先设置下面的变量,然后在这个环境里登录。隧道客户端也应从继承同一变量的终端启动。登录交互请自己完成,不要把认证文件放进源码压缩包。
$env:CODEX_HOME = 'D:\CodexWebBridge\codex-home'
codex login
codex login status
6. 用真实文件验证本地任务
协议检查通过后,再运行一次真实 Codex 调用。这次会使用你的 Codex 额度。
Set-Location 'D:\CodexWebBridge'
node smoke-test.mjs --run-codex
测试程序通过 MCP 启动 analyze 任务,要求 Codex 读取 demo-project/hello.txt,随后查询任务结果。它会检查返回文字是否包含 Hello from the local demo project.,并确认原文件没有变化。同时,它检查同一项目运行时是否拒绝第二个任务。这比只看 Codex 返回了一段文字更可靠。
这里有两个独立结果:status: completed 表示模型这一轮正常结束;文件内容检查通过,才说明这次读取达到了目标。如果模型说“我无法读取文件”,即使会话正常结束,测试也会失败。检查 smoke-report.json 和本机 data/jobs.json,先修复本地问题,再继续接隧道。
实验时应记录 Node.js、SDK、Codex 执行器版本和实际错误。Windows 报 CreateProcessWithLogonW failed: 267,往往需要检查工作目录是否是有效的本地路径;若日志里的 cwd 变成 file:///D:/…,应核对 SDK 与执行器的兼容情况以及具体的工作目录参数。不要靠关闭沙箱把这个错误掩过去。本文的验证结果列在最后一节。
如果服务器返回 model is not supported,先在这个 CODEX_HOME 环境中打开 Codex 的模型选择,确认本地执行器与账号实际支持哪个模型。示例支持用 BRIDGE_MODEL 环境变量指定模型;它只在本地设置,网页不能替你改。发布时的本地测试使用了 model/list 返回的 gpt-5.5,这不是所有账号都必须使用的名称。
$env:BRIDGE_MODEL = 'gpt-5.5'
node smoke-test.mjs --run-codex
7. 建立 Secure MCP Tunnel
本地检查通过后,到 Platform 的 Tunnels 设置创建隧道,记录 tunnel_id,并关联实际要使用它的 ChatGPT 工作区。只关联 Platform 组织,未必会让它出现在目标工作区的插件表单里。个人账户也应按设置页显示的组织和工作区关系操作。工作区关联说明。
从设置页提供的下载入口获取 tunnel-client;下载页也可以从 官方最新发布 打开,选择适合 Windows 和电脑架构的文件。下面假定解压后的程序是 D:\Tools\tunnel-client\tunnel-client.exe,具体文件名以下载包为准。
$tunnelExe = 'D:\Tools\tunnel-client\tunnel-client.exe'
& $tunnelExe help quickstart
先看当前程序的帮助。将运行密钥放进 CONTROL_PLANE_API_KEY 环境变量,不要写入 server.mjs 或 projects.json。下面用隐藏输入,减少密钥出现在屏幕和 PowerShell 命令历史中的机会;变量中的值仍应按凭据处理。
$secret = Read-Host 'Tunnel runtime API key' -AsSecureString
$env:CONTROL_PLANE_API_KEY = [System.Net.NetworkCredential]::new('', $secret).Password
$tunnelId = Read-Host 'Tunnel ID'
本文走 stdio 路径,所以本地服务不需要监听 HTTP 端口。假设 Node 安装在不带空格的 C:\Tools\nodejs\node.exe;请替换成自己机器的实际位置。安装路径带空格时,按当前 tunnel-client 的帮助正确引用命令,不能把 PowerShell 的调用符 & 原样塞进 mcp-command。
$nodeExe = 'C:\Tools\nodejs\node.exe'
$serverFile = 'D:\CodexWebBridge\server.mjs'
$mcpCommand = '"' + $nodeExe + '" "' + $serverFile + '"'
& $tunnelExe init --sample sample_mcp_stdio_local --profile codex-web --tunnel-id $tunnelId --mcp-command $mcpCommand
& $tunnelExe doctor --profile codex-web --explain
& $tunnelExe run --profile codex-web
doctor 应确认配置和本地服务可用。run 是持续运行的进程,保持这个终端开启;它按配置启动 MCP 子进程,不需要再开一份 node server.mjs 与它争抢项目。这里的服务把 stdout 留给 MCP 消息,诊断输出应写到 stderr。一个随手添加的 console.log 也可能破坏 stdio 协议。
8. 查看隧道状态,再去网页添加插件

打开 tunnel-client 启动日志给出的本地管理地址,再查看 /ui。端口以当前配置为准,不要照着示例截图猜。健康、就绪、轮询连接正常以后,才进入 ChatGPT;否则创建插件时的失败,很难判断来自账户还是本机。
- 打开 ChatGPT 网页的设置,找到 Security and login,按账户允许的方式开启 Developer mode。
- 进入 插件目录,点击创建入口。名称可以写 Local Codex Bridge,描述写“Manage jobs in my registered local projects”。
- 在 Connection 中选择 Tunnel,选中刚才建立的隧道;页面允许时也可填写有效的 tunnel_id。
- 检查发现的工具应与本文的六个工具一致。出现不认识的工具,先回头检查连接目标。
- 创建后打开个人插件详情,按当前页面的安装入口完成安装。
- 回到首页新建 Work 聊天,输入 @,选择 Local Codex Bridge。
创建和安装是两步。目录里看得到插件,还不能证明当前聊天已经选中了它。网页的按钮与中文译名可能调整,操作顺序可以对照 连接文档 和 个人插件入门。本文采用私人隧道做个人连接,没有把它发布到公共插件市场。
9. 网页第一次调用,按三个问题来验证
先用这段提示,不要马上要求它修整个网站。
使用 Local Codex Bridge 调用 list_projects。
告诉我有哪些项目、哪个允许写入。
这一步只查看名单,不启动任务。
返回应有 demo,write_enabled 为 false。接着启动读取测试:
使用 Local Codex Bridge 的 start_task。
project 填 demo,mode 填 analyze。
prompt:读取 hello.txt,返回其中的原文;不修改文件,不使用外部服务。
请保留返回的 job_id,随后用它查询状态和结果。
最后问:
查询刚才的任务编号。
如果仍在 running,请说明当前状态。
如果已经结束,调用 get_task_result,给出实际结果。
不要把“任务已提交”写成“文件已读取成功”。
对照三件事:有没有真实工具调用;参数是不是 demo 和 analyze;结果是不是那句已经知道的文字。如果网页只是解释了如何读取文件,先检查当前聊天有没有选中插件。如果返回任务编号后没有继续查,你可以主动要求它查询。后台服务继续运行,不代表网页聊天会无限自动轮询。
结果正确以后,还可以让 continue_task 继续上一项已完成任务,例如“再读 README.txt,说明这个目录的用途”。服务会保留原 Codex 会话,返回新的 job_id;查询新的一轮时使用新编号。
10. 需要改代码时,怎样开放写入
先复制一份测试项目。Git 项目可以另建 worktree;没有 Git 的项目,备份将要修改的文件并记录原始哈希。确认这一份没有生产密钥、发布脚本的自动执行入口或生产数据库连接。停掉隧道进程,等 Codex 子进程确实结束后,再把 demo 的 writeEnabled 改为 true,并重新启动。
{
"demo": {
"path": "./demo-project",
"writeEnabled": true
}
}
这项开关只能在本地配置中改,网页没有开启它的工具。开放后,start_task 的 mode: edit 会使用 workspace-write;analyze 仍是 read-only。示例采用 approvalPolicy: never,含义是不会等待交互式提权批准,沙箱外的操作应被拒绝;它不等于给任务电脑管理员权限。非交互任务的权限说明。
使用 Local Codex Bridge,project 为 demo,mode 为 edit。
只把 hello.txt 的一行改为 Hello from ChatGPT Web.
完成后重新读取文件。报告修改前后内容和实际检查结果。
不安装依赖,不联网,不执行部署,不修改其他文件。
网页显示修改成功后,在本机打开文件核对。换成真实代码库时,还要检查完整差异和测试结果。模型总结里没有提到的变更,也可能实际存在;“执行测试”更应有退出状态、失败项或日志证据。项目名单和提示里的限制,都不能替代操作系统对文件和进程的限制。
示例把同一项目的第二个任务拒绝掉,避免同一进程里同时修改。但这个锁是进程内的;不要同时启动两份服务操作同一目录。正式版本应增加跨进程锁或按任务分配独立工作目录。
11. 停止、恢复与备份:分别处理
cancel_task 会请求中断正在运行的 Codex 任务。已经写入的文件不会因此恢复原状,已经发生的外部操作也不会被撤销。看到 cancelled 后,仍要检查本地差异。任务超过十分钟,示例会请求终止并记录 timed_out;这个时限适合测试,长构建需要按实际情况修改。
服务重启时,原来记录为 queued 或 running 的任务会标为 interrupted,不会自动重试。这样可以避免刚才已经写过一遍的任务,在重启后又写一遍。确认工作目录的实际状态,再决定启动新任务。与此不同,continue_task 只继续已经完成且有会话编号的任务。
关掉网页以后,只要本地进程仍在运行,任务可以继续;电脑休眠、断电或进程退出会影响执行。长期使用时,再把服务配置成普通用户权限的后台进程,明确工作目录、日志位置、环境变量和停止方式。先解决持续运行,再增加并发,维护起来会轻松许多。
Git 恢复需要保留你自己原来的未提交修改;不能把整个目录硬重置当成通用回滚。没有 Git 时,从这次任务之前的备份恢复涉及文件。Codex 会话中的“撤回一轮”和文件系统恢复,也应分开理解。
12. 想做成长期服务,补齐 app-server 这一层
当你需要在网页里查看命令审批、边执行边补充要求,或者管理多个项目的会话,可以将 SDK 执行部分替换为 app-server 适配器,MCP 工具名称尽量保持稳定。两边都是通信协议,但请求格式和生命周期各自不同。协议与事件参考。
- 本地启动 app-server,优先使用 stdio,让它只与桥接进程通信。
- 连接后发送 initialize,再发送 initialized。
- 收到 start_task,使用固定项目目录调用 thread/start,再调用 turn/start。将 threadId、turnId 与 job_id 一起保存。
- 持续消费执行事件,把进度、完成状态和错误写入 SQLite。get_task_status 从数据库读取,不等待整轮结束。
- 收到审批请求,保存具体命令、目录、影响范围和有效期。网页显示内容后,由真实用户选择;桥接层校验身份和请求编号,再响应审批。
- 取消任务调用 turn/interrupt,等待最终中断事件。会话继续用 thread/resume,新一轮用 turn/start。
审批不能只做成一个普通的“approve”文本参数,然后允许模型自己替人填上“同意”。需要把真实用户的点击或经验证的授权与待审批请求绑定,过期请求应失效。否则界面上看起来有审批,实际上执行权限仍由模型自行扩大。
数据库保存任务状态,并不保证断电以后命令能够从中途续跑。遇到进程退出,先标记中断,再检查实际文件和测试状态。正式服务还应对结果做长度限制、分页和敏感内容过滤;示例只遮蔽少数常见令牌格式,不能承诺自动识别所有商业机密。
13. 卡住了,按出错位置查
本地协议检查失败
先执行 node –check server.mjs,确认依赖安装完成、projects.json 存在、目录确实可访问。stdio 服务没有网页,直接运行时等着输入也正常。unknown project 通常是名称没登记;editing is disabled 表示本地开关仍然关闭。
Codex 结束了,却没有完成要求
查看 get_task_result 的 answer,判断它是否实际读到文件、命令是否成功。completed 只表示模型轮次结束。Windows 目录错误、沙箱限制、缺少工具和模型解释性的回答,都可能出现在正常结束的轮次中。先在本机修好;别把同一个问题带到隧道那边再猜。
doctor 正常,ChatGPT 看不到隧道
检查使用的 Platform 组织、ChatGPT 工作区关联和操作者的 Use 权限。权限调整可能需要时间生效。确认 run 进程仍在轮询,再新建连接。不要把 localhost 或 app-server 的地址填成远程 MCP 地址。
创建成功,聊天里没有插件
检查是否完成安装,再新建 Work 聊天并显式选择插件。工具名称或参数变化后,到连接页刷新元数据,重新开始测试;刷新一个聊天页面不一定更新服务器的工具定义。
终止以后文件仍被修改
取消只中断后续执行。检查时间、任务编号和文件差异;如果还有第二个本地服务进程,可能是另一项任务继续运行。恢复代码要使用备份或版本控制,不要重复点击取消期待它把文件还原。
14. 本文验证范围与下一次练习
发布前已通过六个工具的 MCP 协议检查,并完成一次真实 Codex 只读调用:返回 hello.txt 中的已知文字,原文件保持一致。测试使用非敏感的独立目录;原工作区对沙箱用户存在读取拒绝,没有为测试解除这些限制。SDK 0.135.0 与该次 model/list 提供的模型配合完成检查。Windows 目录 URI 和模型兼容错误已记录为排查例子。私人隧道和网页端写入仍未实测。
随文示例的协议检查和真实读取检查,会在发布前分别记录结果。网页端的私人隧道创建、插件安装和写入操作,需要在读者自己的账户与测试目录里继续验证;本文没有声称这些步骤已经替所有账户完成。后面的完整审批适配器是扩展方案,不是压缩包里隐藏的一项现成功能。
第一次保留一条能够核对文件内容的读取结果;第二次在测试副本里修改一行并检查文件;第三次才换成真实项目的只读分析。每次只增加一项能力,出错位置会清楚很多。一个能说明自己读了什么、改了什么、检查了什么的服务,比一开始就接入所有项目更有用。