Skip to main content
Glama
README.md
# Project Moon

**한국어** | [English](README.en.md)

[![Project Moon CI](https://github.com/kankinku/project-moon/actions/workflows/ci.yml/badge.svg)](https://github.com/kankinku/project-moon/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

> ChatGPT·Codex·기타 MCP 클라이언트가 실제 개발 환경에서 명령 실행, 파일 수정, Git 작업, 검증과 독립 리뷰까지 수행할 수 있도록 연결하는 **풀 액세스 원격 개발 MCP 런타임**입니다.

Project Moon은 “AI가 명령을 제안하고 사람이 복사해서 실행하는 방식”을 줄이고, AI가 개발 환경에서 직접 작업하되 **개발 권한과 최종 검수 권한을 분리**할 수 있도록 설계되었습니다.

### 핵심 구성

| 구성 | 역할 | 기본 도구/권한 |
|---|---|---|
| **Developer Runtime** | 구현, 파일 수정, 명령 실행, 테스트, Git 작업, 내부 리뷰 | 기본 MCP 도구 32개 |
| **Merge Gateway** | 동일한 공개 Moon에서 독립 검수·승인·merge 호출 | auditor 초기화 시 +6개 |
| **Merge Auditor Runtime** | 고정된 PR diff 검수, 독립 승인/반려, SHA·CI gate, merge | 내부 전용 9개 |
| **Public Transport** | 외부 MCP 연결 | HTTPS 443 + Tailscale Funnel 1개 |
| **Authentication** | ChatGPT→Moon / Moon→Auditor / Auditor→GitHub 분리 | OAuth / 내부 Bearer / GitHub CLI |
| **Merge Gate** | `main` 보호 | PR + CI `validate` + 검수계정 승인 + SHA 일치 |

```text
ChatGPT / Codex
      │
      │ OAuth 2.1 — 공개 MCP는 하나
      ▼
┌──────────────────────────────┐
│ Project Moon / Developer     │
│ 개발 32도구 + merge proxy 6 │
└───────────┬──────────────────┘
            │ private Docker network
            │ service Bearer only
            ▼
┌──────────────────────────────┐
│ Merge Auditor Runtime        │
│ read-only /audit/shared      │
│ GitHub: secondary account    │
└───────────┬──────────────────┘
            │ SHA-bound review / merge
            ▼
      GitHub Pull Request
       │              │
       ├─ CI validate │
       └─ APPROVED ───┘
            │
            ▼
      protected `main`
```

외부에서는 **기존 Moon 하나만 연결**합니다. `merge_audit_*` 호출만 private Docker network를 통해 별도 Merge Auditor 런타임으로 전달됩니다. 검수계정의 GitHub 자격증명은 auditor 전용 Docker volume에만 남고 Developer Runtime에는 전달되지 않습니다. 감사 대상 `/shared/...`는 auditor에서 `/audit/shared/...`로 read-only 매핑되며, PR 작성자와 검수계정이 같거나 감사 SHA·CI·승인 상태가 어긋나면 승인/merge가 거부됩니다. 자세한 설계는 [`docs/merge-audit-architecture.md`](docs/merge-audit-architecture.md)를 참고하세요.

### 빠른 링크

- **Windows + Docker 시작:** [빠른 시작](#windows--docker-빠른-시작)
- **AI 작업 모드:** [AUTO / DIRECT / HARNESS](#ai-작업-모드-auto--direct--harness)
- **인증 및 보안:** [OAuth 2.1 / Static Bearer](#인증과-보안)
- **ChatGPT 연결:** [ChatGPT 연결](#chatgpt-연결)
- **독립 Merge Audit:** [`docs/merge-audit-architecture.md`](docs/merge-audit-architecture.md)
- **상세 로컬 설치:** [`LOCAL_DOCKER_SETUP.md`](LOCAL_DOCKER_SETUP.md)

> [!CAUTION]
> Project Moon은 **샌드박스가 아닙니다.** Developer Runtime은 인증된 클라이언트에 호스트 수준의 명령 실행과 파일 변경 능력을 제공합니다. 신뢰할 수 있는 개인 개발 환경에서만 실행하고, 인터넷에 노출할 때는 HTTPS와 강한 인증을 사용하세요. 최종 merge 검수는 개발 런타임과 분리된 Merge Auditor 계정/런타임을 사용하는 구성을 권장합니다.

---

## Project Moon이 필요한 이유

일반적인 AI 코딩 흐름은 다음과 같습니다.

```text
AI가 명령 제안
→ 사람이 터미널에 입력
→ 결과 복사
→ AI에게 전달
→ 다음 명령 제안
```

Project Moon을 사용하면 다음과 같이 바뀝니다.

```text
AI가 상황 판단
→ Moon으로 직접 명령 실행
→ 결과 확인
→ 파일 수정
→ 테스트·빌드
→ Git 검증
→ 필요하면 코드 리뷰·수정
```

따라서 다음 작업을 하나의 AI 세션 안에서 처리할 수 있습니다.

- 컴퓨터 및 서버 상태 점검
- Git 저장소 clone / pull / diff / commit
- 프로젝트 코드 수정
- npm, Python, Docker 등 개발 명령 실행
- 장시간 실행되는 프로세스 관리
- 로그 조회 및 장애 분석
- 파일 업로드·다운로드 및 패치
- 테스트·타입체크·빌드 수행
- 작업 전 구조 파악과 구현 계획 고정
- 변경 위험도에 맞는 검증 프로필 자동 강제
- Git Worktree 기반 격리 수정
- 코드 리뷰와 QA 증거 저장
- 리뷰 이후 브랜치가 변경되었는지 감지

---

# Windows + Docker 빠른 시작

Project Moon을 개인 Windows 개발 PC에서 사용하는 경우 현재 권장 구성은 다음과 같습니다.

```text
Windows
├─ Docker Desktop
├─ Tailscale
├─ Project Moon 저장소
│  ├─ Start-PublicMcp.ps1
│  ├─ Stop-PublicMcp.ps1
│  └─ shared/
└─ Tailscale Funnel
       ↓
https://project-moon.<tailnet>.ts.net/mcp
```

## 1. 요구 사항

다음 프로그램이 필요합니다.

- Windows 10/11
- PowerShell
- Git
- Docker Desktop
- Tailscale

GPU 기능을 사용할 경우 추가로 다음이 필요합니다.

- NVIDIA GPU
- 정상 동작하는 NVIDIA 드라이버
- Docker의 NVIDIA GPU 런타임 지원

## 2. 저장소 받기

```powershell
git clone https://github.com/kankinku/project-moon.git
cd project-moon
```

이미 clone한 경우:

```powershell
git pull --ff-only origin main
```

## 3. 로컬 설정 준비

```powershell
Copy-Item tunneling\.env.local.example tunneling\.env.local
New-Item -ItemType Directory -Force shared
```

`tunneling/.env.local`은 로컬 전용 파일이며 Git에 포함되지 않습니다.

기본 예시는 다음과 같습니다.

```dotenv
TZ=Asia/Seoul
WORKMACHINE_IMAGE=project-moon-local:0.1.0
```

`shared/` 디렉터리는 컨테이너의 `/shared`로 연결됩니다. AI가 직접 다룰 프로젝트와 파일을 이 영역에 둘 수 있습니다.

## 4. Project Moon 실행

**관리자 권한 PowerShell**에서 실행합니다.

```powershell
.\Start-PublicMcp.ps1
```

스크립트는 자동으로 다음 작업을 수행합니다.

1. Tailscale 연결 상태 확인
2. Tailscale 호스트명을 `project-moon`으로 설정
3. Tailscale Funnel 활성화
4. 공개 `*.ts.net` HTTPS 주소 자동 감지
5. OAuth 공개 URL 자동 구성
6. Docker Compose 설정 검증
7. Project Moon 이미지 빌드 및 컨테이너 시작
8. 로컬 `/health` 검증
9. 공개 `/health` 검증

정상 실행되면 다음과 유사한 결과가 출력됩니다.

```text
PUBLIC_MCP_URL=https://project-moon.<tailnet>.ts.net/mcp
PUBLIC_HEALTH_URL=https://project-moon.<tailnet>.ts.net/health
PUBLIC_TRANSPORT=tailscale-funnel
OAUTH_ENABLED=true
GPU_ENABLED=false
```

> 최초 Tailscale Funnel 사용 시 Tailscale에서 Funnel 활성화를 승인해야 할 수 있습니다.

## 5. OAuth 승인 키 확인

Project Moon의 OAuth 연결 승인에 사용하는 키는 다음 명령으로 확인할 수 있습니다.

```powershell
.\Get-OAuthApprovalKey.ps1
```

이 값은 **비밀번호와 동일하게 취급**하세요. 저장소, 이슈, 로그, 채팅 등에 공개하면 안 됩니다.

## 6. 종료

```powershell
.\Stop-PublicMcp.ps1
```

이 명령은 Project Moon용 Funnel 리스너와 Docker 컨테이너를 중지합니다.

---

# GPU 사용

NVIDIA GPU를 컨테이너에서 사용하려면:

```powershell
.\Start-PublicMcp.ps1 -Gpu
```

Project Moon은 실행 전에 다음을 확인합니다.

- 호스트 `nvidia-smi`
- Docker NVIDIA 런타임
- 컨테이너 GPU Device Request
- 컨테이너 내부 `nvidia-smi`

실행 후 별도로 점검하려면:

```powershell
.\Test-Gpu.ps1
```

정상이면 `status: PASS`와 GPU/드라이버/CUDA 정보가 출력됩니다.

---

# MCP 도구

## 1. 명령 및 프로세스 관리 — 6개

| 도구 | 기능 |
|---|---|
| `exec_command` | 셸 명령, Git, 빌드, 테스트, 패키지 관리자, 시스템 명령 실행 |
| `run_script` | Bash, sh, Node.js, Python 등 전체 스크립트 실행 |
| `write_stdin` | 실행 중인 프로세스에 입력 전달 |
| `read_process` | 장기 실행 프로세스의 새 출력 및 상태 조회 |
| `terminate_process` | 프로세스 그룹에 `SIGINT`, `SIGTERM`, `SIGKILL` 전달 |
| `list_processes` | 실행 중이거나 최근 완료된 Moon 프로세스 목록 조회 |

명령이 즉시 끝나지 않으면 `sessionId`가 반환될 수 있습니다.

```text
exec_command
     │
     ├─ 즉시 완료 → 결과 반환
     │
     └─ 계속 실행 → sessionId
                       │
                       ├─ read_process
                       ├─ write_stdin
                       └─ terminate_process
```

프로세스 상태는 Project Moon 서비스 메모리에 유지되므로 MCP HTTP 요청이 달라져도 이어서 조회할 수 있습니다. 단, Project Moon 서비스가 재시작되면 해당 상태는 사라집니다.

## 2. 파일시스템 — 14개

### 조회

- `list_directory`
- `stat_path`
- `read_file`
- `hash_file`

### 수정

- `write_file`
- `replace_in_file`
- `apply_patch`
- `chmod_path`

### 전송

- `upload_file`
- `download_file`

### 구조 변경

- `make_directory`
- `copy_path`
- `move_path`
- `remove_path`

상대 경로는 `MCP_DEFAULT_CWD`를 기준으로 해석합니다.

> [!WARNING]
> `remove_path`는 휴지통을 거치지 않고 실제 파일을 삭제합니다. `apply_patch`는 호스트의 `git apply --unsafe-paths`를 사용합니다.

텍스트 파일은 UTF-8 경계를 보존하며, 바이너리 데이터는 Base64 방식으로 전송할 수 있습니다.

---

# AI 작업 모드: AUTO / DIRECT / HARNESS

현재 Moon은 원본의 단순성을 버리지 않고 작업 방식으로 보존합니다. AUTO·DIRECT·HARNESS는 동일한 **32개 개발 도구**를 사용하며, 코드 경로를 이중으로 유지하지 않습니다. Merge Auditor를 초기화한 설치에서는 작업 모드와 무관하게 **6개의 `merge_audit_*` gateway 도구가 추가**되어 총 38개가 노출됩니다. 차이는 **에이전트가 task lifecycle을 언제 사용하는가**입니다.

| 모드 | 용도 | 기본 동작 |
|---|---|---|
| `AUTO` | 권장 기본값 | 조회·단발 작업·작은 국소 수정은 DIRECT, 다단계·고위험 변경은 HARNESS로 자동 선택 |
| `DIRECT` | 원본 Moon 스타일 | `exec_command`, `run_script`, 파일 도구를 바로 사용하고 불필요한 `task_*` 상태를 만들지 않음 |
| `HARNESS` | 복잡하거나 중요한 개발 | Context Brief → Plan → 위험도 검증 → fingerprinted validation → Complete 흐름 사용 |

서버 기본값은 환경변수로 설정합니다.

```dotenv
MCP_WORKFLOW_MODE=auto
```

또한 사용자가 현재 요청에서 “DIRECT 모드로 처리해줘” 또는 “HARNESS 모드로 진행해줘”라고 명시하면 그 요청에 우선 적용합니다. DIRECT는 보안 제한을 없애는 모드가 아니라 **작업 lifecycle 오버헤드를 생략하는 모드**입니다. 작은 수정이라도 테스트가 필요하면 관련 검증은 직접 실행합니다. DIRECT로 시작한 작업이 다중 파일·설계 변경·인증/보안·배포 등의 범위로 커지면 HARNESS로 승격합니다.

---

# AI 작업 하니스 — 6개

Project Moon의 작업 하니스는 에이전트가 곧바로 코드를 수정하는 대신 **구조 파악 → 브리핑 → 계획 → 구현 → 프로그램적 검증 → 완료** 순서로 작업하도록 돕습니다. 작업 산출물은 `.moon/` 아래의 로컬 런타임 데이터로 저장되며 Git에는 포함되지 않습니다.

| 도구 | 기능 |
|---|---|
| `task_start` | 현재 Git SHA와 하니스 정책을 고정하고 저장소 구조·위험도를 파악하여 작업 시작 |
| `task_context` | `brief`, `plan`, `execute`, `validate` 단계별 최소 관련 컨텍스트 제공 |
| `task_record` | 구조 브리핑과 구현 계획을 기록하고 상위 산출물 변경 시 기존 검증 무효화 |
| `task_validate` | 실제 변경 경로를 다시 분석하고 위험도에 맞는 프로그램적 검증 실행 |
| `task_complete` | 최신 검증을 통과했고 검증 후 코드가 바뀌지 않았을 때만 작업 완료 |
| `task_status` | 위험도, 변경 파일, 검증 신선도, `STALE`, 실패 반복·성능 회귀 상태 조회 |

일반적인 흐름:

```text
USER INTENT
    ↓
task_start
    ↓
task_context(brief)
    ↓
task_record(context_brief)
    ↓
task_context(plan)
    ↓
task_record(plan)
    ↓
구현
    ↓
task_validate
    ↓
task_complete
```

## 위험도 기반 검증

기본 검증 강도는 다음과 같습니다.

```text
LOW    → fast
MEDIUM → normal
HIGH   → release
```

Moon은 요청 내용뿐 아니라 **실제로 변경된 파일 경로**를 다시 확인하여 위험도를 올릴 수 있습니다. 인증, 보안, 배포, 네트워크, `moon.config.json` 같은 영역은 높은 검증 강도를 요구하도록 구성할 수 있습니다. 에이전트가 더 약한 프로필을 지정해도 현재 위험도보다 낮은 검증은 거부됩니다.

프로젝트별 규칙은 [`moon.config.json`](moon.config.json)에 선언합니다. 현재 Moon 자체의 `fast / normal / release` 프로필에는 Architecture Guard와 문서 감사가 항상 포함되고, 위험도가 높아질수록 타입체크·테스트·빌드가 추가됩니다.

## 정책 고정과 STALE 방지

`task_start`는 시작 시점의 `moon.config.json` 정책을 `.moon`에 복사하고 SHA-256으로 고정합니다. 따라서 작업 도중 에이전트가 현재 설정을 수정해 Architecture Guard나 검증 명령을 약화하더라도 **진행 중인 task run의 기준은 바뀌지 않습니다.** 정책 변경을 적용하려면 새 작업을 시작해야 합니다.

`task_validate`는 검증한 시점의 HEAD, staged/unstaged diff, untracked 파일을 묶어 fingerprint를 생성합니다. 검증 이후 코드가 바뀌면 기존 증거는 더 이상 현재 코드의 증거가 아니므로 `task_status`가 `STALE`로 판단하고 `task_complete`를 차단합니다.

## 컨텍스트 인덱스

작업 시작 시 코드베이스에서 `.moon/.../repository-index.json`을 자동 생성합니다. 이는 영구 문서가 아니라 현재 Git 기준점에서 파생되는 캐시입니다. `task_context(brief)`는 저장소 전체를 덤프하는 대신 다음을 제공합니다.

- 파일 종류별 개수
- 모듈 단위 요약
- 프로젝트 규칙과 ADR
- 사용자 요청과 경로명이 실제로 연관된 파일 우선 목록
- 제한된 크기의 tracked-file 표본

목표는 컨텍스트 양을 늘리는 것이 아니라 **Signal / Noise 비율을 높이는 것**입니다.

## 프로그램적 Architecture / Knowledge Guard

Moon 자체에서는 다음 결정론적 검사기를 사용합니다.

```bash
npm run check:architecture
npm run check:docs
```

`check:architecture`는 tracked 파일뿐 아니라 새로 생성된 untracked 소스도 검사하여 금지된 레이어 의존성과 파일 비대화를 탐지합니다. `check:docs`는 임시 plan/spec 문서의 영구 추적, 깨진 로컬 링크, 문서 예산 초과를 탐지합니다.

## Failure → Harness Improvement

검증 명령의 실행 시간과 실패 시그니처는 `.moon/metrics/`에 구조화된 메트릭으로 축적됩니다. 장기 메트릭에는 원시 stdout/stderr를 저장하지 않고 정규화된 실패 시그니처만 남깁니다.

- 같은 결정론적 실패가 반복되면 regression test / rule / schema / validator로 승격할 후보라고 표시합니다.
- 같은 검증 명령이 충분한 기준선 대비 크게 느려지면 validation runtime regression으로 표시합니다.

즉 반복되는 문제를 “AI가 또 실수했다”로 끝내지 않고 **하니스가 다음 실수를 막을 수 있는지**를 확인하는 구조입니다.

---

# 코드 리뷰 하니스 — 6개

Project Moon에는 특정 AI 모델에 종속되지 않는 코드 리뷰 하니스가 포함되어 있습니다.

AI가 판단과 분석을 담당하고, Moon은 다음과 같은 **검증 가능한 상태와 증거**를 관리합니다.

- 리뷰 시작 시점의 Git SHA
- base / head / merge-base
- 변경 파일과 diff 통계
- 설계 의도
- 리뷰 기준
- 리뷰 결과
- 수정 판단
- Worktree
- QA 명령과 stdout/stderr
- 최종 통과 여부

## 리뷰 상태 흐름

```text
Git working tree clean
        │
        ▼
CONTEXT_READY
        │ 설계 의도
        ▼
INTENT_READY
        │ 리뷰 기준
        ▼
CRITERIA_READY
        │ PR 설명
        ▼
REVIEW_READY
        │ 리뷰
        ▼
REVIEWED
        │ 수정 판단
        ▼
FIXING
        │ QA
        ├──────────────▶ QA_FAILED
        ▼
QA
        │ 최종 보고서
        ▼
PASSED
```

리뷰가 끝난 뒤 대상 브랜치의 SHA가 바뀌면 기존 검증은 자동으로:

```text
STALE
```

상태로 판단됩니다.

## 리뷰 도구

| 도구 | 기능 |
|---|---|
| `review_start` | clean tree 확인 후 base/head/merge-base SHA 고정 |
| `review_context` | intent / criteria / review / fix 단계별 제한된 컨텍스트 제공 |
| `review_record` | 설계 의도, 기준, PR 설명, 리뷰, 판단, 최종 보고서 저장 |
| `review_worktree` | 리뷰 대상 SHA 기반 격리 Worktree 생성·조회·삭제 |
| `review_qa` | QA 명령 순차 실행 및 증거 저장 |
| `review_status` | SHA, STALE, Worktree, P1, QA, `readyToPush` 상태 조회 |

일반적인 흐름은 다음과 같습니다.

```text
review_start
→ review_context(intent)
→ review_record(design_intent)
→ review_context(criteria)
→ review_record(criteria)
→ review_record(pr_body)
→ review_context(review)
→ review_record(review)
→ review_record(decisions)
→ review_worktree          # 필요할 경우
→ review_context(fix)      # 수정할 경우
→ review_qa
→ review_record(final_report)
→ review_status
```

중요한 규칙:

- `review_start`는 dirty working tree를 거부합니다.
- 리뷰 기준이 바뀌면 그 기준에 의존하던 기존 리뷰·QA 증거가 무효화됩니다.
- `final_report` 생성에는 최신 QA 성공과 `unresolvedP1 == 0`이 필요합니다.
- 리뷰 대상 브랜치가 움직이면 `effectiveState="STALE"`이 됩니다.
- `readyToPush`는 현재 **검토 상태를 나타내는 권고 게이트**이며 `exec_command`로 직접 수행하는 `git push` 자체를 차단하지는 않습니다.

프로젝트별 리뷰 규칙은 다음 파일에서 관리할 수 있습니다.

- [`docs/code-convention.yaml`](docs/code-convention.yaml)
- [`docs/adr.yaml`](docs/adr.yaml)
- [`harnesses/code-review/README.md`](harnesses/code-review/README.md)

---

# MCP 전송 구조

Project Moon의 `/mcp`는 **stateless Streamable HTTP JSON** 방식입니다.

```text
HTTP 요청
   │
   ▼
인증 / Host 검증
   │
   ▼
요청별 MCP transport 생성
   │
   ▼
Moon 도구 실행
   │
   ▼
JSON 응답 + X-Request-Id
```

주요 특징:

- 각각의 `POST /mcp` 요청은 독립적입니다.
- `Mcp-Session-Id`를 필수로 사용하지 않습니다.
- 이전 클라이언트가 보내는 오래된 `Mcp-Session-Id`는 무시합니다.
- 인증된 `GET /mcp`, `DELETE /mcp`는 일반적으로 `405`를 반환합니다.
- MCP transport와 Moon 명령의 `sessionId`는 서로 다른 개념입니다.

---

# 인증과 보안

Project Moon은 두 가지 내장 인증 방식을 지원합니다.

1. Static Bearer Token
2. OAuth 2.1 + DCR + PKCE

Windows + Tailscale Funnel 구성에서는 **OAuth 2.1 사용을 권장**합니다.

## OAuth 2.1

Project Moon의 내장 OAuth 서버는 다음 기능을 제공합니다.

- RFC 9728 Protected Resource Metadata
- RFC 8414 Authorization Server Metadata
- Dynamic Client Registration(DCR)
- Authorization Code
- PKCE `S256`
- Resource Audience 검증
- Access Token
- Refresh Token Rotation
- Refresh Token Replay 탐지
- Token Revocation

사용 범위(scope)는 현재 다음 하나입니다.

```text
mcp:tools
```

주요 엔드포인트:

| 경로 | 기능 |
|---|---|
| `/.well-known/oauth-protected-resource` | OAuth 보호 리소스 메타데이터 |
| `/.well-known/oauth-protected-resource/mcp` | `/mcp`용 보호 리소스 메타데이터 |
| `/.well-known/oauth-authorization-server` | Authorization Server 메타데이터 |
| `/register` | Dynamic Client Registration |
| `/authorize` | 연결 승인 및 Authorization Code 발급 |
| `/token` | Access/Refresh Token 교환 |
| `/revoke` | 토큰 폐기 |

OAuth 클라이언트와 토큰 해시는 `MCP_OAUTH_STATE_FILE`에 저장되며 파일 권한은 `600`으로 관리됩니다.

## Static Bearer Token

`MCP_AUTH_TOKEN`을 설정하면 다음 헤더로 인증합니다.

```http
Authorization: Bearer <MCP_AUTH_TOKEN>
```

강한 랜덤값 생성 예시:

```bash
openssl rand -hex 32
```

OAuth 전용으로 운영하려면 `MCP_AUTH_TOKEN`을 비워 두는 것이 좋습니다.

## 인증을 외부에 위임하는 경우

신뢰할 수 있는 상위 OAuth Gateway 또는 사설 네트워크에서 인증을 완전히 담당할 때만 다음 설정을 사용할 수 있습니다.

```dotenv
MCP_AUTH_TOKEN=
MCP_OAUTH_ENABLED=false
MCP_ALLOW_NO_AUTH=true
```

> [!DANGER]
> `MCP_ALLOW_NO_AUTH=true` 상태로 Project Moon을 인터넷에 직접 노출하면 안 됩니다. Moon은 명령 실행·파일 수정·삭제 권한을 제공하므로 사실상 컴퓨터 제어 권한을 공개하는 것과 같습니다.

---

# ChatGPT 연결

Project Moon 실행 후 `Start-PublicMcp.ps1`이 출력한 주소를 사용합니다.

```text
https://project-moon.<tailnet>.ts.net/mcp
```

ChatGPT에서 MCP 연결을 만들 때 Project Moon의 OAuth 흐름을 사용하면:

```text
ChatGPT
  ↓
Project Moon OAuth Metadata
  ↓
Dynamic Client Registration
  ↓
Authorization + PKCE
  ↓
Moon 승인 페이지
  ↓
MCP_OAUTH_APPROVAL_KEY 입력
  ↓
Access Token 발급
  ↓
MCP 연결
```

승인 키는 다음 명령으로 확인할 수 있습니다.

```powershell
.\Get-OAuthApprovalKey.ps1
```

Project Moon은 파일 쓰기, 삭제, 명령 실행 기능을 제공하므로 클라이언트 측 정책에서도 해당 MCP 기능 사용이 허용되어 있어야 합니다.

관련 OpenAI 문서:

- [ChatGPT Plugins Quickstart](https://developers.openai.com/plugins/quickstart)
- [Developer mode and full MCP connectors in ChatGPT](https://help.openai.com/en/articles/12584461-developer-mode-and-full-mcp-connectors-in-chatgpt-beta)
- [MCP server authentication](https://developers.openai.com/plugins/build/auth)
- [MCP and Connectors in the Responses API](https://developers.openai.com/api/docs/guides/tools-connectors-mcp)

---

# 로컬 Node.js 개발

Docker 없이 Node.js 서버 자체를 개발할 수도 있습니다.

## 요구 사항

- Node.js 22 이상
- npm
- Git

```bash
git clone https://github.com/kankinku/project-moon.git
cd project-moon
npm install
npm run build

export MCP_AUTH_TOKEN="$(openssl rand -hex 32)"
export MCP_DEFAULT_CWD=/tmp
npm start
```

기본 주소:

```text
MCP    http://127.0.0.1:3000/mcp
Health http://127.0.0.1:3000/health
```

개발 모드:

```bash
export MCP_HOST=127.0.0.1
export MCP_AUTH_TOKEN="$(openssl rand -hex 32)"
npm run dev
```

---

# Linux VPS / EC2 배포

`deploy/`에는 다음 예제가 포함되어 있습니다.

- systemd 서비스
- 환경변수 예제
- Nginx 설정

Ubuntu 계열 서버 예시:

```bash
sudo mkdir -p /opt/project-moon
sudo cp -a package.json package-lock.json tsconfig.json src deploy /opt/project-moon/
cd /opt/project-moon
sudo npm ci
sudo npm run build
sudo npm prune --omit=dev

sudo install -d -m 0700 /var/lib/project-moon
sudo cp deploy/project-moon.env.example /etc/project-moon.env
sudo chmod 600 /etc/project-moon.env
sudo editor /etc/project-moon.env

sudo cp deploy/project-moon.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now project-moon
```

공개 배포 시 권장 사항:

- Project Moon 자체는 `127.0.0.1`에 바인딩
- TLS는 Nginx 등 신뢰할 수 있는 Reverse Proxy에서 종료
- 외부에는 HTTPS 포트만 공개
- OAuth 상태 파일을 애플리케이션 checkout 밖에 저장
- Secret은 Git에 저장하지 않음
- 실제 Proxy hop 수와 일치할 때만 `MCP_TRUST_PROXY_HOPS` 설정

OAuth 기반 예시:

```dotenv
MCP_HOST=127.0.0.1
MCP_PUBLIC_URL=https://mcp.example.com
MCP_ALLOWED_HOSTS=mcp.example.com,127.0.0.1,localhost
MCP_TRUST_PROXY_HOPS=1
MCP_AUTH_TOKEN=
MCP_OAUTH_ENABLED=true
MCP_OAUTH_APPROVAL_KEY=<strong-random-value>
MCP_OAUTH_ISSUER=https://mcp.example.com
MCP_OAUTH_RESOURCE=https://mcp.example.com/mcp
MCP_OAUTH_STATE_FILE=/var/lib/project-moon/oauth-state.json
```

---

# 상태 확인과 문제 해결

## Health 확인

로컬 Node 서버:

```bash
curl http://127.0.0.1:3000/health
```

Windows Docker/Tailscale 구성의 로컬 Proxy:

```powershell
curl.exe http://127.0.0.1:2999/health
```

공개 주소:

```text
https://project-moon.<tailnet>.ts.net/health
```

정상 응답 예시:

```json
{
  "status": "ok",
  "service": "project-moon",
  "version": "0.1.0",
  "transportMode": "stateless-json",
  "workflowMode": "auto",
  "activeMcpSessions": 0,
  "activeMcpRequests": 0,
  "managedProcesses": 0,
  "unrestrictedHostAccess": true,
  "oauthEnabled": true
}
```

## 자주 발생하는 문제

| 증상 | 확인할 항목 |
|---|---|
| Tailscale 명령을 찾지 못함 | Tailscale 설치 및 `tailscale.exe` PATH |
| `Start-PublicMcp.ps1` 권한 오류 | 관리자 PowerShell인지 확인 |
| Docker 연결 실패 | Docker Desktop Engine 실행 여부 |
| Funnel URL을 얻지 못함 | Tailscale 로그인 및 Funnel 승인 여부 |
| OAuth 메타데이터 로드 실패 | `MCP_PUBLIC_URL`, `/.well-known/*` 라우팅 |
| `401 Unauthorized` | OAuth 토큰 또는 Bearer Token |
| `403 Host header is not allowed` | `MCP_ALLOWED_HOSTS` |
| 명령이 `sessionId` 반환 | `read_process`로 후속 조회 |
| `GET /mcp`가 `405` | stateless POST 전송에서는 정상 |
| 재시작 후 프로세스 세션 소실 | 프로세스 상태는 메모리에 저장됨 |
| 리뷰가 `STALE` | 리뷰 시작 이후 대상 브랜치 SHA 변경 |
| `final_report` 거부 | P1 해결 및 최신 QA 통과 여부 |

---

# 테스트와 검증

저장소 기본 검증:

```bash
npm run check:architecture
npm run check:docs
npm run typecheck
npm test
npm run build
```

현재 통합 테스트는 다음 영역을 검증합니다.

- 인증
- OAuth 2.1
- Stateless MCP 요청
- 프로세스 lifecycle
- 파일 읽기·쓰기·패치
- UTF-8 / Base64 경계
- 기본 32개 개발 도구 계약과 optional 6개 merge gateway 도구 계약
- Merge Auditor runtime 격리와 SHA/CI/승인 기반 merge gate
- AI 작업 하니스 lifecycle과 위험도 상승
- 검증 정책 고정 및 self-bypass 방지
- 검증 후 변경에 대한 `STALE` 감지
- Architecture dependency / 파일 크기 guard
- 임시 문서·깨진 링크 audit
- 요청 관련 파일을 우선하는 repository context index
- 반복 실패 시그니처와 검증 성능 회귀 탐지
- 코드 리뷰 하니스 lifecycle
- Worktree
- QA invalidation

실제 실행 중인 외부 MCP 서버를 대상으로 E2E 테스트할 수도 있습니다.

```bash
MCP_E2E_URL='https://mcp.example.com/mcp' \
MCP_E2E_TOKEN='<bearer-token>' \
MCP_E2E_ROOT='/tmp/project-moon-tools-e2e-manual' \
npx vitest run test/all-tools.integration.test.ts
```

> E2E 테스트는 대상 호스트에서 실제 명령을 실행하고 파일을 생성·수정·삭제합니다. 운영 데이터 디렉터리를 `MCP_E2E_ROOT`로 사용하지 마세요.

---

# 주요 환경변수

| 변수 | 기본값 | 설명 |
|---|---:|---|
| `MCP_HOST` | `0.0.0.0` | HTTP 바인드 주소 |
| `MCP_PORT` | `3000` | MCP 서버 포트 |
| `MCP_ENDPOINT` | `/mcp` | MCP 엔드포인트 |
| `MCP_PUBLIC_URL` | 없음 | 외부 HTTPS 기본 URL |
| `MCP_ALLOWED_HOSTS` | 없음 | 허용할 Host 헤더 목록 |
| `MCP_TRUST_PROXY_HOPS` | `0` | 신뢰하는 Reverse Proxy hop 수 |
| `MCP_AUTH_TOKEN` | 없음 | Static Bearer Token |
| `MCP_ALLOW_NO_AUTH` | `false` | 내장 인증 없이 시작 허용 |
| `MCP_OAUTH_ENABLED` | `false` | 내장 OAuth 2.1 활성화 |
| `MCP_OAUTH_APPROVAL_KEY` | `MCP_AUTH_TOKEN` | OAuth 승인 페이지 키 |
| `MCP_OAUTH_ISSUER` | `MCP_PUBLIC_URL` | OAuth Issuer |
| `MCP_OAUTH_RESOURCE` | Public URL + endpoint | OAuth Resource Audience |
| `MCP_OAUTH_STATE_FILE` | 작업 디렉터리 내부 | OAuth 영구 상태 파일 |
| `MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS` | `3600` | Access Token 수명 |
| `MCP_OAUTH_REFRESH_TOKEN_TTL_SECONDS` | `2592000` | Refresh Token 수명 |
| `MCP_OAUTH_AUTHORIZATION_CODE_TTL_SECONDS` | `300` | Authorization Code 수명 |
| `MCP_WORKFLOW_MODE` | `auto` | 기본 작업 정책: `auto`, `direct`, `harness` |
| `MCP_DEFAULT_CWD` | 서버 시작 위치 | 상대경로 기준 디렉터리 |
| `MCP_DEFAULT_SHELL` | `$SHELL` 또는 `/bin/bash` | 기본 셸 |
| `MCP_MAX_REQUEST_BODY` | `8mb` | HTTP 요청 크기 제한 |
| `MCP_MAX_OUTPUT_BYTES` | `1048576` | 한 응답의 최대 출력 크기 |
| `MCP_MAX_RETAINED_PROCESS_OUTPUT_BYTES` | `4194304` | 프로세스별 보관 출력 크기 |
| `MCP_PROCESS_RETENTION_MS` | `3600000` | 완료 프로세스 기록 유지 시간 |
| `MCP_MAX_PROCESSES` | `128` | 최대 프로세스 기록 수 |
| `MCP_MAX_FILE_CHUNK_BYTES` | `1048576` | 파일 전송 청크 크기 |
| `MCP_MAX_EDIT_FILE_BYTES` | `67108864` | 텍스트 편집 최대 파일 크기 |

자세한 예시는 다음 파일을 참고하세요.

- [`.env.example`](.env.example)
- [`deploy/project-moon.env.example`](deploy/project-moon.env.example)
- [`tunneling/.env.local.example`](tunneling/.env.local.example)

---

# 저장소 구조

| 경로 | 역할 |
|---|---|
| `src/http-server.ts` | HTTP 전송, 인증 라우팅, Health 엔드포인트 |
| `src/mcp-server.ts` | MCP 서버 및 도구 등록 |
| `src/exec-tools.ts` | 명령·스크립트·프로세스 도구 |
| `src/file-service.ts` | 호스트 파일시스템 구현 |
| `src/file-tools.ts` | 파일 MCP 도구 |
| `src/oauth.ts` | DCR, PKCE, 토큰 발급·갱신·폐기 |
| `src/task/` | AI 작업 lifecycle, 위험도, 컨텍스트 인덱스, 검증·메트릭 |
| `src/review/` | Git 코드 리뷰 상태 머신, Worktree, QA |
| `moon.config.json` | 검증 프로필, 위험도, Architecture/Knowledge 정책 |
| `scripts/check-architecture.mjs` | 레이어 의존성·파일 비대화 결정론적 검사 |
| `scripts/audit-docs.mjs` | 임시 문서·문서 예산·로컬 링크 감사 |
| `Start-PublicMcp.ps1` | Windows 공개 MCP 시작 및 Funnel 자동 구성 |
| `Stop-PublicMcp.ps1` | 공개 MCP 중지 |
| `Get-OAuthApprovalKey.ps1` | OAuth 승인 키 조회 |
| `Test-Gpu.ps1` | NVIDIA GPU 연결 검증 |
| `tunneling/` | Docker/Nginx/Tailscale 배포 구성 |
| `deploy/` | Linux systemd/Nginx 배포 예제 |
| `docs/code-convention.yaml` | 프로젝트 코드 리뷰 규칙 |
| `docs/adr.yaml` | Architecture Decision Record |
| `harnesses/code-review/` | 코드 리뷰 하니스 문서와 프롬프트 계약 |
| `test/` | 단위·통합 테스트 |

Windows Docker 설치에 대한 더 자세한 설명은 [`LOCAL_DOCKER_SETUP.md`](LOCAL_DOCKER_SETUP.md)를 참고하세요.

---

# Secret 및 Git 관리

실제 인증 정보는 저장소에 커밋하지 마세요.

루트 `.gitignore`는 다음과 같은 로컬·민감 파일을 기본적으로 제외합니다.

- `.env`, `.env.*`
- `*.pem`, `*.key`, `*.p12`, `*.pfx`
- `.ssh/`
- `credentials*.json`
- `client_secret*.json`
- `service-account*.json`
- `.secrets/`, `secrets/`
- `*.token`, `*.secret`
- `.cloudflare/`, `.tailscale/`
- OAuth runtime state
- Project Moon 백업 아카이브
- `.moon/`
- `.project-moon-worktrees/`

예제 설정 파일만 저장소에 포함하고 실제 값은 로컬 파일 또는 Secret Manager에 보관하는 방식을 권장합니다.

---

# 기반 프로젝트 및 출처

Project Moon은 MIT 라이선스의 [`kstost/cokacremote`](https://github.com/kstost/cokacremote)를 기반으로 발전한 프로젝트입니다. 원 프로젝트의 저작권 및 라이선스 고지는 [`LICENSE`](LICENSE)에 보존되어 있습니다.

코드 리뷰 워크플로는 MIT 라이선스의 [`vibemafiaclub/mafia-codereview-harness`](https://github.com/vibemafiaclub/mafia-codereview-harness)의 핵심 개념을 참고해 Project Moon용 MCP 도구로 재구현했습니다.

상세 출처:

- [`vendor/mafia-codereview-harness/SOURCE.md`](vendor/mafia-codereview-harness/SOURCE.md)

---

# 라이선스

[MIT License](LICENSE)

---

# 면책 고지

이 소프트웨어는 상품성, 특정 목적 적합성 및 비침해성에 대한 보증을 포함하여 명시적 또는 묵시적인 어떠한 보증도 없이 **있는 그대로(AS IS)** 제공됩니다.

저작권자와 기여자는 이 소프트웨어의 사용 또는 기타 거래로 인해 발생하는 데이터 손실·손상, 시스템 장애, 보안 사고, 취약점, 재산상 손실 및 직·간접적 손해에 대해 책임을 지지 않습니다.

Project Moon은 의도적으로 강력한 시스템 접근 권한을 제공하는 도구입니다. 운영 환경과 권한 범위, 인증 방식, 네트워크 공개 범위를 확인하고 사용하는 책임은 사용자에게 있습니다.