내 기기에서 완전히 실행되는 개인정보 보호 우선 건강 기록 MCP 서버 구축기
요약
개인정보 보호를 위해 로컬 환경에서 실행되는 건강 기록 관리 MCP 서버 MedMemory 구축 방법을 소개합니다. AES-256 암호화와 Gemini Vision을 결합하여 데이터를 기기 외부로 전송하지 않고도 Claude가 건강 데이터를 안전하게 조회할 수 있도록 설계되었습니다.
핵심 포인트
- Model Context Protocol(MCP)을 활용한 LLM과 로컬 데이터의 안전한 연결
- SQLCipher(AES-256)를 이용한 로컬 SQLite 데이터베이스 암호화 구현
- Gemini Vision을 통한 의료 문서의 구조화된 정보 추출
- 도구의 독스트링(docstrings)이 MCP 에이전트의 지능 계층 역할을 수행
데이터를 어디로도 전송하지 않고 Claude가 사용자의 개인 건강 데이터에 관한 질문에 답할 수 있도록 Model Context Protocol (MCP), Gemini Vision, 그리고 AES-256 암호화를 어떻게 활용했는지에 대하여.
건강 AI의 문제점
모든 주요 건강 AI 제품은 동일한 아키텍처를 가지고 있습니다: 사용자가 문서를 클라우드에 업로드하면, 서비스 제공자가 이를 처리하고 저장하며, 사용자는 그들의 개인정보 보호 정책이 잘 지켜지기를 바라야 합니다. 일반적인 웰니스 팁을 얻는 용도라면 아마 괜찮을 것입니다. 하지만 처방전, 검사 결과, 퇴원 요약서와 같은 실제 의료 기록의 경우에는 상당한 수준의 신뢰를 요구하게 됩니다.
저는 다른 것을 원했습니다. 기록이 제 기기를 절대 떠나지 않으면서도, Claude가 실제 건강 기록을 사용하여 "내가 복용 중인 약은 무엇인가요?" 또는 _"현재 복용 중인 약에 Ibuprofen을 추가해도 안전할까요?"_와 같은 질문에 답할 수 있기를 원했습니다.
그 결과물이 바로 MedMemory입니다. 이는 건강 데이터를 로컬의 AES-256 암호화된 SQLite 데이터베이스에 저장하고, Gemini Vision을 사용하여 의료 문서에서 구조화된 정보를 추출하며, Claude Desktop에 8개의 도구(tools)를 노출하여 사용자가 자연어로 건강 기록을 조회할 수 있게 해주는 MCP 서버입니다.
MCP란 무엇인가?
Model Context Protocol (MCP)는 LLM(대규모 언어 모델)이 외부 도구 및 데이터 소스에 접근할 수 있도록 하는 Anthropic의 개방형 표준입니다. 모델을 미세 조정(fine-tuning)하거나 RAG(검색 증강 생성) 파이프라인을 구축하는 대신, 이름, 설명, 입력 스키마를 가진 타입화된 도구(typed tools) — 즉, 함수를 노출하는 서버를 작성하면 LLM이 대화 내용을 바탕으로 해당 도구를 호출할 시점을 결정합니다.
핵심적인 통찰은 도구의 독스트링(docstrings)이 지능 계층(intelligence layer) 역할을 한다는 점입니다. 사용자가 Claude에게 _"내 예방 접종 상태가 최신인가요?"_라고 물었을 때, Claude는 독스트링을 읽기 전까지는 자신에게 예방 접종 도구가 있다는 사실을 알지 못합니다:
@mcp.tool()
async def get_vaccination_status(ctx: Context) -> dict:
"""기록된 모든 예방 접종 내역을 반환하고, 기한이 지났거나 누락된 항목을 표시합니다.
...
그 독스트링이 바로 Claude가 적절한 시점에 적절한 도구를 호출하게 만드는 요소입니다. 좋은 독스트링을 작성하는 것은 MCP 개발에서 가장 중요한 기술입니다.
아키텍처
MedMemory는 세 가지 계층으로 구성됩니다:
1. 저장소 (Storage) — SQLCipher로 암호화된 SQLite
모든 건강 데이터는 SQLCipher (AES-256)로 암호화된 로컬 SQLite 데이터베이스에 저장됩니다. 암호화 키는 첫 실행 시 사용자에 의해 설정되며, 절대로 기기를 벗어나지 않습니다. 만약 어떤 텍스트 에디터로 데이터베이스 파일을 열어본다면, 읽을 수 있는 SQL이 아닌 무작위 바이트를 보게 될 것입니다.
$ xxd medmemory.db | head -3
00000000: e7ea 869f 47b1 bec2 8eb8 78f3 8fe9 57e7 ....G.....x...W.
00000010: 44c2 3e72 3056 bb14 ae19 1b53 5530 54e9 D.>r0V.....SU0T.
일반 SQLite에서 SQLCipher로의 마이그레이션은 정확히 3줄의 코드, 즉 import sqlcipher3 as sqlite3와 get_connection() 함수 내의 두 줄의 PRAGMA 설정뿐이었습니다. 그 외의 모든 것은 동일하게 유지되었습니다. SQLCipher는 진정한 드롭인 교체(drop-in replacement)가 가능합니다.
2. 데이터 수집 (Ingestion) — 실제 문서를 위한 Gemini Vision
현실 세계의 의료 문서는 매우 복잡합니다. 손으로 쓴 처방전, 스캔된 PDF, 각도가 틀어진 사진 등이 그것입니다. 처음에는 Tesseract OCR로 시작했지만, 손으로 쓴 인도식 처방전에서는 완전히 실패했습니다. 해결책은 이미지 기반 문서에 대해 OCR을 완전히 건너뛰고 이미지를 Gemini Vision으로 직접 보내는 것이었습니다. Gemini Vision은 필기체를 네이티브하게 읽을 수 있습니다.
이제 추출 파이프라인은 다음과 같이 작동합니다:
- 텍스트 기반 PDF (예: 디지털 검사 결과 보고서): PyMuPDF가 마크다운(markdown)을 추출 → Gemini가 엔티티(entities)를 구조화
- 스캔된/손글씨 PDF 또는 이미지: PNG로 렌더링 → Gemini Vision으로 직접 전송
추출 프롬프트에는 브랜드명을 일반 약물명으로 매핑하는 명시적인 규칙과 검사 수치 정규화(normalisation) 규칙, 그리고 기대되는 출력 형식을 정확히 보여주는 퓨샷(few-shot) 예시가 포함되어 있습니다. 이는 실제 문서에서의 정확도를 획기적으로 향상시켰습니다:
"Glycomet" → "Metformin"
"Storvas" → "Atorvastatin"
"Gabantin-GRS" → "Gabapentin"
...
3. MCP 도구 (Tools) — 전체 건강 기록을 아우르는 8가지 도구
| 도구 | 기능 |
|---|---|
ingest_health_document | 모든 의료 PDF 또는 이미지를 구조화된 DB 레코드로 파싱 |
| ... |
약물 상호작용 도구 — 임상적으로 가장 중요한 기능
check_drug_interaction은 제가 가장 자랑스럽게 생각하는 도구입니다. 이 도구는 새로 처방받은 약물 이름을 입력받아, 암호화된 DB에서 현재 복용 중인 약물을 가져온 뒤, OpenFDA 약물 라벨 API를 통해 새 약물의 상호작용 데이터를 조회하고, 이 두 가지를 결합한 구조화된 결과를 반환합니다.
# Claude Desktop 대화
사용자: 의사 선생님이 허리 통증 때문에 이부프로펜(Ibuprofen)을 처방해 주셨어요.
지금 복용 중인 약들과 함께 먹어도 안전할까요?
...
사용자의 기록이 없는 일반적인 AI라면 모든 사람에게 동일한 NSAID(비스테로이드성 항염증제) 경고를 보낼 것입니다. 하지만 이 도구는 사용자가 이미 아스피린(Aspirin)을 복용 중이라는 사실을 알고 있으며, 개인화되고 임상적으로 유의미한 답변을 제공합니다. 이것이 일반적인 챗봇과 사용자의 상황을 실제로 파악하고 있는 도구 사이의 차이점입니다.
개인정보 보호 아키텍처 (The Privacy Architecture)
데이터가 어디로 이동하는지 정확히 설명하면 다음과 같습니다.
사용자의 기기에 머무는 데이터:
- SQLite 데이터베이스 (사용자의 암호로 암호화됨)
- 암호화 키 (로컬
.env에 저장되며, 절대 전송되지 않음) - 모든 약물, 검사 결과, 방문 기록, 예방 접종, 알레르기 정보
Gemini API로 전송되는 데이터 (데이터 수집 단계에서만):
- 수집 중인 문서에서 추출된 텍스트 또는 이미지
- 이는 일시적인 API 호출이며, Gemini는 이를 사용자의 건강 기록에 저장하지 않습니다.
OpenFDA API로 전송되는 데이터:
- 확인하려는 약물 이름만 전송되며, 개인 데이터는 포함되지 않습니다.
Anthropic으로 전송되는 데이터 (모든 Claude 대화와 동일):
- Claude가 질문에 답변하기 위해 사용하는 도구 호출(tool call) 결과
- 이는 모든 Claude Desktop 대화에서 흐르는 데이터와 동일합니다.
사용자는 직접 암호화를 확인할 수 있습니다:
xxd ~/medmemory.db | head -3
# "SQLite format 3"가 아닌 무작위 바이트가 표시되어야 합니다.
이를 구축하며 배운 점
1. 독스트링(Docstrings)이 곧 제품입니다. 도구의 독스트링 품질이 Claude가 적절한 시점에 올바른 도구를 호출할지 여부를 결정합니다. 저는 실제 도구 로직을 구현하는 것만큼이나 독스트링을 작성하는 데 많은 시간을 할애했습니다.
2. 실제 문서로 조기에 테스트하세요. 저는 깨끗한 합성 PDF (synthetic PDFs)를 기반으로 데이터 수집 파이프라인 (ingestion pipeline)을 구축했고, 결과는 훌륭해 보였습니다. 하지만 Ghaziabad의 신경과 의사가 작성한 실제 수기 처방전으로 테스트했을 때, 아무것도 추출하지 못했습니다. 실제 세계의 문서들은 테스트 데이터와 근본적으로 다릅니다.
3. SQLCipher는 진정으로 단 3줄이면 마이그레이션이 가능합니다. SQLite 데이터베이스를 암호화하는 것이 며칠이 걸리는 프로젝트가 될 것이라고 예상했습니다. 하지만 import sqlcipher3 as sqlite3와 두 줄의 PRAGMA 명령만으로 충분했습니다. API는 동일합니다. 가장 어려웠던 부분은 Python 패키지를 Apple Silicon에서 컴파일하는 것이었습니다.
4. MCP는 기능이 아니라 아키텍처입니다. MCP 도구들을 구동하는 것과 동일한 DB 헬퍼 (DB helpers)가 Next.js 컴패니언 UI (companion UI)를 제공하는 FastAPI 브릿지 (bridge)도 구동합니다. DB 레이어 (layer)가 곧 비즈니스 로직 (business logic)입니다. MCP와 FastAPI는 단지 이를 노출하는 두 가지 서로 다른 방식일 뿐입니다.
5. OpenFDA는 무료이며 강력합니다. 약물 상호작용 데이터는 약사들이 사용하는 것과 동일한 FDA 약물 라벨 데이터베이스에서 가져옵니다. 낮은 사용량에서는 API 키가 필요하지 않으며, 데이터의 권위가 보장됩니다.
직접 시도해보기
pip install medmemory-mcp
medmemory-setup
그 다음 Claude Desktop 설정에 추가하세요:
{
"mcpServers": {
"medmemory": {
...
또는 호스팅된 데모를 시도해 보세요 (합성 환자 데이터이며, 실제 건강 기록은 포함되지 않음):
{
"mcpServers": {
"medmemory-demo": {
...
링크:
- PyPI: pypi.org/project/medmemory-mcp
- GitHub: github.com/priyanshugoel24/medmemory-mcp
- Web UI: medmemory-ui.vercel.app
Python, FastMCP, SQLCipher, Gemini Vision, OpenFDA, FastAPI, 그리고 Next.js로 구축되었습니다. 질문이나 피드백은 댓글로 환영합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기