Local-first 只通过本地 MCP 返回计数与人工录入的状态;GitHub-first 在云端工作区读取源码、修改和测试,经过分支、PR、CI 与人工批准。
架构边界示意:MCP 输出约束不等于整机零外发;网页端隧道互通尚未在真实 Mac 验证。

如果商业项目的源码不能发给云端模型,我还可以用网页端 ChatGPT 做什么?能不能让它查看本地项目状态,或者从网页上请求一次受控的 SSH 检查?如果源码允许托管,又为什么还要折腾本地 MCP?

真正要选的不是某个工具,而是让工具看见什么、在哪里执行、结果又返回到哪里。

一句话版:网页端不会自动读取你的 Mac;如果不把源码交给模型,它只能依据你明确开放的摘要或状态给建议,不能直接审查或调试没看到的代码。

本地运行 Codex,不等于模型在本地推理;Codex Cloud 不是连接到你的 Mac;MCP 隧道负责转发请求,不会自动限制工具权限;GitHub Private 只限制仓库访问权限,仓库本身仍托管在云端,若把代码交给云端模型,相关上下文也会进入模型的处理范围。下面先给出选择方法,再用两个公开示例说明接入路径和实际边界。

我为这类边界写了两个独立的公开示例:VXI Local-First MCP 和 VXI SSH Ops Bridge。前者只分享本地项目状态,后者只允许请求固定的只读 SSH 操作。

先比较接入路径:工作区在哪里,模型能看到什么?

路径工作区与命令执行位置云端模型可能看到什么能力与适用场景
ChatGPT 桌面应用中的 Codex Local environment + 本地 MCPMac 上的项目 / worktree;本地终端与 MCP 进程取决于模型实际收到的上下文;本地执行不等于本地推理在授权范围内读写本地文件、运行命令、查看 diff;适合已核实模型数据边界的项目
Codex Cloud / 网页端 Cloud task连接的 GitHub 仓库进入隔离的云端工作区云端任务可读取工作区源码和文件修改代码、运行测试、交付分支或结果;适合源码获准进入 GitHub 和云端环境的项目
GitHub 云端 Coding AgentGitHub 仓库与 Agent 的临时云端环境仓库文件、任务上下文和运行中可访问的内容修改分支、运行检查、创建 PR;适合以 GitHub 作为协作与验收中心的团队
ChatGPT 网页端 + Secure MCP Tunnel + Local-First MCPMCP 服务运行在本机;本机主动建立出站隧道该 MCP 明确返回的计数和状态枚举查看有限项目元数据;适合只需项目状态、不需要源码级审查的场景
ChatGPT 网页端 + Secure MCP Tunnel + SSH Ops Bridge本机 / 网络内主机运行 MCP 桥接器与 SSH 客户端目标别名和固定格式的检查结果请求一项预先限定的只读远端检查;适合只需查看非生产目标有限状态的场景
网页端模型 + 本地 coding-agent relay(需另建)本机适配器委派给本地 Codex / coding agent取决于模型推理位置和适配器回传内容可设计为委派本地代码任务,但必须限制工具和输出;适合愿意另建 relay 的场景

先说明一个影响预期的事实:隧道部分是依据 OpenAI 官方流程整理,尚未在真实 Mac 上跑通 ChatGPT Web 与这两个 server 的端到端互通。后文是配置参考,不是已验收的一键教程。

先选路,再看怎么接

  • 源码一字节都不能交给云端模型: 代码级工作留给本地推理或本地可信流程。Local-First MCP 可以分享获准的元数据,但云端看不到源码,就不能独立完成源码级审查。
  • 只想让网页端查看本地项目状态: 使用 Local-First MCP 这类固定字段投影;它不需要获得源码读取或 Shell 权限。
  • 只想从网页端请求 SSH 只读检查: 使用 SSH Ops Bridge 这类命名操作,把主机身份、私钥和目标白名单留在本地。
  • 源码允许托管,而且希望 AI 真正读写代码: 选择 GitHub-first、Codex Cloud 或其他获准的云端 Agent,利用分支、PR、commit 和 CI 留下可复核记录。
  • 希望网页端把代码任务委派给本地 Codex: 需要另建并审查 coding-agent relay;元数据 MCP 和 SSH 桥接器都不承担这项工作。
  • 多个项目的数据等级不同: 按项目分别选择路径,不要因为博客仓库可以上云,就把同一套权限扩展到商业源码。

其他厂商的网页端工具需要单独核验:先确认它是否支持远程 MCP 或本地 Agent、使用什么认证方式,再看模型实际收到哪些输入和工具返回;不能因为都支持 MCP,就假设 OpenAI Secure MCP Tunnel 可以直接复用。

官方说明可参照:Codex Local environments、Codex Cloud environments、Codex MCP、OpenAI Secure MCP Tunnel 和 GitHub Copilot cloud agent。

先看三条数据流

A. 网页端读取本地项目状态

ChatGPT Web
    |
OpenAI Secure MCP Tunnel endpoint
    ^ 本机 tunnel-client 主动建立出站 HTTPS
    |
本机 vxi-local-first-mcp(stdio MCP)
    |
本机项目目录:只统计文件类别,不读取文件内容

返回:计数 + PASS / FAIL / UNKNOWN
不返回:源码、路径、diff、日志、命令

B. 网页端请求固定 SSH 检查

ChatGPT Web
    |
OpenAI Secure MCP Tunnel endpoint
    ^ 本机 tunnel-client 主动建立出站 HTTPS
    |
本机 vxi-ssh-ops-bridge(stdio MCP)
    |
本机 SSH 客户端 + 本地私钥 + pinned known_hosts
    |
非生产 SSH 目标:固定的只读探测脚本
    |
过滤后的 health / service / storage 枚举
    |
返回网页端

C. GitHub-first 云端开发

获准托管的 GitHub 仓库
    |
Codex Cloud / GitHub 云端 Agent
    |
云端工作区读取源码、修改文件、运行检查
    |
分支 + PR + commit + CI
    |
人工审查与批准

这三条路径解决的不是同一件事:前两条限制云端工具能看到或能请求什么;第三条则允许 AI 在获准的云端工作区中对源码做完整的开发循环。

Codex 本地工作区、Codex Cloud 与 MCP,不要混成一个概念

ChatGPT 桌面应用中的 Codex Local environment 用于配置本地项目 / worktree 的准备步骤和常用动作,集成终端在本机执行命令,Git 工具可以查看 diff、暂存、提交、推送和创建 PR。Codex 的本地客户端也可以直接启动本机 stdio MCP 服务;这种连接是“本地 MCP host 启动本地 MCP server”,并不需要为了本地客户端调用而建立网页端隧道。

但“本地执行”只说明文件和命令在哪里运行。若模型本身是托管模型,分析时使用的源码上下文仍可能被发送到云端。只有本地推理或经过验证的本地可信流程,才可能满足严格的源码不出站要求;还需要单独审查设备上的其他进程和网络路径。

Codex Cloud 则会把选定的 GitHub 仓库放进隔离的云端工作区,准备依赖并运行任务。GitHub 云端 Agent 也能在云端环境中读取源码、修改分支、运行检查并创建 PR。这种路线更适合允许进入云端边界的项目,而不是“源码只留在 Mac”的替代方案。

MCP host 与 MCP server 的区别

  • ChatGPT 桌面应用、Codex CLI 与 IDE 扩展作为 MCP host: 可以按客户端支持的方式配置本地 stdio MCP,工具进程由本地客户端启动。官方 CLI 命令形式是 codex mcp add <name> --env KEY=VALUE -- <server-command>;例如接入本地项目状态服务:
codex mcp add vxi-local-status \
  --env "VXI_WORKSPACE=/absolute/path/to/project" \
  -- /absolute/path/to/node /absolute/path/to/vxi-local-first-mcp/bin/vxi-local.mjs mcp

codex mcp list

若要接入 SSH Ops Bridge,可以用同一命令形式,但把环境变量改为 VXI_OPS_CONFIG=/absolute/path/to/ops.config.json,并把 server command 指向 vxi-ssh-ops-bridge/bin/vxi-ops.mjs mcp。配置中的主机名、账号、私钥路径和 ops.config.json 只留在本机;不要把运行时密钥贴进聊天或提交到 Git。ChatGPT 桌面应用、Codex CLI 与 IDE 扩展共享 Codex host 的 MCP 配置;在桌面应用的 Settings → MCP servers 中添加服务器,具体选项受工作区权限影响。

  • ChatGPT 网页端作为调用方: 网页不会读取本机的 ~/.codex/config.toml,也不会自动继承本地 Codex 的命令菜单。它需要使用支持的远程 MCP 连接方式;Secure MCP Tunnel 的作用,就是让本机主动连接 OpenAI 的隧道端点,再把请求转发给本地 MCP。

网页端怎样连接本机 MCP,再触发 SSH?

OpenAI 的 Secure MCP Tunnel 文档 描述了这条连接方式:在能访问私有 MCP 服务的网络内运行 tunnel-client,由它主动建立出站 HTTPS 通道,从 OpenAI 托管的端点取回请求、转发给本地 stdio 或 HTTP MCP server,再把响应通过同一隧道送回去。它不要求给本机 MCP 开公共入站端口。

命令中的路径和隧道 ID 是占位符,运行时密钥只放在本机环境变量中。

  1. 在 OpenAI Platform 创建或选择隧道,确认目标 ChatGPT workspace 和 Platform organization 已正确关联,并取得所需的 Tunnel 权限。
  2. 从 Platform 的隧道设置获取最新的 tunnel-client,先运行 tunnel-client help quickstart,再为每个 MCP server 配置独立 profile。
  3. 先离线运行并测试 MCP server,再配置隧道。进入 vxi-local-first-mcp 仓库,先跑合成测试和演示:
cd /path/to/vxi-local-first-mcp
node --version  # >= 22
npm test
npm run demo

确认通过后,再为 Local-First MCP 配置隧道:

export CONTROL_PLANE_API_KEY="<runtime-key,仅保存在本地终端>"

tunnel-client init \
  --sample sample_mcp_stdio_local \
  --profile vxi-local-status \
  --tunnel-id "<your-tunnel-id>" \
  --mcp-command "/usr/bin/env VXI_WORKSPACE=/absolute/path/to/project /absolute/path/to/node /absolute/path/to/vxi-local-first-mcp/bin/vxi-local.mjs mcp"

tunnel-client doctor --profile vxi-local-status --explain
tunnel-client run --profile vxi-local-status

这里使用绝对路径,是为了避免后台进程的工作目录或 PATH 与交互式终端不同。

如果要接入 SSH Ops Bridge,先在仓库中运行 npm test 和 npm run demo,再从 ops.config.example.json 创建本地的 ops.config.json,并将 mode 从 disabled 改为 read_only。配置中只放经过独立核验的非生产目标、专用低权限账户、私钥路径和固定的 known_hosts 文件;同时按仓库 README 将只读脚本安装到测试主机的 /usr/local/bin/vxi-health-check。然后为这个 MCP server 单独配置 profile:

tunnel-client init \
  --sample sample_mcp_stdio_local \
  --profile vxi-ssh-readonly \
  --tunnel-id "<your-ssh-tunnel-id>" \
  --mcp-command "/usr/bin/env VXI_OPS_CONFIG=/absolute/path/to/ops.config.json /absolute/path/to/node /absolute/path/to/vxi-ssh-ops-bridge/bin/vxi-ops.mjs mcp"

tunnel-client doctor --profile vxi-ssh-readonly --explain
tunnel-client run --profile vxi-ssh-readonly

平台界面与客户端版本可能变化,实际参数以当前客户端的帮助输出为准。

  1. 保持 tunnel-client run 运行。在 ChatGPT 当前支持的自定义 MCP 入口中选择 Add custom MCP server → Tunnel,选择可用隧道,完成认证并确认权限提示。若找不到隧道,优先检查 workspace / organization 关联与权限,而不是把 MCP 服务改成公网开放。
  2. 先调用只读的 vxi_project_status 或 vxi_ops_policy 验证工具发现,再按需请求 vxi_ssh_health。不要用真实生产主机测试;SSH 主机指纹必须通过独立渠道核验。

SSH 桥接器在本机做了什么?

本地管理员把主机名、用户名、端口、私钥路径和经过独立核验的 known_hosts 写入本地 ops.config.json。MCP 只接受诸如 lab 的允许别名,不接受模型生成的命令文本。桥接器忽略个人 SSH 配置,禁用 Agent 转发和交互式密码提示,调用固定的 /usr/local/bin/vxi-health-check,并把输出收敛为三个状态枚举。

所以网页端不是直接拿着你的私钥登录服务器;它请求的是一个固定操作。隧道负责传输,桥接器的工具清单、参数校验、本地配置、主机密钥绑定和远端脚本共同决定权限边界。

如果把 MCP 后面换成可编辑代码的本地 Agent,必须重新审查它每个工具的输入、输出、文件写入、命令执行、超时和人工批准机制。一个受限 SSH MCP 的安全结论,不能自动套用到有代码写入权限的 relay 上。

两个公开仓库各自承担什么角色?

VXI Local-First MCP:只分享本地项目元数据

打开仓库

这个本机 stdio MCP 暴露两个只读工具:

  • vxi_project_status:文件分类计数、跳过的符号链接数量,以及人工记录的 lint / test / build 状态(PASS / FAIL / UNKNOWN;默认是 UNKNOWN,MCP 不会自动运行测试)。计数是有界扫描结果:会跳过点目录和常见构建 / 缓存目录(如 .git、node_modules、dist),最多处理 20,000 个目录项;超过上限会报错,而不是返回部分计数,因此不是全项目全量统计。
  • vxi_security_contract:说明允许输出与禁止输出的字段。

文件分类通过目录项完成,不读取文件内容;固定字段投影不包含源码、路径、diff、日志、环境变量或 Shell 接口。它的作用是让云端看到有限的项目状态,而不是把源码“加密后传上去”。

record 是本机 CLI 操作,不是 MCP 工具,也不会自动运行测试。调用方式是 node bin/vxi-local.mjs record --workspace /path/to/project --kind test --status PASS;kind 可选 lint、test 或 build,状态由操作者手动填写。它的实际用途很有限:把本地检查的粗粒度结果带入网页端讨论,而不上传源码或原始日志;它能帮助模型了解当前状态,却不能定位失败原因,也不是绑定 commit 的签名测试证明。需要排错时,应在本机分析完整日志,或由人工挑选并脱敏最小错误摘要再分享。

VXI SSH Ops Bridge:只允许固定的只读 SSH 操作

打开仓库

桥接器默认关闭,只暴露 vxi_ops_policy 与 vxi_ssh_health。后者接收本地配置允许的目标别名,调用固定远端脚本,并将返回值过滤成 health / service / storage 三个枚举。当前示例脚本的 health: PASS 只证明脚本成功运行;在接入并验证应用专属检查前,service 和 storage 仍为 UNKNOWN。它不提供通用 exec(command)、文件传输、部署、重启或任意日志导出。

两个仓库彼此独立:一个只暴露本地项目状态,另一个只暴露固定 SSH 检查;它们没有代码读写工具,也不会互相调用。

测试绿灯究竟证明了什么?

这些数字对应不同仓库、不同测试层级,不是同一组测试反复计数:

  • Local-First MCP: main 基线有 6 个单元测试(基线 CI)。PR #3 没有增加测试用例,只增加 Ubuntu / macOS 矩阵;同样的 6 项在两个系统上分别 6/6 通过(PR #3 CI)。
  • SSH Ops Bridge: main 基线有 7 个单元测试(基线 CI)。PR #3 保留这 7 项单元测试,并另加一次性 GitHub-hosted Ubuntu Runner 上的 OpenSSH localhost 集成作业;该运行的单元测试和回环 SSH 检查均通过(PR #3 CI)。
  • SSH Ops Bridge PR #4: 在 7 项基础上新增 1 个测试用例,专门覆盖主机名 / 用户名缺失或类型不正确的情况;同时补上相应的字符串类型校验。该 PR 分支的 8/8 单元测试和 Demo 通过(PR #4 CI)。

回环测试也暴露过真实的夹具问题:早期 Runner 用户与 PAM 配置不匹配,导致认证失败;后来又发现服务端 ForceCommand 会覆盖客户端请求,可能让测试在没执行预期命令时产生假阳性。修正后,夹具明确不配置 ForceCommand,让真实 ssh 客户端执行代码生成的固定远端脚本;测试同时检查直接调用和经 MCP 调用的结果,并确认错误的 pinned host key 与任意 exec 请求会被拒绝。

这些结果只对应各自链接中的源码版本。截至本次核对,三个源代码 PR 仍为 Draft、尚未合并;PR #3 的跨平台矩阵与回环作业、PR #4 的输入校验修复都还不属于 main。

结论:按数据边界选择,而不是按工具名字选择

如果源码允许进入云端,GitHub-first 能让 AI 直接读写代码,并用分支、PR、commit 与 CI 留下持久的工程证据。如果源码必须留在本机,Local-First MCP 可以让网页端参与状态检查,SSH Ops Bridge 可以让网页端请求一项固定的只读远端操作;代码级开发则仍需本地人工、本地推理或其他经过审查的本地流程。

真正要守住的边界,不是“用了本地工具”或“接上了 MCP”,而是每条路径实际把什么交给了模型、模型能调用什么、返回内容又去了哪里。

这两份仓库目前仍是最小原型。除文中说明的隧道互通尚未真机验证外,本轮也没有测试外部 SSH 主机、整机源码出站审计、真正的本地模型推理,或同一任务的质量 / 耗时 / Token / 费用对比。