roam-research-mcp 2.4.3 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +175 -669
  2. package/build/Roam_Markdown_Cheatsheet.md +24 -4
  3. package/build/cache/page-uid-cache.js +40 -2
  4. package/build/cli/batch/translator.js +1 -1
  5. package/build/cli/commands/batch.js +2 -0
  6. package/build/cli/commands/get.js +401 -14
  7. package/build/cli/commands/refs.js +2 -0
  8. package/build/cli/commands/save.js +56 -1
  9. package/build/cli/commands/search.js +45 -0
  10. package/build/cli/commands/status.js +3 -4
  11. package/build/cli/utils/graph.js +6 -2
  12. package/build/cli/utils/output.js +28 -5
  13. package/build/cli/utils/sort-group.js +110 -0
  14. package/build/config/graph-registry.js +31 -13
  15. package/build/config/graph-registry.test.js +42 -5
  16. package/build/markdown-utils.js +114 -4
  17. package/build/markdown-utils.test.js +125 -0
  18. package/build/query/generator.js +330 -0
  19. package/build/query/index.js +149 -0
  20. package/build/query/parser.js +319 -0
  21. package/build/query/parser.test.js +389 -0
  22. package/build/query/types.js +4 -0
  23. package/build/search/ancestor-rule.js +14 -0
  24. package/build/search/block-ref-search.js +1 -5
  25. package/build/search/hierarchy-search.js +5 -12
  26. package/build/search/index.js +1 -0
  27. package/build/search/status-search.js +10 -9
  28. package/build/search/tag-search.js +8 -24
  29. package/build/search/text-search.js +70 -27
  30. package/build/search/types.js +13 -0
  31. package/build/search/utils.js +71 -2
  32. package/build/server/roam-server.js +2 -1
  33. package/build/shared/index.js +2 -0
  34. package/build/shared/page-validator.js +233 -0
  35. package/build/shared/page-validator.test.js +128 -0
  36. package/build/shared/staged-batch.js +144 -0
  37. package/build/tools/helpers/batch-utils.js +57 -0
  38. package/build/tools/helpers/page-resolution.js +136 -0
  39. package/build/tools/helpers/refs.js +68 -0
  40. package/build/tools/operations/batch.js +75 -3
  41. package/build/tools/operations/block-retrieval.js +15 -4
  42. package/build/tools/operations/block-retrieval.test.js +87 -0
  43. package/build/tools/operations/blocks.js +1 -288
  44. package/build/tools/operations/memory.js +29 -91
  45. package/build/tools/operations/outline.js +38 -156
  46. package/build/tools/operations/pages.js +169 -122
  47. package/build/tools/operations/todos.js +5 -37
  48. package/build/tools/schemas.js +14 -8
  49. package/build/tools/tool-handlers.js +2 -2
  50. package/build/utils/helpers.js +27 -0
  51. package/package.json +1 -1
package/README.md CHANGED
@@ -7,767 +7,273 @@
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
  [![GitHub](https://img.shields.io/github/license/2b3pro/roam-research-mcp)](https://github.com/2b3pro/roam-research-mcp/blob/main/LICENSE)
9
9
 
10
- A Model Context Protocol (MCP) server and standalone CLI that provides comprehensive access to Roam Research's API functionality. The MCP server enables AI assistants like Claude to interact with your Roam Research graph through a standardized interface, while the CLI (`roam`) lets you fetch, search, and import content directly from the command line. Supports multi-graph configurations, write protection, standard input/output (stdio) and HTTP Stream communication. (Personal project, not officially endorsed by Roam Research)
11
-
12
10
  <a href="https://glama.ai/mcp/servers/fzfznyaflu"><img width="380" height="200" src="https://glama.ai/mcp/servers/fzfznyaflu/badge" alt="Roam Research MCP server" /></a>
13
11
  <a href="https://mseep.ai/app/2b3pro-roam-research-mcp"><img width="380" height="200" src="https://mseep.net/pr/2b3pro-roam-research-mcp-badge.png" alt="MseeP.ai Security Assessment Badge" /></a>
14
12
 
15
- ## Installation and Usage
13
+ ## Introduction
16
14
 
17
- This MCP server supports two primary communication methods:
15
+ I created this project to solve a personal problem: I wanted to manage my Roam Research graph directly from **Claude Code** (and other LLMs). As I built the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server to give AI agents access to my notes, I realized the underlying tools were powerful enough to stand on their own.
18
16
 
19
- 1. **Stdio (Standard Input/Output):** Ideal for local inter-process communication, command-line tools, and direct integration with applications running on the same machine. This is the default communication method when running the server directly.
20
- 2. **HTTP Stream:** Provides network-based communication, suitable for web-based clients, remote applications, or scenarios requiring real-time updates over HTTP. The HTTP Stream endpoint runs on port `8088` by default.
17
+ What started as an backend for AI agents evolved into a full-featured **Standalone CLI**. Now, you can use the same powerful API capabilities directly from your terminal—piping content into Roam, searching your graph, and managing tasks—without needing an LLM at all.
21
18
 
22
- ### Running with Stdio
19
+ Whether you want to give Claude superpowers over your knowledge base or just want a robust CLI for your own scripts, this project has you covered.
23
20
 
24
- You can install the package globally and run it:
21
+ ## Standalone CLI: `roam`
25
22
 
26
- ```bash
27
- npm install -g roam-research-mcp
28
- roam-research-mcp
29
- ```
23
+ The `roam` CLI lets you interact with your graph directly from the terminal. It supports **standard input (stdin) piping** for all content creation and retrieval commands, making it perfect for automation workflows.
30
24
 
31
- Or clone the repository and build from source:
25
+ ### Quick Examples
32
26
 
33
27
  ```bash
34
- git clone https://github.com/2b3pro/roam-research-mcp.git
35
- cd roam-research-mcp
36
- npm install
37
- npm run build
38
- npm start
39
- ```
40
-
41
- ### Running with HTTP Stream
28
+ # Save a quick thought to your daily page
29
+ roam save "Idea: A CLI for Roam would be cool"
42
30
 
43
- To run the server with HTTP Stream support, you can either:
31
+ # Pipe content from a file to a new page
32
+ cat meeting_notes.md | roam save --title "Meeting: Project Alpha"
44
33
 
45
- 1. **Use the default ports:** Run `npm start` after building (as shown above). The server will automatically listen on port `8088` for HTTP Stream.
46
- 2. **Specify custom ports:** Set the `HTTP_STREAM_PORT` environment variable before starting the server.
47
-
48
- ```bash
49
- HTTP_STREAM_PORT=9000 npm start
50
- ```
51
-
52
- Or, if using a `.env` file, add `HTTP_STREAM_PORT=9000` to it.
34
+ # Create a TODO item on today's daily page
35
+ echo "Buy milk" | roam save --todo
53
36
 
54
- ## Docker
37
+ # Search your graph and pipe results to another tool
38
+ roam search "important" --json | jq .
55
39
 
56
- This project can be easily containerized using Docker. A `Dockerfile` is provided at the root of the repository.
40
+ # Search for pages by namespace prefix
41
+ roam search --namespace "Convention" # Finds all Convention/* pages
57
42
 
58
- ### Build the Docker Image
43
+ # Fetch a page by title
44
+ roam get "Roam Research"
59
45
 
60
- To build the Docker image, navigate to the project root and run:
46
+ # Fetch page by UID or Roam URL
47
+ roam get page abc123def
48
+ roam get page "https://roamresearch.com/#/app/my-graph/page/abc123def"
61
49
 
62
- ```bash
63
- docker build -t roam-research-mcp .
64
- ```
50
+ # Sort and group results
51
+ roam get --tag Project --sort created --group-by tag
65
52
 
66
- ### Run the Docker Container
67
-
68
- To run the Docker container and map the necessary ports, you must also provide the required environment variables. Use the `-e` flag to pass `ROAM_API_TOKEN`, `ROAM_GRAPH_NAME`, and optionally `MEMORIES_TAG` and `HTTP_STREAM_PORT`:
53
+ # Find references (backlinks) to a page
54
+ roam refs "Project Alpha"
69
55
 
70
- ```bash
71
- docker run -p 3000:3000 -p 8088:8088 \
72
- -e ROAM_API_TOKEN="your-api-token" \
73
- -e ROAM_GRAPH_NAME="your-graph-name" \
74
- -e MEMORIES_TAG="#[[LLM/Memories]]" \
75
- -e CUSTOM_INSTRUCTIONS_PATH="/path/to/your/custom_instructions_file.md" \
76
- -e HTTP_STREAM_PORT="8088" \
77
- roam-research-mcp
78
- ```
56
+ # Update a block (e.g., toggle TODO status)
57
+ roam update ((block-uid)) --todo
79
58
 
80
- Alternatively, if you have a `.env` file in the project root (which is copied into the Docker image during build), you can use the `--env-file` flag:
59
+ # Multi-graph: read from a specific graph
60
+ roam get "Page Title" -g work
81
61
 
82
- ```bash
83
- docker run -p 3000:3000 -p 8088:8088 --env-file .env roam-research-mcp
62
+ # Multi-graph: write to a protected graph
63
+ roam save "Note" -g work --write-key "$ROAM_SYSTEM_WRITE_KEY"
84
64
  ```
85
65
 
86
- ## Standalone CLI: `roam`
87
-
88
- A standalone command-line tool for interacting with Roam Research directly, without running the MCP server. Provides eight subcommands: `get`, `search`, `save`, `refs`, `update`, `batch`, `rename`, and `status`.
89
-
90
- All content creation, update, and retrieval commands support **standard input (stdin) piping**, allowing for powerful automation workflows (e.g., `cat notes.md | roam save`, `roam search "query" | roam get`).
66
+ **Available Commands:** `get`, `search`, `save`, `refs`, `update`, `batch`, `rename`, `status`.
67
+ Run `roam <command> --help` for details on any command.
91
68
 
92
69
  ### Installation
93
70
 
94
- After building the project, make the command globally available:
95
-
96
- ```bash
97
- npm link
98
- ```
99
-
100
- Or run directly without linking:
101
-
102
71
  ```bash
103
- node build/cli/roam.js <command> [options]
72
+ npm install -g roam-research-mcp
73
+ # The 'roam' command is now available globally
104
74
  ```
105
75
 
106
- ### Requirements
107
-
108
- Same environment variables as the MCP server:
109
- - `ROAM_API_TOKEN`: Your Roam Research API token
110
- - `ROAM_GRAPH_NAME`: Your Roam graph name
111
-
112
- Configure via `.env` file in the project root or set as environment variables.
113
-
114
76
  ---
115
77
 
116
- ### `roam get` - Fetch pages, blocks, or TODOs
117
-
118
- Fetch content from Roam and output as markdown or JSON.
119
-
120
- ```bash
121
- # Fetch a page by title
122
- roam get "Daily Notes"
123
-
124
- # Fetch a block by UID
125
- roam get "((AbCdEfGhI))"
126
- roam get AbCdEfGhI
127
-
128
- # Output as JSON
129
- roam get "Daily Notes" --json
130
-
131
- # Control child depth (default: 4)
132
- roam get "Daily Notes" --depth 2
133
-
134
- # Flatten hierarchy
135
- roam get "Daily Notes" --flat
136
-
137
- # Fetch TODO items
138
- roam get --todo
139
-
140
- # Fetch DONE items
141
- roam get --done
142
-
143
- # Filter TODOs by page
144
- roam get --todo -p "January 2nd, 2026"
145
-
146
- # Include/exclude filter
147
- roam get --todo -i "urgent,important" -e "someday"
148
-
149
- # Debug mode
150
- roam get "Daily Notes" --debug
151
- ```
152
-
153
- **Options:**
154
- - `--json` - Output as JSON instead of markdown
155
- - `--depth <n>` - Child levels to fetch (default: 4)
156
- - `--refs <n>` - Block ref expansion depth (default: 1)
157
- - `--flat` - Flatten hierarchy to single-level list
158
- - `--todo` - Fetch TODO items
159
- - `--done` - Fetch DONE items
160
- - `-p, --page <title>` - Filter TODOs/DONEs by page title
161
- - `-i, --include <terms>` - Include only items containing these terms (comma-separated)
162
- - `-e, --exclude <terms>` - Exclude items containing these terms (comma-separated)
163
- - `--debug` - Show query metadata
78
+ ## MCP Server Tools
79
+
80
+ The MCP server exposes these tools to AI assistants (like Claude), enabling them to read, write, and organize your Roam graph intelligently.
81
+
82
+ > **Multi-Graph Support:** All tools accept optional `graph` and `write_key` parameters. Use `graph` to target a specific graph from your `ROAM_GRAPHS` config, and `write_key` for write operations on protected graphs.
83
+
84
+ | Tool Name | Description |
85
+ | :--- | :--- |
86
+ | `roam_fetch_page_by_title` | Fetch page content by title. |
87
+ | `roam_fetch_block_with_children` | Fetch a block and its nested children by UID (resolves refs). |
88
+ | `roam_create_page` | Create new pages, optionally with mixed text and table content. |
89
+ | `roam_update_page_markdown` | Update a page using smart diff (preserves block UIDs). |
90
+ | `roam_search_by_text` | Full-text search across the graph or within specific pages. Supports namespace prefix search for page titles. |
91
+ | `roam_search_block_refs` | Find blocks that reference a page, tag, or block UID. |
92
+ | `roam_search_by_status` | Find TODO or DONE items. |
93
+ | `roam_search_for_tag` | Find blocks containing specific tags (supports exclusion). |
94
+ | `roam_search_by_date` | Find blocks/pages by creation or modification date. |
95
+ | `roam_find_pages_modified_today` | List pages modified since midnight. |
96
+ | `roam_add_todo` | Add TODO items to today's daily page. |
97
+ | `roam_create_table` | Create properly formatted Roam tables. |
98
+ | `roam_create_outline` | Create hierarchical outlines. |
99
+ | `roam_process_batch_actions` | Execute multiple low-level actions (create, move, update, delete) in one batch. |
100
+ | `roam_move_block` | Move a block to a new parent or position. |
101
+ | `roam_remember` / `roam_recall` | specialized tools for AI memory management within Roam. |
102
+ | `roam_datomic_query` | Execute raw Datalog queries for advanced filtering. |
103
+ | `roam_markdown_cheatsheet` | Retrieve the Roam-flavored markdown reference. |
164
104
 
165
105
  ---
166
106
 
167
- ### `roam search` - Search content
168
-
169
- Search for blocks containing text or tags.
170
-
171
- ```bash
172
- # Full-text search
173
- roam search "keyword"
174
-
175
- # Multiple terms (AND logic)
176
- roam search "term1" "term2"
107
+ ## Configuration
177
108
 
178
- # Tag-only search
179
- roam search --tag "[[Project]]"
180
- roam search --tag "#TODO"
109
+ ### Environment Variables
181
110
 
182
- # Text + tag filter
183
- roam search "meeting" --tag "[[Work]]"
111
+ #### Single Graph Mode
184
112
 
185
- # Scope to a specific page
186
- roam search "task" --page "Daily Notes"
187
-
188
- # Case-insensitive search
189
- roam search "keyword" -i
190
-
191
- # Limit results (default: 20)
192
- roam search "keyword" -n 50
193
-
194
- # Output as JSON
195
- roam search "keyword" --json
196
- ```
197
-
198
- **Options:**
199
- - `--tag <tag>` - Filter by tag (e.g., `#TODO` or `[[Project]]`)
200
- - `--page <title>` - Scope search to a specific page
201
- - `-i, --case-insensitive` - Case-insensitive search
202
- - `-n, --limit <n>` - Limit number of results (default: 20)
203
- - `--json` - Output as JSON
204
- - `--debug` - Show query metadata
205
-
206
- ---
207
-
208
- ### `roam save` - Import markdown or create TODOs
209
-
210
- Import markdown content to Roam, creating or updating pages, or add TODO items.
113
+ For a single Roam graph, set these in your environment or a `.env` file:
211
114
 
212
115
  ```bash
213
- # From a file (title derived from filename)
214
- roam save document.md
215
-
216
- # With explicit title
217
- roam save document.md --title "Meeting Notes"
218
-
219
- # Update existing page with smart diff (preserves block UIDs)
220
- roam save document.md --update
221
-
222
- # From stdin (requires --title)
223
- cat notes.md | roam save --title "Quick Notes"
224
- pbpaste | roam save --title "Clipboard Content"
225
-
226
- # From here-doc
227
- roam save --title "Quick Note" << EOF
228
- # Heading
229
- - Item 1
230
- - Item 2
231
- - Nested item
232
- EOF
233
-
234
- # Create a TODO item on today's daily page
235
- roam save --todo "Buy groceries"
236
-
237
- # Create multiple TODOs from stdin (newline-separated)
238
- echo -e "Task 1\nTask 2\nTask 3" | roam save --todo
239
-
240
- # Pipe TODO list from file
241
- cat todos.txt | roam save --todo
116
+ ROAM_API_TOKEN=your-api-token
117
+ ROAM_GRAPH_NAME=your-graph-name
242
118
  ```
243
119
 
244
- **Options:**
245
- - `--title <title>` - Page title (defaults to filename without `.md`)
246
- - `--update` - Update existing page using smart diff (preserves block UIDs)
247
- - `-t, --todo [text]` - Add a TODO item to today's daily page (text or stdin)
248
- - `--debug` - Show debug information
249
-
250
- **Features:**
251
- - Creates a new page with the specified title (or appends to existing page)
252
- - Automatically links the new page from today's daily page
253
- - Converts standard markdown to Roam-flavored markdown
254
- - Smart diff mode (`--update`) preserves block UIDs for existing content
255
- - TODO mode creates `{{[[TODO]]}}` items on the daily page
256
-
257
- ---
258
-
259
- ### `roam refs` - Find references
120
+ #### Multi-Graph Mode (v2.0+)
260
121
 
261
- Find blocks that reference a page or block (backlinks).
122
+ Connect to multiple Roam graphs from a single server instance:
262
123
 
263
124
  ```bash
264
- # Find references to a page
265
- roam refs "Project Alpha"
266
- roam refs "December 30th, 2025"
267
-
268
- # Find references to a tag
269
- roam refs "#TODO"
270
- roam refs "[[Meeting Notes]]"
271
-
272
- # Find references to a block
273
- roam refs "((AbCdEfGhI))"
274
-
275
- # Limit results
276
- roam refs "My Page" -n 100
277
-
278
- # Output as JSON (for LLM/programmatic use)
279
- roam refs "My Page" --json
280
-
281
- # Raw output (for piping)
282
- roam refs "My Page" --raw
125
+ ROAM_GRAPHS='{
126
+ "personal": {"token": "token-1", "graph": "personal-db", "memoriesTag": "#[[Personal Memories]]"},
127
+ "work": {"token": "token-2", "graph": "work-db", "protected": true, "memoriesTag": "#[[Work Memories]]"},
128
+ "research": {"token": "token-3", "graph": "research-db"}
129
+ }'
130
+ ROAM_DEFAULT_GRAPH=personal
131
+ ROAM_SYSTEM_WRITE_KEY=your-secret-key
283
132
  ```
284
133
 
285
- **Options:**
286
- - `-n, --limit <n>` - Limit number of results (default: 50)
287
- - `--json` - Output as JSON array
288
- - `--raw` - Output raw UID + content lines (no grouping)
289
- - `--debug` - Show query metadata
290
-
291
- **Output Formats:**
134
+ **Graph Configuration Options:**
292
135
 
293
- Default output groups results by page:
294
- ```
295
- [[Reading List: Inbox]]
296
- tiTqNBvYA Date Captured:: [[December 30th, 2025]]
297
-
298
- [[Week 53, 2025]]
299
- g0ur1z7Bs [Sun 28]([[December 28th, 2025]]) | [Mon 29](...
300
- ```
136
+ | Property | Required | Description |
137
+ |----------|----------|-------------|
138
+ | `token` | Yes | Roam API token for this graph |
139
+ | `graph` | Yes | Graph name/database identifier |
140
+ | `protected` | No | If `true`, writes require `ROAM_SYSTEM_WRITE_KEY` confirmation |
141
+ | `memoriesTag` | No | Tag for `roam_remember`/`roam_recall` (overrides global default) |
301
142
 
302
- JSON output for programmatic use:
303
- ```json
304
- [
305
- {"uid": "tiTqNBvYA", "content": "Date Captured:: [[December 30th, 2025]]", "page": "Reading List: Inbox"}
306
- ]
307
- ```
143
+ **Write Protection:**
144
+ Protected graphs require the `write_key` parameter matching `ROAM_SYSTEM_WRITE_KEY` for any write operation. This prevents accidental writes to sensitive graphs.
308
145
 
309
- ---
146
+ *Optional:*
147
+ - `ROAM_MEMORIES_TAG`: Default tag for `roam_remember`/`roam_recall` (fallback when per-graph `memoriesTag` not set).
148
+ - `HTTP_STREAM_PORT`: To enable HTTP Stream (defaults to 8088).
310
149
 
311
- ### `roam batch` - Execute multiple operations in one API call
150
+ ### Running the Server
312
151
 
313
- Execute multiple operations in a single batch API call to reduce rate limiting issues.
152
+ **1. Stdio Mode (Default)**
153
+ Best for local integration (e.g., Claude Desktop, IDE extensions).
314
154
 
315
155
  ```bash
316
- # From a JSON file
317
- roam batch commands.json
318
-
319
- # From stdin
320
- cat commands.json | roam batch
321
-
322
- # Dry run (validate without executing)
323
- roam batch --dry-run commands.json
324
-
325
- # With debug output
326
- roam batch --debug commands.json
156
+ npx roam-research-mcp
327
157
  ```
328
158
 
329
- **Command Format:**
330
-
331
- Input is a JSON array of command objects:
332
-
333
- ```json
334
- [
335
- { "command": "create", "params": { "text": "Parent block", "parent": "pageUid", "as": "p1" } },
336
- { "command": "create", "params": { "text": "Child block", "parent": "{{p1}}" } },
337
- { "command": "todo", "params": { "text": "Task item" } },
338
- { "command": "codeblock", "params": { "parent": "{{p1}}", "language": "ts", "code": "const x = 1;" } }
339
- ]
340
- ```
341
-
342
- **Supported Commands:**
343
-
344
- | Command | Description |
345
- |---------|-------------|
346
- | `create` | Create a block |
347
- | `update` | Update block content |
348
- | `delete` | Delete a block |
349
- | `move` | Move block to new location |
350
- | `todo` | Create TODO item |
351
- | `table` | Create table structure |
352
- | `outline` | Create nested outline |
353
- | `remember` | Create tagged memory |
354
- | `page` | Create page with content |
355
- | `codeblock` | Create code block |
356
-
357
- **Features:**
358
-
359
- - Placeholder references (`{{name}}`) for cross-command dependencies
360
- - Automatic page title → UID resolution
361
- - Daily page auto-resolution for `todo` and `remember`
362
- - Level-based hierarchy for `outline` command
363
- - `--dry-run` mode for validation
364
-
365
- **Options:**
366
- - `--dry-run` - Validate and show planned actions without executing
367
- - `--debug` - Show debug information
368
- - `-g, --graph <name>` - Target graph (multi-graph mode)
369
- - `--write-key <key>` - Write confirmation key
370
-
371
- See [docs/batch-cli-spec.md](docs/batch-cli-spec.md) for full specification.
372
-
373
- ---
374
-
375
- ### `roam status` - Show available graphs
376
-
377
- Display configured graphs and their connection status.
159
+ **2. HTTP Stream Mode**
160
+ Best for remote access or web clients.
378
161
 
379
162
  ```bash
380
- # Show available graphs
381
- roam status
382
-
383
- # Test connectivity to all graphs
384
- roam status --ping
385
-
386
- # Output as JSON
387
- roam status --json
163
+ HTTP_STREAM_PORT=8088 npx roam-research-mcp
388
164
  ```
389
165
 
390
- **Example Output:**
391
-
392
- ```
393
- Roam Research MCP v2.4.0
394
-
395
- Graphs:
396
- • personal (default) ✓ connected
397
- • work [protected] ✓ connected
398
-
399
- Write-protected graphs require --write-key flag for modifications.
400
- ```
401
-
402
- **Options:**
403
- - `--ping` - Test connection to each graph
404
- - `--json` - Output as JSON for scripting
405
-
406
- ---
407
-
408
- ## To Test
409
-
410
- Run [MCP Inspector](https://github.com/modelcontextprotocol/inspector) after build using the provided npm script:
166
+ **3. Docker**
411
167
 
412
168
  ```bash
413
- npm run inspector
169
+ docker run -p 3000:3000 -p 8088:8088 --env-file .env roam-research-mcp
414
170
  ```
415
171
 
416
- ## Features
417
-
418
- The server provides powerful tools for interacting with Roam Research:
419
-
420
- - Environment variable handling with .env support
421
- - Comprehensive input validation
422
- - Case-insensitive page title matching
423
- - Recursive block reference resolution
424
- - Markdown parsing and conversion
425
- - Daily page integration
426
- - Detailed debug logging
427
- - Efficient batch operations
428
- - Hierarchical outline creation
429
- - Enhanced documentation for Roam Tables in `Roam_Markdown_Cheatsheet.md` for clearer guidance on nesting.
430
- - Custom instruction appended to the cheat sheet about your specific Roam notes.
431
-
432
- 1. `roam_fetch_page_by_title`: Fetch page content by title. Returns content in the specified format.
433
- 2. `roam_fetch_block_with_children`: Fetch a block by its UID along with its hierarchical children down to a specified depth. Automatically handles `((UID))` formatting.
434
- 3. `roam_create_page`: Create new pages with optional content and headings. **Now supports mixed content types** - content array can include both text blocks and tables in a single call using `{type: "table", headers, rows}` format. Automatically adds a "Processed: [[date]]" block at the end of the page linking to today's daily page.
435
- 4. `roam_create_table`: Create a properly formatted Roam table with specified headers and rows. Abstracts Roam's complex nested table structure, validates row/column consistency, and handles empty cells automatically.
436
- 5. `roam_import_markdown`: Import nested markdown content under a specific block. (Internally uses `roam_process_batch_actions`.)
437
- 6. `roam_add_todo`: Add a list of todo items to today's daily page. (Internally uses `roam_process_batch_actions`.)
438
- 7. `roam_create_outline`: Add a structured outline to an existing page or block, with support for `children_view_type`. Best for simpler, sequential outlines. For complex nesting (e.g., tables), consider `roam_process_batch_actions`. If `page_title_uid` and `block_text_uid` are both blank, content defaults to the daily page. (Internally uses `roam_process_batch_actions`.)
439
- 8. `roam_search_block_refs`: Search for block references within a page or across the entire graph. Now supports `title` parameter to find blocks referencing a page title using `:block/refs` (captures `[[page]]` and `#tag` links semantically).
440
- 9. `roam_search_hierarchy`: Search for parent or child blocks in the block hierarchy.
441
- 10. `roam_find_pages_modified_today`: Find pages that have been modified today (since midnight), with pagination and sorting options.
442
- 11. `roam_search_by_text`: Search for blocks containing specific text across all pages or within a specific page. This tool supports pagination via the `limit` and `offset` parameters.
443
- 12. `roam_search_by_status`: Search for blocks with a specific status (TODO/DONE) across all pages or within a specific page.
444
- 13. `roam_search_by_date`: Search for blocks or pages based on creation or modification dates.
445
- 14. `roam_search_for_tag`: Search for blocks containing a specific tag and optionally filter by blocks that also contain another tag nearby or exclude blocks with a specific tag. This tool supports pagination via the `limit` and `offset` parameters.
446
- 15. `roam_remember`: Add a memory or piece of information to remember. Supports optional `heading` parameter to nest under a specific heading on the daily page (created if missing), or `parent_uid` to nest under a specific block. Use `include_memories_tag: false` to omit the MEMORIES_TAG. (Internally uses `roam_process_batch_actions`.)
447
- 16. `roam_recall`: Retrieve all stored memories.
448
- 17. `roam_datomic_query`: Execute a custom Datomic query on the Roam graph for advanced data retrieval beyond the available search tools. Now supports client-side regex filtering for enhanced post-query processing. Optimal for complex filtering (including regex), highly complex boolean logic, arbitrary sorting criteria, and proximity search.
449
- 18. `roam_markdown_cheatsheet`: Provides the content of the Roam Markdown Cheatsheet resource, optionally concatenated with custom instructions if `CUSTOM_INSTRUCTIONS_PATH` environment variable is set.
450
- 19. `roam_process_batch_actions`: Execute a sequence of low-level block actions (create, update, move, delete) in a single, non-transactional batch. Provides granular control for complex nesting like tables. **Now includes pre-validation** that catches errors before API execution, with structured error responses and automatic rate limit retry with exponential backoff. (Note: For actions on existing blocks or within a specific page context, it is often necessary to first obtain valid page or block UIDs using tools like `roam_fetch_page_by_title`.)
451
- 20. `roam_update_page_markdown`: Update an existing page with new markdown content using smart diff. **Preserves block UIDs** where possible, keeping references intact across the graph. Uses three-phase matching (exact text → normalized → position fallback) to generate minimal operations. Supports `dry_run` mode to preview changes. Ideal for syncing external markdown files, AI-assisted content updates, and batch modifications without losing block references.
452
- 21. `roam_move_block`: Move a block to a new location (different parent or position). Convenience wrapper around `roam_process_batch_actions` for single block moves. Parameters: `block_uid` (required), `parent_uid` (required), `order` (optional, defaults to "last").
453
-
454
- **Deprecated Tools**:
455
- The following tools have been deprecated as of `v0.36.2` in favor of the more powerful and flexible `roam_process_batch_actions`:
456
-
457
- - `roam_create_block`: Use `roam_process_batch_actions` with the `create-block` action.
458
- - `roam_update_block`: Use `roam_process_batch_actions` with the `update-block` action.
459
- - `roam_update_multiple_blocks`: Use `roam_process_batch_actions` with multiple `update-block` actions.
460
-
461
- ---
462
-
463
- ### Tool Usage Guidelines and Best Practices
172
+ ### Configuring in LLMs
464
173
 
465
- **Pre-computation and Context Loading:**
466
- ✅ Before attempting any Roam operations, **it is highly recommended** to load the `Roam Markdown Cheatsheet` resource into your context. This ensures you have immediate access to the correct Roam-flavored Markdown syntax, including details for tables, block references, and other special formatting. Example prompt: "Read the Roam cheatsheet first. Then, … <rest of your instructions>"
174
+ **Claude Desktop / Cline:**
467
175
 
468
- - **Specific notes and preferences** concerning my Roam Research graph. Users can add their own specific notes and preferences for working with their own graph in the Cheatsheet.
469
-
470
- **Identifying Pages and Blocks for Manipulation:**
471
- To ensure accurate operations, always strive to identify target pages and blocks using their Unique Identifiers (UIDs) whenever possible. While some tools accept case-sensitive text titles or content, UIDs provide unambiguous references, reducing the risk of errors due to ambiguity or changes in text.
472
-
473
- - **For Pages:** Use `roam_fetch_page_by_title` to retrieve a page's UID if you only have its title. Example: "Read the page titled 'Trip to Las Vegas'"
474
- - **For Blocks:** If you need to manipulate an existing block, first use search tools like `roam_search_by_text`, `roam_search_for_tag`, or `roam_fetch_page_by_title` (with raw format) to find the block and obtain its UID. If the block exists on a page that has already been read, then a search isn't necessary.
475
-
476
- **Case-Sensitivity:**
477
- Be aware that text-based inputs (e.g., page titles, block content for search) are generally case-sensitive in Roam. Always match the exact casing of the text as it appears in your graph.
478
-
479
- **Iterative Refinement and Verification:**
480
- For complex operations, especially those involving nested structures or multiple changes, it is often beneficial to break down the task into smaller, verifiable steps. After each significant tool call, consider fetching the affected content to verify the changes before proceeding.
481
-
482
- **Understanding Tool Nuances:**
483
- Familiarize yourself with the specific behaviors and limitations of each tool. For instance, `roam_create_outline` is best for sequential outlines, while `roam_process_batch_actions` offers granular control for complex structures like tables. Refer to the individual tool descriptions for detailed usage notes.
484
-
485
- When making changes to your Roam graph, precision in your requests is crucial for achieving desired outcomes.
486
-
487
- **Specificity in Requests:**
488
- Some tools allow for identifying blocks or pages by their text content (e.g., `parent_string`, `title`). While convenient, using **Unique Identifiers (UIDs)** is always preferred for accuracy and reliability. Text-based matching can be prone to errors if there are multiple blocks with similar content or if the content changes. Tools are designed to work best when provided with explicit UIDs where available.
489
-
490
- **Example of Specificity:**
491
- Instead of:
492
- `"parent_string": "My project notes"`
493
-
494
- Prefer:
495
- `"parent_uid": "((some-unique-uid))"`
496
-
497
- **Caveat Regarding Heading Formatting:**
498
- Please note that while the `roam_process_batch_actions` tool can set block headings (H1, H2, H3), directly **removing** an existing heading (i.e., reverting a heading block to a plain text block) through this tool is not currently supported by the Roam API. The `heading` attribute persists its value once set, and attempting to remove it by setting `heading` to `0`, `null`, or omitting the property will not unset the heading.
499
-
500
- ---
176
+ Add to your MCP settings file (e.g., `~/Library/Application Support/Claude/claude_desktop_config.json`):
501
177
 
502
- ## Example Prompts
503
-
504
- Here are some examples of how to creatively use the Roam tool in an LLM to interact with your Roam graph, particularly leveraging `roam_process_batch_actions` for complex operations.
505
-
506
- ### Example 1: Creating a Project Outline
507
-
508
- This prompt demonstrates creating a new page and populating it with a structured outline using a single `roam_process_batch_actions` call.
509
-
510
- ```
511
- "Create a new Roam page titled 'Project Alpha Planning' and add the following outline:
512
- - Overview
513
- - Goals
514
- - Scope
515
- - Team Members
516
- - John Doe
517
- - Jane Smith
518
- - Tasks
519
- - Task 1
520
- - Subtask 1.1
521
- - Subtask 1.2
522
- - Task 2
523
- - Deadlines"
178
+ *Single Graph:*
179
+ ```json
180
+ {
181
+ "mcpServers": {
182
+ "roam-research": {
183
+ "command": "npx",
184
+ "args": ["-y", "roam-research-mcp"],
185
+ "env": {
186
+ "ROAM_API_TOKEN": "your-token",
187
+ "ROAM_GRAPH_NAME": "your-graph"
188
+ }
189
+ }
190
+ }
191
+ }
192
+ ```
193
+
194
+ *Multi-Graph:*
195
+ ```json
196
+ {
197
+ "mcpServers": {
198
+ "roam-research": {
199
+ "command": "npx",
200
+ "args": ["-y", "roam-research-mcp"],
201
+ "env": {
202
+ "ROAM_GRAPHS": "{\"personal\":{\"token\":\"token-1\",\"graph\":\"personal-db\",\"memoriesTag\":\"#[[Memories]]\"},\"work\":{\"token\":\"token-2\",\"graph\":\"work-db\",\"protected\":true}}",
203
+ "ROAM_DEFAULT_GRAPH": "personal",
204
+ "ROAM_SYSTEM_WRITE_KEY": "your-secret-key"
205
+ }
206
+ }
207
+ }
208
+ }
524
209
  ```
525
210
 
526
- ### Example 2: Updating Multiple To-Dos and Adding a New One
527
-
528
- This example shows how to mark existing to-do items as `DONE` and add a new one, all within a single batch.
211
+ ## Query Block Parser (v2.11.0+)
529
212
 
530
- ```
531
- "Mark 'Finish report' and 'Review presentation' as done on today's daily page, and add a new todo 'Prepare for meeting'."
532
- ```
213
+ A utility for parsing and executing Roam query blocks programmatically. Converts `{{[[query]]: ...}}` syntax into Datalog queries.
533
214
 
534
- ### Example 3: Moving and Updating a Block
215
+ ### Supported Clauses
535
216
 
536
- This demonstrates moving a block from one location to another and simultaneously updating its content.
217
+ | Clause | Syntax | Description |
218
+ |--------|--------|-------------|
219
+ | Page ref | `[[page]]` | Blocks referencing a page |
220
+ | Block ref | `((uid))` | Blocks referencing a block |
221
+ | `and` | `{and: [[a]] [[b]]}` | All conditions must match |
222
+ | `or` | `{or: [[a]] [[b]]}` | Any condition matches |
223
+ | `not` | `{not: [[tag]]}` | Exclude matches |
224
+ | `between` | `{between: [[date1]] [[date2]]}` | Date range filter |
225
+ | `search` | `{search: text}` | Full-text search |
226
+ | `daily notes` | `{daily notes: }` | Daily notes pages only |
227
+ | `by` | `{by: [[User]]}` | Created or edited by user |
228
+ | `created by` | `{created by: [[User]]}` | Created by user |
229
+ | `edited by` | `{edited by: User}` | Edited by user |
537
230
 
538
- ```
539
- "Move the block 'Important note about client feedback' (from page 'Meeting Notes 2025-06-30') under the 'Action Items' section on the 'Project Alpha Planning' page, and change its content to 'Client feedback reviewed and incorporated'."
540
- ```
231
+ ### Relative Dates
541
232
 
542
- ### Example 4: Making a Table
233
+ The `between` clause supports relative dates: `today`, `yesterday`, `last week`, `last month`, `this year`, `7 days ago`, `2 months ago`, etc.
543
234
 
544
- This demonstrates creating a standalone table on a page.
235
+ ### Usage
545
236
 
546
- ```
547
- "In Roam, add a new table on the page "Fruity Tables" that compares four types of fruits: apples, oranges, grapes, and dates. Choose randomly four areas to compare."
548
- ```
237
+ ```typescript
238
+ import { QueryExecutor } from 'roam-research-mcp/query';
549
239
 
550
- ### Example 5: Creating a Page with Mixed Content (Text + Table)
240
+ const executor = new QueryExecutor(graph);
551
241
 
552
- This demonstrates creating a new page with both text blocks and a table in a single call using `roam_create_page`.
242
+ // Execute a query
243
+ const results = await executor.execute(
244
+ '{{[[query]]: "My Query" {and: [[Project]] {between: [[last month]] [[today]]}}}}'
245
+ );
553
246
 
554
- ```
555
- "Create a new Roam page titled 'Product Comparison' with:
556
- - A heading 'Overview'
557
- - An introduction paragraph explaining the comparison
558
- - A comparison table with columns: Feature, Plan A, Plan B
559
- - Rows: Price ($10, $20), Storage (10GB, 50GB), Support (Email, 24/7)
560
- - A conclusion section"
247
+ // Parse without executing (for debugging)
248
+ const { name, query } = QueryParser.parseWithName(queryBlock);
561
249
  ```
562
250
 
563
- ### Example 6: Updating a Page with Smart Diff
251
+ ### Utility Functions
564
252
 
565
- This demonstrates updating an existing page while preserving block UIDs (and therefore block references across the graph).
253
+ ```typescript
254
+ import { isQueryBlock, extractQueryBlocks } from 'roam-research-mcp/query';
566
255
 
567
- ```
568
- "Update the 'Project Alpha Planning' page with this revised content, preserving block references:
569
- - Overview (keep existing UID)
570
- - Updated Goals section
571
- - Revised Scope with new details
572
- - Team Members
573
- - John Doe (Senior Dev)
574
- - Jane Smith (PM)
575
- - New hire: Bob Wilson
576
- - Updated Timeline
577
- - Remove the old 'Deadlines' section"
578
- ```
256
+ // Detect if text is a query block
257
+ isQueryBlock('{{[[query]]: [[tag]]}}'); // true
579
258
 
580
- The tool will match existing blocks by content, update changed text, add new blocks, and remove deleted ones - all while keeping UIDs stable for blocks that still exist.
259
+ // Extract all query blocks from a string
260
+ extractQueryBlocks(pageContent); // ['{{[[query]]: ...}}', ...]
261
+ ```
581
262
 
582
263
  ---
583
264
 
584
- ## Setup
585
-
586
- 1. Create a [Roam Research API token](https://x.com/RoamResearch/status/1789358175474327881):
587
-
588
- - Go to your graph settings
589
- - Navigate to the "API tokens" section (Settings > "Graph" tab > "API Tokens" section and click on the "+ New API Token" button)
590
- - Create a new token
591
-
592
- 2. Configure the environment variables:
593
-
594
- ### Single Graph Mode (Default)
595
-
596
- For most users with one Roam graph, use the simple configuration:
597
-
598
- **Option 1: Using a .env file (Recommended for development)**
265
+ ## Support
599
266
 
600
- Create a `.env` file in the roam-research directory:
267
+ If this project helps you manage your knowledge base or build cool agents, consider buying me a coffee! It helps keep the updates coming.
601
268
 
602
- ```
603
- ROAM_API_TOKEN=your-api-token
604
- ROAM_GRAPH_NAME=your-graph-name
605
- MEMORIES_TAG='#[[LLM/Memories]]'
606
- CUSTOM_INSTRUCTIONS_PATH='/path/to/your/custom_instructions_file.md'
607
- HTTP_STREAM_PORT=8088 # Or your desired port for HTTP Stream communication
608
- ```
269
+ <a href="https://paypal.me/2b3/5">
270
+ <img src="https://img.shields.io/badge/Donate-PayPal-blue.svg" alt="Donate with PayPal" />
271
+ </a>
609
272
 
610
- **Option 2: Using MCP settings (Alternative method)**
611
-
612
- Add the configuration to your MCP settings file. Note that you may need to update the `args` to `["/path/to/roam-research-mcp/build/index.js"]` if you are running the server directly.
613
-
614
- - For Cline (`~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`):
615
- - For Claude desktop app (`~/Library/Application Support/Claude/claude_desktop_config.json`):
616
-
617
- ```json
618
- {
619
- "mcpServers": {
620
- "roam-research": {
621
- "command": "node",
622
- "args": ["/path/to/roam-research-mcp/build/index.js"],
623
- "env": {
624
- "ROAM_API_TOKEN": "your-api-token",
625
- "ROAM_GRAPH_NAME": "your-graph-name",
626
- "MEMORIES_TAG": "#[[LLM/Memories]]",
627
- "CUSTOM_INSTRUCTIONS_PATH": "/path/to/your/custom_instructions_file.md",
628
- "HTTP_STREAM_PORT": "8088"
629
- }
630
- }
631
- }
632
- }
633
- ```
634
-
635
- Note: The server will first try to load from .env file, then fall back to environment variables from MCP settings.
636
-
637
- ---
638
-
639
- ### Multi-Graph Mode (v2.0.0+)
640
-
641
- For users with multiple Roam graphs, you can configure a single MCP server instance to connect to all of them. This is more token-efficient than running multiple server instances.
642
-
643
- **Configuration:**
644
-
645
- ```json
646
- ROAM_GRAPHS="{\"personal\":{\"token\":\"roam-graph-token-xxx\",\"graph\":\"my-personal-graph\"},\"work\":{\"token\":\"roam-graph-token-yyy\",\"graph\":\"company-graph\",\"write_key\":\"confirm-work-write\"}}"
647
- ROAM_DEFAULT_GRAPH=personal
648
- ```
649
-
650
- | Field | Required | Description |
651
- |-------|----------|-------------|
652
- | `token` | Yes | Roam API token for this graph |
653
- | `graph` | Yes | Roam graph name |
654
- | `write_key` | No | Required confirmation string for writes to non-default graphs |
655
-
656
- **Usage in Tools:**
657
-
658
- All tools accept optional `graph` and `write_key` parameters:
659
-
660
- ```json
661
- {
662
- "title": "My Page",
663
- "graph": "work",
664
- "write_key": "confirm-work-write"
665
- }
666
- ```
667
-
668
- - **Read operations**: Can target any graph using the `graph` parameter
669
- - **Write operations on default graph**: Work without additional parameters
670
- - **Write operations on non-default graphs**: Require the `write_key` if configured
671
-
672
- **CLI Usage:**
673
-
674
- All CLI commands support the `-g, --graph` flag:
675
-
676
- ```bash
677
- # Read from work graph
678
- roam get "Meeting Notes" -g work
679
-
680
- # Write to work graph (requires --write-key if configured)
681
- roam save notes.md -g work --write-key "confirm-work-write"
682
- ```
683
-
684
- **Safety Model:**
685
-
686
- The `write_key` serves as a confirmation gate (not a secret) to prevent accidental writes to non-default graphs. When a write is attempted without the required key, the error message reveals the expected key:
687
-
688
- ```
689
- Write to "work" graph requires write_key confirmation.
690
- Provide write_key: "confirm-work-write" to proceed.
691
- ```
692
-
693
- 3. Build the server (make sure you're in the root directory of the MCP):
694
-
695
- Note: Customize 'Roam_Markdown_Cheatsheet.md' with any notes and preferences specific to your graph BEFORE building.
696
-
697
- ```bash
698
- cd roam-research-mcp
699
- npm install
700
- npm run build
701
- ```
702
-
703
- ## Error Handling
704
-
705
- The server provides comprehensive error handling for common scenarios:
706
-
707
- - Configuration errors:
708
- - Missing API token or graph name
709
- - Invalid environment variables
710
- - API errors:
711
- - Authentication failures
712
- - Invalid requests
713
- - Failed operations
714
- - Tool-specific errors:
715
- - Page not found (with case-insensitive search)
716
- - Block not found by string match
717
- - Invalid markdown format
718
- - Missing required parameters
719
- - Invalid outline structure or content
720
-
721
- Each error response includes:
722
-
723
- - Standard MCP error code
724
- - Detailed error message
725
- - Suggestions for resolution when applicable
273
+ **[https://paypal.me/2b3/5](https://paypal.me/2b3/5)**
726
274
 
727
275
  ---
728
276
 
729
- ## Development
730
-
731
- ### Building
732
-
733
- To build the server:
734
-
735
- ```bash
736
- npm install
737
- npm run build
738
- ```
739
-
740
- This will:
741
-
742
- 1. Install all required dependencies
743
- 2. Compile TypeScript to JavaScript
744
- 3. Make the output file executable
745
-
746
- You can also use `npm run watch` during development to automatically recompile when files change.
747
-
748
- ### Testing with MCP Inspector
749
-
750
- The MCP Inspector is a tool that helps test and debug MCP servers. To test the server:
751
-
752
- ```bash
753
- # Inspect with npx:
754
- npx @modelcontextprotocol/inspector node build/index.js
755
- ```
756
-
757
- This will:
758
-
759
- 1. Start the server in inspector mode
760
- 2. Provide an interactive interface to:
761
- - List available tools and resources
762
- - Execute tools with custom parameters
763
- - View tool responses and error handling
764
-
765
277
  ## License
766
278
 
767
- MIT License
768
-
769
- ---
770
-
771
- ## About the Author
772
-
773
- This project is maintained by [Ian Shen](https://github.com/2b3pro).
279
+ MIT License - Created by [Ian Shen](https://github.com/2b3pro).