MCP 서버로 개인 노트/대화 저장하기
한눈에 보는 전체 데이터 흐름
한국어의 구조를 보여주는 다이어그램
기본 구성 요소: Bun, Hono, SQLite
만들려는 건 데이터를 저장하고(CRUD) 꺼내보는 작은 서버다. 세 가지 재료의 역할:
Bun — 자바스크립트/타입스크립트 실행 런타임. 이 모든 걸 돌리는 기반.
bun:sqlite라는 SQLite 드라이버가 내장돼 있어 별도 설치 없이 DB를 바로 쓸 수 있다.Hono — 라우터 + 웹 프레임워크. "어떤 URL + HTTP 메서드가 들어오면 어떤 함수를 실행할지"를 정해준다.
SQLite — 실제 데이터(노트/일정)가 저장되는 파일 기반 데이터베이스.
API 엔드포인트의 역할
엔드포인트는 클라이언트가 요청을 보내고 응답을 받는 "창구"다. 캘린더라면 보통:
메서드 + 경로
동작
GET /events
일정 목록 조회 (날짜 범위 등으로 필터)
GET /events/:id
특정 일정 상세 조회
POST /events
새 일정 생성
PUT /events/:id
일정 수정
DELETE /events/:id
일정 삭제
노트 앱이면 events → notes로 바뀔 뿐 구조는 같다.
Open optionsauto
클라이언트 → [HTTP 요청] → Hono 라우터 → 핸들러 함수 → SQLite
클라이언트 ← [JSON 응답] ← Hono ← 핸들러 함수 ← 조회/저장 결과
MCP 서버로 AI 활용하기
API 위에 MCP 서버를 얹으면, Claude 같은 AI가 자연어로 그 서버를 조작할 수 있게 된다.
MCP 서버는 데이터를 직접 저장하지 않는다. AI가 쓸 수 있는 도구(tool) 를 정의해 노출하고, AI가 그 도구를 부르면 내부적으로 API를 호출하는 중계자다.
Open optionsauto
Claude ──(MCP 프로토콜)──→ MCP 서버 ──(HTTP)──→ 노트 API ──→ SQLite
노트 앱이라면 도구 두 개로 시작:
save_note— 내용을 받아 저장 (POST /notes로 변환)search_notes— 검색해서 꺼내옴 (GET /notes로 변환)
핵심 구분:
API 엔드포인트 = 기계(프로그램)가 호출하는 정형화된 창구
MCP 서버 = AI가 자연어 맥락에서 그 창구를 알아서 골라 쓰도록 놓는 다리
Anthropic 서버와의 연결 이해하기
오해
"Anthropic 서버에 내 대화가 저장돼 있고, MCP가 그걸 내 서버로 옮겨준다" → 틀림
실제
저장은 자동이 아니라 매번 일어나는 행위다. 내가 "저장해줘" 하면, Claude가 그 순간 대화 내용을 정리해
save_note도구 인자로 만들어 내 서버에 보낸다. 어딘가 보관돼 있던 걸 꺼내오는 게 아니다.내용도 판단(어떤 도구를 부를지)도 내 폰이 아니라 Anthropic 클라우드에 있다. Claude 모델은 폰 안이 아니라 Anthropic 서버에서 돈다. 폰/웹 창은 입출력 창일 뿐.
Open optionsauto
1. 폰/웹: "방금 대화 저장해줘" (입력창)
↓ 메시지 전송
2. Anthropic 클라우드: Claude가 여기서 돎
→ "save_note를 부르자" 판단 + 도구 호출이 여기서 발생
↓
3. Anthropic 클라우드 → 내 서버 (커넥터 URL로 접속)
↓
4. 내 서버 → SQLite 저장
→ 2번과 3번이 전부 Anthropic 클라우드에서 일어난다. 그래서 내 서버를 부르는 쪽은 내 폰이 아니라 Anthropic 클라우드다. 이 사실이 아래 Tailscale 문제로 이어진다.
클라이언트 쪽엔 "설치할 MCP"가 없다
MCP는 양 끝이 있다:
MCP 클라이언트 (도구 목록 읽고, 어떤 도구 부를지 정하고, 결과 받기) → 이미 claude.ai·폰 앱에 Anthropic이 내장. 내가 건드릴 것 없음.
MCP 서버 (도구의 실체) → 내가 만들어야 함.
내가 하는 일은 claude.ai 커넥터 설정에 내 서버 URL 한 줄을 등록하는 것뿐. 같은 계정이면 폰에서도 그대로 쓰인다(폰에서 새 커넥터 추가는 불가, 사용은 가능).
서버 연결 옵션과 Tailscale 활용
내 서버를 "누가 부르냐"에 따라 필요한 게 갈린다.
기기에서 직접 연결하는 경우
폰/랩탑의 앱, Claude Desktop 로컬 MCP 등이 내 기기 → 내 서버로 직접 붙는다.
폰·랩탑·집 PC를 같은 Tailscale 테일넷에 넣으면, 공인 IP·포트 개방 없이 사설 주소로 안전하게 통신.
컴퓨터만 켜두면 됨. 공개 노출 불필요.
claude.ai 커넥터를 통한 연결
claude.ai 커넥터는 내 기기가 아니라 Anthropic 클라우드에서 내 서버로 접속한다.
Tailscale 사설 주소는 테일넷 안에서만 보임 → Anthropic 클라우드는 도달 불가.
Open optionsauto
Anthropic 클라우드 ──→ 공개 인터넷 주소 ✅
Anthropic 클라우드 ──X→ Tailscale 사설 주소 ❌ (밖에서 안 보임)
→ 그래서 claude.ai 커넥터로 쓰려면 둘 중 하나:
Tailscale Funnel — 특정 서비스를 공개 HTTPS 주소로 노출. 집 PC를 켜둬야 함.
클라우드 배포 — PC 안 켜둬도 항상 떠 있음. 개인 노트 규모면 무료 한도에 드는 경우 많음.
어느 쪽이든 공개로 여는 거라 인증(보호 토큰/OAuth) 필수.
연결 방식 정리
Open optionsauto
컴퓨터 켜두기 + Tailscale 사설 → 폰·랩탑 직접 연결 OK (커넥터는 X)
컴퓨터 켜두기 + Funnel(공개) + 토큰 → claude.ai 커넥터 OK
클라우드 배포 + 토큰 → PC 안 켜둬도 + 커넥터 OK
MCP 서버 보안 설정
공개 HTTPS 주소를 내면 URL 아는 사람·봇 누구나 문 앞까지 온다.
인증 없으면 = 문 활짝 열림 → 아무나 내 노트 읽고 씀 ❌
인증 있으면 = 문은 보이지만 열쇠 필요 → 나만 들어감 ✅
인증 방식:
토큰 방식 (간단) — 길고 추측 불가능한 비밀 문자열을 헤더로 검사. 개인용은 이걸로 충분.
OAuth 방식 (표준) — claude.ai 커넥터가 정식 지원. 손이 더 가지만 안전.
추가 빗장: 요청 횟수 제한(rate limit)을 같이 두면 무차별 시도 방어.
파일 전송의 제약과 해결책
두 종류의 "파일"을 구분해야 한다.
이 창에서 Claude가 만들어주는 다운로드 파일 (docx, 다이어그램 등) — Anthropic 환경에서 생성해 다운로드 링크로 줌. 내 MCP 서버로 자동으로 가는 통로는 없다.
MCP 도구로 오가는 것 — 가능.
save_file같은 도구를 정의하면 Claude가 내용을 인자로 실어 보냄.
Open optionsauto
[이 창의 다운로드 파일] 나 → 링크 → 내가 받음 (서버로 자동연결 X)
[MCP 도구] 나 → save_file(내용) → 내 서버 ✅
제약:
MCP로 오가는 건 본질적으로 텍스트/구조화 데이터. 텍스트·md·json·코드는 자연스럽다.
이미지·PDF 같은 바이너리는 base64로 변환하면 되지만 용량 커지면 비효율.
→ "대화 텍스트 저장"엔 딱 맞고, "큰 파일 동기화"엔 부적합.
결론: 대화를 저장하려고 굳이 "파일"로 주고받을 필요 없다. save_note로 텍스트를 넘기면 서버가 알아서 DB든 .md 파일이든 저장하면 된다.
실행 가이드 — 결정 과정과 따라 하는 방법
01_개념정리.md에서 이해한 내용을 바탕으로, 실제로 무엇을 결정했고
어떤 순서로 만들면 되는지 정리한 문서.
개인 노트 서버 구축 결정 과정
대화하며 좁혀온 선택들:
무엇을 만드나 → 캘린더가 아니라 개인 노트/대화 저장 서버.
같은 bun+hono+sqlite 패턴, 데이터만notes로.도구는 →
save_note(저장),search_notes(검색) 두 개로 시작.검색 방식 → 우선 SQL 키워드 검색으로 무료 시작.
부족하면 나중에 로컬 임베딩 의미 검색을 얹는다. (둘 다 비용 0)어디서 돌리나 → (미정 — 아래 분기에서 택1)
집 PC(WSL) + Tailscale 사설 → 폰·랩탑 직접 연결용
집 PC(WSL) + Tailscale Funnel + 보호 토큰 → claude.ai 커넥터용
클라우드 배포 + 보호 토큰 → PC 안 켜둬도 + 커넥터용
인증 → 공개로 열면 보호 토큰(헤더 검사) 필수. 개인용은 토큰 방식으로 충분.
비용 → 위 구성만이면 0원.
(Console API 키/외부 임베딩 API를 안 넣는 한)파일 → 대화는 "파일"이 아니라 텍스트로
save_note하면 됨.
서버가 원하면 .md로 떨어뜨리게 만들 수 있음.
추가 결정 사항
Telegram을 붙인다면: "노트 저장/검색만"(무료) vs "AI가 답하는 챗봇"(Console API 키 필요, 과금).
claude.ai 커넥터만 쓸 거면 Telegram은 나중 문제.
MCP 서버 구축 작업 과정
아래는 "집 PC + Funnel + 보호 토큰 → claude.ai 커넥터" 기준의 큰 흐름.
클라우드 배포를 택했다면 5단계만 배포로 바뀐다.
준비물 확인
Bun 설치 (WSL 안에)
Tailscale 계정 (Funnel 쓸 경우)
claude.ai 계정 (커넥터 등록용)
프로젝트 뼈대 구성
Open optionsauto
notes-mcp/
├─ db.ts # SQLite 연결 + 테이블 생성
├─ api.ts # hono로 /notes CRUD 엔드포인트
├─ mcp.ts # MCP 서버: save_note / search_notes 도구 정의
├─ auth.ts # 보호 토큰 검사 미들웨어
└─ index.ts # 전부 묶어서 서버 실행
DB와 테이블 설정
노트 한 건 = id, body(본문), created_at(저장 시각), tags(키워드).bun:sqlite로 파일 하나(notes.db) 만들고 테이블 생성.
API 엔드포인트 설정
POST /notes→ 본문 받아 INSERTGET /notes?q=키워드→WHERE body LIKE '%키워드%'로 검색(나중에)
GET /notes/:id,DELETE /notes/:id등 추가
보호 토큰 인증 설정
길고 추측 불가능한 문자열 하나 생성 (예:
openssl rand -hex 32)모든 요청에서
Authorization헤더의 토큰이 일치할 때만 통과, 아니면 401이 토큰은 내가 만든 비밀 — 어디 등록·결제 대상 아님
공개 주소로 노 출하기
서버를 로컬 포트(예: 3000)에서 실행
Tailscale Funnel로 그 포트를 공개 HTTPS 주소로 노출
→https://내기기.테일넷.ts.net형태 주소가 생김(클라우드 배포 택했으면: 이 단계 대신 클라우드에 올림 → 자동으로 공개 HTTPS)
MCP 도구 정의
save_note(body, tags?)→ 내부에서POST /notes호출search_notes(query)→ 내부에서GET /notes?q=...호출MCP 서버 엔드포인트를 위 공개 주소 아래 경로로 노출 (예:
/mcp)
claude.ai 커넥터 등록
claude.ai → 설정 → 커넥터 → 커스텀 커넥터 추가
공개 MCP 주소 입력 (예:
https://내기기.테일넷.ts.net/mcp)보호 토큰은 커넥터 인증 설정에 넣음
연결되면 폰 앱에서도 같은 계정으로 사용 가능
테스트
이 창에서 "방금 대화 요약해서 내 노트에 저장해줘" →
save_note호출 확인새 대화에서 "지난번 MCP 얘기 찾아줘" →
search_notes호출 확인