roam-mcp
MCP server for Roam Research that allows AI assistants like Claude to read and write to your Roam Research graphs. Supports OAuth authentication and multiple graph connections via Cloudflare Workers.
README
roam-mcp
Roam Research MCP 서버 — Cloudflare Workers에 배포하여 Claude.ai 모바일을 포함한 모든 MCP 클라이언트에서 Roam Research 그래프에 접근할 수 있습니다.
구성
[Claude.ai / Claude Desktop / 모바일] → [Cloudflare Worker] → [Roam Research API]
사전 준비
- Node.js 18+
- Cloudflare 계정 (무료)
- Roam Research API 토큰
Roam API 토큰 발급
- roamresearch.com 접속 후 그래프 열기
- 우측 상단
...→ Settings → API tokens 탭 - + New API Token 클릭하여 발급
- 토큰 형식:
roam-graph-token-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
설치 및 배포
순서가 중요합니다. Secret은 Worker가 배포된 후에 등록해야 안정적으로 동작합니다.
1. 의존성 설치
npm install
2. Cloudflare 로그인
npx wrangler login
브라우저가 열리면 Cloudflare 계정으로 로그인합니다.
3. KV namespace 생성 (OAuth 토큰 저장용, 필수)
OAuth provider 가 grant/access token 을 저장할 KV namespace 를 1개 만듭니다:
npx wrangler kv namespace create OAUTH_KV
출력에 찍히는 id = "..." 값을 복사해서 wrangler.toml 의 placeholder 자리에 붙여넣습니다:
[[kv_namespaces]]
binding = "OAUTH_KV"
id = "여기에-출력된-ID-붙여넣기"
KV namespace ID 는 secret 이 아닙니다 — 외부에서 직접 접근할 수 없는 계정 내부 식별자라 평문 커밋해도 안전합니다. 비용은 무료 티어 안에서 충분 (100k reads/day, 1k writes/day).
3-b. R2 버킷 생성 (이미지 업로드 도구용, 선택)
roam_upload_image 를 사용하려면 R2 버킷이 필요합니다. 사용 안 할 거면 이 단계 건너뛰어도 다른 도구는 정상 동작합니다.
npx wrangler r2 bucket create roam-images
생성한 뒤 Cloudflare Dashboard → R2 → roam-images → Settings 에서 다음 중 하나를 선택:
- r2.dev 공개 접근 활성화 (빠른 시작):
Public access→Allow Access→pub-<hash>.r2.devURL 발급 - 커스텀 도메인 연결 (장기 운영용):
Custom Domains→Connect Domain→ 본인 도메인의 서브도메인 (예:img.happytk.dev) 입력
발급된 base URL 을 wrangler.toml 의 [vars] R2_PUBLIC_BASE_URL 에 붙여넣고 재배포합니다:
[vars]
R2_PUBLIC_BASE_URL = "https://pub-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.r2.dev"
이 버킷은 단일 버킷 +
<graph>/...prefix 로 그래프별 격리. 즉 같은 객체 listing 권한도 한 곳만 관리하면 됩니다. r2.dev URL 은 그대로 두고 나중에 custom domain 으로 갈아끼우려면R2_PUBLIC_BASE_URL한 줄만 바꾸면 됨.
저작권 / 사용 의도: 이 버킷은 개인 학습·주석 용도이며 third-party 콘텐츠를 public 배포할 의도가 없습니다. 객체 키에 random suffix 8자 이상을 포함해 enumeration 을 어렵게 두지만, 공유가 곤란한 자료는 업로드하지 마세요.
4. 그래프 이름 설정 (선택 — env 폴백 / /check 용)
그래프 이름은 secret으로 등록합니다. (5단계의 토큰과 같은 방식)
npx wrangler secret put ROAM_GRAPH_NAME
그래프 이름은 Roam URL
roamresearch.com/#/app/<graph-name>의<graph-name>과 정확히 일치해야 합니다. 대소문자와 하이픈까지 동일해야 합니다.
이 값은 OAuth 흐름과 무관한 폴백입니다 — /check 엔드포인트와 환경변수 기반 호출(curl/CI)에서 사용. Claude.ai 처럼 OAuth 로 연결되는 클라이언트는 이 값을 무시하고 사용자가 /authorize 에서 직접 입력한 graph + token 을 grant 단위로 사용합니다. 한 Worker 에 그래프 N 개를 붙이려면 OAuth 흐름이 정도이고, 이 secret 은 단일 그래프 환경에 편의용입니다.
5. 최초 배포 (Worker 생성)
npx wrangler deploy
이 시점에서는 ROAM_API_TOKEN 이 없어서 API 호출은 실패하지만, Worker 자체는 생성됩니다. 배포 완료 시 URL이 출력됩니다:
https://roam-mcp.{your-account}.workers.dev
6. API 토큰을 Secret으로 등록 (선택 — env 폴백 / /check 용)
npx wrangler secret put ROAM_API_TOKEN
프롬프트에 Roam API 토큰을 앞뒤 공백 없이 붙여넣습니다. (.dev.vars나 wrangler.toml에 평문으로 저장하지 않음)
주의: 토큰은
roam-graph-token-으로 시작해야 합니다.roam-graph-local-token-으로 시작하는 로컬 전용 토큰은 API로 사용할 수 없습니다.
등록 확인:
npx wrangler secret list
Secret은 즉시 반영되므로 재배포가 필요하지 않습니다.
7. 토큰 검증 (선택)
셋업이 올바른지 한 번에 확인할 수 있는 진단 엔드포인트입니다:
curl https://roam-mcp.{your-account}.workers.dev/check
성공 응답:
{
"ok": true,
"graph": "your-graph-name",
"message": "Token and graph name are valid. Roam API responded successfully.",
"sampleCount": 1
}
실패 응답 예시와 대응:
stage |
원인 | 해결 |
|---|---|---|
token + "not set" |
Secret이 미등록 | 6단계 재실행 |
token + "does not start with" |
토큰 접두사 오류 | roam-graph-token-으로 시작하는 토큰으로 재등록 |
roam-api + "Token cannot be verified" |
토큰이 해당 그래프 소유가 아님 | 그래프 이름/토큰 매칭 재확인 |
roam-api + "404" |
그래프 이름 오타 | wrangler.toml 수정 후 npx wrangler deploy |
8. MCP 엔드포인트 동작 확인
curl https://roam-mcp.{your-account}.workers.dev/
# {"status":"ok","server":"roam-research-mcp","graph":"your-graph-name","tokenConfigured":true,"oauth":{...}}
# OAuth metadata (Claude.ai 가 자동으로 fetch)
curl https://roam-mcp.{your-account}.workers.dev/.well-known/oauth-authorization-server
# curl/CI: env 폴백 토큰 또는 직접 Bearer 토큰으로 호출 (resolveExternalToken 경로)
curl -X POST https://roam-mcp.{your-account}.workers.dev/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer roam-graph-token-..." \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
인증 모델
서버는 두 가지 인증 경로를 지원합니다 (한 Worker 가 둘 다 동시에 처리):
- OAuth 2.1 (Claude.ai 등 원격 MCP 커넥터용) — Claude.ai 가
/.well-known/oauth-authorization-server로 메타데이터 발견 → DCR 로 클라이언트 등록 → 사용자가/authorize페이지에서 graph + roam-graph-token 입력 → 서버가 토큰을 Roam API 에 검증한 뒤 grant 발급. 이후 모든 요청은 OAuth access token (Bearer) 으로 인증되고, grant 에 묶인 graph + token 이ctx.props로 핸들러에 주입됨. 그래프 N 개 = grant N 개 = 별도 OAuth 토큰 N 개. - External token passthrough (curl/CI 호환) —
Authorization: Bearer roam-graph-token-...처럼 토큰 자체가roam-graph-token-으로 시작하면 OAuth 조회를 건너뛰고 그대로 사용. graph 는 path/header/query/env 중에서 결정. 환경변수만 세팅된 단일 그래프 셋업이나 스크립트 호출에 편리.
요청별 설정 (per-request override)
매 요청마다 그래프/토큰/옵션을 OAuth grant, 헤더, path, query 중 어느 것으로든 전달할 수 있습니다. 우선순위: OAuth props > header > query > path > env. OAuth grant 가 있으면 이를 신뢰하고 외부 헤더/query 로 graph·token 을 덮어쓸 수 없습니다 (스푸핑 방어). 플래그(aiTag/mutate/dryRun)는 grant 와 무관하게 매 요청마다 토글 가능.
1) 헤더 — curl, CI, Claude Desktop 등 커스텀 헤더가 가능한 클라이언트
| 헤더 | 의미 | 기본값 |
|---|---|---|
X-Roam-Graph |
그래프 이름 | path → ROAM_GRAPH_NAME 환경변수 (없으면 에러) |
X-Roam-Token |
API 토큰 (Authorization: Bearer ... 도 허용) |
ROAM_API_TOKEN 시크릿 (없으면 에러) |
X-Roam-Ai-Tag |
루트 블록·신규 페이지에 #ai 자동 태그 부착 여부. false/0/off/no 면 끔 |
true (켜짐) |
X-Roam-Mutate |
true/1/on/yes 면 update/delete/move 도구를 노출. 끄면 tools/list에서도 숨겨지고 호출도 거부됨 |
false (꺼짐) |
X-Roam-Dry-Run |
true이면 모든 쓰기 호출이 no-op이 되고 응답에 dry_run: true 포함. 권한 검증/사전 시뮬레이션 용도 |
false (꺼짐) |
curl -X POST https://roam-mcp.{your-account}.workers.dev/mcp \
-H "Content-Type: application/json" \
-H "X-Roam-Graph: my-graph" \
-H "X-Roam-Token: roam-graph-token-..." \
-H "X-Roam-Ai-Tag: false" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
2) Path + Query — Claude.ai 커넥터처럼 커스텀 헤더를 못 보내는 클라이언트
Claude.ai 의 Custom Connector UI 는 Authorization: Bearer ... 외 임의 헤더를 추가할 수 없습니다. 이 경우 그래프는 path 로, 플래그는 query string 으로 인코딩하면 헤더 방식과 동일한 결과를 얻을 수 있습니다. 한 Worker 배포에 그래프별 커넥터를 N 개 등록하는 패턴입니다.
| 위치 | 키 | 의미 |
|---|---|---|
| path | /g/<graph>/mcp |
그래프 이름. /mcp, /check 모두 /g/<graph>/ 프리픽스 아래에서 동작 |
| query | ?graph=<graph> |
path 대신 query 로도 그래프 지정 가능 |
| query | ?aiTag=0 |
#ai 자동 태그 끔 (ai_tag 도 허용) |
| query | ?mutate=1 |
mutation 도구 노출 |
| query | ?dryRun=1 |
모든 쓰기 no-op (dry_run 도 허용) |
토큰은 query 에 넣지 마세요. URL 은 액세스 로그·브라우저 히스토리·Referer 헤더에 그대로 남습니다. 토큰은 반드시
Authorization: Bearer ...헤더(Claude.ai 커넥터의 표준 토큰 슬롯)로 전달하세요.
Claude.ai 에 등록할 URL 예시 — 그래프마다 별도 커넥터로 등록:
https://roam-mcp.{your-account}.workers.dev/g/personal/mcp
https://roam-mcp.{your-account}.workers.dev/g/work/mcp?mutate=1
https://roam-mcp.{your-account}.workers.dev/g/sandbox/mcp?mutate=1&dryRun=1
각 커넥터의 인증 토큰 칸에는 해당 그래프의 roam-graph-token-... 을 넣으면 됩니다.
MCP 클라이언트 연결
Claude.ai (모바일 포함) — OAuth 흐름
- claude.ai → Settings → Integrations
- Add Integration 클릭
- URL 입력 (그래프별 1 개씩 등록):
https://roam-mcp.{your-account}.workers.dev/g/personal/mcphttps://roam-mcp.{your-account}.workers.dev/g/work/mcp?mutate=1https://roam-mcp.{your-account}.workers.dev/g/sandbox/mcp?mutate=1&dryRun=1
- Claude.ai 가 자동으로 OAuth metadata 를 발견하고 인증 페이지로 이동시킵니다.
- 우리
/authorize페이지가 뜨면:- Graph name: URL path 에서 자동으로 채워집니다 (
/g/personal/...→personal). 비어 있으면 직접 입력. - Roam API token: 해당 그래프의
roam-graph-token-...붙여넣기. - Authorize 클릭 → 서버가 Roam API 로 토큰 검증 → Claude.ai 로 자동 redirect.
- Graph name: URL path 에서 자동으로 채워집니다 (
- 인증 완료. 이후 Claude.ai 가 보내는 모든 요청은 OAuth access token 으로 인증되고, 입력하신 graph + token 이 grant 에 묶여 사용됩니다.
토큰을 갱신하거나 권한을 회수하려면 Claude.ai 에서 해당 connector 를 disconnect → 다시 등록하면 됩니다 (새 OAuth grant 발급). 서버 KV 의 grant 는 access/refresh token TTL 에 따라 만료됩니다.
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json 수정:
{
"mcpServers": {
"roam-research": {
"command": "npx",
"args": ["-y", "roam-research-mcp"],
"env": {
"ROAM_API_TOKEN": "roam-graph-token-...",
"ROAM_GRAPH_NAME": "your-graph-name"
}
}
}
}
Claude Desktop은 roam-research-mcp npm 패키지를 로컬에서 직접 실행하는 방식도 사용할 수 있습니다.
로컬 개발
.dev.vars.example 파일을 복사해 .dev.vars 를 만듭니다 (.gitignore에 포함됨):
cp .dev.vars.example .dev.vars
# 이후 .dev.vars 파일을 열어 본인 토큰과 그래프 이름으로 수정
.dev.vars는 로컬npm run dev전용입니다. 배포 환경에는 영향을 주지 않으며, 배포 환경은wrangler secret put으로 등록한 값을 사용합니다.
로컬 서버 실행:
npm run dev
# http://localhost:8787 에서 실행
# 로컬에서도 /check 로 검증 가능
curl http://localhost:8787/check
CI/CD (GitHub Actions)
.github/workflows/ci.yml 이 포함되어 있습니다:
- PR:
tsc --noEmit타입 체크만 수행 - main 푸시: 타입 체크 →
wrangler deploy→/check스모크 테스트
배포 결과가 성공으로 찍혀도 토큰이 깨진 상태면 /check 가 실패하므로 워크플로 전체가 실패 처리됩니다.
필요한 GitHub Secrets
리포지토리 Settings → Secrets and variables → Actions → Secrets 에 등록:
| 이름 | 값 |
|---|---|
CLOUDFLARE_API_TOKEN |
Cloudflare Dashboard → My Profile → API Tokens → Create Token → "Edit Cloudflare Workers" 템플릿 |
CLOUDFLARE_ACCOUNT_ID |
Cloudflare Dashboard 우측 사이드바의 Account ID |
ROAM_API_TOKEN |
(선택) /check 스모크 테스트용 폴백 토큰 |
ROAM_GRAPH_NAME |
(선택) /check 스모크 테스트용 폴백 그래프 이름 |
OAuth 흐름은 KV 에 저장된 grant 만 쓰므로
ROAM_API_TOKEN/ROAM_GRAPH_NAME은 더 이상 운영에 필수가 아닙니다. CI 의/check스모크 테스트가 빨리 끝나도록 둘 다 등록해두는 것을 권장합니다.OAUTH_KVnamespace ID 는 secret 이 아니므로wrangler.toml에 직접 박아두세요.
필요한 GitHub Variables (선택)
Settings → Secrets and variables → Actions → Variables 에 등록:
| 이름 | 값 |
|---|---|
WORKER_URL |
https://roam-mcp.<your-account>.workers.dev — wrangler-action 이 deployment URL을 반환하지 못할 때 스모크 테스트에서 사용 |
제공 도구
| 도구 | 설명 |
|---|---|
roam_find_pages_modified_today |
오늘 수정된 페이지 목록 조회 |
roam_fetch_page_by_title |
제목으로 페이지 전체 내용 조회 |
roam_search_by_text |
텍스트 전체 검색 |
roam_search_for_tag |
특정 태그/페이지를 참조하는 블록 검색 |
roam_search_by_status |
TODO / DONE / LATER 상태별 블록 검색 |
roam_create_page |
새 페이지 생성 (데일리 노트에는 사용 금지) |
roam_add_todo |
TODO 항목 추가 (page 생략 시 오늘 데일리 노트) |
roam_create_block |
블록 추가 (page 생략 시 오늘 데일리 노트) |
roam_update_block ⚑ |
기존 블록 텍스트 교체 (uid 기반) |
roam_delete_block ⚑ |
블록과 그 자식들 영구 삭제 |
roam_move_block ⚑ |
블록을 다른 부모/페이지로 이동 |
roam_rename_page ⚑ |
페이지 제목 변경 |
roam_delete_page ⚑ |
페이지와 모든 블록을 영구 삭제 (블록 삭제보다 파급 큼) |
roam_datomic_query |
직접 Datalog 쿼리 실행 |
roam_upload_image |
base64 이미지를 R2 에 업로드하고 Roam 블록에 붙여넣을 마크다운 스니펫과 public URL 반환 (책 그림 + 출처 메타데이터 보존용) |
⚑ 표시는 mutate 도구 — 기본 OFF. 요청에 X-Roam-Mutate: true 헤더를 보내야 노출되고 호출 가능. dry-run 시뮬레이션은 X-Roam-Dry-Run: true 헤더로.
LLM이 지켜야 할 Roam 컨벤션
서버가 MCP initialize 응답의 instructions 필드로 아래 규칙을 LLM에 전달합니다. 개별 도구 description에도 동일 규칙이 박혀 있어서 도구 호출 직전에도 다시 읽게 됩니다.
-
데일리 노트 제목은 ordinal suffix 필수:
April 16th, 2026✅ /April 16, 2026❌ Roam은 접미사 유무에 따라 완전히 다른 페이지로 취급합니다. -
"오늘"에 쓸 때는
page인자를 생략.roam_add_todo와roam_create_block둘 다page미지정 시 서버가 올바른 형식으로 오늘 데일리 노트 제목을 계산해서 사용합니다. -
roam_create_page로 오늘 데일리 노트를 만들지 않음. 데일리 노트는roam_add_todo/roam_create_block이 쓰기 시 자동 생성합니다. -
방어적 정규화: LLM이 실수로
April 16, 2026형식을 넘겨도 서버가April 16th, 2026으로 자동 교정합니다. 하지만 이건 안전망이고, LLM이 처음부터 올바른 형식으로 넘기는 것이 선호됩니다.
트러블슈팅
토큰 오류 (Token cannot be verified)
- 먼저
/check엔드포인트로 원인을 진단:curl https://roam-mcp.xxx.workers.dev/check - Roam API 토큰이
roam-graph-token-으로 시작하는지 확인 roam-graph-local-token-으로 시작하는 것은 로컬 전용 토큰으로 API 사용 불가- 토큰이 등록한 그래프 이름과 일치하는지 확인 (각 그래프마다 별도 토큰 발급)
- Secret 재등록:
npx wrangler secret put ROAM_API_TOKEN
Secret이 사라진 경우
npx wrangler secret put ROAM_API_TOKEN으로 재등록- Secret은 배포와 무관하게 유지되지만 계정/Worker 이름이 다르면 별도 등록 필요
Claude.ai 연결 실패
- URL이
/mcp로 끝나는지 확인:https://roam-mcp.xxx.workers.dev/mcp - Worker가 정상 배포됐는지 확인:
npx wrangler deployments list
쓰기 성공했는데 Claude가 실패로 표시
- Roam write API가 빈 응답을 반환할 때 발생하던 문제 (수정 완료)
오늘 수정 페이지가 0개로 표시
- Cloudflare Worker는 UTC 기준으로 실행됨
- 한국 시간(KST = UTC+9) 기준 자정은 UTC 15:00이므로 자정~09:00 사이 수정 항목이 누락될 수 있음
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.