local-mcp-chatgpt-tunnel
Local MCP ChatGPT Tunnel
Windows에서 실행되는 stdio 형식의 MCP 서버를 OpenAI 공식 Secure MCP Tunnel을 통해 ChatGPT Developer Mode에 연결하기 위한 로컬 Gateway입니다. 여러 stdio MCP를 하나로 통합하고, 도구 이름의 네임스페이스화, 공개 도구 제외, 경로 허용, 직렬 실행, 지연 시작을 설정 파일에서 제어할 수 있습니다.
설치 방법
[!IMPORTANT] Windows 환경에서의 도입 절차는 INSTALL.md를 참조하세요.
Related MCP server: Windows Local MCP
보안 경고
[!WARNING] 자신의 Windows PC, 자신의 OpenAI Platform Organization, 자신의 ChatGPT Workspace에서만 사용하는 개인 전용 도구입니다. 임의 코드 실행 능력을 가진 MCP를 연결할 수 있으므로, 제3자와의 공유나 공개 Plugin으로의 운영은 가정하지 않습니다.
codex 샌드박스에 대하여
[!IMPORTANT] 2026년 8월 11일 버전에서 codex 샌드박스를 직접 사용하여 경계 불일치나 임의 코드 실행으로부터 컴퓨터를 보호하는 메커니즘이 구현되었습니다. 일반 셸이나 임의 실행 파일 선택은 제공하지 않지만, 고정 runtime에서 기존 스크립트를 실행하는
codex-script가 동봉되었습니다.codex-script는elevated또는unelevatedsandbox가 필수입니다. 그 외의 동봉 MCP나 외부 stdio MCP도 MCP별로 Codex sandbox 내에서 시작할 수 있으므로, 앞으로는 가능한 범위에서elevated모드를 통한 경계 강화를 권장합니다.
AI에 의한 구현에 대하여
[!CAUTION] 이 리포지토리는 ChatGPT 5.6 Sol High에 의해 구현되었습니다. AI가 생성한 코드를 포함하므로 오류나 취약성이 남아 있을 가능성이 있습니다. 실제로 사용하기 전에 코드와 설정 내용을 확인하고, 이용자 본인의 책임으로 사용하세요.
무엇을 할 수 있는가
ChatGPT에서 Windows의 stdio MCP 서버를 호출합니다
여러 MCP를
<prefix>__<tool>형식의 도구 이름으로 통합합니다임의의 stdio MCP를
config/gateway.toml에 추가합니다MCP별로 허용하는 디렉터리와 파일을 제한합니다
위험한 도구를 이름 또는 부분 문자열로 비공개 처리합니다
동시 실행을 원하지 않는 MCP를
serial_group으로 직렬화합니다필요에 따라 특정 MCP 전체를 비활성화합니다
필요에 따라 공개된 도구를 전체 식별자 또는 prefix로 검색하는 내장 디렉터리를 공개합니다
이 리포지토리가 수행하지 않는 일
OpenAI Responses API나 Chat Completions API 호출
자체 AI 에이전트, 자체 하네스, 모델 과금 처리 구현
공개 MCP URL이나 로컬 수신 포트 제공
Node.js, Git, ripgrep, Python, tunnel-client 자동 설치
Ghidra MCP, Chrome DevTools MCP, DQ9 MCP 등 제3자 MCP 재배포
Secure MCP Tunnel 연결은 공식 tunnel-client.exe가 담당합니다.이 리포지토리는 그 표준 입출력에 연결하는 로컬 MCP Gateway와 동봉 MCP를 제공합니다.
지원 환경
현재 도입 절차는 Windows 11용입니다.실행에는 Node.js LTS와 OpenAI 공식 tunnel-client.exe를 사용합니다.동봉된 파일 검색 기능에는 ripgrep을 사용하고, GitHub Actions 확인에는 GitHub CLI를 사용합니다. 진단 스크립트는 node, npm, git, gh, rg, py를 확인합니다.
macOS와 Linux용 도입 절차, Docker 구성, 수신 포트를 여는 구성은 제공하지 않습니다.
사용을 시작하기까지
사용할 수 있게 되기까지의 절차는 INSTALL.md에 정리되어 있습니다. 대략적인 흐름은 다음과 같습니다.
필요한 소프트웨어와 공식
tunnel-client.exe를 수동으로 준비합니다config/gateway.example.toml을config/gateway.toml로 복사하고 절대 경로를 수정합니다OpenAI Platform에서 개인용 Tunnel과 실행 전용 runtime API key를 만듭니다
Tunnel ID와 runtime API key를 Windows 사용자 환경 변수에 저장합니다
start.cmd로 진단 후 Tunnel을 시작합니다ChatGPT Developer Mode에서 개인용 Tunnel을 선택합니다 설정이나 권한을 추측하여 진행하지 말고, 반드시 INSTALL.md를 위에서부터 확인하세요.
동봉 MCP
MCP | 공개 도구 예 | 용도 |
|
| 허용된 Workspace 내의 목록, UTF-8 검색, 여러 파일·줄 범위 읽기, 파일 정보, 읽기/쓰기, Workspace 간 파일 이동·복제, 제한된 패치 적용 |
|
| PNG, JPEG, WebP를 ChatGPT의 이미지 콘텐츠로 읽기 |
|
| 허용된 소스를 단일 파일이든 ZIP이든 ChatGPT로 전달 |
|
| 허용된 리포지토리에 대한 로컬 Git 작업. commit / push / pull / clone은 포함하지 않음 |
|
|
|
|
| 명시적으로 허용한 GitHub 리포지토리의 Actions 실행 상태 확인과 run 취소 |
|
| MCP 시작 시 고정된 mjs / Node.js / Python / PHP runtime으로 허용 Workspace 내의 기존 스크립트 실행 또는 구문 검사. |
|
|
|
|
| 고정 7-Zip만 사용하는 archive 생성·해제 |
|
| 기존 GitHub Codespace만을 대상으로 remote 검색·SSH·전송·중지·임시 public deployment를 처리. localhost나 로컬 수신 포트의 자동 감지는 하지 않으며, Codespace 생성 도구도 없음 |
동봉 MCP는 외부 npm 의존성을 가지지 않습니다. 모든 도구가 outputSchema를 선언합니다.
Gateway는 isolated__create, isolated__list, isolated__close를 공개하고, 동봉 MCP의 모든 도구에 고유한 isolatedId를 필수화합니다. isolated__create는 1개 이상의 절대 디렉터리를 workspaces 배열로 받는 것 외에도, 해당 AI/session이 어떤 작업에 사용하는 격리인지 설명하는 purpose도 필수입니다. Gateway는 createdAt을 자동 기록하고, isolated__list에서는 각 prefix의 lastOperationAt도 반환합니다. ID별로 복수의 Workspace와 MCP별 상대 경로 기준을 유지합니다. 동봉 MCP 프로세스 자체는 복제하지 않고, 호출마다 대상 ID의 root 집합을 전달합니다. 일반적인 bundled tool call은 Gateway에서 불필요한 직렬화를 하지 않고 자식 MCP 쪽에 병렬 처리를 맡기며, Codespace만 동일한 codespaceId의 경쟁 방지용 queue를 가집니다.
Gateway는 시작 시 동봉 MCP별 랜덤 키를 생성하고, isolatedId, 정규화된 기준 경로, root 집합을 HMAC-SHA-256으로 서명하여 비공개 인수로 전달합니다. 동봉 MCP는 서명되지 않음, 변조됨, 구조가 올바르지 않은 컨텍스트를 거부하고, 공개 인수를 통한 root, roots, workspace, workspaces 덮어쓰기도 거부합니다.
Gateway는 시작한 모든 자식 MCP에 <prefix>__get_gateway_access_scope를 추가합니다. 동봉 MCP에서는 isolatedId를 붙여 호출하고, 해당 ID에 적용되는 기준 디렉터리, root 집합, 설정값, 정규화된 허용·거부 경로를 확인할 수 있습니다.
허용 범위 밖의 경로가 거부된 경우, 오류 본문에 현재 허용된 디렉터리와 파일을 정규화된 절대 경로로 반환합니다. 동봉 MCP의 공통 출력 형식에서는 structuredContent.result.accessScope에도 동일한 목록을 반환합니다. 거부 후 AI가 다른 작업 디렉터리를 추측하여 재시도할 필요가 없습니다.
safe-files
safe-files에서 외부로 "MCP root"라고 부르는 것은 대상 isolatedId에 저장된 현재 기준 디렉터리입니다. 상대 경로는 이 기준에서 해석되고, set_working_directory는 같은 ID의 root 집합 내에서만 기준을 변경합니다. 다른 ID나 공유 MCP 프로세스의 상태는 변경하지 않습니다.
read_text는 MCP root 기준 상대 경로와 절대 경로를 모두 받지만, 정규화 후 및 실제 경로 해석 후의 대상이 설정된 허용 디렉터리 내에 남는 경우에만 읽습니다.
주요 기능은 다음과 같습니다.
고정된
rg --files --hidden을 사용한 재귀 목록고정된
rg를 사용한 UTF-8 텍스트 검색UTF-8 텍스트의 읽기/쓰기와 완전 일치 치환
크기를 제한한 base64 파일 전송
디렉터리 생성
설정된 허용 Workspace 간의 일반 파일 복제와 이동
내장 파서 또는 고정된
git apply를 사용한 패치 적용copy와move는 현재 MCP root 기준 상대 경로와 절대 경로를 받으며, 여러allowed_directories간에도 일반 파일을 전송할 수 있습니다. 송신원과 송신 대상 양쪽에 허용·거부 정책을 적용하고, 심볼릭 링크, 디렉터리, 기존 송신 대상으로의 덮어쓰기를 거부합니다. 이동은 다른 드라이브 간에도 동작하도록, 배타적 복제에 성공한 후 송신원을 삭제하고, 삭제 실패 시 송신 대상을 되돌립니다. 경로 문자열은 셸로 전달하지 않으며, 기호를 명령으로 해석하지 않습니다.재귀 목록에서는.git내부를 항상 제외하고, 패치에서는.git내부를 대상으로 할 수 없습니다. 허용 루트 밖, 심볼릭 링크를 통한 탈출, 높은 확률로 자격 증명으로 보이는 내용 등도 거부합니다.일반 셸, PowerShell, 임의 명령 실행 도구는 포함하지 않습니다.
safe-images
safe-images는 읽기 전용입니다. PNG, JPEG, WebP의 확장자와 매직 바이트를 대조하고, 초기 상태에서는 8 MiB, 50메가픽셀까지로 제한합니다.
SVG, HEIC, 빈 파일, 허용 루트 밖, 심볼릭 링크, UNC 경로, NTFS 대체 데이터 스트림을 거부합니다.
safe-download
safe-download는 읽기 전용이며, 단일 파일 또는 디렉터리를 항상 ZIP으로 반환합니다. safe-files와는 별도의 cwd와 허용 목록을 설정하고, ChatGPT로 전달해도 되는 소스만 공개합니다.
디렉터리는 고정된 rg --files --hidden으로 열거하고, .git 내부, ROM, Save, State, 비밀 키 형식, 자격 증명으로 보이는 내용, 허용 범위 밖, 심볼릭 링크를 거부합니다. disallowed_path_globs가 설정된 경우, 이용자 지정의 globs나 excludePaths를 적용하기 전에 대상 디렉터리 전체를 확인하고, 거부 패턴에 일치하는 파일 또는 폴더가 1개라도 있으면 ZIP 생성 전체를 거부합니다. 오류에는 일치한 설정 패턴과 대상 경로를 포함합니다.
internet
internet은 임의의 HTTP/HTTPS URL에서 파일 1개를 가져오는 동봉 MCP입니다. 공개 도구는 download_file뿐이며, 송신 대상은 Gateway 서명된 isolatedId의 workspace 내로 한정됩니다. 기존 파일 덮어쓰기, UNC/ADS, workspace 밖으로의 쓰기, 임의 header·cookie·credential 주입은 받지 않습니다. 도중 실패 시 임시 파일을 삭제합니다.
이 MCP는 반드시 sandbox = "onlineworkspace"로 시작합니다. onlineworkspace는 Codex의 workspace-write filesystem 경계를 유지하면서, 해당 permission profile의 network만 활성화합니다. sandbox = "never"로 폴백하지 않습니다.
archive
archive는 시작 시 --seven-zip-executable=<absolute-7z.exe-path>로 7-Zip을 고정하고, create_zip, create_7z, extract_archive만 공개하는 동봉 MCP입니다. 일반 셸, 임의 실행 파일, 임의 7-Zip 인수는 공개하지 않습니다. 입력·출력은 서명된 workspace 내로 한정합니다. extract_archive는 source와 destination이 서로 다른 허용 root에 있어도 처리할 수 있으므로, 예를 들어 Downloads 내의 archive를 Project workspace로 직접 해제할 수 있습니다. 해제 대상은 존재하지 않는 경우 생성하고, 기존인 경우 빈 일반 디렉터리만 받습니다. 경로는 해석 후에도 1024자 이내로 제한합니다.
archive 자체도 Codex sandbox 내에서 시작하고, 7-Zip 설치 위치는 sandbox_read_only_directories로 read-only trust input으로 전달합니다.
codespace
codespace는 이미 존재하는 GitHub Codespace만 조작하는 동봉 MCP입니다. list_codespaces가 반환한 name을 각 도구의 codespaceId로 사용합니다. Codespace의 create, rebuild, machine 변경, 명시적 start, delete를 수행하는 도구는 구현하지 않습니다. 기동은 SSH나 copy의 연결로 기존 Codespace를 암묵적으로 시작하고, 작업 종료 시 stop_codespace로 gh codespace stop -c <name>을 실행하여 명시적으로 중지할 수 있습니다. 중지 전에는 해당 isolated session이 소유한 동일 Codespace용 async SSH를 cancel하고, SSH readiness cache도 폐기합니다. 중지 후에도 Codespace 자체나 저장된 변경 사항은 삭제하지 않습니다. AI가 변덕스럽게 Codespace를 마구 생성할 수 있는 경로는 없습니다. 동일한 codespaceId는 하나의 isolated session만 소유하며, 다른 새로운 isolated session이 접근하면 후승(後勝) 방식으로 소유권을 이전합니다. 이전 session은 자동으로 되찾을 수 없으며, 경합 오류에서 isolated__list의 purpose와 codespace prefix의 lastOperationAt을 확인하여 사용자에게 판단을 요청하도록 지시됩니다. 동일한 codespaceId의 호출만 Gateway에서 직렬화하고, files 등 다른 bundled MCP는 불필요하게 직렬화하지 않습니다.
MCP 자체는 반드시 sandbox = "onlineworkspace"로 기동합니다. --gh-executable=<absolute-gh.exe-path>는 필수입니다. Windows Credential Manager에 저장된 일반적인 gh auth login 자격 증명이 sandbox user에게 보이지 않는 구성에 대비하여, 선택적으로 --token-file=<absolute-file>을 지정할 수 있습니다. 이 파일은 고정 read-only trust input으로 Codex permission profile에 전달되며, 내용은 MCP 내부에서만 GH_TOKEN으로 설정합니다. 상위 환경의 GH_TOKEN / GITHUB_TOKEN은 상속하지 않습니다. 사용자 SSH 키는 설정·읽기·허용하지 않습니다. SSH/cp에 필요한 키는 Gateway가 준비한 non-hidden 임시 runtime directory 내에서 Codespace MCP 자체가 ssh-keygen으로 자동 생성하고, Gateway가 자식 MCP를 close할 때 삭제합니다. 이 내부 directory는 Codex permission profile에만 write 허용되며, allowed_directories나 Gateway의 일반 파일 액세스 범위에는 추가하지 않습니다. gh.exe와 token file은 write 가능한 allowed_directories 내에 둘 수 없습니다.
ssh는 remote command를 문자열 1개가 아닌 token 배열로 받으며, 공백, quote, !, @, backtick, $, ;, &, pipe 등 shell expansion / metacharacter를 거부합니다. timeoutMs는 underlying operation 자체의 hard runtime으로, 동기 응답으로 기다리는 시간과는 별개입니다. 보통은 syncWaitMs만큼만 동기로 기다리며, 기본/최대 10,000 ms입니다. 완료되지 않으면 처리를 중단하지 않고 shared async registry로 옮겨 asyncId를 반환합니다. syncWaitMs=0..1000은 즉시 async로 취급하고, async=true면 syncWaitMs를 무시하고 처음부터 즉시 asyncId를 반환합니다. get_async_status는 asyncId 생략 시 해당 isolation의 보유 중 async operation을 한꺼번에 반환하고, 개별 ID로는 상세/완료 result를 얻을 수 있습니다. get_async_logs는 process-backed job의 보유 중 stdout/stderr 전체를 가져오는 용도입니다. wait_async는 호환 구현으로 남겨두지만, 장시간 MCP 응답을 유지하여 Gateway/tunnel을 끌어들이지 않도록 보통은 get_async_status / get_async_logs를 사용합니다.
copy_to_codespace는 sourceDirectory 하위에서 paths 열거 또는 globs 중 하나로 선택한 local file/directory를 caller가 명시한 remote: destination으로 보냅니다. MCP는 remote:를 추측·자동 부여하지 않습니다. 예를 들어 paths=["scripts/a.js"]라면 remote:/workspaces/project 하위의 /workspaces/project/scripts/a.js에 배치하고, basename만 destination 바로 아래로 flatten하지 않습니다. 계층 유지를 위해 필요한 remote parent directory만 고정 helper로 만들고, 각 selection을 해당 destination으로 복사합니다. copy_from_codespace는 반대 방향으로, caller가 명시한 remote:/workspaces/<workspace>/... source 1건을 signed local workspace 내의 기존 destination directory로 복사합니다. remote source는 복사 전에 검사하여 symlink/special entry, 과도한 entry 수, CODESPACE_MCP_MAX_TRANSFER_BYTES 이상의 전송을 거부합니다. local target basename이 이미 존재하는 경우도 거부합니다. 두 copy tool 모두 remote 쪽만 remote:이고, local 쪽은 local path여야 하며, remote protocol이 없거나 양쪽 모두 remote인 모호한 지정은 거부합니다. gh codespace cp는 기존 remote path에서도 -e 없이는 No such file or directory가 되는 GitHub CLI 알려진 문제가 있으므로, 양방향 모두 -e를 항상 붙입니다. remote: 자체는 caller가 명시하며 MCP는 자동 부여하지 않습니다. SSH readiness는 필요할 때만 고정 echo started probe로 확인하고, cache 재사용 중 cp 실패 시에만 probe 후 1회 재시도합니다.
remote 검색은 roots로 /workspaces 바로 아래의 workspace만 열거하고, git_root로 지정 path의 Git top-level을 얻을 수 있습니다. search_text는 files__search_text에 상당하는 일급 ripgrep 검색으로, 매번 searchBase=/workspaces/<workspace>/...을 필수로 합니다. /, /workspaces, home, /etc 등을 검색 root로 할 수 없습니다. searchBase는 remote realpath 후에도 재검증합니다. query와 glob은 SSH command 문자열로 연결하지 않고 base64화하여 stdin에서 고정 remote script로 전달합니다. .git은 항상 검색 대상에서 제외하고, 파일 1개당 16 MiB를 상한으로 하며, 결과 건수도 최대 500건으로 제한합니다. ripgrep_version으로 rg --version을 확인할 수 있고, install_ripgrep은 이미 rg가 있으면 아무것도 하지 않으며, 없는 경우에만 고정 installer로 apt/dnf/yum/apk 중 하나를 사용해 도입 후 다시 version을 확인합니다. package 이름이나 임의 shell 문자열을 tool 인수에서 전달할 수 없습니다.
list_temporary_public_deployments는 GitHub 쪽에서 이미 인식된 Codespace의 임시 공개 후보와 browseUrl / port / visibility를 가져옵니다. 이는 localhost, 로컬 PC의 수신 socket, 브라우저 탭, 로컬 개발 서버를 탐색하는 도구가 아니며, port 자동 감지도 수행하지 않습니다. GitHub 쪽 후보가 0건이면 빈 배열을 정상 결과로 반환하지 않고, "이것은 로컬 port 자동 감지 실패가 아니다", "localhost 탐색·port scan·URL 추측·gh codespace ports forward로의 우회를 하지 않는다"는 점을 명시하는 보정 오류를 반환합니다. open_temporary_public_deployment는 호출 측이 명시한 1개의 Codespace port만 대상으로, 먼저 GitHub에 public visibility 변경을 요청하고, 성공 후 완전한 https://...app.github.dev URL을 확인하여 반환합니다. 정확한 port를 알고 있다면 이 도구를 직접 호출하고, list_temporary_public_deployments를 사전 조건으로 하지 않습니다. list가 0건이었다는 사실만으로 .devcontainer의 forwardPorts가 필요하다고 추측해서는 안 됩니다. GitHub가 지정 port를 거부하면 그 실제 오류를 반환하고, localhost를 탐색하여 대체 port를 추측하지 않습니다. close_temporary_public_deployment도 명시된 동일한 port만 private로 되돌려 임시 공개를 닫습니다. 어느 쪽도 localhost port tunnel을 만들지 않으며, GitHub 쪽 forward entry 자체도 새로 생성·삭제하지 않습니다. 반환된 browseUrl은 그대로 Chrome DevTools 등에서 임시 배포의 통신 확인에 사용할 수 있습니다.
gitmcp
gitmcp는 허용된 디렉터리 내 Git 리포지토리에 대한 로컬 조작만 고정된 Git 서브커맨드와 옵션으로 실행합니다. 기동 시 --git-executable=<absolute-path>를 필수로 하며, 그 실체만 shell=false로 기동합니다. 일반 셸이나 임의 Git 인수는 받지 않으며, .git 직접 편집, 훅 추가, branch 삭제, force 조작은 지원하지 않습니다. index를 재작성하는 add_all, stage_paths, unstage_paths와 commit, push, pull, clone_repository는 경계 분리를 위해 별도의 git-capability MCP로 이동했습니다. 기존 --disable-push, --disable-pull, --disable-clone은 이전 gateway.toml을 기동 불가로 만들지 않기 위해 no-op로 수용하지만, 이들을 false로 설정해도 이동된 capability는 부활하지 않습니다.
status, 추적 파일 목록, branch·remote·이력 확인, 작업 트리 또는 staged diff, 특정 commit의 show, 기존 branch로의 전환과 checkout, 상위 commit을 지정한 branch 생성, 허용 root 내 worktree 생성·목록·일반 삭제를 이용할 수 있습니다. branch 삭제, primary worktree 삭제, dirty 또는 locked worktree의 강제 삭제는 구현하지 않습니다.
.gitignore와 표준 ignore 설정을 존중하기 위해 status는 ignore된 미추적 파일을 표시하지 않습니다. .gitattributes, .git/info/attributes, 글로벌 attributes, core.autocrlf 등의 줄바꿈 변환, 시스템·글로벌 설정의 clean/smudge filter, 외부 diff, textconv도 일반 Git과 동일하게 존중합니다. 리포지토리 내 .git/config 또는 worktree config에 배치된 실행 가능한 설정은 사전에 거부합니다. system/global의 filter나 diff helper는 의도대로 실행될 수 있으므로, 파일 조작 권한을 가진 gitmcp는 가능하면 Codex OS sandbox 내에서 실행하는 구성을 권장합니다. Windows의 Codex sandbox에서는 permission profile의 :minimal read가 C:\Program Files 등의 system read root를 부여하므로, 표준 C:\Program Files\Git\cmd\git.exe는 추가 read 설정 없이 사용할 수 있습니다. Portable Git 등 system read root 밖의 Git을 지정하는 경우에만 해당 Git 설치 디렉터리를 sandbox_read_only_directories에 추가합니다. sandbox = "never"도 하위 호환성을 위해 사용할 수 있습니다.
list_worktree_files는 추적 파일과 ignore되지 않은 미추적 파일을 Git 자체의 exclude 판정으로 열거합니다. check_ignore는 각 경로에 적용된 ignore 규칙과 최종 판정, check_attributes는 text, binary, diff, merge, filter, 줄바꿈 속성 등의 실효값을 반환합니다. get_effective_config는 credential.*, author 이름, 이메일 주소를 조회 대상에서 제외하고, core.autocrlf, filter, attributes, diff/textconv 등 로컬 gitmcp의 동작과 관련된 설정을 scope·origin과 함께 반환합니다.
안전 대책은 Git 설정 전체의 무효화가 아니라, 리포지토리 자체의 .git/config 또는 worktree config에 배치된 실행 가능한 hook, helper, filter, 외부 diff/textconv, merge driver, 서명 program, proxy, 자체 transport 설정의 거부로 한정합니다. 훅, fsmonitor, file·ext protocol, 대화형 credential prompt는 비활성화됩니다. get_policy로 현재 방침을 기계 판독 가능하게 확인할 수 있습니다.
repositoryPath에 서브모듈이나 중첩 Git 리포지토리를 직접 지정하면 해당 리포지토리 자체의 status, diff, log 등을 얻을 수 있습니다. 상위 리포지토리 하위를 재귀 탐색하여 모든 중첩 리포지토리를 자동 열거하는 도구는 포함하지 않습니다.
git-capability
git-capability는 mcp/git-capability/server.mjs를 --mode=stage|commit|push|pull|clone으로 여러 개 등록하고, 용도별로 Git capability를 분리하는 동봉 MCP입니다. 각 등록은 독립된 [mcp_servers.<name>]이므로 sandbox, allowed_directories, timeout, serial_group을 개별로 선택할 수 있습니다. sandbox = "never"는 금지하지 않으며, Git index, 서명 agent, network와의 호환성이 필요한 이용자도 기존 경로를 선택할 수 있습니다.
전 mode에서 --git-executable=<absolute-path>를 기동 시 고정하고, tool 인수에서 Git 실행 파일, repositoryPath, 환경 변수, 임의 Git 인수를 선택할 수 없습니다. Gateway 경유 시에는 일반 bundled MCP와 동일한 HMAC 서명된 isolated workspace가 필수입니다. 리포지토리 내 .git/config 또는 worktree config에 실행 가능한 hook / helper / filter / diff / merge driver / signing program / proxy / transport 설정이 있으면 capability 실행 전에 거부합니다.
stage mode는 add_all, stage_paths, unstage_paths만 공개하고, repository 선택은 서명된 workspace/base에서 고정합니다. Gateway는 sandboxed Git MCP 기동 시, 쓰기 가능 root 아래에 그 시점에 존재하는 .git을 자체적으로 탐색하고, Codex permission profile에 구체적인 Git metadata write root를 추가합니다. 이는 Codex 쪽의 is_metadata_write_denied / has_explicit_write_entry_for_metadata_path가 보호 metadata 내 더 구체적인 명시 write entry를 허용하는 구현에 기반합니다. .git/hooks, .git/objects/info, .git/modules는 write 거부 상태로 두고, 기존 .git/config, config.worktree, commondir, gitdir도 write 거부합니다. 따라서 stage나 일반적인 branch/worktree metadata 갱신은 sandbox 내에서 이용할 수 있지만, submodule 추가는 대상 외입니다. 기동 후 새로 만들어지는 .git은 자동 허용하지 않으므로 git init과 sandbox 내 clone은 이 메커니즘으로 처리하지 않습니다. stage 시에도 표준 ignore, attributes, line-ending conversion, system/global clean filter를 존중하고, deny 대상 worktree path는 거부합니다.
commit mode의 tool 인수는 message뿐이며, 이미 stage된 index만 git commit --no-verify -m <message>로 commit합니다. stage 기능이나 repository 선택은 없습니다. system/global의 commit signing 설정은 유지하므로, 서명 agent에 액세스시키려는 구성에서는 commit MCP만 sandbox = "never"로 하고, 더 큰 gitmcp는 sandbox 내에 둘 수 있습니다.
push와 pull은 기동 시 --remote=와 1개 이상의 --repository=OWNER/REPO를 고정하고, remote URL에서 GitHub의 repository identity를 정규화하여 허용 목록의 하나와 대조합니다. 따라서 https://github.com/OWNER/REPO.git과 git@github.com:OWNER/REPO.git은 동일 repository로 취급하지만, repository 이름의 부분 일치는 허용하지 않습니다. 여러 workspace를 하나의 capability에 허용하려면 --repository=를 반복할 수 있습니다. 기존 --expected-remote-url=<exact-url>도 하위 호환성을 위해 사용할 수 있습니다. tool 호출은 remote, URL, refspec을 받지 않습니다. push는 current branch만 force 없이 전송하고, upstream 설정을 재작성하지 않습니다. pull은 고정 remote를 fetch하고, incoming tree에 path policy를 적용한 후 동일 이름의 current branch에 --ff-only로 반영합니다.
clone은 기동 시 --url=을 폐지하고, tool 쪽에서 url, 새 자식 디렉터리 이름, 선택적 depth를 받습니다. url은 임의 host의 http://, https://, ssh://user@host/path, user@host:path 형식을 허용합니다. HTTP(S) URL에 인증 정보를 포함하거나 SSH URL에 비밀번호를 포함하는 것은 거부하고, 일반적인 Git credential helper, askpass, SSH agent / SSH 설정 등의 계승 인증 경로는 유지합니다. --no-checkout으로 가져온 후 incoming tree의 허용·거부 경로를 검사한 다음 checkout하고, 실패 시 그 호출에서 새로 생성한 clone 대상만 삭제합니다. submodule 재귀와 임의 parent는 공개하지 않습니다.
gh-workflow
gh-workflow는 기동 인수 --repository=OWNER/REPO로 명시적으로 허용한 GitHub 리포지토리에 대해 GitHub Actions의 실행 상황을 확인하고, 명시된 run을 취소합니다. --repository=는 여러 번 지정할 수 있으며, 지정되지 않은 리포지토리는 선택할 수 없습니다. 허용 리포지토리가 1건이면 각 도구에서 생략할 수 있고, 여러 건이면 대상 리포지토리 지정이 필수입니다. 설정 예에서는 DaisukeDaisuke/desmume_webassembly를 지정하며, MCP 자체는 기본 비활성화입니다.
gh run list --branch main --limit 3, gh run watch RUN_ID --exit-status, gh run cancel RUN_ID, gh run view RUN_ID에 해당하는 도구 외에 job 목록, 전체 로그, 실패 로그, workflow 목록, workflow 개요, workflow YAML을 얻을 수 있습니다. cancel_run은 검증된 10진 run ID와 허용 리포지토리만 고정 인수로 전달합니다. workflow dispatch, rerun, delete, artifact download, gh api는 공개하지 않습니다.
gh는 spawn에서 shell=false로 직접 기동하고, 서브커맨드와 옵션을 고정합니다. run ID, branch, workflow 식별자는 개별로 검증하고, 표준 입력을 닫고, 출력 크기를 제한합니다. 자식 프로세스의 cwd는 반드시 gateway.toml에서 명시하세요. 인증에는 로컬 gh auth login으로 저장된 GitHub CLI 설정을 이용할 수 있습니다.
codex-script
codex-script는 MCP 기동 시 --runtime=mjs|nodejs|python|php와 --runtime-executable=<absolute-path>로 실행 runtime을 고정하고, 허용 Workspace 내에 이미 존재하는 스크립트만 실행하는 동봉 MCP입니다. 동일한 server.mjs를 여러 개 등록하고, mjs_script, nodejs_script, python_script, php_script처럼 독립된 prefix로 공개할 수 있습니다.
--mode=run에서는 run_script, --mode=check에서는 check_file을 공개합니다. run_script는 runtime 자체, check_file은 Node.js --check, Python py_compile, PHP -l의 고정 checker만 기동합니다. check_file은 하위 호환의 filePath 1건 지정 외에 filePaths로 최대 500건을 한 번에 검사할 수 있으며, 반환은 pass, fault, 실패한 파일만의 messages입니다. 성공한 checker의 stdout/stderr는 반환하지 않습니다. 일반 셸, 임의 실행 파일 선택, 임의 환경 변수 주입, npm script나 package manager 호출은 공개하지 않습니다. 인수는 literal argv로 전달하고, stdin을 닫고, timeout과 출력 크기를 제한합니다.
Gateway는 codex-script를 isBundled로 취급하고, isolatedId로 선택한 서명된 base / roots와 일반적인 path policy를 적용합니다. 또한 codex-script는 gateway.toml에서 sandbox = "never"를 지정하면 설정 로드 시 거부되고, elevated 또는 unelevated의 Codex Windows sandbox 내에서 MCP 프로세스 자체를 기동해야 합니다. 각 script 호출에서 별도의 sandbox를 만드는 것이 아니라, 고정 runtime은 이미 sandbox화된 MCP의 자식 프로세스로 동작합니다.
임의 코드를 실행하는 --mode=run에서는 허용한 Workspace 내에서 코드가 동작하므로 allowed_directories는 필요 최소한으로 하고, runtime, Codex CLI, MCP 실행 파일을 쓰기 가능 root 밖에 두세요. disallowed_directories와 disallowed_files는 바깥쪽 Codex permission profile의 exact deny로 이용할 수 있습니다. disallowed_path_globs는 임의 코드 sandbox로 안전하게 동등 변환할 수 없으므로 run/check 모두 거부하고, 필요하면 exact deny로 대체하거나 allowed_directories 자체를 좁힙니다.
임의의 stdio MCP를 추가하기
연결할 MCP의 기동 커맨드나 인수는 Gateway 본체가 아니라 config/gateway.toml의 [mcp_servers.<name>]에 기술합니다.
private_use_only = true
publish_tool_directory = false
[mcp_servers.example]
command = "py"
args = ['C:\path\to\server.py']
cwd = 'C:\path\to'
enabled = true
prefix = "example"
annotation_config = true
startup_timeout_sec = 30
tool_timeout_sec = 1800
allowed_directories = ['C:\work\project']
allowed_files = ['C:\Users\owner\Downloads\one-upload-file.png']
[mcp_servers.example.env]
EXAMPLE_CONFIG = 'C:\path\to\config.json'유효한 stdio MCP만 자식 프로세스로 기동하고, 원래 도구 이름 tool_name은 ChatGPT 쪽에서 example__tool_name으로 공개됩니다. enabled = false 엔트리는 기동하지 않습니다.
Codex 설정에서 복사한 tool_output_token_limit, 도구별 승인 설정, Gateway가 인식하지 못하는 항목은 무시됩니다. 이 Gateway에서는 효과가 없습니다.
외부 MCP의 도구 annotations
외부 MCP는 자식 MCP가 반환한 annotations를 기준으로 하되, 누락된 readOnlyHint, destructiveHint, idempotentHint, openWorldHint를 명시적 값으로 보완하여 공개합니다. 자식 MCP가 readOnlyHint = true만 반환한 경우, 명시 지정이 없는 한 destructiveHint = false, idempotentHint = true로 보완합니다.
Gateway 시작 시 tool_annotations_path로 지정한 TOML이 없으면 생성하고, 활성 외부 MCP의 prefix에 해당하는 [tool_annotations.<prefix>]가 없으면 끝에 추가합니다. 자식 MCP에서 가져온 도구 식별명도 [tool_annotations.<prefix>.tools]에 UNCLASSIFIED로 추가합니다. 기존 prefix 설정이나 도구 할당은 덮어쓰지 않으며, 사라진 도구도 자동 삭제하지 않습니다.
번들 MCP는 각 server.mjs에서 annotations를 정의하므로 gateway.toml에서 annotation_config = false로 설정합니다. 외부 MCP는 생략 시 true로 처리됩니다.
자동 생성된 TOML 안에는 다음의 약식 이름과 4가지 hint의 의미가 주석으로 기록됩니다. open_world_hint는 prefix 전체를, open_world_tools는 개별 도구의 openWorldHint를 덮어씁니다.
[tool_annotations.chrome-devtools]
default = "LOCAL_STATE_ANNOTATIONS"
open_world_hint = true
[tool_annotations.chrome-devtools.tools]
take_snapshot = "READ_ONLY_ANNOTATIONS"
click = "UNCLASSIFIED"
[tool_annotations.chrome-devtools.open_world_tools]
take_snapshot = false
click = trueUNCLASSIFIED는 자식 MCP가 반환한 annotations의 기존 값을 유지하면서 누락된 hint만 보완하는 미분류 마커입니다. 분류할 때는 각 도구 식별명의 값을 READ_ONLY_ANNOTATIONS, LOCAL_STATE_ANNOTATIONS, LOCAL_DESTRUCTIVE_IDEMPOTENT_ANNOTATIONS, LOCAL_DESTRUCTIVE_NON_IDEMPOTENT_ANNOTATIONS, LOCAL_ADDITIVE_IDEMPOTENT_ANNOTATIONS 중 하나로 변경합니다.
Gateway 설정
사용자의 결정은 존중됩니다
Gateway의 동작은 사용자가 config/gateway.toml에 명시한 설정에 따라 결정됩니다. MCP를 자동으로 검출하여 임의로 등록하거나 설정 파일을 자동으로 다시 쓰지 않습니다.
예외적으로 외부 MCP의 도구 annotations만 tool_annotations_path에 지정된 별도 TOML에 미등록 prefix와 새로 발견한 도구 식별명을 추가합니다. 새 도구는 UNCLASSIFIED가 되며 gateway.toml, 기존 prefix, 기존 도구 설정은 변경하지 않습니다.
연결할 MCP, 그 시작 명령, 인수, 작업 디렉터리, 환경 변수, 유효/무효, Codex 샌드박스 모드, 샌드박스용 읽기 전용 경로, 비공개 도구, 경로의 허용/거부 범위, 직렬 실행, 지연 시작은 모두 사용자가 선택합니다.
Gateway는 그 설정을 읽고 검증하여 적용하지만, 사용자를 대신해 안전성이나 용도를 추측하여 설정을 추가하거나 허용 범위를 넓히지 않습니다.
config/gateway.example.toml은 설정 예시이며, 그대로 적용되는 "마법의 스크립트"가 아닙니다. 필요한 항목만 확인하여 config/gateway.toml에 작성하고, 실제로 시작하는 프로그램과 공개하는 기능을 사용자 자신이 파악할 수 있는 구성입니다.
일반적인 명령 실행은 제공하지 않습니다
이 저장소에는 일반 셸, PowerShell, 명령 프롬프트, 임의 실행 파일 선택, 임의 환경 변수 주입 등과 같이 Windows 사용자 권한을 그대로 노출하는 범용 명령 실행기를 포함하지 않습니다.
예외는 이른 codex-script이며, 실행 런타임을 MCP 시작 시에 고정한 후 허용된 Workspace 안의 기존 스크립트만 Codex Windows 샌드박스에서 실행합니다. 이것은 경로 허용만으로 임의 코드를 안전하게 하는 것이 아니라 OS 샌드박스를 필수로 하는 제한적인 스크립트 러너입니다.
일반적인 임의 코드 실행을 직접 공개하면 Tunnel ID나 runtime API key 같은 연결 정보가 의도하지 않게 노출되고, 그것이 오용되면 공격자가 Windows 사용자 권한으로 임의의 조작을 실행할 수 있습니다. 따라서 외부 임의 코드 실행 MCP를 추가하는 경우에도 sandbox = "elevated" 또는 "unelevated"를 사용하고 쓰기 가능한 루트를 최소한도로 하십시오.
코드 생성이나 변환 등 로컬 실행이 필요하지 않은 작업은 남은 ChatGPT 쪽 샌드박스를 우선하십시오. 로컬 소스를 전달만 하려면 safe-download에서 허용한 파일만 ZIP으로 만들 수 있습니다.
Gateway 실행 코드 보호
protect_gateway_app = true로 설정하면 Gateway 자신의 app 디렉터리가 허용 Workspace와 겹쳐도 자식 MCP에서 읽기 전용으로 취급됩니다. Gateway 코드상 기본값은 false지만, 포함된 설정 예에서는 true입니다. 샌드박스 MCP에서는 Codex 권한 프로필에 더 구체적인 읽기 항목을 추가하고, safe-files에서는 읽기와 file_info을 유지하는 대신 write, 직렬 실행, 보안 MCP 실행와 함께 쓰기, replace, move 원본 삭제를 거부합니다. 이 경우 하위 디렉터리 생성도 거부됩니다. file_info에서 보호 대상은 prohibited=true로 표시됩니다.
이 설정은 sandbox = "never"인 하위 프로세스가 임의 코드 실행까지 손상된 경우에도 OS 경계가 되지 않습니다. never에서는 하위 프로세스 자신이 Gateway의 경로 정책을 무시할 수 있으므로, 실행 코드에 대한 강제 쓰기 거부가 필요한 경우 Codex OS 샌드박스를 사용하십시오.
경로 허용
allowed_directories는 지정한 디렉터리와 그 하위를 허용하고, allowed_files는 지정한 파일만 완전 일치로 허용합니다.
Gateway는 모든 자식 MCP의 도구 인수를 재귀 검사하여 path, filePath, files, directory과 같은 키 또는 절대 경로로 보이는 문자열을 허용 목록에 정확히 일치시킵니다. 상대 경로는 대상 MCP의 cwd를 기준으로 해석합니다.
각 자식 MCP에 자동 추가되는 <prefix>__get_gateway_access_scope는 이 검사에 사용되는 설정 값과 정규화된 실제 허용 범위를 반환합니다. AI가 작업 디렉터리나 허용 경로를 과거 대화에서 추측하는 대신, 현재 Gateway 상태를 직접 확인하는 도구입니다.
allowed_directories = ['C:\work\project']
allowed_files = ['C:\Users\owner\Downloads\upload.png']
disallowed_directories = ['C:\work\project\private']
disallowed_files = ['C:\work\project\.env']
disallowed_path_globs = ['**.ssh**']disallowed_path_globs는 파일과 폴더 모두를 대상으로 정규화된 전체 경로에 적용되는 거부 glob입니다.
*은 경로 구분자를 넘지 않는 임의 문자열, **는 경로 구분자를 포함하는 임의 문자열, ?는 경로 구분자 이외의 임의의 한 문자와 일치합니다.
예를 들어 '**.ssh**'는 경로의 어딘가에 .ssh를 포함하면 일률적으로 거부합니다. Windows에서는 \와 /를 같을 구분자로 처리하고 대문자/소문자를 구분하지 않습니다.
macOS와 Linux에서는 /를 경로 구분자로 처리하고 대문자/소문자를 구분합니다.
거부 시 오류에는 disallowed_path_globs를 통해 거부된 점과 일치한 glob, 정규화된 대상 경로가 표시됩니다.
Gateway 측의 검사는 ChatGPT에서 자식 MCP로 전달되는 도구 인수를 보호하는 가드입니다.
번들된 safe-files, safe-images, safe-download, gitmcp, git-capability, codex-script는 서명된 Workspace context와 각 MCP 자신의 경로 검증도 사용합니다. 타사 MCP는 Gateway의 인수 가드로만은 내부 파일 접근을 제한할 수 없으므로, 필요한 경우 sandbox = "elevated" 또는 "unelevated"로 MCP 프로세스 자체를 Codex OS 샌드박스 안에서 시작합니다.
MCP 서버 설정 형식
Gateway는 Codex의 MCP 설정과 동일하게 MCP마다의 설정을 [mcp_servers.<name>] 테이블에 정리하는 형식을 채택합니다.
Codex의 설정 파일을 그대로 읽는 호환 기능이 아니라 Gateway가 구현하는 항목만 인식합니다.
config/gateway.toml에 MCP를 추가할 때는 # 주석 표시를 붙이지 않고 다음과 같이 기술합니다. 아래는 Gateway가 인식하는 모든 옵션을 담은 템플릿입니다.
private_use_only = true
protect_gateway_app = true
publish_tool_directory = false
tool_annotations_path = "tool-annotations.toml"
[mcp_servers.my_server]
command = 'C:\Program Files\nodejs\node.exe'
args = ['C:\path\to\server.mjs', '--example=value']
cwd = 'C:\work\project'
enabled = true
sandbox = "elevated"
codex_executable = 'C:\Users\owner\AppData\Roaming\npm\codex.cmd'
sandbox_read_only_directories = ['C:\path\to\read-only-data']
prefix = "my_server"
annotation_config = true
dangerous_allow_gateway_config_access = false
startup_timeout_sec = 30
tool_timeout_sec = 1800
serial_group = "my_server"
deferred = true
blocked_tools = ["dangerous_tool"]
blocked_tool_substrings = ["script", "shell", "execute"]
allowed_directories = ['C:\work\project']
allowed_files = ['C:\Users\owner\Downloads\upload.png']
disallowed_directories = []
disallowed_files = []
disallowed_path_globs = []
[mcp_servers.my_server.start_after]
server = "controller"
tool = "prepare_my_server"
[mcp_servers.my_server.stop_after]
server = "controller"
tool = "stop_my_server"
[mcp_servers.my_server.env]
EXAMPLE_CONFIG = 'C:\path\to\config.json'항목 | 설명 |
| Gateway 전체의 필수 설정입니다. 안전 확인을 위해 반드시 |
|
|
| 외부 MCP의 annotations 설정 TOML입니다. 상대 경로는 |
| 1개의 stdio MCP 연결을 정의하는 단위입니다. |
| 자식 MCP를 시작하는 실행 파일 또는 명령입니다. |
|
|
| 자식 MCP의 작업 디렉터리입니다. 상대 경로는 |
|
|
| 자식 MCP의 시작 경계입니다. |
|
|
| sandbox 유효 시 추가로 읽기 전용으로 Codex permission profile에 전달하는 절대 디렉터리 배열입니다. |
| ChatGPT에 공개하는 도구 이름의 접두사입니다. 원래 |
| 외부 annotations 설정을 적용할지 지정합니다. 생략 시 |
| 기본값은 |
| 자식 MCP의 시작과 초기화를 기다리는 초 수입니다. 양수로 지정하며, 생략 시 30초입니다. |
| 자식 MCP의 도구 호출을 기다리는 초 수입니다. 양수로 지정하며, 생략 시 1800초입니다. |
|
|
| 같은 값을 가진 MCP의 도구 호출을 직렬화합니다. 같은 브라우저나 리포지토리 등, 동시 조작을 원하지 않는 리소스에 사용합니다. |
|
|
| ChatGPT에 공개하지 않을 도구 이름을 완전 일치 문자열 배열로 지정합니다. |
| ChatGPT에 공개하지 않을 도구 이름의 부분 문자열을 지정합니다. 대소문자를 구분하지 않으며, glob이나 정규식으로 취급하지 않습니다. |
| 지정한 절대 경로의 디렉터리와 그 하위에 대한 접근을 허용합니다. sandbox 유효 시 Codex permission profile의 쓰기 가능 root도 됩니다. |
| 지정한 절대 경로의 파일만 완전 일치로 허용합니다. sandbox 유효 시 Codex permission profile에 읽기 가능한 개별 경로로도 전달됩니다. |
| 허용 범위 내에 있어도 거부하는 디렉터리와 그 하위를 절대 경로로 지정합니다. |
| 허용 범위 내에 있어도 거부하는 파일을 절대 경로로 지정합니다. |
| 정규화된 경로 전체에 적용하는 거부 glob을 지정합니다. 파일과 폴더 모두 대상입니다. |
|
|
|
|
| 자식 MCP에 추가로 전달하는 환경 변수입니다. 값에는 문자열, 숫자, 불리언을 지정할 수 있습니다. Gateway의 패스 정책용으로 예약된 환경 변수는 덮어쓸 수 없습니다. |
일반적인 MCP는 deferred = false 또는 생략으로 기동합니다. 그 경우 start_after는 불필요합니다.
sandbox = "elevated" 또는 "unelevated"에서는 Codex permission profile의 network가 비활성화되고, sandbox = "onlineworkspace"만 network를 활성화합니다. 어느 sandbox 유효 모드에서도 allowed_directories가 write, allowed_files와 sandbox_read_only_directories가 read로 구성됩니다. 추가로, MCP 실행 파일의 디렉터리, 알려진 interpreter의 entry script 디렉터리, 동봉 MCP에서는 Gateway의 app 디렉터리가 필요에 따라 read로 추가됩니다. codex_executable는 쓰기 가능 root 밖에 둬야 하며, elevated와 onlineworkspace에서는 command 자체도 쓰기 가능 root 밖에 둬야 합니다.
sandbox화한 외부 MCP에서도 절대 path로 지정한 disallowed_directories, disallowed_files, 보호 중인 gateway.toml 등은 Codex permission profile의 deny로 전달되므로, write root 내부의 exact deny hole을 이용할 수 있습니다. 한편, Gateway 고유의 disallowed_path_globs는 Codex 측의 glob semantics로 동등 변환할 수 있다는 보장이 없으므로, sandbox화한 외부 MCP에서는 fail closed로 거부합니다. 동봉 MCP는 스스로도 Gateway의 glob deny policy를 검증하므로, 이 호환성 체크의 예외입니다.
url에 의한 원격 MCP 설정은 거부됩니다. Codex 고유의 tool_output_token_limit는 읽혀도 사용되지 않으며, 이 Gateway에서는 효과가 없습니다.
Gateway 자체의 환경 변수 LOCAL_MCP_FILES_MAX_RESPONSE_BYTES와 LOCAL_MCP_CODESPACE_MAX_RESPONSE_BYTES로, 각각 files__*와 codespace__*가 터널로 반환하는 최종 JSONL 응답의 상한을 bytes 단위로 변경할 수 있습니다. 둘 다 생략 시 15KB(15360 bytes)입니다. 상한 초과 시 실제 반환 문자열 크기를 KB·MB·GB로 표시하고, 결과 본문 대신 원래 최종 JSONL의 처음 1024 bytes(1KB)만 디버그용 프리뷰로 반환합니다. "파괴적 작업이 이미 수행되었을 수 있습니다."라는 경고는 유지합니다. files__*에서는 downloads__download_zip 이용, codespace__*에서는 큰 출력을 파일로 저장하여 codespace__copy_from_codespace로 가져오는 방법, 또는 쿼리를 좁히는 방법을 안내합니다. 이 Gateway 최종 응답 제한은 files__*와 codespace__*에만 적용하며, downloads__*나 images__*의 자체 제한에는 적용하지 않습니다. Codespace MCP 내부에서도 CODESPACE_MCP_MAX_OUTPUT_BYTES가 stdout/stderr 보유량을 제한하며, 기본값은 15KB입니다. 이 값도 환경 변수로 변경할 수 있습니다.
내장 도구 디렉터리
최상위에서 publish_tool_directory = true를 지정하면 gateway__list_available_tools, gateway__get_prefix_list, gateway__get_config를 공개합니다. gateway__get_prefix_list는 현재 기동하여 공개 도구를 가진 prefix에 더해, Gateway 내장의 gateway와, 동봉 MCP가 기동 중인 경우의 isolated를 반환합니다.
gateway__list_available_tools와 gateway__get_prefix_list는 Gateway가 이미 보유한 공개 도구 레지스트리만 참조합니다. gateway__get_config는 기동 시에 읽어들인 설정에서 각 MCP의 name, prefix, allowed_directories, allowed_files, disallowed_directories, disallowed_files, disallowed_path_globs, sandbox용 read-only path만 JSON으로 반환합니다. 설정 파일을 다시 읽지 않으며, 설정 파일 자체의 경로, env, args, command, 그 외 비밀 값은 반환하지 않습니다.
enabled = false인 MCP는 기동하지 않고, gateway__list_available_tools에서는 이름만 disabledProxyNames로, gateway__get_config에서는 이름만 disabledServerNames로 반환합니다.
입력을 생략하면 현재 이용 가능한 도구를 모두 반환하고, prefix를 지정하면 대소문자를 구분하지 않고 전체 식별자의 접두 일치로 필터링합니다. 해당 건수가 0건이면 오류로 처리하지 않고 전체를 반환합니다.
반환하는 도구 정보는 chrome-devtools__click 같은 생략하지 않은 공개 이름과 설명뿐입니다. 입력 스키마, 출력 스키마, 기동 명령, 인수, 경로, 환경 변수, 거부된 도구 이름은 반환하지 않습니다. enabledProxyCount는 설정상 유효한 MCP 수, rejectedToolCount는 기동된 MCP에서 공개를 거부한 도구 수입니다.
Gateway 초기화 시의 [gateway] INFO에는 공개가 거부된 도구만 1건씩 기록하고, 공개된 개별 도구 이름은 열거하지 않습니다. 대신 prefix별 found/rejected/published 건수, enabled = false인 prefix, 기동 실패한 prefix, 전체 집계를 기록합니다.
공개 도구 제외
도구 이름의 완전 일치는 blocked_tools, 대소문자를 구분하지 않는 부분 일치는 blocked_tool_substrings로 비공개할 수 있습니다.
blocked_tools = ["dangerous_tool"]
blocked_tool_substrings = ["script", "shell", "execute"]blocked_tool_substrings는 glob이나 정규 표현식이 아닙니다.
예를 들어 "script"는 evaluate_script, runScript, SCRIPT_debug를 모두 대상으로 합니다.
직렬 실행과 지연 기동
같은 자원을 동시에 조작하고 싶지 않은 MCP는 같은 serial_group에 소속시킬 수 있습니다.
deferred = true로 한 MCP는 초기화 시에 기동하지 않고, 다른 MCP의 지정 도구가 성공한 후에 start_after로 기동할 수 있습니다.
stop_after에서는 마찬가지로 정지할 수 있습니다.
[mcp_servers.browser]
command = "node"
args = ["browser-server.mjs"]
cwd = ".."
enabled = true
prefix = "browser"
deferred = true
serial_group = "browser"
[mcp_servers.browser.start_after]
server = "controller"
tool = "prepare_browser"
[mcp_servers.browser.stop_after]
server = "controller"
tool = "stop_browser"보안상의 전제
[!WARNING]
gateway.toml의command는 로컬 프로그램을 실행합니다. 신뢰할 수 있는 MCP만 등록하세요. 명령에 따라서는 인터넷상의 MCP 프로그램을 직접 취득하여 실행하는 것도 있습니다.gateway.toml에서 지정한 명령은 샌드박스 내가 아니라 실제 PC에서 Windows 사용자의 권한으로 실행됩니다. 신뢰할 수 없는 MCP를 지정하지 마세요.
Gateway는 관리자 권한으로의 기동을 거부하고, 자식 MCP로 부모 프로세스의 비밀 정보로 보이는 환경 변수를 그대로 계승하지 않습니다. 단, 같은 Windows 사용자가 읽을 수 있는 파일을 OS 레벨에서 격리하는 것은 아닙니다.
Tunnel은 자신의 Platform Organization과 자신의 ChatGPT Workspace에만 연결하고, runtime API key에는 Tunnels Read + Use 이외의 권한을 부여하지 않는 구성을 권장합니다. 자세한 내용은 SECURITY.md와 INSTALL.md를 확인하세요.
SDK
main 브랜치의 ZIP, tunnel-client-source을 다운로드하여 ChatGPT에 첨부하고, 다음 프롬프트를 보내면 이 리포지토리에 추가할 서명 대응의 동봉 stdio MCP를 만들 수 있습니다.
생성한 MCP를 일반적인 외부 MCP로 등록한 것만으로는 Gateway의 서명된 isolated workspace가 전송되지 않습니다. mcp/<name>/server.mjs로 배치하고, app/server-config.mjs의 BUNDLED_SERVER_PATHS에 등록하는 차분도 적용하세요.
<Describe the MCP tools you need here.>는 만들고 싶은 도구와 조작 대상의 구체적인 설명으로 바꾸세요.
The attached local-mcp-chatgpt-tunnel-main.zip is the SDK and reference implementation. Inspect it before writing code.
Create a new bundled stdio MCP at mcp/<name>/server.mjs for the following purpose:
<Describe the MCP tools you need here.>
Requirements:
- Return the complete mcp/<name>/server.mjs file, the exact app/server-config.mjs BUNDLED_SERVER_PATHS patch required to mark it as bundled, and the minimal config/gateway.toml entry.
- Do not modify the attached archive directly. Return complete replacement content or an exact patch for every required file.
- Use only Node.js built-in modules and the repository's existing local helpers unless I explicitly permit another dependency.
- Follow the repository's MCP protocol handling, JSON Schema conventions, outputSchema declarations, tool annotations, error handling, stdout/stderr separation, timeouts, and bounded-output design.
- Write only JSON-RPC protocol messages to stdout. Write diagnostics and logs to stderr.
- Import createBundledIsolation and environmentWithoutBundledIsolationKey from ../../app/bundled-isolation.mjs. Every tools/call operation must run through createBundledIsolation().run(arguments, operation) before any side effect or path access.
- In Gateway mode, LOCAL_MCP_GATEWAY_ISOLATION_KEY is present. Every call must require and verify the private __localMcpIsolation envelope. Missing, malformed, unsupported-version, unsigned, or incorrectly signed envelopes must fail closed before the public tool executes. Do not implement an unsigned fallback while the key is present.
- The Gateway sends the signature and the paths permitted for that call together in this private argument. This is the envelope shape; the signature placeholder below is not a valid signature:
{
"__localMcpIsolation": {
"version": 1,
"roots": ["C:\\work\\project"],
"base": "C:\\work\\project",
"signature": "<64 hexadecimal HMAC-SHA-256 characters>"
}
}
- Verify HMAC-SHA-256 over exactly JSON.stringify({ base, roots }) using LOCAL_MCP_GATEWAY_ISOLATION_KEY, compare signatures in constant time, require one or more absolute roots, and require base to be an absolute path inside at least one root. Prefer the repository helper instead of duplicating the cryptographic code.
- Treat the verified roots and base as the only authoritative path context in Gateway mode. roots are the directories the operation may access; base is the current relative-path base. Never replace them with process.cwd(), a public argument, a cached global root, or a path remembered from another call.
- Reject public arguments named root, roots, workspace, workspaces, or equivalent nested variants. Public tool input must not override the signed path context.
- Never expose LOCAL_MCP_GATEWAY_ISOLATION_KEY or pass it to subprocesses. When spawning a child process, use environmentWithoutBundledIsolationKey() or an equivalent explicit environment filter.
- Shell injection must be impossible under all circumstances. Treat every MCP argument, path, filename, identifier, option, and environment-derived value as untrusted input.
- Never pass a constructed or user-controlled command string to a shell. Do not use child_process.exec, execSync, spawn with shell: true, cmd.exe /c, powershell -Command, bash -c, or sh -c.
- When a native program is genuinely required, invoke a fixed executable directly with spawn or execFile, shell: false, a fixed subcommand, and individually validated arguments. Use an explicit allowlist and a -- separator where the target program supports it.
- Do not expose a general-purpose command runner, arbitrary script execution, arbitrary executable selection, arbitrary environment-variable injection, or unrestricted native-program arguments.
- Implement `roots`, `get_working_directory`, and `set_working_directory` only when the MCP has a real filesystem, repository, workspace, current-directory, input-directory, or output-directory concept. If the capability has no directory concept, do not add these tools and do not invent a meaningless root.
- When those directory tools are applicable, `roots` must return only the verified signed roots and current base, `get_working_directory` must return the verified base, and `set_working_directory` must accept an absolute path or a path relative to the current base, resolve it to an existing directory inside one signed root, apply every deny rule, and return the canonical absolute path. Gateway interception and direct standalone behavior must both remain safe.
- Any stdio MCP that performs filesystem operations must support and enforce these exact configuration arrays:
`allowed_directories = []`
`allowed_files = []`
`disallowed_directories = []`
`disallowed_files = []`
`disallowed_path_globs = []`
- Apply the allowlist and denylist to every filesystem operation, including working-directory changes. Deny rules must take precedence over allow rules.
- Resolve relative filesystem paths from the verified base. Absolute paths may be accepted only when they remain inside a verified root and pass the complete configured allow/deny policy.
- Reject parent traversal that escapes a signed root, root-relative ambiguity, drive-relative paths, UNC paths unless explicitly required and safely constrained, NTFS alternate data streams, and any syntax that could reinterpret the target. Canonicalize existing paths and verify the real target remains inside a signed root after symlink resolution.
- Do not require callers to provide redundant absolute paths when the same target can be identified safely relative to the verified base.
- A tool that accepts input files must accept multiple files as an array unless the underlying operation can inherently and safely operate on exactly one file. Validate every file independently and enforce bounded file counts, sizes, and output sizes.
- For build-related tools, require the caller to select a narrow project, target, package, configuration, or input-file set. Do not default to building an entire workspace or repository when a narrower target is possible. Keep the executable, subcommand, and build options fixed or allowlisted.
- This stdio MCP is not executed inside the ChatGPT sandbox. It runs on the user's real Windows PC with the permissions of the current Windows user. Remove unsafe capabilities by design instead of relying on the model to ask for confirmation.
- Do not download, install, update, or access the network unless I explicitly require that behavior. If network access is required, restrict destinations and operations to an explicit allowlist.
- Close child-process stdin, impose timeouts and output limits, handle cancellation and termination, and return structured MCP errors without crashing the process.
- Include clear tool descriptions, strict input schemas, strict output schemas, accurate annotations, and a short security explanation for every capability.
- Prefer a small, auditable implementation. Do not add convenience features that expand the security boundary beyond the stated purpose.진단과 테스트
필요한 명령의 검출과 버전 확인을 수행합니다. 설치나 설정 변경은 하지 않습니다.
node app\doctor.mjs리포지토리의 테스트는 다음으로 실행할 수 있습니다.
npm test외부 npm 의존은 없습니다.
라이선스
이 리포지토리 본체는 MIT License입니다.공식 tunnel-client.exe 등 제3자 컴포넌트에 대해서는 THIRD_PARTY_NOTICES.md를 확인하세요.
비고
ChatGPT에서 로컬 MCP로 연결하는 것은 "회색 꼼수"인가
https://gist.github.com/DaisukeDaisuke/0d0af93dd8cb376a36879702afb176ee
This server cannot be installed
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 Servers
- FlicenseCqualityCmaintenanceEnables ChatGPT to control a Windows PC remotely via OpenAI Secure MCP Tunnel, executing file operations, PowerShell commands, and system actions through a local MCP server.15
- AlicenseNot gradedqualityBmaintenanceEnables ChatGPT to securely operate a single Windows development workspace via a local MCP server, offering file editing, Git status, static analysis, approved test/build, and limited ADB operations with audit logging.MIT
- AlicenseNot gradedqualityBmaintenanceA Windows proof-of-concept MCP server that connects ChatGPT developer-mode to a local Codex CLI via Secure MCP Tunnel, exposing a small set of read-only, allowlisted tools in an isolated workspace.1Apache 2.0
- FlicenseNot gradedqualityAmaintenanceSafe MCP gateway that lets ChatGPT securely control a Windows Desktop Agent, enabling project file reads, git status/diff, and npm build/test within a designated workspace.
Related MCP Connectors
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Security-first WordPress MCP server. 129 tools for Claude, ChatGPT, Gemini. Free on wp.org.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
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/DaisukeDaisuke/local-mcp-chatgpt-tunnel'
If you have feedback or need assistance with the MCP directory API, please join our Discord server