roam-research-mcp 0.25.5 → 0.25.7
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 +49 -19
- package/build/server/roam-server.js +48 -27
- package/build/tools/schemas.js +18 -15
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -26,12 +26,42 @@ npm install
|
|
|
26
26
|
npm run build
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Docker
|
|
30
|
+
|
|
31
|
+
This project can be easily containerized using Docker. A `Dockerfile` is provided at the root of the repository.
|
|
32
|
+
|
|
33
|
+
### Build the Docker Image
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
To build the Docker image, navigate to the project root and run:
|
|
32
36
|
|
|
37
|
+
```bash
|
|
38
|
+
docker build -t roam-research-mcp .
|
|
33
39
|
```
|
|
34
|
-
|
|
40
|
+
|
|
41
|
+
### Run the Docker Container
|
|
42
|
+
|
|
43
|
+
To run the Docker container and map port 3000 (if your application uses it), you must also provide the necessary environment variables. Use the `-e` flag to pass `ROAM_API_TOKEN`, `ROAM_GRAPH_NAME`, and optionally `MEMORIES_TAG`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker run -p 3000:3000 \
|
|
47
|
+
-e ROAM_API_TOKEN="your-api-token" \
|
|
48
|
+
-e ROAM_GRAPH_NAME="your-graph-name" \
|
|
49
|
+
-e MEMORIES_TAG="#[[LLM/Memories]]" \
|
|
50
|
+
roam-research-mcp
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
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:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
docker run -p 3000:3000 --env-file .env roam-research-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## To Test
|
|
60
|
+
|
|
61
|
+
Run [MCP Inspector](https://github.com/modelcontextprotocol/inspector) after build using the provided npm script:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm run inspector
|
|
35
65
|
```
|
|
36
66
|
|
|
37
67
|
## Features
|
|
@@ -48,22 +78,22 @@ The server provides powerful tools for interacting with Roam Research:
|
|
|
48
78
|
- Efficient batch operations
|
|
49
79
|
- Hierarchical outline creation
|
|
50
80
|
|
|
51
|
-
1. `roam_fetch_page_by_title`: Fetch
|
|
52
|
-
2. `roam_create_page`: Create new pages with optional content
|
|
53
|
-
3. `roam_create_block`:
|
|
54
|
-
4. `roam_import_markdown`: Import nested markdown content under specific
|
|
55
|
-
5. `roam_add_todo`: Add
|
|
56
|
-
6. `roam_create_outline`:
|
|
57
|
-
7. `roam_search_block_refs`: Search for block references within
|
|
58
|
-
8. `roam_search_hierarchy`:
|
|
59
|
-
9. `roam_find_pages_modified_today`: Find
|
|
60
|
-
10. `roam_search_by_text`: Search for blocks containing specific text
|
|
61
|
-
11. `roam_update_block`: Update
|
|
62
|
-
12. `roam_search_by_date`: Search for blocks
|
|
63
|
-
13. `roam_search_for_tag`: Search for blocks containing specific
|
|
64
|
-
14. `roam_remember`:
|
|
65
|
-
15. `roam_recall`:
|
|
66
|
-
16. `roam_datomic_query`: Execute custom
|
|
81
|
+
1. `roam_fetch_page_by_title`: Fetch page content by title.
|
|
82
|
+
2. `roam_create_page`: Create new pages with optional content and headings.
|
|
83
|
+
3. `roam_create_block`: Add new blocks to an existing page or today's daily note.
|
|
84
|
+
4. `roam_import_markdown`: Import nested markdown content under a specific block.
|
|
85
|
+
5. `roam_add_todo`: Add a list of todo items to today's daily page.
|
|
86
|
+
6. `roam_create_outline`: Add a structured outline to an existing page or block.
|
|
87
|
+
7. `roam_search_block_refs`: Search for block references within a page or across the entire graph.
|
|
88
|
+
8. `roam_search_hierarchy`: Search for parent or child blocks in the block hierarchy.
|
|
89
|
+
9. `roam_find_pages_modified_today`: Find pages that have been modified today (since midnight).
|
|
90
|
+
10. `roam_search_by_text`: Search for blocks containing specific text.
|
|
91
|
+
11. `roam_update_block`: Update a single block identified by its UID.
|
|
92
|
+
12. `roam_search_by_date`: Search for blocks or pages based on creation or modification dates.
|
|
93
|
+
13. `roam_search_for_tag`: Search for blocks containing a specific tag and optionally filter by blocks that also contain another tag nearby.
|
|
94
|
+
14. `roam_remember`: Add a memory or piece of information to remember.
|
|
95
|
+
15. `roam_recall`: Retrieve all stored memories.
|
|
96
|
+
16. `roam_datomic_query`: Execute a custom Datomic query on the Roam graph beyond the available search tools.
|
|
67
97
|
|
|
68
98
|
## Setup
|
|
69
99
|
|
|
@@ -5,43 +5,58 @@ import { initializeGraph } from '@roam-research/roam-api-sdk';
|
|
|
5
5
|
import { API_TOKEN, GRAPH_NAME } from '../config/environment.js';
|
|
6
6
|
import { toolSchemas } from '../tools/schemas.js';
|
|
7
7
|
import { ToolHandlers } from '../tools/tool-handlers.js';
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
// Read package.json to get the version
|
|
14
|
+
const packageJsonPath = join(__dirname, '../../package.json');
|
|
15
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
16
|
+
const serverVersion = packageJson.version;
|
|
8
17
|
export class RoamServer {
|
|
9
18
|
constructor() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
try {
|
|
20
|
+
this.graph = initializeGraph({
|
|
21
|
+
token: API_TOKEN,
|
|
22
|
+
graph: GRAPH_NAME,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
27
|
+
throw new McpError(ErrorCode.InternalError, `Failed to initialize Roam graph: ${errorMessage}`);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
this.toolHandlers = new ToolHandlers(this.graph);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
34
|
+
throw new McpError(ErrorCode.InternalError, `Failed to initialize tool handlers: ${errorMessage}`);
|
|
35
|
+
}
|
|
36
|
+
// Ensure toolSchemas is not empty before proceeding
|
|
37
|
+
if (Object.keys(toolSchemas).length === 0) {
|
|
38
|
+
throw new McpError(ErrorCode.InternalError, 'No tool schemas defined in src/tools/schemas.ts');
|
|
39
|
+
}
|
|
15
40
|
this.server = new Server({
|
|
16
41
|
name: 'roam-research',
|
|
17
|
-
version:
|
|
42
|
+
version: serverVersion, // Use the version from package.json
|
|
18
43
|
}, {
|
|
19
44
|
capabilities: {
|
|
20
45
|
tools: {
|
|
21
|
-
|
|
22
|
-
roam_recall: {},
|
|
23
|
-
roam_add_todo: {},
|
|
24
|
-
roam_fetch_page_by_title: {},
|
|
25
|
-
roam_create_page: {},
|
|
26
|
-
roam_create_block: {},
|
|
27
|
-
roam_import_markdown: {},
|
|
28
|
-
roam_create_outline: {},
|
|
29
|
-
roam_search_for_tag: {},
|
|
30
|
-
roam_search_by_status: {},
|
|
31
|
-
roam_search_block_refs: {},
|
|
32
|
-
roam_search_hierarchy: {},
|
|
33
|
-
roam_find_pages_modified_today: {},
|
|
34
|
-
roam_search_by_text: {},
|
|
35
|
-
roam_update_block: {},
|
|
36
|
-
roam_update_multiple_blocks: {},
|
|
37
|
-
roam_search_by_date: {},
|
|
38
|
-
roam_datomic_query: {}
|
|
46
|
+
...Object.fromEntries(Object.keys(toolSchemas).map((toolName) => [toolName, {}])),
|
|
39
47
|
},
|
|
40
48
|
},
|
|
41
49
|
});
|
|
42
50
|
this.setupRequestHandlers();
|
|
43
51
|
// Error handling
|
|
44
|
-
this.server.onerror = (error) => {
|
|
52
|
+
this.server.onerror = (error) => {
|
|
53
|
+
// Re-throw as McpError to be caught by the MCP client
|
|
54
|
+
if (error instanceof McpError) {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
58
|
+
throw new McpError(ErrorCode.InternalError, `MCP server internal error: ${errorMessage}`);
|
|
59
|
+
};
|
|
45
60
|
process.on('SIGINT', async () => {
|
|
46
61
|
await this.server.close();
|
|
47
62
|
process.exit(0);
|
|
@@ -220,7 +235,13 @@ export class RoamServer {
|
|
|
220
235
|
});
|
|
221
236
|
}
|
|
222
237
|
async run() {
|
|
223
|
-
|
|
224
|
-
|
|
238
|
+
try {
|
|
239
|
+
const transport = new StdioServerTransport();
|
|
240
|
+
await this.server.connect(transport);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
244
|
+
throw new McpError(ErrorCode.InternalError, `Failed to connect MCP server: ${errorMessage}`);
|
|
245
|
+
}
|
|
225
246
|
}
|
|
226
247
|
}
|
package/build/tools/schemas.js
CHANGED
|
@@ -19,21 +19,24 @@ export const toolSchemas = {
|
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
roam_fetch_page_by_title: {
|
|
22
|
+
name: 'roam_fetch_page_by_title',
|
|
22
23
|
description: 'Fetch page by title, defaults to raw JSON string.',
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
title: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Title of the page. For date pages, use ordinal date formats such as January 2nd, 2025'
|
|
30
|
+
},
|
|
31
|
+
format: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
enum: ['markdown', 'raw'],
|
|
34
|
+
default: 'raw',
|
|
35
|
+
description: "Format output as markdown or JSON. 'markdown' returns as string; 'raw' returns JSON string of the page's blocks"
|
|
36
|
+
}
|
|
28
37
|
},
|
|
29
|
-
|
|
30
|
-
type: 'string',
|
|
31
|
-
enum: ['markdown', 'raw'],
|
|
32
|
-
default: 'raw',
|
|
33
|
-
description: "Format output as markdown or JSON. 'markdown' returns as string; 'raw' returns JSON string of the page's blocks"
|
|
34
|
-
}
|
|
38
|
+
required: ['title']
|
|
35
39
|
},
|
|
36
|
-
required: ['title']
|
|
37
40
|
},
|
|
38
41
|
roam_create_page: {
|
|
39
42
|
name: 'roam_create_page',
|
|
@@ -149,7 +152,7 @@ export const toolSchemas = {
|
|
|
149
152
|
},
|
|
150
153
|
roam_import_markdown: {
|
|
151
154
|
name: 'roam_import_markdown',
|
|
152
|
-
description: 'Import nested markdown content into Roam under a specific block. Can locate the parent block by UID or by exact string match within a specific page.',
|
|
155
|
+
description: 'Import nested markdown content into Roam under a specific block. Can locate the parent block by UID (preferred) or by exact string match within a specific page.',
|
|
153
156
|
inputSchema: {
|
|
154
157
|
type: 'object',
|
|
155
158
|
properties: {
|
|
@@ -171,7 +174,7 @@ export const toolSchemas = {
|
|
|
171
174
|
},
|
|
172
175
|
parent_string: {
|
|
173
176
|
type: 'string',
|
|
174
|
-
description: 'Optional: Exact string content of the parent block to add content under (must provide either page_uid or page_title)'
|
|
177
|
+
description: 'Optional: Exact string content of the parent block to add content under (must provide either page_uid (preferred) or page_title)'
|
|
175
178
|
},
|
|
176
179
|
order: {
|
|
177
180
|
type: 'string',
|
|
@@ -311,7 +314,7 @@ export const toolSchemas = {
|
|
|
311
314
|
},
|
|
312
315
|
roam_update_block: {
|
|
313
316
|
name: 'roam_update_block',
|
|
314
|
-
description: 'Update a single block identified by its UID. Use this for individual block updates when you need to either replace the entire content or apply a transform pattern to modify specific parts of the content.\nNOTE
|
|
317
|
+
description: 'Update a single block identified by its UID. Use this for individual block updates when you need to either replace the entire content or apply a transform pattern to modify specific parts of the content.\nNOTE Roam-flavored markdown: For direct linking: use [[link]] syntax. For aliased linking, use [alias]([[link]]) syntax. Do not concatenate words in links/hashtags - correct: #[[multiple words]] #self-esteem (for typically hyphenated words).',
|
|
315
318
|
inputSchema: {
|
|
316
319
|
type: 'object',
|
|
317
320
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roam-research-mcp",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.7",
|
|
4
4
|
"description": "A Model Context Protocol (MCP) server for Roam Research API integration",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"build": "tsc && chmod 755 build/index.js",
|
|
32
32
|
"prepare": "npm run build",
|
|
33
33
|
"watch": "tsc --watch",
|
|
34
|
-
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
|
|
34
|
+
"inspector": "npx @modelcontextprotocol/inspector build/index.js",
|
|
35
|
+
"start": "node build/index.js"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@modelcontextprotocol/sdk": "0.6.0",
|