Skip to main content
Glama
temporary111111

agent-mcp-gateway

Agent Gateway

一个面向生产的本地 Agent 网关,通过 Model Context Protocol (MCP) over Streamable HTTP,让 ChatGPT Web(GPT-5.6 Sol)能够以确定性的方式访问你的本地机器。

直连模式是默认架构。 网关暴露精确、确定性的 MCP 工具(文件系统、搜索、进程、git),这些工具在操作者授权的目录内运行。GPT-5.6 Sol 是唯一的推理 Agent:它负责规划和决策循环,网关执行它的工具调用——网关从不调用第二个 LLM。网关在没有 OpenCode 服务器、没有配置任何模型/提供商的情况下即可工作。

可选的 OpenCode Agent 模式(默认禁用)额外将整个任务委托给本地 OpenCode Agent,用于更长时间、更自主的工作。

ChatGPT Web (GPT-5.6 Sol)  <-- the reasoning agent
        │
        │  MCP over HTTPS (Streamable HTTP)
        ▼
Cloudflare Quick Tunnel
        │
        ▼
Agent Gateway  http://127.0.0.1:8000/mcp
        │
        ├── Direct mode (default): deterministic tools
        │       workspace_open / file_* / code_search / process_run / git_*
        │       (filesystem, search, process, git — no OpenCode, no LLM)
        │
        └── OpenCode agent mode (optional, ENABLE_OPENCODE_AGENT=true)
                agent_start_task / agent_status / agent_messages / agent_diff
                → OpenCode  http://127.0.0.1:4096  (localhost only)
        │
        ▼
Local system / repositories / tools

本项目取代了早期的 chatgpt-local-repo-mcp 原型,提供了一个干净、经过测试、可扩展的基础。它不是该原型的复制品。


为什么需要网关

  • ChatGPT 无法访问你的 localhost。 隧道化的 MCP 端点是经过验证的桥梁。

  • 直接的确定性工具优于第二个 Agent。 对于大多数文件、搜索、进程和 git 操作,网关的原语精确、快速,且不需要额外的模型。GPT-5.6 Sol 负责推理;网关负责机器。

  • 你可以扩展。 OpenCode(或未来的 Codex/Claude Code 适配器)可以在同一个稳定的 MCP 接口后面启用,用于自主任务委托。

Related MCP server: chatgpt-local-coding-agent

信任边界

边界

信任

ChatGPT ⇄ Cloudflare 隧道

公共;HTTPS

Cloudflare 隧道 ⇄ 网关

本地隧道;MCP 传输安全 + 可选 bearer token

网关 ⇄ OpenCode(启用时)

仅限 localhost(127.0.0.1:4096),可选 Basic Auth

网关 ⇄ 文件系统

仅限 AGENT_ALLOWED_ROOTS 中明确列出的目录

网关的 /mcp 端点是唯一的公共表面。远程调用者不能:

  • 访问配置的允许根目录之外的目录,

  • 运行不受限制的 shell 命令(命令通过 AGENT_ENABLE_COMMANDS 选择启用,并且有时间限制),

  • 除非操作者启用了该模式,否则将任务委托给 OpenCode,

  • 自动批准自己的权限请求(从未实现),

  • 在设置了 AGENT_GATEWAY_TOKEN 时,在没有 bearer token 的情况下访问网关。

架构

tools/  (MCP tools)            thin, callable by GPT-5.6 Sol
   │
   ├── tools/direct.py         deterministic primitives (default mode)
   │       workspace_open → workspace_tree / file_read / file_stat /
   │       file_find / code_search / file_write / file_replace /
   │       file_apply_patch / process_run / git_status / git_diff /
   │       git_log / git_show
   │
   ├── workspaces/             WorkspaceManager: opaque ws_ IDs bound to
   │                           allowed roots; every path re-validated
   │
   └── services/delegation.py  OpenCode mode: session lifecycle + registry
           │
           ▼
       executors/base.py       Executor interface (health, sessions, prompts,
           │                   status, messages, diffs, abort, permissions)
           ▼
       executors/opencode/     OpenCodeExecutor → OpenCodeClient → HTTP API

每个模块都依赖于其下方的层;MCP 工具从不直接接触 httpx。

MCP 工具 — 直连模式(默认,无 OpenCode,无模型)

只要网关运行,直连工具就可用。它们只在通过 workspace_open 打开的工作区内操作(这要求目录位于 AGENT_ALLOWED_ROOTS 内)。

工具

只读

用途

workspace_open

否

验证目录并将其绑定到不透明的 ws_... ID

workspace_tree

是

目录树列表(深度/条目上限)

file_read

是

读取文件(带大小上限和 offset/limit)

file_stat

是

文件或目录的元数据

file_find

是

按名称/glob 在目录下查找文件

code_search

是

不区分大小写的内容搜索,带行命中

file_write

否

创建/替换文件

file_replace

否

精确的旧字符串 → 新字符串替换(全部或第 N 次出现)

file_apply_patch

否

带上下文验证的统一 diff 补丁

process_run

否

在工作区内运行命令(选择启用,有界)

git_status

是

工作树状态

git_diff

是

工作树 diff

git_log

是

提交历史

git_show

是

某个修订版本的提交/文件内容

所有直连工具:经过验证的路径(无绝对路径、无 ..、无符号链接逃逸)、读取大小上限、列表条目上限、绑定工作区内严格的相对路径参数。

直连模式循环(ChatGPT 的使用方式)

workspace_open("C:\...\project")
   → ws_abc123
file_read(ws_abc123, "src/main.py")          → current content
file_apply_patch(ws_abc123, "src/main.py", <<<diff>>>)   → patch applied
process_run(ws_abc123, executable="pytest", args=["-q"], timeout_seconds=60) → verification
git_diff(ws_abc123)                           → review the change set

MCP 工具 — OpenCode Agent 模式(可选)

仅在 ENABLE_OPENCODE_AGENT=true 时启用。添加通用委托生命周期以及 OpenCode 诊断:

工具

只读

后端操作

gateway_health

是

网关 + 每个执行器的健康检查

agent_executors

是

列出已配置的执行器和能力

agent_start_task

否

创建会话 + 异步 prompt_async

agent_continue

否

在现有会话上异步跟进提示

agent_status

是

会话状态(busy / idle / retry)+ 待处理权限

agent_session

是

会话元数据 + 变更摘要

agent_messages

是

包含文本和工具调用部分的消息历史

agent_diff

是

Agent 生成的逐文件 diff

agent_abort

否

中止繁忙的会话

agent_pending_permissions

是

列出等待决策的权限请求

agent_reply_permission

否

回复 once / always / reject

opencode_health

是

详细的后端健康/版本/URL

opencode_agents

是

列出 OpenCode Agent

opencode_providers

是

列出模型提供商(不含密钥)

委托生命周期

agent_start_task(executor, task, directory)
      │
      ▼  returns session ID immediately (async dispatch)
agent_status(session_id)
      │
      ├── busy / retry   → wait and poll again
      │
      └── idle + completed
            ├── agent_messages(session_id)   → read what the agent did
            ├── agent_diff(session_id)        → review file changes
            ├── agent_continue(session_id, followup)  → keep going
            └── agent_abort(session_id)       → stop runaway work

长时间运行的 Agent 工作使用 OpenCode 的异步提示 API(POST /session/{id}/prompt_async)。网关立即返回,绝不在 Agent 工作时保持 MCP 请求打开。只有在会话空闲且最后一个助手轮次以 finish="stop" 结束时,才报告完成。

对现有会话的每个操作都会重新验证会话的真实目录仍然位于 AGENT_ALLOWED_ROOTS 内(失败即关闭)。

权限工作流

网关从不自动批准。当 Agent 需要批准时,它会提出权限请求,监督者通过 agent_status / agent_pending_permissions 看到它,然后由人类通过 agent_reply_permission 决定。允许的回复:once、always、reject。

安全模型

  • 传输认证:当设置了 AGENT_GATEWAY_TOKEN 时,对 /mcp 的每个请求都必须携带 Authorization: Bearer <token>(常量时间比较)。没有有效 token 的请求会收到 401。当 MCP_HOST 是非回环地址(例如 0.0.0.0、LAN IP)时,也需要 token,以防止意外的公共暴露。

  • 目录安全:AGENT_ALLOWED_ROOTS 是一个以分号分隔的绝对路径列表。如果未设置,则拒绝所有目录(失败即关闭)。每个候选路径都会被规范化,必须存在(对于任务根目录),不能是文件系统根目录,并且必须位于允许根目录内部。拒绝路径遍历、符号链接逃逸和兄弟前缀欺骗(sample vs sample-evil);在 Windows 上比较不区分大小写。

  • 默认无不受限制的 shell:process_run 需要 AGENT_ENABLE_COMMANDS=true,并强制执行超时(默认 300 秒)。

  • 有界 I/O:读取大小、树条目、搜索结果和进程输出都有上限;巨大的负载会被截断,而不是无限制地流式传输。

  • OpenCode 模式是选择启用的(ENABLE_OPENCODE_AGENT=true);没有它,agent_* 工具不会被注册,也不会联系任何后端。

  • OpenCode 模式下的权限从不自动批准。

  • 网络:OpenCode 保持仅限 localhost。只有 /mcp 被隧道化。PUBLIC_MCP_HOST 将隧道主机加入白名单,同时保持 DNS 重绑定保护启用。

  • 密钥:密码和 Authorization 头从不记录;配置摘要会掩码密码;提供商模型列表排除密钥。

安装

要求:Python 3.11+(在 3.14 上测试过)、git。OpenCode CLI 仅在可选的 OpenCode 模式下需要。

cd C:\Users\dev\Desktop\chatgpt-like\chatgpt-agent-gateway
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"

配置

将 .env.example 复制为 .env 并编辑,或直接设置环境变量:

$env:MCP_PORT = "8000"
$env:PUBLIC_MCP_HOST = "your-tunnel.trycloudflare.com"   # optional
$env:AGENT_ALLOWED_ROOTS = "C:\Users\dev\Desktop\sample-repo;C:\Users\dev\Desktop\projects"
$env:AGENT_GATEWAY_TOKEN = "generate-a-long-random-token"   # recommended
$env:AGENT_ENABLE_COMMANDS = "true"   # allow process_run
$env:LOG_LEVEL = "INFO"

变量

默认值

含义

MCP_HOST

127.0.0.1

网关绑定地址(保持 localhost)

MCP_PORT

8000

网关端口

PUBLIC_MCP_HOST

(无)

添加到 MCP 传输安全的公共主机名(例如 Cloudflare 隧道)

AGENT_ALLOWED_ROOTS

(空)

以分号分隔的允许目录;空 ⇒ 失败即关闭

AGENT_GATEWAY_TOKEN

(空)

/mcp 的 Bearer token;空 ⇒ 不需要 token(仅限 localhost)

AGENT_INSECURE_NO_TOKEN_OPT_OUT

false

在设置了 PUBLIC_MCP_HOST 时,无 token 运行所必需(危险)

AGENT_ENABLE_COMMANDS

false

启用 process_run

AGENT_PROCESS_TIMEOUT_MAX

300

process_run 可能花费的最大秒数

AGENT_MAX_READ_BYTES

200_000

file_read 输出的上限

AGENT_MAX_TREE_ENTRIES

1000

workspace_tree 条目的上限

AGENT_MAX_SEARCH_RESULTS

200

code_search 结果的上限

AGENT_MAX_PROCESS_OUTPUT_BYTES

100_000

process_run 输出的上限

ENABLE_OPENCODE_AGENT

false

启用可选的 OpenCode Agent 模式

OPENCODE_URL

http://127.0.0.1:4096

本地 OpenCode 无头服务器

OPENCODE_USERNAME / OPENCODE_PASSWORD

(空)

OpenCode 的可选 Basic Auth

LOG_LEVEL

INFO

日志详细程度

运行网关

agent-gateway
# or
python -m agent_gateway.server

本地 MCP 端点:http://127.0.0.1:8000/mcp

通过 Cloudflare 暴露

网关的传输安全机制保持 DNS 重绑定保护开启,并允许 localhost 以及你在 PUBLIC_MCP_HOST 中设置的主机名。启动一个指向 http://127.0.0.1:8000 的 Quick Tunnel:

cloudflared tunnel --url http://127.0.0.1:8000

将打印出的 https://<id>.trycloudflare.com 设置为 PUBLIC_MCP_HOST,然后重启网关。设置 AGENT_GATEWAY_TOKEN —— 除非你显式设置 AGENT_INSECURE_NO_TOKEN_OPT_OUT=true,否则网关拒绝公开暴露无令牌的 /mcp。安全检查绝不会为了隧道工作而被禁用;相反,公共主机被显式加入允许列表。

运行 OpenCode(可选代理模式)

opencode serve --port 4096 --hostname 127.0.0.1

验证:Invoke-RestMethod http://127.0.0.1:4096/global/health

测试

pytest                     # default suite: direct mode only (150 passed, 9 skipped)
pytest tests/unit          # unit tests — no services needed
$env:ENABLE_OPENCODE_AGENT = "true"
pytest                     # full suite incl. OpenCode mode (158 passed, 1 skipped)

e2e 套件会在一个临时端口上启动真实的网关进程,并通过 MCP-over-HTTP 以 ChatGPT 所用的精确协议驱动它。有两种形式:

  • tests/e2e/test_direct_e2e.py —— 无 OpenCode 且无模型的直接模式:无令牌时返回 401、工具列表、工作区 → 读取 → 补丁 → 写入 → 进程 → git diff,以及拒绝未授权的目录。在默认套件中运行。

  • tests/e2e/test_opencode_e2e.py —— OpenCode 模式(仅在 ENABLE_OPENCODE_AGENT=true 且服务器在线时运行):只读委派任务(仓库经逐字节验证未修改)以及完整的 MCP 协议流程,包括错误情况。

仓库布局

src/agent_gateway/
├── config.py            typed configuration (env-driven, validated)
├── errors.py            gateway error taxonomy
├── logging.py           redacted logging
├── security/
│   ├── paths.py         allowed-roots enforcement
│   └── auth.py          bearer-token middleware (constant-time compare)
├── workspaces/          WorkspaceManager: ws_ IDs, per-workspace validation
├── direct/              deterministic primitives (filesystem, search,
│   │                    process, git) shared by the direct tools
├── executors/
│   ├── base.py          Executor interface
│   └── opencode/        OpenCode client, models, errors, executor
├── services/delegation.py  OpenCode orchestration + session registry
├── tools/               MCP tool registration (direct, gateway, delegation,
│   │                    permissions, opencode)
└── server.py            MCP server assembly + entry point

未来的执行器架构

通过实现 executors/base.py、在 executors/__init__.py 中注册它,并在 tools/ 中添加任何后端特定的诊断工具,即可添加新后端。通用的 agent_* 工具和委派服务无需更改。不附带任何伪造的 Codex/Claude 适配器。

限制

  • OpenCode 会话注册表位于内存中;网关重启后会忘记会话来自哪些目录(OpenCode 本身会按 ID 持久化会话)。

  • 直接模式的工作区(ws_...)也会在网关重启后过期;使用 workspace_open 重新打开它们。

  • file_apply_patch 需要精确的上下文匹配;不支持模糊应用。

  • OpenCode API 作为 v1 OpenAPI 路径的超集被使用;未来的后端版本应针对各自的 /doc 重新验证。

  • always 权限回复在协议层面受支持;运维人员可能希望全局禁用它以强制每次运行都需批准。

Related MCP Connectors

Related MCP Servers