코드를 클라우드에 올리지 않고 웹 AI를 어디까지 쓸 수 있을까? Local-first와 GitHub-first의 연결 경계
상용 프로젝트의 소스 코드를 클라우드 모델에 보낼 수 없다면 웹 ChatGPT로 무엇을 할 수 있을까요? 로컬 프로젝트 상태를 확인하거나 제한된 SSH 검사를 요청할 수 있을까요? 반대로 소스 코드를 호스팅해도 된다면 로컬 MCP를 왜 사용해야 할까요?
선택의 핵심은 특정 도구가 아닙니다. 도구가 무엇을 볼 수 있는지, 작업이 어디서 실행되는지, 결과가 어디로 돌아가는지가 중요합니다.
간단히 말해 웹 앱이 Mac을 자동으로 읽는 것은 아닙니다. 소스 코드를 모델에 제공하지 않으면 명시적으로 공유한 요약이나 상태를 바탕으로 조언할 수는 있지만, 보지 못한 코드를 독립적으로 검토하거나 디버깅할 수는 없습니다.
Codex를 로컬에서 실행한다고 추론까지 로컬에서 이뤄지는 것은 아닙니다. Codex Cloud는 Mac에 연결된 세션이 아닙니다. MCP 터널은 요청을 전달하지만 그 자체로 도구 권한을 제한하지는 않습니다. GitHub Private는 저장소 접근을 제어할 뿐, 클라우드에 있는 저장소를 로컬 저장소로 바꾸지 않습니다. 소스 코드를 클라우드 모델에 전달하면 해당 컨텍스트는 모델의 처리 경계 안으로 들어갑니다. 아래에서는 선택 가이드와 두 가지 공개 예시인 VXI Local-First MCP, VXI SSH Ops Bridge를 살펴봅니다. 전자는 로컬 프로젝트 상태만 공유하고, 후자는 고정된 읽기 전용 SSH 작업만 허용합니다.
연결 경로 비교: 작업 공간은 어디에 있고 모델은 무엇을 볼 수 있을까?
| 경로 | 작업 공간 및 실행 위치 | 클라우드 모델이 볼 수 있는 것 | 적합한 용도 |
|---|---|---|---|
| 데스크톱 앱의 Codex Local environment + 로컬 MCP | Mac의 프로젝트/worktree, 터미널 및 MCP 프로세스 | 실제로 모델에 전달된 컨텍스트에 따라 다름. 로컬 실행이 로컬 추론을 뜻하지 않음 | 권한 범위 안에서 파일 읽기/쓰기, 명령 실행, diff 확인. 모델의 데이터 경계를 확인한 경우에 적합 |
| Codex Cloud / 웹 클라우드 작업 | 선택한 GitHub 저장소가 격리된 클라우드 작업 공간에 배치됨 | 작업에서 접근할 수 있는 소스 및 작업 공간 파일 | 소스의 GitHub 및 클라우드 사용이 허용된 경우 코드 수정, 검사 실행, 브랜치나 결과물 전달 |
| GitHub 클라우드 Coding Agent | 저장소와 임시 클라우드 Agent 환경 | 저장소 파일, 작업 컨텍스트, 실행 중 접근 가능한 자료 | 브랜치, PR, 검사를 통한 협업 |
| ChatGPT Web + Secure MCP Tunnel + Local-First MCP | MCP는 로컬에서 실행되고 로컬 장치가 아웃바운드 터널을 시작 | MCP가 명시적으로 반환하는 수와 상태 열거형만 | 소스 읽기나 Shell 권한 없이 제한된 프로젝트 메타데이터 공유 |
| ChatGPT Web + Secure MCP Tunnel + SSH Ops Bridge | 로컬 MCP 브리지와 SSH 클라이언트가 설정된 호스트에 연결 | 대상 별칭과 고정·필터링된 상태 결과 | 비운영 대상에 대해 허용 목록에 포함된 읽기 전용 검사 요청 |
| 웹 모델 + 로컬 coding-agent relay (별도 구축 필요) | 로컬 어댑터가 Codex 또는 다른 로컬 coding agent에 위임 | 추론 위치와 어댑터가 반환하는 내용에 따라 다름 | 향후 가능한 설계지만 도구, 출력, 쓰기, 타임아웃 및 사람의 승인 제어를 별도로 설계해야 함 |
먼저 중요한 제한을 밝힙니다. 아래 터널 설정은 OpenAI 공식 문서를 바탕으로 하지만, 작성자의 실제 Mac에서 ChatGPT Web과 로컬 MCP 사이의 엔드투엔드 연결은 아직 검증되지 않았습니다. 검증된 원클릭 튜토리얼이 아니라 설정 참고 자료로 봐야 합니다.
설정 전에 경로를 선택하기
- 소스 코드를 클라우드 모델에 절대 보내면 안 되는 경우: 코드 수준의 작업은 로컬 추론이나 신뢰할 수 있는 로컬 워크플로에 남겨야 합니다. 메타데이터 전용 MCP로 승인된 상태를 공유할 수는 있지만, 소스를 볼 수 없는 클라우드 모델이 코드를 독립적으로 검토할 수는 없습니다.
- 웹 ChatGPT가 로컬 상태만 보면 되는 경우: Local-First MCP처럼 고정 필드만 투영하는 방식을 사용합니다. 소스 읽기 권한이나 Shell 권한이 필요하지 않습니다.
- 웹에서 고정 SSH 상태 점검만 요청하려는 경우: SSH Ops Bridge처럼 이름이 정해진 작업을 사용하고 호스트 신원, 개인 키, 대상 허용 목록은 로컬에 둡니다.
- 소스 호스팅이 허용되고 AI가 코드를 읽고 수정해야 하는 경우: GitHub-first, Codex Cloud 또는 승인된 클라우드 Agent를 사용하고 브랜치, PR, commit, CI를 검토 가능한 기록으로 남깁니다.
- 웹 AI가 로컬 Codex에 코드 작업을 위임해야 하는 경우: 별도의 로컬 Agent relay를 구축하고 검토해야 합니다. 메타데이터 MCP와 SSH 브리지는 이 기능을 제공하지 않습니다.
- 프로젝트마다 데이터 등급이 다른 경우: 프로젝트별로 경로를 선택하세요. 블로그 저장소를 호스팅할 수 있다고 해서 상용 소스도 같은 경로로 보내도 되는 것은 아닙니다.
다른 업체의 웹 도구는 각각 따로 확인해야 합니다. 지원하는 원격 MCP 또는 로컬 Agent 경로, 인증 방식, 로컬 Agent 기능, 모델에 실제로 전달되는 입력과 도구 반환값을 확인하세요. MCP를 지원한다는 이유만으로 OpenAI Secure MCP Tunnel을 그대로 재사용할 수 있다고 가정해서는 안 됩니다.
공식 참고 자료: Codex Local environments, Codex Cloud environments, Codex MCP, OpenAI Secure MCP Tunnel, GitHub Copilot cloud agent.
세 가지 데이터 흐름
A. 웹 AI가 로컬 프로젝트 상태를 읽는 경우
ChatGPT Web
|
OpenAI Secure MCP Tunnel endpoint
^ 로컬 tunnel-client가 아웃바운드 HTTPS를 시작
|
로컬 vxi-local-first-mcp (stdio MCP)
|
로컬 프로젝트 디렉터리: 항목 수만 세고 소스 내용은 읽지 않음
반환: 수 + PASS / FAIL / UNKNOWN
반환하지 않음: 소스, 경로, diff, 로그, 명령
B. 웹 AI가 고정 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
|
클라우드 작업 공간에서 소스를 읽고 파일을 수정하며 검사 실행
|
branch + PR + commit + CI
|
사람의 검토와 승인
세 경로는 서로 다른 모델입니다. 앞의 두 경로는 웹 도구가 볼 수 있는 정보와 요청할 수 있는 작업을 제한합니다. 세 번째는 승인된 클라우드 작업 공간에서 AI가 소스 수준 개발을 수행하도록 허용합니다.
Codex Local, Codex Cloud, MCP를 혼동하지 않기
데스크톱 앱의 Codex Local environment는 로컬 프로젝트나 worktree의 준비 단계와 자주 쓰는 작업을 설정합니다. 통합 터미널은 로컬에서 명령을 실행하고, Git 도구로 diff 확인, stage, commit, push, PR 생성을 할 수 있습니다. 로컬 Codex 클라이언트는 로컬 stdio MCP 서버도 시작할 수 있습니다. 이는 로컬 MCP host가 로컬 서버를 실행하는 방식이며 웹 터널이 필요하지 않습니다.
하지만 “로컬 실행”은 파일과 명령이 어디서 동작하는지만 뜻합니다. 모델이 호스팅 모델이라면 분석에 사용되는 소스 컨텍스트가 클라우드로 전송될 수 있습니다. 소스 외부 전송을 엄격히 막으려면 로컬 추론 또는 검증된 신뢰 로컬 워크플로가 필요하며, 장치의 다른 프로세스와 네트워크 경로도 별도로 감사해야 합니다.
Codex Cloud는 선택한 GitHub 저장소를 격리된 클라우드 작업 공간에 배치하고 의존성을 준비한 뒤 작업을 실행합니다. GitHub 클라우드 Agent도 클라우드 환경에서 소스를 읽고 브랜치를 수정하며 검사를 실행하고 PR을 만들 수 있습니다. 이는 클라우드 경계를 넘어도 되는 프로젝트에 적합하며, 소스를 Mac에 남기는 대안은 아닙니다.
MCP host와 MCP server의 차이
- 데스크톱 ChatGPT, Codex CLI, IDE 확장 기능을 MCP host로 사용하는 경우: 각 클라이언트가 지원하는 방식으로 로컬 stdio 서버를 시작할 수 있습니다. 공식 CLI 형식은 다음과 같습니다.
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를 로컬 ops.config.json 경로로 지정하고 server command를 vxi-ssh-ops-bridge/bin/vxi-ops.mjs로 바꿉니다. 호스트명, 계정, 개인 키 경로와 ops.config.json은 로컬에 보관하세요. 실행 시 비밀 정보를 채팅에 붙여 넣거나 Git에 커밋하면 안 됩니다. 데스크톱 앱, Codex CLI 및 지원되는 IDE 확장 기능은 Codex host의 MCP 설정을 사용할 수 있지만 권한은 각 클라이언트의 작업 공간 설정에 따라 달라집니다.
- ChatGPT Web을 호출자로 사용하는 경우: 웹 앱은 로컬 ~/.codex/config.toml을 읽지 않으며 로컬 Codex의 명령 목록을 자동으로 상속하지 않습니다. 지원되는 원격 MCP 경로가 필요합니다. Secure MCP Tunnel은 로컬 tunnel client가 OpenAI 호스팅 엔드포인트로 아웃바운드 연결을 만들고 요청을 로컬 stdio 또는 HTTP MCP 서버로 전달하도록 합니다.
웹 앱을 로컬 MCP에 연결한 뒤 SSH를 요청하는 방법
OpenAI의 Secure MCP Tunnel 문서는 비공개 MCP 서비스에 접근할 수 있는 네트워크에서 tunnel-client를 실행하는 흐름을 설명합니다. 클라이언트가 아웃바운드 HTTPS를 시작하고 호스팅 엔드포인트에서 요청을 받아 로컬 stdio 또는 HTTP MCP 서버로 전달한 뒤 같은 터널을 통해 응답을 돌려보냅니다. Mac에 공개 인바운드 포트를 열 필요가 없습니다.
아래 경로와 tunnel ID는 예시용 자리표시자입니다. 실행 시 인증 정보는 로컬 환경 변수에만 보관하세요.
- OpenAI Platform에서 터널을 만들거나 선택합니다. 대상 ChatGPT workspace와 Platform organization의 연결 및 필요한 Tunnel 권한을 확인합니다.
- Platform 터널 설정에서 최신 tunnel-client를 받습니다. 현재 help/quickstart를 확인하고 MCP 서버별로 별도 profile을 구성합니다.
- 터널을 구성하기 전에 각 MCP 서버를 오프라인으로 테스트합니다. Local-First MCP의 경우:
cd /path/to/vxi-local-first-mcp
node --version # >= 22
npm test
npm run demo
테스트가 통과하면 Local-First profile을 구성합니다.
export CONTROL_PLANE_API_KEY="<runtime-key kept in the local terminal>"
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로 설치한 다음 별도 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
Platform 화면과 클라이언트 버전은 바뀔 수 있으므로 실제 옵션은 설치된 클라이언트의 help 출력을 확인하세요.
- tunnel-client run을 실행 상태로 둡니다. ChatGPT의 지원되는 사용자 지정 MCP 메뉴에서 Add custom MCP server → Tunnel을 선택하고 사용 가능한 터널을 고른 뒤 인증하고 권한 안내를 확인합니다. 터널이 보이지 않으면 로컬 MCP를 공개하지 말고 workspace/organization 연결과 권한을 확인합니다.
- 먼저 읽기 전용 vxi_project_status 또는 vxi_ops_policy를 호출해 도구 검색이 되는지 확인하고, 필요할 때만 vxi_ssh_health를 요청합니다. 운영 호스트에서 테스트하지 말고 SSH host key를 독립적인 경로로 검증하세요.
SSH 브리지가 로컬에서 하는 일
로컬 관리자는 호스트, 사용자명, 포트, 개인 키 경로와 독립적으로 검증한 known_hosts를 ops.config.json에 보관합니다. MCP는 lab 같은 로컬 허용 목록 별칭만 받으며 모델이 생성한 명령 문자열은 받지 않습니다. 브리지는 개인 SSH 설정을 무시하고 agent forwarding과 대화형 비밀번호 입력을 비활성화하며, 고정된 /usr/local/bin/vxi-health-check를 호출하고 결과를 세 가지 상태로 제한합니다.
웹 앱이 개인 키를 받아 직접 서버에 로그인하는 것은 아닙니다. 웹 앱이 요청하는 것은 고정된 작업입니다. 터널은 요청을 전달하고, 도구 목록·입력 검증·로컬 설정·host key 고정·원격 스크립트가 함께 권한 경계를 결정합니다.
MCP 뒤에 코드 수정이 가능한 로컬 Agent를 연결한다면 도구, 입력, 출력, 파일 쓰기, 명령 실행, 타임아웃과 사람의 승인을 별도로 검토해야 합니다. 제한된 SSH MCP의 안전성 결론을 쓰기 가능한 coding-agent 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개 테스트가 각 OS에서 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개에 host/user 값이 없거나 문자열이 아닌 경우를 다루는 테스트 1개를 추가하고 관련 문자열 검증을 보강했습니다. 아직 병합되지 않은 Draft 브랜치에서 단위 테스트 8/8과 데모가 통과했습니다(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를 연결했다”는 표식이 아닙니다. 각 경로가 모델에 실제로 무엇을 보내는지, 모델이 어떤 작업을 요청할 수 있는지, 응답이 어디로 가는지를 확인해야 합니다.
두 저장소 모두 아직 최소 프로토타입입니다. 작성자의 실제 Mac에서 터널 연결은 검증되지 않았고, 외부 SSH 호스트 테스트, 장치 전체의 소스 외부 전송 감사, 진정한 로컬 모델 추론, 동일 작업의 품질·지연·토큰·비용 비교도 수행하지 않았습니다.