AI가 준 답을 다시 공유하기 — 커뮤니티용 MCP 서버 'Shared Knowledge'
AI와 대화로 해결한 문제를 마크다운 글로 만들어 GitHub PR로 올리고, 사람이 검토해 병합하면 문서 사이트와 오디오까지 자동 발행하는 MCP 서버. 주말 PoC로 만든 개발자의 구현 기록이다.

From AI Solutions to Shared Knowledge: Building an MCP for the Community
This is a submission for the Weekend Challenge: Generosity Edition Don't Just Ask AI. Give the...
개요 #
AI에게 물어 문제를 해결하면 그 지식은 대화창에 묻힌다. 다른 사람이 같은 벽에 부딪히면 같은 질문을 처음부터 다시 한다. Pascal CESCATO가 Dev.to의 주말 챌린지(Generosity Edition)에 출품한 Shared Knowledge MCP는 이 반복을 끊어보려는 시도다.
핵심 동작은 단순하다. AI 대화에서 나온 해결책을 마크다운 글로 정리해 GitHub Pull Request로 올린다. 사람이 검토해 병합하면 공개 문서 사이트에 실리고, 병합 이후 ElevenLabs로 오디오 버전이 생성된다. 대화 자체는 밖으로 나가지 않는다. MCP 서버는 관련된 해결책만 뽑아 독립적인 영어 마크다운 글로 구조화하고 검증한 뒤 PR을 연다.
자동 발행은 없다. 저자가 파이프라인에서 끝까지 양보하지 않은 지점이 사람의 검토다. MCP가 지식을 구조화하고 기여를 준비하는 것까지는 하되, 무엇이 공개 지식이 될 자격이 있는지는 남을 대신해 정하지 않는다.
AI 대화 → 명시적 공유 결정 → MCP → 마크다운 → Pull Request → 사람 검토 → 병합 → 문서 + 오디오
두 가지 경로로 검증한 동작 #
공개 문서 사이트는 이미 운영 중이고, 오디오 버전을 갖춘 글 네 편이 올라가 있다.
저자는 하드코딩 없이 서로 다른 클라이언트에서 publish_knowledge가 실제로 동작하는지 두 경로로 확인했다.
스크립트 직접 실행 #
첫 기여는 실제 PR로 나갔다. Optional dependency crashes the import chain when the import itself isn't optional이다. pyproject.toml의 optional dependency가 import 체인을 깨뜨린 실제 문제를 AI 어시스턴트와 함께 해결하고, 이를 섹션·메타데이터·태그를 갖춘 마크다운 글로 바꿔 MCP 서버가 검증한 뒤 PR을 열었다. 이후 GitHub Copilot의 자동 리뷰가 YAML 포맷과 heading 문제를 지적했고, 수정 후 main에 병합됐다. 병합 다음 단계로 ElevenLabs 오디오가 생성돼 문서 사이트에 올라갔다.
대화형 에이전트 모드 #
두 번째는 Codespace 안에서 Agent 모드로 돌아가는 GitHub Copilot Chat이었다. 여기서 어시스턴트는 발행을 결정하기 전에 스스로 search_knowledge를 호출해 기존 글에 중복이 없는지 확인했다(PR #2). MCP 서버 어디에도 그런 순서를 강제한 코드는 없다. 서버는 도구만 제공하고, 호출하는 어시스턴트가 사용법을 판단한다. 저자는 이 지점을 강조한다. Shared Knowledge는 특정 모델에 묶인 닫힌 AI 앱이 아니라 지식 공유를 위한 열린 MCP 인터페이스라는 것이다.
프로젝트 전체는 GitHub에 공개돼 있다. MCP 서버, 지식 글, Astro/Starlight 정적 사이트, GitHub Actions 워크플로, 테스트 스위트, 문서가 모두 저장소에 들어 있다.
주말 MVP의 선택 #
Photo by Jakub Zerdzicki on Pexels
혼자 주말 동안 PoC를 만들면 한계선을 그어야 한다. PostgreSQL 데이터베이스를 설계하고 임베딩 기반 벡터 검색을 붙이고 인증 시스템과 관리자 대시보드까지 만들 수도 있었지만 하지 않았다.
- GitHub가 유일한 원본이다. 지식 베이스는 평범한 마크다운 파일이다. 버전 관리, 이력, 브랜치, diff, 코드 리뷰는 Git이 이미 해준다.
- 렌더링은 Astro + Starlight가 맡는다. 사람이 이미 승인한 정적 콘텐츠를 내보내려고 애플리케이션 서버를 24시간 띄워둘 이유가 없다.
- 검색은 의도적으로 단순하게 뒀다. 필드 가중치를 준 키워드 검색으로 이 규모는 충분하다. 글 네 편에 벡터 DB를 붙여도 시스템이 똑똑해지지는 않고 프로토타입만 무거워진다.
좁게 설계한 MCP 도구 세 개 #
서버가 노출하는 도구는 셋뿐이다.
search_knowledge— 필드 가중치 랭킹으로 지식 베이스를 검색한다.get_knowledge— 특정 글을 안전하게 가져온다(path traversal 방어 포함).publish_knowledge— 구조를 검증하고 GitHub PR을 연다.
stdio를 지원하는 MCP 클라이언트라면 연결할 수 있다. Claude Desktop, Agent 모드의 GitHub Copilot Chat이 붙어 있는 VS Code 등이다. 설정은 최소한의 .vscode/mcp.json 하나로 끝난다.
{
"servers": {
"shared-knowledge": {
"type": "stdio",
"command": "${workspaceFolder}/.venv/bin/python3",
"args": ["${workspaceFolder}/server.py"],
"env": {
"GITHUB_TOKEN": "${env:GITHUB_TOKEN}",
"GITHUB_REPO": "pcescato/shared-knowledge",
"KNOWLEDGE_DIR": "${workspaceFolder}/knowledge"
}
}
}
}저장소를 클론하고 pip install -e .를 실행한 뒤 자신의 GITHUB_TOKEN을 넣고 자기 지식 저장소를 가리키게 하면, MCP를 말하는 어시스턴트가 자신의 GitHub 신원으로 PR을 열며 지식 베이스를 읽고 기여할 수 있다.
상 대신 상호운용성을 택한 설계 변경 #
첫 구현에서는 MCP 서버가 내부에서 Gemini를 직접 호출해 대화 요약을 구조화된 글로 바꿨다. 동작은 했지만 MCP의 취지와 어긋났다. 서버가 특정 AI 벤더에 묶인 모놀리식 앱으로 변해가고 있었다.
그래서 개발 중간에 구조를 갈아치웠다. 이제 서버는 knowledge_article_guidelines라는 MCP 프롬프트로 구조화 규칙만 내보낸다. 영어로 출력할 것, ## Problem과 ## Solution 섹션을 반드시 넣을 것, 카테고리와 태그는 정해진 어휘를 쓸 것 같은 규칙이다. 내용을 실제로 구조화하는 쪽은 자기 모델을 쓰는 호출자 어시스턴트이고, publish_knowledge는 검증과 발행만 담당한다. 클라이언트가 Claude든 GPT든 Gemini든 로컬 모델이든 상관이 없어졌다.
이 결정에는 대가가 있었다. Gemini를 핵심 경로에서 빼면서 챌린지의 Best Use of Google AI 부문 자격을 스스로 포기했다. 상 부문 체크박스를 채우려고 의존성을 억지로 넣는 것보다, 상호운용성이라는 취지에 맞는 구조로 출품하는 편을 택했다는 설명이다.
스스로 주장하는 방식으로 만들었다 #
이 프로젝트에는 재미있는 순환 구조가 있다. 스스로 옹호하는 패러다임을 그대로 써서 만들어졌다. 저자는 어시스턴트 하나에 의존하지 않고 여러 AI 환경에 각각 역할을 주고 사람 감독 아래 협업시켰다.
- FreeBuff + GLM 5.3 — 순차적으로 격리된 일곱 개 배치로 개발을 진행했다. 배치마다 "Do NOT implement...", "Do ONLY..." 같은 명시적 가드레일을 걸어 범위가 번지거나 한 컴포넌트 변경이 다른 쪽을 깨뜨리지 않게 막았다.
- GitHub Copilot CLI + Haiku 4.5 — 독립 코드 리뷰어 역할로 PR을 점검하고 중요한 검사를 돌렸다.
- OpenCode + Big Pickle — 로컬 코드 반복, 리팩터링, 엣지 케이스 대응, 버그 처리를 맡았다.
실제로 나온 버그들 #
주말 PoC는 아키텍처 다이어그램이 현실과 다르다는 걸 빠르게 알려준다.
존재하지 않는 AI 생성 버그 #
Copilot CLI 자동 리뷰가 GitHub 인증 버그를 상당히 그럴듯하게 보고했다. 코드 발췌와 줄 번호까지 붙어 있었다. 손대기 전에 확인해보니 그 줄도, 설명된 코드도 저장소에 없었다. AI 리뷰는 분명 유용하지만 사람이 숙제 검사를 해야 한다는 사실을 다시 확인한 사례다.
ElevenLabs Voice Library 함정 #
오디오 생성이 계속 실패하면서 invalid_uid라는 오해를 부르는 오류를 뱉었다. 웹 인터페이스에서 고른 목소리가 공유 Voice Library 소속이었고, 무료 계정에서는 API로 접근할 수 없었다. "My Voices"에 목소리를 추가하자 두 번째 문제가 드러났다. GitHub Actions의 ELEVENLABS_MODEL_ID 변수가 빈 값으로 설정돼 코드의 기본값을 조용히 덮어쓰고 있었다. os.environ.get()은 키가 없을 때만 기본값으로 떨어지고, 빈 문자열로 설정된 경우에는 그 값을 그대로 쓴다.
손으로 깨뜨린 상태 #
로컬 테스트 중에 MP3 파일을 지우고 .audio_manifest.json은 그대로 남겨뒀다. 다음 CI 실행에서 워크플로가 매니페스트를 읽고 오디오가 최신이라고 판단했다. 코드가 고장 난 게 아니라 파일을 손으로 편집해 시스템 상태를 어긋나게 만든 것이었다.
남은 과제 #
ElevenLabs 오디오 생성은 사람 검토와 병합 이후에만 일어난다. 검토되지 않은 PR에 오디오가 만들어지는 일은 없다.
다만 생성된 MP3를 들어보니 엔지니어링 현실이 하나 드러났다. 사람이 읽고 Git으로 diff를 보기에 적합한 포맷이 TTS 엔진에 적합하다는 보장은 없다. 마크다운은 Git을 위해 만들어진 형식이지 음성을 위한 형식이 아니다. TTS 엔진이 원본 마크다운을 읽으면 ## Problem, ## Context 같은 섹션 제목이 뒤따르는 본문과 끊김 없이 이어져 운율적 휴지가 생기지 않는다. 결과물에 숨 쉴 틈과 서사 구조가 없다.
그래서 오디오 파이프라인에 중간 스크립팅 단계가 필요하다.
검증된 마크다운 글
↓
구조 파서
↓
낭독 스크립트 (휴지 · 전환 신호 포함)
↓
ElevenLabs API
↓
최종 MP3 파일원본 마크다운 문법을 ElevenLabs에 바로 보내는 대신, 편집 구조를 실제 낭독 스크립트로 변환한다는 계획이다. 마크다운 글은 그대로 단일 원본으로 남고, 오디오는 목적에 맞게 파생된 포맷이 된다.
저자는 이걸 투표·댓글·벡터 검색·대시보드를 갖춘 완전한 커뮤니티 플랫폼으로 키우는 방향은 우선순위가 아니라고 본다. 먼저 검증할 것은 루프 자체의 단순함이다. 누군가 문제를 해결하고, 답을 돌려주기로 선택하고, 다른 누군가가 그것을 재사용한다는 흐름이다.
실제로 쓸 만한 제품으로 가는 다음 단계로는 Streamable HTTP 기반 원격 호스팅을 꼽았다. 로컬 설치 없이 이미 쓰고 있는 어시스턴트에 URL만 추가하면 되는 형태다. 그 루프가 돌아가는 데 투표나 대시보드, 더 큰 모델은 필요하지 않다. 답을 돌려줄 사람과, 그 답을 읽어볼 만큼 신뢰하는 다른 사람이 필요할 뿐이다.
출품 부문 #
Best Use of ElevenLabs 부문에 출품했다. 검증을 거친 기술 해결책을 소리로 들을 수 있게 만드는 쪽이다. 오디오 생성은 MCP 서버와 분리돼 PR 병합 이후 GitHub Actions 안에서만 돌아간다. 검토와 승인을 거친 콘텐츠만 음성으로 합성된다는 보장을 구조로 박아둔 셈이다.
Best Use of Google AI 부문에는 출품하지 않았다. 앞서 설명한 구조 변경으로 Gemini를 핵심 경로에서 빼고 모델에 종속되지 않는 구조화를 택한 결과다. 저자는 실수가 아니라 의도한 트레이드오프였다고 못 박았다.
이 글은 위 출처를 바탕으로 한국 독자를 위해 재작성한 기사입니다. 원문의 사실과 수치에 근거하며, 별도의 견해를 포함하지 않습니다.
