Roam Research MCP Server について
Roam Research MCP + CLI は、Roam の バックエンド REST API を通じてRoam グラフを管理する MCP サーバー兼コマンドラインツールです。Roam デスクトップアプリを起動せずに動作するため、サーバーやコンテナ、スクリプト環境に向いています。単独の CLI としても利用できます。
主な機能
- 01ページやブロックの読み取り、検索、保存
- 02ブロック UID を保持するスマートな差分更新
- 03stdin パイプに対応した roam コマンドライン
- 04Bearer 認証に対応した共有 HTTP デーモン
- 05ROAM_GRAPHS と書き込みキーによる複数グラフの管理
活用シーン
- 01Claude Code などのクライアントから Roam のノートを読み書き
- 02cron ジョブや CI からの Roam へのコンテンツ自動保存
- 03スクリプトによるブロック構造の一括作成、移動、更新
MCP 対応
本プロジェクトは MCP サーバーとして動作し、ページの読み取り、検索、書き込み、一括操作、メモリのツールを AI アシスタントに公開します。書き込みツールは構造化された結果を返します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細

Roam Research MCP + CLI
はじめに
このプロジェクトは、個人的な課題を解決するために作成しました。Claude Code(およびほかの LLM)から Roam Research のグラフを直接管理したいと考えたのです。AI エージェントがノートにアクセスできるようにするため、Model Context Protocol (MCP) サーバーを構築しているうちに、基盤となるツールは単独でも十分に強力だと気付きました。
AI エージェント向けのバックエンドとして始まったものは、フル機能のスタンドアロン CLIへと進化しました。今では、同じ強力な API 機能をターミナルから直接利用できます。LLM がなくても、コンテンツを Roam にパイプで渡したり、グラフを検索したり、タスクを管理したりできます。
Claude にナレッジベース上で強力な機能を持たせたい場合も、自分のスクリプト用に堅牢な CLI が欲しい場合も、このプロジェクトが役立ちます。

v5.0 の新機能
ひと言で言うと: roam save には、親ブロックの指定方法ごとにフラグが用意され、どちらも推測しなくなりました。--parent-uid は常に UID、--parent は常にテキストです。
4.1.0 までは、--parent にブロック UID または見出しテキストを渡すと、値に数字が含まれているかどうかでどちらかを判定していました。Roam の UID の約 5 件に 1 件は数字を含まないため、該当する保存先は気付かないうちに誤って振り分けられていました。4.1.0 では --parent-uid を追加し、--parent に UID を渡す方法を非推奨にしました。5.0 でこの分離が完了しました。
--parent-uid <uid>は、その UID を持つブロックの下にネストします。uidまたは((uid))を受け付けます。該当するブロックが存在しない場合、コマンドはゼロ以外の終了コードで終了し、何も書き込みません。--parent "<text>"は、対象ページにある指定テキストのブロックの下にネストし、存在しない場合は作成します。UID として読み取られることはありません。--parent "((uid))"は、その参照をコンテンツとするブロックを検索または作成します。これは以前は確実に行えませんでした。- 親ブロックを作成すると、そのことが UID とともに stderr に通知されます。
--parentに指定したテキストが UID のように見える場合は、何が起きたかを説明し、代わりに使用する--parent-uidコマンドを示す2行目も表示されます。stdout は変わりません。 roam save --helpでは、この選択について最初に説明します。 例の前に「親ブロックの選び方」セクションがあり、2つのフラグの違いを最初に確認できます。
メジャーバージョンを上げた理由。 以前は roam save --parent "((uid))" と roam save --parent <uid> でそのブロックの下にネストしていましたが、現在はそのテキストを含むブロックの下にネストします。スクリプトで --parent に UID を渡している場合は、フラグを --parent-uid に変更してください。 影響を受けるのは CLI のみです。MCP ツールでは型付きフィールドとして parent-uid を受け取り、これまでとまったく同じ動作をするため、AI アシスタント経由でサーバーを使用している場合、対応は不要です。
詳しくは変更履歴をご覧ください。
v4.0 の新機能
一言で言うと: ソフト改行(Shift+Enter)を含むブロックが、ページの書き換え後も保持されるようになりました。ページを読み込み、そのまま書き戻しても何も変わりません。
これまでは、複数行のブロックは物理的に2行としてレンダリングされ、2行目はカラム0から始まっていました。そのためパーサーのインデント基準がリセットされ、後続のすべてのブロックがルートに向かって折りたたまれていました。そして roam_update_page_markdown は、実際のページをその状態に合わせるための移動を忠実に生成していました。ページを読み込み、リビジョンを書き戻すだけで、この問題が発生していました。このツールの説明されている用途そのものです。コールアウトの本文やフェンス付きコードブロックは、まさにソフト改行を含むブロックです。
- ソフト改行は
⏎としてレンダリングされます。 ソフト改行を含むページでは、先頭に `` マーカー行が追加されます。マークダウンを書き戻す場合は、この行を残してください。複数行のブロックがないページは、マーカーもエンコードもなく、3.x とバイト単位で同一にレンダリングされます。 - バックスラッシュは特別扱いされません。 以前の設計では改行を
\nとしてエスケープしていましたが、これは作成者が記述したテキストの一般的な接頭辞でもあります:\nabla、\neq、C:\newdir。センチネルにはそのようなルールは不要なので、これらはすべて、どこでも入力されたとおりに書き込まれます。 - そのままのラウンドトリップでは変更は発生しません。 タイトルヘッダーを含め、レンダラーの出力を変更せずに送信すると、アクションは一切発生しません。CLI にも同じ修正が適用されています。
roam getの出力をroam save --updateにパイプしても、ページはそのままです。 - ページ書き換えに対する保護がさらに2つ追加されました。 ブロックが1つもない状態に解析される空でないマークダウンは、ページ上のすべてのブロックを削除するのではなく、更新を拒否するようになりました(説明にあるとおり、本当に空のマークダウンであればページをクリアします)。また、手作業で作成した最初のブロックがページタイトルを繰り返す H1 であっても、通常の更新時に削除されなくなりました。
- リンクされた参照もエンコードされます。
roam_fetch_page_full_viewは、ページ自体のコンテンツだけでなく、参照元ブロックやパンくずリストのソフト改行もエスケープします。 - ブラウザーのクライアントが CORS プリフライトを通過できるようになりました。 HTTP トランスポートで
MCP-Protocol-VersionとLast-Event-IDが許可されるようになりました。クライアントは初期化後にこれらを送信する必要があります。ブラウザー以外のクライアントには、これまで影響はありませんでした。 - MCP SDK を固定しました。 これにより、新規インストールでは、その日に npm が提供するものではなく、テストスイートが実行されるバージョンと同じ、テスト済みのプロトコル仕様を利用できます。
メジャーバージョンを上げた理由。 複数行のブロックを含むページでは、4つの読み取りインターフェースが異なるバイト列を返します: roam_fetch_page_by_title(format: "markdown")、roam_fetch_page_full_view、roam_get_subpages、および roam get です。AI アシスタント経由でサーバーを使用する場合、特に対応は必要ありません。複数行のページのマークダウン出力を解析するスクリプトでは、新しいエンコードが認識されます。roam-research-mcp@3 に固定している場合は、バージョンを再固定するまで、3.2.0 の修正と、ドキュメントに記載されている複数行に関する制限がそのまま適用されます。
各修正を以前の状態と照らし合わせてどのように検証したかや、エッジケースを含む詳細は、変更履歴をご覧ください。
Roam の公式 MCP サーバーとの違い
Roam Research は独自の MCP サーバーと CLI(@roam-research/roam-mcp)を提供しています。優れたツールであり、このプロジェクトは置き換えを目的としていません。両者は異なる Roam API と通信しており、ほかの違いはすべてここから生じています。
| このプロジェクト | 公式の @roam-research/roam-mcp | |
|---|---|---|
| 通信先 | Roam のバックエンド REST API(グラフトークン+グラフ名) | Roam Desktop のローカル HTTP API |
| Roam の起動が必要か | いいえ — ヘッドレスで動作します | はい。デスクトップアプリを開いておく必要があります(ディープリンクで起動します) |
| 実行可能な場所 | どこでも:ノート PC、サーバー、コンテナ、CI | Roam Desktop を実行しているマシン |
| 共有デーモン | はい — roam server はすべてのクライアント向けに 1 つの HTTP デーモンを実行します | クライアントごとの stdio |
| 複数のグラフ | ROAM_GRAPHS 環境変数。選択したグラフには write_key による保護を設定できます | ~/.roam-tools.json。グラフごとに 1 つのトークン |
| Web 専用のグラフ | 動作します | Desktop のみ |
公式サーバーを選ぶのは、Roam が公式にサポートする方法を使いたい場合や、起動中のアプリでしかできない操作が必要な場合です。たとえば、Desktop UI の操作(ページを開く、現在の選択範囲を読み取る、サイドバーを操作する)、セマンティック検索/埋め込み検索、リンクの提案、ファイルのアップロード、コメント、Roam の拡張機能が登録するツールの呼び出しなどです。
こちらを選ぶのは、Roam が起動していない、またはインストールされていない環境(サーバー、コンテナ、cron ジョブ、CI ステップ)で使う場合です。または、このプロジェクトに追加された機能を使いたい場合です。標準入力のパイピングに対応した完全なスタンドアロン CLI、オプションでベアラ認証を使える共有 HTTP デーモン、ブロック UID(ひいてはブロック参照)を保持するスマートなページ差分処理、1 回の呼び出しでネスト構造を作成するための UID プレースホルダーを使った一括操作、エージェントメモリーツールなどがあります。
意図的に省いている機能が 1 つあります。ここにはページ削除ツールはありません。 Roam には、API による一括削除を取り消す方法がありません。公式サーバーには delete_page がありますが、このプロジェクトではより慎重な方針を取っています。
相互運用できます
両サーバーは意図的に共通の規約を採用しているため、両方を実行しても問題ありません。
[[roam/agent guidelines]]— どちらも、設定した規約を記載した同じページを読み取ります。一度書けば、両方で適用されます。エージェントのガイドラインをご覧ください。#.rm-hide/#.rm-private— どちらも、タグ付けされたブロックを AI 向けコンテンツから除外します。一度タグ付けすれば、両方から非表示になります。AI からコンテンツを隠すをご覧ください。
スタンドアロン CLI:roam
roam CLI を使うと、ターミナルからグラフを直接操作できます。コンテンツの作成と取得を行うすべてのコマンドで標準入力(stdin)のパイピングに対応しているため、自動化ワークフローに最適です。
使用例
# Save a quick thought to your daily page
roam save "Idea: A CLI for Roam would be cool"
# Pipe content from a file to a new page
cat meeting_notes.md | roam save --title "Meeting: Project Alpha"
# Create a TODO item on today's daily page
echo "Buy milk" | roam save --todo
# Prepend to top of page (newest-first ordering)
roam save -p "Changelog" --order first "v2.18.0 release"
# Search your graph and pipe results to another tool
roam search "important" --json | jq .
# Search for pages by namespace prefix
roam search --namespace "Convention" # Finds all Convention/* pages
# Fetch a page by title
roam get "Roam Research"
# Fetch daily pages using any date format (auto-normalized)
roam get today # Today's daily page
roam get 2026-03-21 # ISO date → "March 21st, 2026"
roam get "03/21/2026" # US date → "March 21st, 2026"
roam get "March 21" # Named (assumes current year)
# Fetch a block with ancestors (parent chain to page root)
roam get abc123def -a # Block + children + ancestors
roam get abc123def -a -d 0 # Ancestors only, no children
# Fetch page by UID or Roam URL
roam get page abc123def
roam get page "https://roamresearch.com/#/app/my-graph/page/abc123def"
# Sort and group results
roam get --tag Project --sort created --group-by tag
# Find references (backlinks) to a page
roam refs "Project Alpha"
# Update a block (e.g., toggle TODO status)
roam update ((block-uid)) --todo
# Multi-graph: read from a specific graph
roam get "Page Title" -g work
# Multi-graph: write to a protected graph
roam save "Note" -g work --write-key "$ROAM_SYSTEM_WRITE_KEY"
利用可能なコマンド: get、search、save、refs、update、batch、rename、status、server。
各コマンドの詳細は roam <command> --help を実行してください。
インストール
npm install -g roam-research-mcp
# The 'roam' command is now available globally
MCP サーバーのツール
MCP サーバーは、AI アシスタント(Claude など)に以下のツールを公開し、Roam グラフの読み取り、書き込み、整理をインテリジェントに行えるようにします。
マルチグラフ対応: すべてのツールで、
graphとwrite_keyのパラメーターを省略可能です。graphを使うと、ROAM_GRAPHS設定から特定のグラフを対象にできます。また、保護されたグラフへの書き込み操作ではwrite_keyを使用します。
| ツール名 | 説明 |
|---|---|
roam_fetch_page_by_title | タイトルでページの内容を取得します。 |
roam_fetch_page_full_view | パンくずリストのコンテキストと子ページを含め、ページの内容とリンクされた参照をすべて取得します。 |
roam_fetch_block | UID でブロックを取得します。子ブロック(深さ)や祖先(ページのルートまで)を任意で指定できます。 |
roam_create_page | テキストとテーブルを組み合わせた内容を含む、新しいページを作成します。 |
roam_update_page_markdown | スマート差分を使用してページを更新します(ブロック UID を保持します)。 |
roam_get_subpages | 名前空間プレフィックス(例:「Project/」)の下にあるサブページを、任意のタグフィルターを指定して一覧表示します。 |
roam_search_by_text | グラフ全体、または特定のページ内を全文検索します。ページタイトルの名前空間プレフィックス検索に対応しています。 |
roam_search_block_refs | ページ、タグ、またはブロック UID を参照するブロックを検索します。 |
roam_search_by_status | TODO または DONE の項目を検索します。 |
roam_search_for_tag | 特定のタグを含むブロックを検索します(除外に対応)。 |
roam_search_by_date | 作成日または更新日でブロックやページを検索します。 |
roam_find_pages_modified_today | 深夜以降に更新されたページを一覧表示します。 |
roam_add_todo | 今日の日次ページに TODO 項目を追加します。 |
roam_create_table | 書式が正しい Roam テーブルを作成します。 |
roam_create_outline | 階層構造のアウトラインを作成します。 |
roam_process_batch_actions | 複数の低レベルアクション(作成、移動、更新、削除)を一括で実行します。 |
roam_move_block | ブロックを新しい親または位置に移動します。 |
roam_remember / roam_recall | Roam 内での AI のメモリー管理に特化したツールです。 |
roam_datomic_query | 高度なフィルタリングのために、生の Datalog クエリを実行します。 |
roam_markdown_cheatsheet | Roam 仕様の Markdown リファレンスを取得します。 |
roam_get_guidelines | このグラフでユーザーが定義したエージェントの規約を取得します。 |
書き込みツールからの構造化結果(v3.0.0以降)
10 個の書き込みツールは outputSchema を宣言し、通常のテキストに加えて、検証済みオブジェクトである structuredContent を返します。クライアントは文字列内の JSON を探さずに、page_uid、uid_map、success を直接読み取れるため、呼び出しの連結がより確実になります。
// roam_process_batch_actions
{ "success": true, "uid_map": { "parent1": "Xk7mN2pQ9" },
"validation_passed": true, "actions_attempted": 4 }
知っておくべきことは 3 つあります。
- 何も削除されていません。 テキストチャネルに変更はないため、
structuredContentを無視するクライアントは以前とまったく同じように動作します。 - 読み取りツールには意図的にどちらもありません。 結果全体をすでにテキストチャネルにシリアライズしているため、スキーマを追加するとペイロードが単に二重になります。
- これらのフィールドは追加のみです。 一部のクライアントは、実行時の応答をキャッシュ済みのツール一覧と照合して検証するため、フィールドの追加や非推奨化はあっても、メジャーバージョン以外で名前が変更されたり削除されたりすることはありません。
5.0.0 へのアップグレード: CLI のみです。
roam save --parentは常にテキストを受け取るようになりました。そのため、ブロック UID を渡すスクリプト(--parent "((uid))"または--parent <uid>)は、--parent-uidに切り替える必要があります。変更しない場合、この呼び出しは終了コード 0 で終了し、-pが指定されていなければ、参照を含む新しいブロックの下にコンテンツがネストされ、デイリーページに保存されます。MCP ツールには影響しません。変更履歴を参照してください。
4.0.0 へのアップグレード: ソフト改行(Shift+Enter)を含むページを Markdown で読み取ると、その改行は
⏎としてレンダリングされ、先頭に `` マーカーが付きます。これにより、書き戻してもページがそのまま保たれます。複数行ブロックのないページは 3.x とバイト単位で同一です。AI アシスタントのユーザーは何もする必要はありません。複数行ページの Markdown 出力を解析するスクリプトには、新しいエンコーディングが適用されます。変更履歴を参照してください。
2.x からのアップグレード: 書き込み結果の 3 つのフィールド名が変更されました。
uid→page_uid(roam_create_page)、created_uids→created_blocks(roam_create_outline、roam_import_markdown)、preservedUids→preserved_uids(roam_update_page_markdown)です。これはこれらの名前を読み取るコードにのみ影響します。AI アシスタント経由でサーバーを使用している場合、変更はありません。変更理由については変更履歴を参照してください。
エージェントのガイドライン(グラフごと)
roam_get_guidelines は、グラフ内のページ(デフォルトでは [[roam/agent guidelines]])を読み込みます。このページには、タグ付けの方法、ページの名前空間の付け方、エージェントが決して行ってはならないことなど、独自の規約を記載します。Roam の公式 MCP サーバーも同じページタイトルを読み込むため、1 つのページを両方で使用できます。
これは CUSTOM_INSTRUCTIONS_PATH とは別のものであり、両者は組み合わせて使用できます。
CUSTOM_INSTRUCTIONS_PATH | [[roam/agent guidelines]] | |
|---|---|---|
| 保存場所 | ディスク上のファイル | グラフ内のページ |
| 適用範囲 | サーバー全体、すべてのグラフ | グラフごと |
| 変更方法 | ファイルを編集し、サーバーを再起動 | ページを編集 |
| 内容 | Roam の Markdown の書き方 | このユーザー が このグラフ をどのように扱ってほしいか |
ページを作成するだけです。 設定が何もなくても、roam_get_guidelines は [[roam/agent guidelines]] を読み込みます。これは Roam 自体のサーバーが読み込むものと同じタイトルなので、一度作成すれば、両方に反映されます。この正確な名前空間付きタイトルのページを作成することがオプトインとなります。エージェントが明示的にツールを呼び出さない限り、グラフから何かが読み込まれることはありません。
ページが存在しない場合、ツールは失敗するのではなく exists: false を返すため、いつでも安全に呼び出せます。
自分では設定できないルールも返します
独自の規約に加えて、各 roam_get_guidelines のレスポンスには roamSyntax フィールドが含まれます。これは、コンテンツを破壊する操作をまとめた短いリストです。roam_update_page_markdown が、Markdown に記載されていないブロックをすべて削除すること、切り詰められた structure のプレビューがコンテンツであるかのように書き戻されること、ブロック参照がプレーンテキストとして再入力されることなどが含まれます。また、読み取りでは #.rm-hide サブツリーが黙って除外されるという注意と、Roam の Markdown が標準の Markdown と逆の動作をする少数の箇所についても記載されています。
これがチートシートではなく、ここに含まれている理由は2つあります。roam_markdown_cheatsheet を一度も呼び出さないクライアントも含め、すべてのクライアントに届くこと、そして、グラフにガイドラインページがない場合でも返されることです。これは、エージェントが最も手がかりを得られない状況です。このレイヤー構成には意図があります。**スタイルについては独自の規約が優先され、データの安全性については roamSyntax が優先されます。**どのような規約があっても、切り詰められたプレビューが完全なものになることはありません。
コンポーネント、クエリ、埋め込み、ツールの選択などを含む構文の完全なリファレンスは、引き続き roam_markdown_cheatsheet にあります。roamSyntax は約800トークンで、意図的に上限が設けられています。
各グラフで異なるページを指定したり、無効にしたりできます。
ROAM_GRAPHS='{
"personal": {"token": "...", "graph": "..."},
"work": {"token": "...", "graph": "...", "guidelinesPage": "work/agent rules"},
"private": {"token": "...", "graph": "...", "guidelinesPage": false}
}'
ROAM_GUIDELINES_PAGE='team/agent guidelines' # change the default for every graph
解決の優先順位は、グラフごとの guidelinesPage → ROAM_GUIDELINES_PAGE → roam/agent guidelines です。上の例では、personal は環境変数の設定を使い、work は独自のページを使い、private ではガイドラインが完全に無効になっています。無効にできるのは明示的に false を指定した場合のみです。値が設定されていない場合は無効になりません。
結果は30秒間キャッシュされるため、ページを編集すると再起動なしで変更が反映されます。スターターテンプレートは .roam/agent-guidelines.template.md にあります。
ガイドラインは通常のページ読み取り経由で取得されるため、#.rm-hide / #.rm-private タグが付いたブロックはガイドラインからも除外されます。詳細は以下をご覧ください。
ソフト改行を含むページを読み取ると、各ブロックが1行に収まるように ⏎ として表示されます。エスケープされていない改行があると、書き戻し時にその後のすべてが列0に配置され、別の親ブロックに割り当てられてしまいます。このようなペイロードには先頭に
`` マーカーが付いています。Markdown を書き戻す場合は、このマーカーを残してください。作成した Markdown がデコードされることはありません。バックスラッシュは特別扱いされず、マーカー付きペイロード内の ⏎ だけが解釈されます。roam_get_guidelines の出力はプレーンテキストです。センチネルもマーカーも含まれません。
AI からコンテンツを隠す
#.rm-hide または #.rm-private が付けられたブロックと、その下にネストされたすべての内容は、これらのツールが返すコンテンツから除外されます。ハッシュタグ形式(#.rm-hide、#[[.rm-hide]])とリンク形式([[.rm-hide]])のどちらも使用できます。.rm-private は Roam で既存の「他のユーザーから非表示にする」タグです。.rm-hide は AI からのみ非表示にします。
これは Roam 公式 MCP サーバーと同じ規則に従っているため、一方で非表示にされたブロックは、もう一方でも非表示になります。
適用対象:roam_fetch_page_by_title、roam_fetch_block、roam_fetch_page_full_view、roam_get_subpages、roam_search_by_text、roam_search_for_tag、roam_search_by_status、roam_search_block_refs、roam_search_hierarchy、roam_search_by_date。
**非表示のブロックはページ書き換え時の差分からも除外されます。**これにより、エージェントが書き込めなかった Markdown に存在しないという理由で、ブロックが削除されるのを防ぎます。roam_update_page_markdown(および roam save --update)は、指定した内容でページを置き換え、Markdown から省略したものを削除します。そのため、ベースラインにも同じフィルターを適用します。これは、差分による削除の基準となるベースラインは、呼び出し元が読み取りを許可されたページと同じでなければならないという原則に基づいています。何かを保護した場合は、preserved_hidden が報告されます。コンテンツは保持されますが、表示されている兄弟ブロックとの正確な順序が変わることがあります。修正前には実際にデータ損失のバグが発生していました。詳しくは変更履歴をご覧ください。
これは利便性のためのフィルターであり、セキュリティを保証するものではありません。roam_datomic_query はデータベースを直接読み取り、意図的にこのフィルターを適用しません。そのため、能力のあるエージェントは生の Datalog を通じて、非表示のブロックを取得できます。これらのタグは「AI の邪魔にならないようにする」ためのものであり、「秘密にする」ためのものではないと考えてください。
タグの照合では大文字と小文字を区別せず、完全一致するタグのみが対象です。#.rm-hidden と #.rm-highlight はそのまま残ります。非表示 UID のセットは 30 秒間キャッシュされるため、タグを付けたばかりのブロックが最大でその時間、表示されることがあります。
設定
環境変数
単一グラフモード
単一の Roam グラフを使用する場合は、環境または .env ファイルに次の値を設定します。
ROAM_API_TOKEN=your-api-token
ROAM_GRAPH_NAME=your-graph-name
マルチグラフモード(v2.0+)
1 つのサーバーインスタンスから複数の Roam グラフに接続します。
ROAM_GRAPHS='{
"personal": {"token": "token-1", "graph": "personal-db", "memoriesTag": "#[[Personal Memories]]"},
"work": {"token": "token-2", "graph": "work-db", "protected": true, "memoriesTag": "#[[Work Memories]]"},
"research": {"token": "token-3", "graph": "research-db"}
}'
ROAM_DEFAULT_GRAPH=personal
ROAM_SYSTEM_WRITE_KEY=your-secret-key
グラフ設定オプション:
| プロパティ | 必須 | 説明 |
|---|---|---|
token | はい | このグラフの Roam API トークン |
graph | はい | グラフ名/データベース識別子 |
protected | いいえ | true の場合、書き込みには ROAM_SYSTEM_WRITE_KEY による確認が必要です。ただし、デフォルトのグラフは例外です。詳細は下記をご覧ください |
memoriesTag | いいえ | roam_remember/roam_recall 用のタグ(グローバルのデフォルト設定を上書きします) |
このサーバーには独立したロックが 2 つあります。どちらも「キー」なので混同しやすいですが、簡単に説明すると次のとおりです(どちらも任意で、デフォルトでは無効です)。
ベアラートークン — HTTP_AUTH_TOKEN | 書き込みキー — ROAM_SYSTEM_WRITE_KEY | |
|---|---|---|
| ひとことで言うと | 玄関の鍵 | 金庫の中にある掛け金 |
| 制御するもの | サーバーにアクセスできるユーザー | protected グラフへの書き込みが許可されるかどうか |
| 対象範囲 | すべて。すべてのグラフの読み取りと書き込み | protected に設定されたグラフへの書き込みのみ |
| 読み取りを保護するか | はい | いいえ |
| 必要になる場合 | サーバーが自分のマシンの外部からアクセス可能な場合のみ(例:-H 0.0.0.0) | 重要なグラフへの誤った編集を防ぐための保護策が必要な場合 |
| 送信方法 | HTTP ヘッダー:Authorization: Bearer <token> | 書き込みツール/CLI コマンドの write_key 引数 |
家にたとえると、ベアラートークンは玄関の鍵です(見知らぬ人を完全に締め出します)。一方、書き込みキーは家の中にある金庫の鍵です(すでに家の中にいる人でも、金庫の中身を変えるには鍵が必要です)。自分のマシンで 127.0.0.1 にバインドしている場合、玄関は壁に面しています。また、トークンのないサーバーも、DNS リバインディングによってアクセスしようとする Web ページを拒否します(下記の HTTP_ALLOWED_HOSTS を参照)。そのため、そこでベアラートークンは不要です。書き込みキーはローカルでも「本当に実行しますか?」という確認用のガードとして便利です。Roam には元に戻す機能がないためです。 |
つまり、グラフの書き込みに書き込みキーを必要とするには、そのグラフで protected: true を設定し、ROAM_SYSTEM_WRITE_KEY を構成します。呼び出し側は、そのグラフへの書き込みごとに一致する write_key を渡す必要があります。
⚠️ デフォルトのグラフでは
protectedは何の効果もありません。ROAM_DEFAULT_GRAPHが指定するグラフへの書き込みは、protectedが参照される前に常に許可されます。このフラグは、名前を指定して明示的に要求する必要があるグラフを保護します。デフォルト以外のグラフにアクセスする行為こそ、確認する価値のある意図的な操作だという考えに基づいています。グラフの書き込みをガードしたい場合、そのグラフをデフォルトにしてはいけません。
オプション:
ROAM_MEMORIES_TAG:roam_remember/roam_recallのデフォルトタグです(グラフごとのmemoriesTagが設定されていない場合のフォールバック)。HTTP_STREAM_PORT: HTTP Stream トランスポートのポートです(デフォルトは 8088)。--serverモード専用です。stdio モードではソケットを開かないため、ここでの設定は無視されます。HTTP_STREAM_HOST: HTTP トランスポートのバインド先ホストです(デフォルトは127.0.0.1、ループバックのみ)。--serverモード専用です。 LAN 上に公開するには0.0.0.0に設定し、その場合はHTTP_AUTH_TOKENも設定してください。HTTP_AUTH_TOKEN: HTTP エンドポイント全体を保護する任意のベアラートークンです。未設定の場合、トークンなしでサーバーはlocalhost、IP アドレス、またはHTTP_ALLOWED_HOSTSに含まれる名前宛てのリクエストにのみ応答し、ブラウザーからのリクエストについてはCORS_ORIGINに含まれるオリジンからのものにのみ応答します。設定すると、すべての MCP リクエストでAuthorization: Bearer <token>を送信する必要があります(GET /healthは引き続き公開されます)。127.0.0.1以外にバインドする場合は必ず使用してください。ROAM_SYSTEM_WRITE_KEYとは異なります。詳しくは2 種類のアクセス制御とその違いを参照してください。HTTP_ALLOWED_HOSTS:HTTP_AUTH_TOKENが設定されていないサーバーが、localhostと IP アドレス以外に応答するホスト名です(カンマ区切り。ポートは無視されます)。例:Docker サービス名のroam-mcp、またはmybox.local。これ以外の名前宛てのリクエストには 403 が返されます。これにより、Web ページが自身のホスト名を127.0.0.1に向けてサーバーにアクセスすることを防ぎます(DNS リバインディング)。HTTP_AUTH_TOKENが設定されている場合、この設定は無視されます。CORS_ORIGIN: HTTP サーバーへの呼び出しを許可するブラウザーのオリジンです(カンマ区切り。デフォルトはhttp://localhost:5678,https://roamresearch.com。*を指定するとすべて許可されます)。HTTP_AUTH_TOKENが設定されていない場合、これ以外のオリジンからのリクエストには 403 が返されます。
サーバーの実行
1. デフォルトモード(stdio) ローカル統合(例:Claude Desktop、IDE 拡張機能)に最適です。MCP クライアントがセッションごとにプロセスを起動し、stdin/stdout 経由で通信します。ポートは開きません — stdio 経由の MCP 通信にポートは必要ありません。
3.1.0 より前のバージョンでは、このモードでも HTTP リスナーが開き、すべてのインターフェースにバインドされていました。そのエンドポイントを使っていた場合は、代わりに
--serverデーモンを実行してください。以下を参照してください。
npx roam-research-mcp
2. 共有サーバーモード(--server)
複数の MCP クライアントが共有する、長時間稼働する HTTP 専用デーモンに最適です。セッションごとに独自のサブプロセスを起動する必要がなくなります。メモリを節約でき、クライアントに安定した URL を提供できます。
HTTP_STREAM_PORT=8088 npx roam-research-mcp --server
または、roam CLI で管理できます。起動/停止/ステータス/ログの機能が追加されます。
roam server start # start the shared daemon in the background
roam server start -H 0.0.0.0 # expose on the LAN (no transport auth!)
roam server status # is it up? version, graphs, active sessions
roam server logs -f # follow the log
roam server stop # stop a CLI-started daemon
roam server status は、デーモンの起動方法にかかわらず動作し(/health を確認します)、LaunchAgent/systemd ユニットによって起動したデーモンも報告します。状態(pidfile とログ)は ~/.roam/ に保存されます(ROAM_HOME で変更できます)。
2 つのモードは相互に排他的で、それぞれ開くトランスポートは 1 つだけです。stdio モードは stdio で通信し、何もバインドしません。--server は HTTP で通信し、stdin を読み込みません。--server モードでは、サーバーは次のように動作します。
- HTTP 専用で実行されます(stdio トランスポートなし)。
HTTP_STREAM_HOST上のHTTP_STREAM_PORTに正確にバインドし、ポートが使用中の場合はゼロ以外の終了コードで終了します(暗黙に別のポートへ変更しません — 共有デーモンは安定した URL を維持する必要があります)。- 稼働状況の確認用に
GET /health→{"status":"ok", ...}を公開します。
HTTP トランスポート設定で、MCP クライアントからこのサーバーに接続します。
{
"mcpServers": {
"roam-research-mcp": {
"type": "http",
"url": "http://127.0.0.1:8088/mcp"
}
}
}
環境変数(トークン、グラフ)はクライアント設定ではなく、サーバープロセスに設定します。
公開サーバーの保護(2 つのレイヤー):
ループバック以外(-H 0.0.0.0)にバインドする場合は、境界での保護を追加します。
HTTP_AUTH_TOKEN=$(openssl rand -hex 32) roam server start -H 0.0.0.0
クライアントは、次のようにヘッダーでトークンを送信します。
{
"mcpServers": {
"roam-research-mcp": {
"type": "http",
"url": "http://<host>:8088/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
両方を設定してください。それぞれ役割が異なります(上記の2 種類のアクセス制御とその違いを参照)。ベアラートークンは接続できるユーザーを制御し、書き込みキーは保護されたグラフへの書き込みのみを制限します。
⚠️ 書き込みキーは、ベアラートークンの代わりにはなりません。公開サーバーで
HTTP_AUTH_TOKENを設定していない場合、ネットワーク上の誰でも、すべてのグラフを読み取ることができ(保護されていないグラフには書き込むこともできます)。ループバック以外に公開する場合は、HTTP_AUTH_TOKENを設定してください。
稼働状態の維持(macOS LaunchAgent):
~/Library/LaunchAgents/com.example.roam-mcp.plist を作成し、RunAtLoad と KeepAlive を設定します。環境変数は EnvironmentVariables に指定し、ProgramArguments の最後のエントリーに --server を指定してください。StandardOutPath/StandardErrorPath はローカルパス(例:~/Library/Logs/)に設定してから、次を実行します。
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.roam-mcp.plist
curl -s http://127.0.0.1:8088/health # verify
3. Docker
docker build -t roam-research-mcp .
docker run --init -p 127.0.0.1:8088:8088 \
-e HTTP_STREAM_HOST=0.0.0.0 -e HTTP_STREAM_PORT=8088 \
--env-file .env roam-research-mcp --server
実行前に .env で HTTP_AUTH_TOKEN をランダムなシークレットに設定してください。MCP リクエストには Authorization: Bearer <token> を含める必要があります。公開ポートはデフォルトでループバックのみです。リモートアクセスする場合は、公開サーバーの保護に従い、必要なホストアドレスで意図的にポートを公開してください。
-e の値は --env-file より優先されるため、.env の内容にかかわらず、サーバーは公開ポートで待ち受けます。--init を指定すると、docker stop でサーバーをすぐに終了でき、10 秒後に強制終了されるのを防げます。
LLM での設定
Claude Desktop / Cline:
MCP 設定ファイル(例:~/Library/Application Support/Claude/claude_desktop_config.json)に追加します:
バージョンの固定。
npx -y roam-research-mcpは、クライアントがサーバーを起動するたびに最新リリースを取得するため、新しいメジャーバージョンが予告なく適用されます。いつ移行するかを自分で決められるよう、メジャーバージョンを固定してください:
args使用されるバージョン ["-y", "roam-research-mcp"]常に最新 — 次のメジャーバージョンも含む ["-y", "roam-research-mcp@3"]3.x のみ。メジャーバージョンの変更にはここを編集する必要があります ["-y", "[email protected]"]このビルドに固定 メジャーバージョンを固定するのが賢明なデフォルトです。修正や新しいツールは引き続き利用できますが、破壊的変更は自分で選択して適用できます。以下の例は、ほとんどの人が最初に貼り付ける設定に合わせて、バージョンを固定していません。
単一グラフ:
{
"mcpServers": {
"roam-research": {
"command": "npx",
"args": ["-y", "roam-research-mcp"],
"env": {
"ROAM_API_TOKEN": "your-token",
"ROAM_GRAPH_NAME": "your-graph"
}
}
}
}
複数グラフ:
{
"mcpServers": {
"roam-research": {
"command": "npx",
"args": ["-y", "roam-research-mcp"],
"env": {
"ROAM_GRAPHS": "{\"personal\":{\"token\":\"token-1\",\"graph\":\"personal-db\",\"memoriesTag\":\"#[[Memories]]\"},\"work\":{\"token\":\"token-2\",\"graph\":\"work-db\",\"protected\":true}}",
"ROAM_DEFAULT_GRAPH": "personal",
"ROAM_SYSTEM_WRITE_KEY": "your-secret-key"
}
}
}
}
クエリブロックパーサー(v2.11.0+)
Roam のクエリブロックをプログラムから解析、実行するためのユーティリティです。{{[[query]]: ...}} 構文を Datalog クエリに変換します。
サポートされる句
| 句 | 構文 | 説明 |
|---|---|---|
| ページ参照 | [[page]] | ページを参照するブロック |
| ブロック参照 | ((uid)) | ブロックを参照するブロック |
and | {and: [[a]] [[b]]} | すべての条件に一致する必要があります |
or | {or: [[a]] [[b]]} | いずれかの条件に一致します |
not | {not: [[tag]]} | 一致するものを除外します |
between | {between: [[date1]] [[date2]]} | 日付範囲で絞り込みます |
search | {search: text} | 全文検索 |
daily notes | {daily notes: } | デイリーノートのページのみ |
by | {by: [[User]]} | ユーザーが作成または編集したもの |
created by | {created by: [[User]]} | ユーザーが作成したもの |
edited by | {edited by: User} | ユーザーが編集したもの |
相対日付
between 句では、相対日付(today、yesterday、last week、last month、this year、7 days ago、2 months ago など)をサポートしています。
使用方法
import { QueryExecutor } from 'roam-research-mcp/query';
const executor = new QueryExecutor(graph);
// Execute a query
const results = await executor.execute(
'{{[[query]]: "My Query" {and: [[Project]] {between: [[last month]] [[today]]}}}}'
);
// Parse without executing (for debugging)
const { name, query } = QueryParser.parseWithName(queryBlock);
ユーティリティ関数
import { isQueryBlock, extractQueryBlocks } from 'roam-research-mcp/query';
// Detect if text is a query block
isQueryBlock('{{[[query]]: [[tag]]}}'); // true
// Extract all query blocks from a string
extractQueryBlocks(pageContent); // ['{{[[query]]: ...}}', ...]
サポート
このプロジェクトがナレッジベースの管理や、便利なエージェントの構築に役立った場合は、コーヒーをごちそうしていただけると幸いです。更新を続ける助けになります。
ライセンス
MIT ライセンス - Ian Shen が作成しました。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。
