roam-research-mcp 0.12.3 → 0.17.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.
- package/README.md +270 -1
- package/build/config/environment.js +44 -0
- package/build/index.js +1 -823
- package/build/markdown-utils.js +151 -37
- package/build/search/block-ref-search.js +72 -0
- package/build/search/hierarchy-search.js +105 -0
- package/build/search/index.js +7 -0
- package/build/search/status-search.js +43 -0
- package/build/search/tag-search.js +35 -0
- package/build/search/text-search.js +32 -0
- package/build/search/types.js +7 -0
- package/build/search/utils.js +98 -0
- package/build/server/roam-server.js +178 -0
- package/build/test-addMarkdownText.js +1 -1
- package/build/tools/schemas.js +317 -0
- package/build/tools/tool-handlers.js +972 -0
- package/build/types/roam.js +1 -0
- package/build/utils/helpers.js +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
A Model Context Protocol (MCP) server that provides comprehensive access to Roam Research's API functionality. This server enables AI assistants like Claude to interact with your Roam Research graph through a standardized interface.
|
|
8
8
|
|
|
9
|
+
<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>
|
|
10
|
+
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
11
13
|
You can install the package globally:
|
|
@@ -25,13 +27,19 @@ npm run build
|
|
|
25
27
|
|
|
26
28
|
## Features
|
|
27
29
|
|
|
28
|
-
The server provides
|
|
30
|
+
The server provides eleven powerful tools for interacting with Roam Research:
|
|
29
31
|
|
|
30
32
|
1. `roam_fetch_page_by_title`: Fetch and read a page's content by title, recursively resolving block references up to 4 levels deep
|
|
31
33
|
2. `roam_create_page`: Create new pages with optional content
|
|
32
34
|
3. `roam_create_block`: Create new blocks in a page (defaults to today's daily page)
|
|
33
35
|
4. `roam_import_markdown`: Import nested markdown content under specific blocks
|
|
34
36
|
5. `roam_add_todo`: Add multiple todo items to today's daily page with checkbox syntax
|
|
37
|
+
6. `roam_create_outline`: Create hierarchical outlines with proper nesting and structure
|
|
38
|
+
7. `roam_search_block_refs`: Search for block references within pages or across the graph
|
|
39
|
+
8. `roam_search_hierarchy`: Navigate and search through block parent-child relationships
|
|
40
|
+
9. `find_pages_modified_today`: Find all pages that have been modified since midnight today
|
|
41
|
+
10. `roam_search_by_text`: Search for blocks containing specific text across all pages or within a specific page
|
|
42
|
+
11. `roam_update_block`: Update block content with direct text or pattern-based transformations
|
|
35
43
|
|
|
36
44
|
## Setup
|
|
37
45
|
|
|
@@ -158,6 +166,59 @@ Returns:
|
|
|
158
166
|
}
|
|
159
167
|
```
|
|
160
168
|
|
|
169
|
+
### Create Outline
|
|
170
|
+
|
|
171
|
+
Create a hierarchical outline with proper nesting and structure:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
use_mcp_tool roam-research roam_create_outline {
|
|
175
|
+
"outline": [
|
|
176
|
+
{
|
|
177
|
+
"text": "I. Top Level",
|
|
178
|
+
"level": 1
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"text": "A. Second Level",
|
|
182
|
+
"level": 2
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"text": "1. Third Level",
|
|
186
|
+
"level": 3
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
"page_title_uid": "optional-target-page",
|
|
190
|
+
"block_text_uid": "optional-header-text"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Features:
|
|
195
|
+
|
|
196
|
+
- Create complex outlines with up to 10 levels of nesting
|
|
197
|
+
- Validate outline structure and content
|
|
198
|
+
- Maintain proper parent-child relationships
|
|
199
|
+
- Optional header block for the outline
|
|
200
|
+
- Defaults to today's daily page if no page specified
|
|
201
|
+
- Efficient batch operations for creating blocks
|
|
202
|
+
|
|
203
|
+
Parameters:
|
|
204
|
+
|
|
205
|
+
- `outline`: Array of outline items, each with:
|
|
206
|
+
- `text`: Content of the outline item (required)
|
|
207
|
+
- `level`: Nesting level (1-10, required)
|
|
208
|
+
- `page_title_uid`: Target page title or UID (optional, defaults to today's page)
|
|
209
|
+
- `block_text_uid`: Header text for the outline (optional)
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"success": true,
|
|
216
|
+
"page_uid": "target-page-uid",
|
|
217
|
+
"parent_uid": "header-block-uid",
|
|
218
|
+
"created_uids": ["uid1", "uid2", ...]
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
161
222
|
### Add Todo Items
|
|
162
223
|
|
|
163
224
|
Add one or more todo items to today's daily page:
|
|
@@ -224,6 +285,212 @@ Parameters:
|
|
|
224
285
|
- `parent_string`: Exact string content of the parent block (must provide either page_uid or page_title)
|
|
225
286
|
- `order`: Where to add the content ("first" or "last", defaults to "first")
|
|
226
287
|
|
|
288
|
+
### Search Block References
|
|
289
|
+
|
|
290
|
+
Search for block references within pages or across the entire graph:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
use_mcp_tool roam-research roam_search_block_refs {
|
|
294
|
+
"block_uid": "optional-block-uid",
|
|
295
|
+
"page_title_uid": "optional-page-title-or-uid"
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Features:
|
|
300
|
+
|
|
301
|
+
- Find all references to a specific block
|
|
302
|
+
- Search for any block references within a page
|
|
303
|
+
- Search across the entire graph
|
|
304
|
+
- Supports both direct and indirect references
|
|
305
|
+
- Includes block content and location context
|
|
306
|
+
|
|
307
|
+
Parameters:
|
|
308
|
+
|
|
309
|
+
- `block_uid`: UID of the block to find references to (optional)
|
|
310
|
+
- `page_title_uid`: Title or UID of the page to search in (optional)
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"success": true,
|
|
317
|
+
"matches": [
|
|
318
|
+
{
|
|
319
|
+
"block_uid": "referenced-block-uid",
|
|
320
|
+
"content": "Block content with ((reference))",
|
|
321
|
+
"page_title": "Page containing reference"
|
|
322
|
+
}
|
|
323
|
+
],
|
|
324
|
+
"message": "Found N block(s) referencing..."
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Search By Text
|
|
329
|
+
|
|
330
|
+
Search for blocks containing specific text across all pages or within a specific page:
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
use_mcp_tool roam-research roam_search_by_text {
|
|
334
|
+
"text": "search text",
|
|
335
|
+
"page_title_uid": "optional-page-title-or-uid",
|
|
336
|
+
"case_sensitive": false
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Features:
|
|
341
|
+
|
|
342
|
+
- Search for any text across all blocks in the graph
|
|
343
|
+
- Optional page-scoped search
|
|
344
|
+
- Case-sensitive or case-insensitive search
|
|
345
|
+
- Returns block content with page context
|
|
346
|
+
- Efficient text matching using Datalog queries
|
|
347
|
+
|
|
348
|
+
Parameters:
|
|
349
|
+
|
|
350
|
+
- `text`: The text to search for (required)
|
|
351
|
+
- `page_title_uid`: Title or UID of the page to search in (optional)
|
|
352
|
+
- `case_sensitive`: Whether to perform a case-sensitive search (optional, default: false)
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"success": true,
|
|
359
|
+
"matches": [
|
|
360
|
+
{
|
|
361
|
+
"block_uid": "matching-block-uid",
|
|
362
|
+
"content": "Block content containing search text",
|
|
363
|
+
"page_title": "Page containing block"
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
"message": "Found N block(s) containing \"search text\""
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Update Block Content
|
|
371
|
+
|
|
372
|
+
Update a block's content using either direct text replacement or pattern-based transformations:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
use_mcp_tool roam-research roam_update_block {
|
|
376
|
+
"block_uid": "target-block-uid",
|
|
377
|
+
"content": "New block content"
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Or use pattern-based transformation:
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
use_mcp_tool roam-research roam_update_block {
|
|
385
|
+
"block_uid": "target-block-uid",
|
|
386
|
+
"transform_pattern": {
|
|
387
|
+
"find": "\\bPython\\b",
|
|
388
|
+
"replace": "[[Python]]",
|
|
389
|
+
"global": true
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Features:
|
|
395
|
+
|
|
396
|
+
- Two update modes:
|
|
397
|
+
- Direct content replacement
|
|
398
|
+
- Pattern-based transformation using regex
|
|
399
|
+
- Verify block existence before updating
|
|
400
|
+
- Return updated content in response
|
|
401
|
+
- Support for global or single-match replacements
|
|
402
|
+
- Preserve block relationships and metadata
|
|
403
|
+
|
|
404
|
+
Parameters:
|
|
405
|
+
|
|
406
|
+
- `block_uid`: UID of the block to update (required)
|
|
407
|
+
- `content`: New content for the block (if using direct replacement)
|
|
408
|
+
- `transform_pattern`: Pattern for transforming existing content:
|
|
409
|
+
- `find`: Text or regex pattern to find
|
|
410
|
+
- `replace`: Text to replace with
|
|
411
|
+
- `global`: Whether to replace all occurrences (default: true)
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
|
|
415
|
+
```json
|
|
416
|
+
{
|
|
417
|
+
"success": true,
|
|
418
|
+
"content": "Updated block content"
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Find Pages Modified Today
|
|
423
|
+
|
|
424
|
+
Find all pages that have been modified since midnight today:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
use_mcp_tool roam-research find_pages_modified_today {}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Features:
|
|
431
|
+
|
|
432
|
+
- Tracks all modifications made to pages since midnight
|
|
433
|
+
- Detects changes at any level in the block hierarchy
|
|
434
|
+
- Returns unique list of modified page titles
|
|
435
|
+
- Includes count of modified pages
|
|
436
|
+
- No parameters required
|
|
437
|
+
|
|
438
|
+
Returns:
|
|
439
|
+
|
|
440
|
+
```json
|
|
441
|
+
{
|
|
442
|
+
"success": true,
|
|
443
|
+
"pages": ["Page 1", "Page 2"],
|
|
444
|
+
"message": "Found 2 page(s) modified today"
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Search Block Hierarchy
|
|
449
|
+
|
|
450
|
+
Navigate and search through block parent-child relationships:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
use_mcp_tool roam-research roam_search_hierarchy {
|
|
454
|
+
"parent_uid": "optional-parent-block-uid",
|
|
455
|
+
"child_uid": "optional-child-block-uid",
|
|
456
|
+
"page_title_uid": "optional-page-title-or-uid",
|
|
457
|
+
"max_depth": 3
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Features:
|
|
462
|
+
|
|
463
|
+
- Search up or down the block hierarchy
|
|
464
|
+
- Find children of a specific block
|
|
465
|
+
- Find parents of a specific block
|
|
466
|
+
- Configure search depth (1-10 levels)
|
|
467
|
+
- Optional page scope filtering
|
|
468
|
+
- Includes depth information for each result
|
|
469
|
+
|
|
470
|
+
Parameters:
|
|
471
|
+
|
|
472
|
+
- `parent_uid`: UID of the block to find children of (required if searching down)
|
|
473
|
+
- `child_uid`: UID of the block to find parents of (required if searching up)
|
|
474
|
+
- `page_title_uid`: Title or UID of the page to search in (optional)
|
|
475
|
+
- `max_depth`: How many levels deep to search (optional, default: 1, max: 10)
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"success": true,
|
|
482
|
+
"matches": [
|
|
483
|
+
{
|
|
484
|
+
"block_uid": "related-block-uid",
|
|
485
|
+
"content": "Block content",
|
|
486
|
+
"depth": 2,
|
|
487
|
+
"page_title": "Page containing block"
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
"message": "Found N block(s) as children/parents..."
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
227
494
|
## Error Handling
|
|
228
495
|
|
|
229
496
|
The server provides comprehensive error handling for common scenarios:
|
|
@@ -240,6 +507,7 @@ The server provides comprehensive error handling for common scenarios:
|
|
|
240
507
|
- Block not found by string match
|
|
241
508
|
- Invalid markdown format
|
|
242
509
|
- Missing required parameters
|
|
510
|
+
- Invalid outline structure or content
|
|
243
511
|
|
|
244
512
|
Each error response includes:
|
|
245
513
|
|
|
@@ -259,6 +527,7 @@ The server is built with TypeScript and includes:
|
|
|
259
527
|
- Daily page integration
|
|
260
528
|
- Detailed debug logging
|
|
261
529
|
- Efficient batch operations
|
|
530
|
+
- Hierarchical outline creation
|
|
262
531
|
|
|
263
532
|
To modify or extend the server:
|
|
264
533
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as dotenv from 'dotenv';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
// Get the project root from the script path
|
|
5
|
+
const scriptPath = process.argv[1]; // Full path to the running script
|
|
6
|
+
const projectRoot = dirname(dirname(scriptPath)); // Go up two levels from build/index.js
|
|
7
|
+
// Try to load .env from project root
|
|
8
|
+
const envPath = join(projectRoot, '.env');
|
|
9
|
+
if (existsSync(envPath)) {
|
|
10
|
+
dotenv.config({ path: envPath });
|
|
11
|
+
}
|
|
12
|
+
// Required environment variables
|
|
13
|
+
const API_TOKEN = process.env.ROAM_API_TOKEN;
|
|
14
|
+
const GRAPH_NAME = process.env.ROAM_GRAPH_NAME;
|
|
15
|
+
// Validate environment variables
|
|
16
|
+
if (!API_TOKEN || !GRAPH_NAME) {
|
|
17
|
+
const missingVars = [];
|
|
18
|
+
if (!API_TOKEN)
|
|
19
|
+
missingVars.push('ROAM_API_TOKEN');
|
|
20
|
+
if (!GRAPH_NAME)
|
|
21
|
+
missingVars.push('ROAM_GRAPH_NAME');
|
|
22
|
+
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}\n\n` +
|
|
23
|
+
'Please configure these variables either:\n' +
|
|
24
|
+
'1. In your MCP settings file:\n' +
|
|
25
|
+
' - For Cline: ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n' +
|
|
26
|
+
' - For Claude: ~/Library/Application Support/Claude/claude_desktop_config.json\n\n' +
|
|
27
|
+
' Example configuration:\n' +
|
|
28
|
+
' {\n' +
|
|
29
|
+
' "mcpServers": {\n' +
|
|
30
|
+
' "roam-research": {\n' +
|
|
31
|
+
' "command": "node",\n' +
|
|
32
|
+
' "args": ["/path/to/roam-research/build/index.js"],\n' +
|
|
33
|
+
' "env": {\n' +
|
|
34
|
+
' "ROAM_API_TOKEN": "your-api-token",\n' +
|
|
35
|
+
' "ROAM_GRAPH_NAME": "your-graph-name"\n' +
|
|
36
|
+
' }\n' +
|
|
37
|
+
' }\n' +
|
|
38
|
+
' }\n' +
|
|
39
|
+
' }\n\n' +
|
|
40
|
+
'2. Or in a .env file in the roam-research directory:\n' +
|
|
41
|
+
' ROAM_API_TOKEN=your-api-token\n' +
|
|
42
|
+
' ROAM_GRAPH_NAME=your-graph-name');
|
|
43
|
+
}
|
|
44
|
+
export { API_TOKEN, GRAPH_NAME };
|