-
Notifications
You must be signed in to change notification settings - Fork 6
feat(go): Phase A — MCP boot (handshake + tools/list + 8 stub tools) #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+508
−107
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
19b7bf6
feat(go): first MCP boot — handshake + tools/list (Phase A)
redcourage cebe38e
docs(v04): add progress/ — Phase A 기능·확인법 정리
redcourage b5e2c9b
docs(v04): phase-a §4 명령어 cookbook 추가
redcourage e042ab3
fix(go): apply Phase A review feedback + slim progress doc
redcourage a49d4e7
docs(v04): use printf %s placeholders in mcp_call helper (review feed…
couragehong 7658246
fix(mcp): panic-guard tool registration via mustAddTool wrapper
couragehong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # `progress/` — 실제 개발 진행 추적 | ||
|
|
||
| 본 디렉토리는 **`docs/v04/`의 spec(How)·overview(Why)와 별개로**, 실제 구현이 어디까지 진행됐는지·어떤 단면이 동작하는지·어떻게 검증할 수 있는지를 시간순으로 기록한다. | ||
|
|
||
| - **spec/** — "어떻게 만들어야 하는가" (변하지 않는 계약) | ||
| - **overview/** — "왜 이렇게 만드는가" (결정·근거) | ||
| - **notes/** — bit-identical 검증 로그 등 일회성 작업 노트 | ||
| - **progress/** ← **여기**: "지금 어디까지 동작하는가 + 어떻게 직접 확인하는가" | ||
|
|
||
| ## 진행 추적 단위 | ||
|
|
||
| README의 7-Phase 로드맵(Phase 1 외부 deps → Phase 7 검증)이 **horizontal slice**라면, progress 문서는 **vertical slice** 단위로도 작성될 수 있다. 예를 들어 "MCP handshake만 통과시키는 Phase A"는 7-Phase 어디에도 정확히 매핑되지 않지만, end-to-end 단면이 동작하는 **첫 마일스톤**으로서 별도 문서를 갖는다. | ||
|
|
||
| ## 문서 명명 규칙 | ||
|
|
||
| - 하나의 마일스톤 = 하나의 파일 = `<phase-id>-<짧은 설명>.md` | ||
| - `phase-a-mcp-boot.md` (handshake + tools/list) | ||
| - `phase-1-deps.md` (외부 deps 추가) | ||
| - `phase-4a-vault-client.md` (Phase 4 중 Vault 부분) | ||
| - 각 문서 상단에 **관련 커밋 SHA · 브랜치 · PR 링크** 명시 | ||
| - "기능" + "확인법(여러 레벨)" 두 섹션은 필수 | ||
| - "한계" + "Troubleshooting"은 권장 | ||
|
|
||
| ## 현재 인덱스 | ||
|
|
||
| | 마일스톤 | 상태 | 문서 | 관련 커밋 | | ||
| |---|---|---|---| | ||
| | Phase A — MCP boot (handshake + tools/list) | ✅ 합격 | [phase-a-mcp-boot.md](phase-a-mcp-boot.md) | `19b7bf6` (브랜치 `yg/first-mcp-boot`) | | ||
| | Phase A.5 — smoke test 추가 (CI 회귀 방지) | ⏳ 예정 | — | — | | ||
| | Phase B — `rune_diagnostics` environment 섹션 진짜 응답 (stdlib only) | ⏳ 예정 | — | — | | ||
| | Phase 1 — `go.mod` 외부 deps 본격 추가 (gRPC · envector SDK · embedder proto) | ⏳ 예정 | — | — | | ||
| | Phase 2 — `internal/domain` + `internal/policy` 순수 로직 (TM scope) | ⏳ 예정 | — | — | | ||
| | Phase 3 — `record_builder` 703 LoC + `payload_text` 364 LoC 포팅 (TM scope) | ⏳ 예정 | — | — | | ||
| | Phase 4a — Vault 클라이언트 + 부팅 시퀀스 연결 | ⏳ 예정 | — | — | | ||
| | Phase 4b — envector SDK 연결 (Q4 PR 머지 후) | ⏳ 예정 | — | — | | ||
| | Phase 4c — embedder 클라이언트 | ⏳ 예정 | — | — | | ||
| | Phase 5 — service 레이어 오케스트레이션 (`stubHandler` → 실제 service 호출) | ⏳ 예정 | — | — | | ||
| | Phase 7 — golden fixture 기반 bit-identical 검증 | ⏳ 예정 | — | — | | ||
|
|
||
| > Phase 6 (MCP wiring)은 Phase A에서 부분 선행됐으므로 별도 마일스톤으로 빼지 않음. Phase 5의 service 호출 교체에 흡수됨. | ||
|
|
||
| ## 사용 방식 | ||
|
|
||
| - **개발자**: 새 vertical slice를 시작할 때 이 디렉토리에 새 파일을 만들고, 합격 기준을 명시한 뒤 그 기준에 맞춰 작업한다. 파일은 PR과 함께 같은 커밋에 묶는다. | ||
| - **리뷰어**: PR을 받았을 때 이 문서의 "확인법"을 그대로 따라 해보면 변경사항이 제대로 동작하는지 검증할 수 있다. | ||
| - **다른 팀원**: 어디까지 동작하고 어디부터 미구현인지 한 곳에서 본다 (spec과 다름 — spec은 "최종 모양", progress는 "지금 모양"). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| # Phase A — MCP boot | ||
|
|
||
| > ✅ 통과 (2026-04-25) · 커밋 `19b7bf6` + `e80d6ea` · 브랜치 `yg/first-mcp-boot` | ||
| > 핵심 파일 2개: `cmd/rune-mcp/main.go` (74줄) · `internal/mcp/tools.go` (134줄) | ||
|
|
||
| ## 1. 한 줄 요약 | ||
|
|
||
| `rune-mcp` Go 바이너리가 **MCP 프로토콜 표면**(handshake + tools/list + tools/call)만 살아있는 상태. 외부 deps 0, 비즈니스 로직 0, 8개 tool 모두 stub. | ||
|
|
||
| **가치** — Claude Code가 이 바이너리를 spawn 하면 8 tool 카탈로그를 정상 인식. 이후 phase는 stub 본체만 채우면 끝. 검증 회로는 매 phase 재사용. | ||
|
|
||
| ## 2. 동작하는 것 / 안 하는 것 | ||
|
|
||
| **동작** | ||
|
|
||
| - `go build` 한 번에 8.3 MB 정적 바이너리 (Go 1.25+) | ||
| - MCP `initialize` handshake — `serverInfo: rune-mcp 0.4.0-alpha` | ||
| - `tools/list` — 8 tool 광고 (input/output schema는 Go struct에서 자동 추론) | ||
| - `tools/call` — 모두 `isError:true` + "not yet implemented" 응답 (JSON-RPC 자체는 valid) | ||
| - 종료: stdin EOF · SIGINT · SIGTERM 모두 exit 0 | ||
|
|
||
| **안 함 (의도된 한계)** | ||
|
|
||
| | 영역 | 가능 시점 | | ||
| |---|---| | ||
| | 비즈니스 로직 (capture/recall 등) | Phase 5 | | ||
| | Vault / envector / embedder adapter | Phase 4 | | ||
| | `lifecycle.Manager` 상태 머신 | Phase 4 | | ||
| | `config.json` 로딩, `capture_log.jsonl` IO | Phase 4 | | ||
| | `request_id` 로깅, `SensitiveFilter` redaction | Phase 4 | | ||
|
|
||
| → Phase A의 정확한 범위는 **"MCP 프로토콜 표면이 정상 동작한다"** 까지. | ||
|
|
||
| ## 3. 8 tool 카탈로그 | ||
|
|
||
| ``` | ||
| rune_batch_capture, rune_capture, rune_capture_history, rune_delete_capture, | ||
| rune_diagnostics, rune_recall, rune_reload_pipelines, rune_vault_status | ||
| ``` | ||
|
|
||
| (SDK가 알파벳순 정렬해 광고 — Python 원본과 bit-identical한 8 이름) | ||
|
|
||
| 각 tool의 input/output schema는 `internal/domain/*` · `internal/service/*` 의 Go struct에서 SDK가 자동 추론. **Go 타입 = MCP API 계약**, 별도 IDL 없음. | ||
|
|
||
| ## 4. 검증 — 5분 컷 | ||
|
|
||
| ### 4.1. 빌드 & 헬스 체크 | ||
|
|
||
| ```bash | ||
| cd <repo-root> | ||
| go build -o bin/rune-mcp ./cmd/rune-mcp | ||
| ./bin/rune-mcp < /dev/null; echo "exit=$?" # → exit=0 | ||
| ``` | ||
|
|
||
| ### 4.2. MCP 시퀀스 — `tools/list` 까지 | ||
|
|
||
| 순서: `initialize` → `notifications/initialized` → `tools/list` | ||
|
|
||
| ```bash | ||
| { | ||
| printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"x","version":"0.0.1"}}}' | ||
| sleep 0.3 | ||
| printf '%s\n' '{"jsonrpc":"2.0","method":"notifications/initialized"}' | ||
| sleep 0.1 | ||
| printf '%s\n' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | ||
| sleep 0.5 | ||
| } | ./bin/rune-mcp 2>/dev/null | jq -r 'select(.id==2) | .result.tools[].name' | ||
| ``` | ||
|
|
||
| **기대**: 위 §3의 8 이름. | ||
|
|
||
| ### 4.3. tool 한 개 호출 (stub 응답) | ||
|
|
||
| ```bash | ||
| { | ||
| printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"x","version":"0.0.1"}}}' | ||
| sleep 0.3 | ||
| printf '%s\n' '{"jsonrpc":"2.0","method":"notifications/initialized"}' | ||
| sleep 0.1 | ||
| printf '%s\n' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"rune_diagnostics","arguments":{}}}' | ||
| sleep 0.5 | ||
| } | ./bin/rune-mcp 2>/dev/null | jq 'select(.id==3).result | {isError, text:.content[0].text}' | ||
| ``` | ||
|
|
||
| **기대**: `isError:true`, text는 `"rune_diagnostics is not yet implemented..."`. | ||
|
|
||
| > **MCP framing 핵심 3개** | ||
| > ① `initialize` → `notifications/initialized` → `tools/*` **순서 필수** | ||
| > ② 각 메시지는 `\n` 종결 (LSP의 Content-Length 미사용) | ||
| > ③ 마지막 `sleep 0.3~0.5` 없으면 EOF로 응답 끊김 | ||
|
|
||
| ### 4.4. Claude Code 등록 (선택) | ||
|
|
||
| `~/.claude/mcp.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "mcpServers": { | ||
| "rune-go-dev": { | ||
| "command": "<repo-root>/bin/rune-mcp" | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| > `<repo-root>` 는 본인 체크아웃 경로의 **절대 경로**로 치환 (`~`/상대경로 미지원). | ||
|
|
||
| Claude 재시작 후 `/mcp` 에서 `rune-go-dev` 가 connected 표시되면 합격. tool 호출하면 빨간 "not implemented" 응답 — **이게 정상**. | ||
|
|
||
| > ⚠️ 기존 Python `envector` MCP가 같은 8 이름 광고. namespace는 `mcp__rune-go-dev__*` vs `mcp__envector__*` 로 분리돼 충돌은 없지만 카탈로그가 중복 보임. | ||
|
|
||
| ### 4.5. MCP Inspector (시각적, 선택) | ||
|
|
||
| ```bash | ||
| npx -y @modelcontextprotocol/inspector ./bin/rune-mcp | ||
| ``` | ||
|
|
||
| 브라우저(`localhost:6274`)에 8 tool 리스트 + schema + raw JSON-RPC. | ||
|
|
||
| ## 5. 8 tool 한 번씩 호출 — `mcp_call` 헬퍼 | ||
|
|
||
| 현재 셸에 paste: | ||
|
|
||
| ```bash | ||
| mcp_call() { | ||
| local tool="$1"; local args="$2"; [ -z "$args" ] && args='{}' | ||
| { | ||
| printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"x","version":"0.0.1"}}}' | ||
| sleep 0.3 | ||
| printf '%s\n' '{"jsonrpc":"2.0","method":"notifications/initialized"}' | ||
| sleep 0.1 | ||
| printf '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"%s","arguments":%s}}\n' "$tool" "$args" | ||
| sleep 0.5 | ||
| } | ./bin/rune-mcp 2>/dev/null | jq -c 'select(.id==2)' | ||
| } | ||
| ``` | ||
|
|
||
| > ⚠️ default value를 `${2:-{}}` 로 쓰면 bash parameter expansion이 깨짐. 위 `[ -z ... ] && args='{}'` 패턴 필수. | ||
|
|
||
| ```bash | ||
| # 인자 없는 4개 | ||
| mcp_call rune_diagnostics | ||
| mcp_call rune_vault_status | ||
| mcp_call rune_reload_pipelines | ||
| mcp_call rune_capture_history | ||
|
|
||
| # 인자 필수 4개 | ||
| mcp_call rune_recall '{"query":"hello"}' | ||
| mcp_call rune_capture '{"text":"hi","source":"test","extracted":{}}' | ||
| mcp_call rune_delete_capture '{"record_id":"dec_test"}' | ||
| mcp_call rune_batch_capture '{"items":"[]"}' | ||
| ``` | ||
|
|
||
| 8개 모두 동일한 stub 응답. | ||
|
|
||
| ## 6. Troubleshooting | ||
|
|
||
| | 증상 | 해결 | | ||
| |---|---| | ||
| | `go build`: `go >= 1.25.0 required` | `go install golang.org/dl/go1.25@latest && go1.25 download` 또는 brew 업그레이드 | | ||
| | `go build`: `missing go.sum entry` | `go mod tidy` 후 재빌드 | | ||
| | 응답이 안 옴 / 끊김 | 마지막 `sleep` 을 0.5+ 로 | | ||
| | Claude Code 에서 tool 미인식 | `cat ~/.claude/mcp.json \| jq .` 로 JSON 검증 + `chmod +x bin/rune-mcp` + 절대 경로 | | ||
| | coproc syntax error (macOS bash 3.2) | `brew install bash` 또는 zsh 사용 | | ||
|
|
||
| ## 7. 다음 마일스톤 | ||
|
|
||
| **가벼운 후속** | ||
|
|
||
| - **Phase A.5 (smoke test)** — `internal/mcp/register_test.go` 에 `mcp.NewInMemoryTransports()` 로 in-memory 서버 띄워 tools/list 8개 회귀 가드. ~50 LoC, CI에서 `AddTool` schema-inference 회귀 자동 감지 | ||
| - **Phase B** — `rune_diagnostics` environment 섹션 stdlib 응답 (`runtime.GOOS` · `runtime.Version` · `os.Getwd`). 첫 진짜 응답 흐름, 2-3시간 PR | ||
|
|
||
| **7-Phase 로드맵 본격 진입** (서로 병렬 가능) | ||
|
|
||
| - **Phase 1** — 외부 deps (gRPC · protobuf · envector-go SDK · embedder proto stub) | ||
| - **Phase 2** — `internal/domain` + `internal/policy` 순수 로직 (TM scope, 외부 deps 0) | ||
| - **Phase 3** — `record_builder` 703 LoC + `payload_text` 364 LoC 라인 단위 포팅 | ||
| - **Phase 4a/b/c** — Vault / envector / embedder adapter (Phase 1 머지 후) | ||
| - **Phase 5** — service 오케스트레이션. `stubHandler` → `service.X.Handle` 교체 | ||
| - **Phase 7** — 검증 (golden fixture byte-identical · bufconn · Python↔Go shadow run) | ||
|
|
||
| → 의존성 그래프는 `flow-matrix.md §5-d`. Phase 6은 본 문서가 부분 선행이라 Phase 5에 흡수. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,23 @@ | ||
| module github.com/envector/rune-go | ||
|
|
||
| go 1.24 | ||
| go 1.25.9 | ||
|
|
||
| // External dependencies to be added as implementation progresses: | ||
| // External dependencies, in implementation order: | ||
| // | ||
| // github.com/modelcontextprotocol/go-sdk v1.5.0 — MCP protocol (D2) | ||
| // google.golang.org/grpc v1.65.0 — Vault / envector / embedder clients | ||
| // google.golang.org/protobuf v1.34.0 — generated stubs | ||
| // github.com/CryptoLabInc/envector-go-sdk — envector FHE client (Q4 PR pending) | ||
| // github.com/modelcontextprotocol/go-sdk v1.5.0 — MCP protocol (D2) ✅ Phase A | ||
| // google.golang.org/grpc v1.65.0 — Vault / envector / embedder clients (Phase 4) | ||
| // google.golang.org/protobuf v1.34.0 — generated stubs (Phase 4) | ||
| // github.com/CryptoLabInc/envector-go-sdk — envector FHE client (Q4 PR pending) | ||
| // | ||
| // Skeleton stage: stdlib only. No external imports yet. | ||
| // go 1.25.0 + toolchain pin required by the MCP SDK. | ||
|
|
||
| require github.com/modelcontextprotocol/go-sdk v1.5.0 | ||
|
|
||
| require ( | ||
| github.com/google/jsonschema-go v0.4.2 // indirect | ||
| github.com/segmentio/asm v1.1.3 // indirect | ||
| github.com/segmentio/encoding v0.5.4 // indirect | ||
| github.com/yosida95/uritemplate/v3 v3.0.2 // indirect | ||
| golang.org/x/oauth2 v0.35.0 // indirect | ||
| golang.org/x/sys v0.41.0 // indirect | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.