agents-mcp-gateway
Secure localhost MCP gateway for Windows-native local agent work.
Only one MCP server is exposed externally: agents-mcp-gateway at http://127.0.0.1:3333/mcp. Codex and Claude are no longer used as child MCP servers. Agent work runs through ordinary non-interactive CLI subprocesses with fixed argv from local config.
Architecture
ChatGPT
-> OpenAI Secure MCP Tunnel
-> http://127.0.0.1:3333/mcp
-> native bounded file/Git/search/check tools
-> codex CLI subprocess adapter
-> claude CLI subprocess adapter
Configuration
config/projects.yaml has two registries:
projects:
agents-mcp-gateway:
description: Gateway source tree
path: D:\Projects\agents-mcp-gateway
agents:
codex-readonly:
description: Codex CLI non-interactive read-only agent
adapter: codex
args: ["exec", "--json", "-s", "read-only", "-c", "approval_policy='never'"]
claude-readonly:
description: Claude Code non-interactive JSON agent
adapter: claude
args: ["-p", "--output-format", "json", "--permission-mode", "dontAsk"]
Remote MCP callers cannot pass command, args, env, model, cwd, or arbitrary filesystem paths for an agent. They can only choose a configured agent, provide a configured project_id, and send a prompt.
Public Agent Tools
list_projects()list_agents()create_task(project_id, agent, prompt) -> task_id, thread_idresume_thread(thread_id, prompt) -> task_idget_task(task_id)await_task(task_id, timeout_ms?)β wait up to 60 seconds for a terminal task state, defaulting to 30 seconds; if the timeout elapses, returns the latest task withwait_timed_out: truecancel_task(task_id)list_tasks(status?, limit?)get_thread(thread_id)list_threads(status?, limit?)close_thread(thread_id)
A task is one CLI subprocess execution. A thread stores the gateway thread ID, provider session ID, adapter, agent, and canonical cwd so later tasks can resume the provider conversation without accepting project_id or agent again.
Native Tools
Native file/Git/search tools remain project-scoped:
list_files(project_id, relative_path, depth)read_file(project_id, relative_path, start_line, end_line)search_code(project_id, query, glob, max_results)git_status(project_id)git_diff(project_id, base, max_chars)git_log(project_id, limit)run_check(project_id, check_id)
run_check does not accept arbitrary commands. It only runs detected package scripts named test, lint, typecheck/check, or build.
CLI Probe Findings
Codex 0.146.0-alpha.3.1:
- new session:
codex exec --json -C <cwd> ... <prompt> - JSONL event
thread.started.thread_idis the provider session ID - resume:
codex exec resume --json <thread_id> <prompt> - resume command must run with process cwd set to the original cwd;
resumehas no-C - fixture probe confirmed new session, remembered context, and cwd continuity
Claude Code 2.1.220:
- new session:
claude -p --output-format json ...with prompt on stdin - JSON result has
session_id - resume help exposes
--resume <session_id> - current provider probe returned a quota
429, so command shape andsession_idparsing are implemented, while semantic resume could not be completed in this run
Run
cd D:\Projects\agents-mcp-gateway
pnpm install
pnpm build
pnpm start
Doctor:
pnpm doctor
Tests:
pnpm test
Automatic Start
powershell -ExecutionPolicy Bypass -File scripts\install-task-scheduler.ps1
Remove:
powershell -ExecutionPolicy Bypass -File scripts\uninstall-task-scheduler.ps1
Security Notes
- Server binds only to
127.0.0.1. - No router port forwarding,
0.0.0.0, or public tunnel URL is used. - External access should go through OpenAI Secure MCP Tunnel only.
- Agent argv is fixed in local config.
- Environment is allowlisted.
- Sensitive files, credential folders,
.git,node_modules, browser session stores, symlink/junction escapes, UNC paths, URL paths, and project traversal are blocked.