Skip to content

feat(mcp): Wiki MCP — 추상화 + GitHub Wiki 어댑터 #37

@hagyutae

Description

@hagyutae

배경

이슈만으로 표현하기 어려운 비즈니스 정책 / 데이터 모델 등의 디테일은 wiki
문서로 기록 (사용자 지시). M3 의 wiki 구현은 GitHub Wiki, 대상 repo 는
vonkernel/guestbook.

본 이슈는 #36 (IssueTracker MCP) 와 같은 패턴 적용 — mcp/CLAUDE.md §0 (thin
bridge) + §2.2 (API-client) + ISP + composition.

호출자 (proposal §6.1단계)

P 가 PRD 작성 후:

  1. Doc Store(wiki_pages collection) 에 영속 (Librarian 통해)
  2. GitHub Wiki MCP 호출해 GitHub Wiki 에 동기화

본 PR 의 스코프는 위 2번의 MCP 도구 노출 + SDK 까지. P 의 graph 가 SDK 호출
하는 wiring 은 별 이슈 (M3 의 P 그래프 확장 #39 등).

모듈 구조 (#36 미러)

mcp/wiki/ (서버, §2.2 API-client 패턴, ISP)

src/wiki_mcp/
├── adapters/
│   ├── base.py            # PageOps ABC + Wiki (composition) ABC
│   └── github/            # 패키지 (도메인별 모듈 분할)
│       ├── adapter.py     # GitHubWikiAdapter (composition)
│       ├── page.py        # GitHubPageOps (6 op)
│       ├── _ctx.py        # 공유 _Ctx
│       └── _git.py        # subprocess git wrapper (clone/commit/push)
├── factory.py             # WIKI_TYPE → 어댑터 (OCP)
├── tools/page.py          # 6 도구 (delegate to tracker.pages.X)
├── mcp_instance.py
└── server.py
scripts/
├── verify_sandbox.sh
└── verify_sandbox.py      # 자동 검증

shared/src/dev_team_shared/wiki/ (consumer SDK, doc-store/issue_tracker 미러)

├── schemas/page.py        # PageCreate / PageUpdate / PageRead / PageRef
├── tool_names.py          # PageTools
├── _ops_client.py         # PageClient
└── client.py              # WikiClient (composition: 1 property `pages`)

추상화 — Wiki ABC (ISP)

class PageOps(ABC):
    async def create(doc: PageCreate) -> PageRead
    async def update(slug: str, patch: PageUpdate) -> PageRead | None
    async def get(slug: str) -> PageRead | None
    async def list() -> list[PageRef]                         # slug + title 만 (가벼움)
    async def delete(slug: str) -> bool
    async def count() -> int

class Wiki(ABC):  # 컴포지트
    @property @abstractmethod
    def pages(self) -> PageOps

transition / close 같은 lifecycle 없음 — wiki page 는 just data.

GitHub Wiki 어댑터 — subprocess git

GitHub Wiki = 별 git repo (<owner>/<repo>.wiki.git). GraphQL / REST 미지원
(GitHub API 에 wiki 페이지 CRUD endpoint 없음 — git access 만 공식).

구현: subprocess git 호출 (외부 라이브러리 dulwich 등 미사용 — 표준 git
binary 가 일관성 / 디버그 / standard 우위).

op 동작
create / update clone → write <slug>.md (front matter + content) → commit → push
get clone → read <slug>.md → front matter parse
list clone → ls *.md (front matter title 추출)
delete clone → rm <slug>.md → commit → push
count clone → ls 카운트

인증: HTTPS URL 에 token 임베드 (https://x-access-token:{token}@github.com/...).
workdir 은 매 호출마다 임시 디렉터리 + 작업 후 cleanup → token leak 방지.

Dockerfile: apt install -y --no-install-recommends git 추가 (~30MB).

front matter (page metadata 인코딩)

YAML front matter — 표준 필드 + 도메인 필드 분리:

---
title: GuestBook PRD
created_at: 2026-05-04T17:39:00Z
updated_at: 2026-05-04T17:39:00Z
page_type: prd
structured:
  milestones:
    - {name: M1}
  in_scope: ["..."]
---

# GuestBook — PRD
...

GitHub Wiki UI 가 front matter 를 hide 하지 않고 그대로 렌더 (사람이 보기 약간
noisy 하지만 round-trip 가능). doc-store 의 wiki_pages.page_type / structured
와 키 일치.

식별자 — slug

GitHub Wiki 의 페이지 파일명 = <slug>.md. URL 도 slug 기반:
github.com/<owner>/<repo>/wiki/<slug>.

slug 컨벤션 — kebab-case (doc-store wiki_pages.slug 와 일치).

도구 면 (6 op)

도구 args return
page.create doc: PageCreate{slug, title, content_md, page_type, structured?} PageRead
page.update slug: str, patch: PageUpdate{title?, content_md?, structured?} PageRead | None
page.get slug: str PageRead | None
page.list (없음) list[PageRef{slug, title}]
page.delete slug: str bool
page.count (없음) int

환경변수

#36 과 재활용:

  • GITHUB_TOKEN (PAT, repo scope 가 wiki 권한 포함)
  • GITHUB_TARGET_OWNER
  • GITHUB_TARGET_REPO

신규: WIKI_TYPE (default github, factory 가 사용).

포트

mcp/CLAUDE.md §3 표 — 9102 (이미 예약).

비-스코프

검증 (sandbox: vonkernel/guestbook)

scripts/verify_sandbox.sh 자동:

  • page.create("[verify]-sandbox", title, content) → wiki 에 실 생성
  • page.get 라운드트립 (front matter parse 확인)
  • page.list 가 만든 페이지 포함
  • page.update content 변경 반영
  • page.deletepage.get → None
  • 단위 테스트 (mocked subprocess)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions