roam-mcp

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.

Category
Visit Server

README

roam-mcp

Roam Research MCP 서버 — Cloudflare Workers에 배포하여 Claude.ai 모바일을 포함한 모든 MCP 클라이언트에서 Roam Research 그래프에 접근할 수 있습니다.

구성

[Claude.ai / Claude Desktop / 모바일] → [Cloudflare Worker] → [Roam Research API]

사전 준비

Roam API 토큰 발급

  1. roamresearch.com 접속 후 그래프 열기
  2. 우측 상단 ...SettingsAPI tokens
  3. + New API Token 클릭하여 발급
  4. 토큰 형식: 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-imagesSettings 에서 다음 중 하나를 선택:

  • r2.dev 공개 접근 활성화 (빠른 시작): Public accessAllow Accesspub-<hash>.r2.dev URL 발급
  • 커스텀 도메인 연결 (장기 운영용): Custom DomainsConnect 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.varswrangler.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 가 둘 다 동시에 처리):

  1. 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 개.
  2. 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 흐름

  1. claude.aiSettingsIntegrations
  2. Add Integration 클릭
  3. URL 입력 (그래프별 1 개씩 등록):
    • 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
  4. Claude.ai 가 자동으로 OAuth metadata 를 발견하고 인증 페이지로 이동시킵니다.
  5. 우리 /authorize 페이지가 뜨면:
    • Graph name: URL path 에서 자동으로 채워집니다 (/g/personal/...personal). 비어 있으면 직접 입력.
    • Roam API token: 해당 그래프의 roam-graph-token-... 붙여넣기.
    • Authorize 클릭 → 서버가 Roam API 로 토큰 검증 → Claude.ai 로 자동 redirect.
  6. 인증 완료. 이후 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_KV namespace ID 는 secret 이 아니므로 wrangler.toml 에 직접 박아두세요.

필요한 GitHub Variables (선택)

Settings → Secrets and variables → Actions → Variables 에 등록:

이름
WORKER_URL https://roam-mcp.<your-account>.workers.devwrangler-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에도 동일 규칙이 박혀 있어서 도구 호출 직전에도 다시 읽게 됩니다.

  1. 데일리 노트 제목은 ordinal suffix 필수: April 16th, 2026 ✅ / April 16, 2026 ❌ Roam은 접미사 유무에 따라 완전히 다른 페이지로 취급합니다.

  2. "오늘"에 쓸 때는 page 인자를 생략. roam_add_todoroam_create_block 둘 다 page 미지정 시 서버가 올바른 형식으로 오늘 데일리 노트 제목을 계산해서 사용합니다.

  3. roam_create_page 로 오늘 데일리 노트를 만들지 않음. 데일리 노트는 roam_add_todo / roam_create_block 이 쓰기 시 자동 생성합니다.

  4. 방어적 정규화: 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured