reflect-mcp 1.0.1 → 1.0.3
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 +132 -0
- package/dist/tools/index.js +83 -16
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Reflect MCP Server
|
|
2
|
+
|
|
3
|
+
Connect your [Reflect](https://reflect.app) notes to Claude Desktop.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Before installing, make sure you have:
|
|
8
|
+
|
|
9
|
+
- **Reflect Desktop** - Must be installed (but does not need to be running)
|
|
10
|
+
- Download from [reflect.app](https://reflect.app/download)
|
|
11
|
+
|
|
12
|
+
- **Claude Desktop** - Required to use MCP servers
|
|
13
|
+
- Download from [claude.ai](https://claude.com/download)
|
|
14
|
+
|
|
15
|
+
- **Node.js** - Version 18 or higher recommended
|
|
16
|
+
- Download from [nodejs.org](https://nodejs.org)
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
**1. Install the `reflect-mcp` package:**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install reflect-mcp
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**2. Install the server:**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx reflect-mcp install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**3. Add to Claude Desktop config** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"reflect": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "mcp-remote", "http://localhost:3000/mcp"]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**4. Restart Claude Desktop**
|
|
47
|
+
|
|
48
|
+
That's it! First time you use a Reflect tool, your browser will open to authenticate.
|
|
49
|
+
|
|
50
|
+
> **Note:** If you see auth errors, try restarting Claude Desktop one more time.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Usage Examples
|
|
54
|
+
|
|
55
|
+
Once installed, you can ask Claude to read and write your notes:
|
|
56
|
+
|
|
57
|
+
- "Read all my notes tagged #spanish and create a study guide note with my biggest gaps"
|
|
58
|
+
|
|
59
|
+
- "Read my last 3 daily notes and create a weekly summary note tagged #reflection"
|
|
60
|
+
|
|
61
|
+
- "Look at notes tagged #work. Create a 'Career Development Plan' note based on what I'm learning and struggling with"
|
|
62
|
+
|
|
63
|
+
- "Read my 1:1 meeting notes with [[manager]] and create a performance review prep note "
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
reflect-mcp install [db-path] # Install as auto-start service
|
|
69
|
+
reflect-mcp uninstall # Remove auto-start service
|
|
70
|
+
reflect-mcp status # Check service status
|
|
71
|
+
reflect-mcp [db-path] # Run server manually
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Options
|
|
75
|
+
|
|
76
|
+
| Option | Description | Default |
|
|
77
|
+
|--------|-------------|---------|
|
|
78
|
+
| `db-path` | Path to Reflect SQLite database | `~/Library/Application Support/Reflect/File System/000/t/00/00000000` |
|
|
79
|
+
| `--port <port>` | Server port | `3000` |
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Install with default settings
|
|
85
|
+
npx reflect-mcp install
|
|
86
|
+
|
|
87
|
+
# Install with custom database path
|
|
88
|
+
npx reflect-mcp install ~/custom/path/to/reflect/db
|
|
89
|
+
|
|
90
|
+
# Install with custom port
|
|
91
|
+
npx reflect-mcp install --port 4000
|
|
92
|
+
|
|
93
|
+
# Check if service is running
|
|
94
|
+
npx reflect-mcp status
|
|
95
|
+
|
|
96
|
+
# Remove auto-start
|
|
97
|
+
npx reflect-mcp uninstall
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Tools Available
|
|
101
|
+
|
|
102
|
+
- `get_graphs` - List all Reflect graphs
|
|
103
|
+
- `get_backlinks` - Get backlinks for a note
|
|
104
|
+
- `get_daily_notes` - Get recent daily notes
|
|
105
|
+
- `get_daily_note_by_date` - Get daily note for specific date
|
|
106
|
+
- `get_backlinked_notes` - Get notes with most backlinks
|
|
107
|
+
- `get_tags` - Get all tags with usage counts
|
|
108
|
+
- `get_notes_with_tag` - Get notes with a specific tag
|
|
109
|
+
- `get_note` - Get a note by title
|
|
110
|
+
- `create_note` - Create a new note
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
**Server won't start**
|
|
115
|
+
- Check if port 3000 is available: `lsof -i :3000`
|
|
116
|
+
- Try a different port: `npx reflect-mcp install --port 4000`
|
|
117
|
+
|
|
118
|
+
**OAuth not working**
|
|
119
|
+
- Restart Claude Desktop after installation
|
|
120
|
+
- Check server is running: `npx reflect-mcp status`
|
|
121
|
+
- Try uninstalling and reinstalling: `npx reflect-mcp uninstall && npx reflect-mcp install`
|
|
122
|
+
|
|
123
|
+
**Database not found**
|
|
124
|
+
- Ensure Reflect Desktop is installed
|
|
125
|
+
- Verify database path exists at default location
|
|
126
|
+
- Try specifying custom path: `npx reflect-mcp install /path/to/db`
|
|
127
|
+
|
|
128
|
+
## Demo:
|
|
129
|
+
https://www.loom.com/share/455b1d3eb7184bdea1ae4e8d5904fc53
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
package/dist/tools/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export function registerTools(server, dbPath) {
|
|
|
11
11
|
// Tool: Get all Reflect graphs
|
|
12
12
|
server.addTool({
|
|
13
13
|
name: "get_graphs",
|
|
14
|
-
description: "Get a list of all Reflect graphs
|
|
14
|
+
description: "Get a list of all Reflect graphs.",
|
|
15
15
|
parameters: z.object({}),
|
|
16
16
|
execute: async (_args, { session }) => {
|
|
17
17
|
if (!session) {
|
|
@@ -59,7 +59,7 @@ export function registerTools(server, dbPath) {
|
|
|
59
59
|
// Tool: Get backlinks for a note from local Reflect SQLite database
|
|
60
60
|
server.addTool({
|
|
61
61
|
name: "get_backlinks",
|
|
62
|
-
description: "Get backlinks for a note from
|
|
62
|
+
description: "Get backlinks for a note from Reflect. Use this tool to get more context about a note after calling the get_note tool.",
|
|
63
63
|
parameters: z.object({
|
|
64
64
|
subject: z.string().describe("The subject/title of the note to get backlinks for"),
|
|
65
65
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
@@ -111,7 +111,7 @@ export function registerTools(server, dbPath) {
|
|
|
111
111
|
// Tool: Get recent daily notes
|
|
112
112
|
server.addTool({
|
|
113
113
|
name: "get_daily_notes",
|
|
114
|
-
description: "Get the most recent daily notes from
|
|
114
|
+
description: "Get the most recent daily notes from Reflect.",
|
|
115
115
|
parameters: z.object({
|
|
116
116
|
limit: z.number().default(5).describe("Number of recent daily notes to return"),
|
|
117
117
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
@@ -163,7 +163,7 @@ export function registerTools(server, dbPath) {
|
|
|
163
163
|
// Tool: Get daily note by date
|
|
164
164
|
server.addTool({
|
|
165
165
|
name: "get_daily_note_by_date",
|
|
166
|
-
description: "Get the daily note for a specific date
|
|
166
|
+
description: "Get the daily note for a specific date.",
|
|
167
167
|
parameters: z.object({
|
|
168
168
|
date: z.string().describe("The date in YYYY-MM-DD format"),
|
|
169
169
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
@@ -225,7 +225,7 @@ export function registerTools(server, dbPath) {
|
|
|
225
225
|
// Tool: Get notes with most backlinks
|
|
226
226
|
server.addTool({
|
|
227
227
|
name: "get_backlinked_notes",
|
|
228
|
-
description: "Get notes that have at least a minimum number of backlinks from
|
|
228
|
+
description: "Get notes that have at least a minimum number of backlinks from Reflect.",
|
|
229
229
|
parameters: z.object({
|
|
230
230
|
minBacklinks: z.number().default(5).describe("Minimum number of backlinks a note must have"),
|
|
231
231
|
limit: z.number().default(10).describe("Maximum number of notes to return"),
|
|
@@ -278,7 +278,7 @@ export function registerTools(server, dbPath) {
|
|
|
278
278
|
// Tool: Get all tags with usage counts
|
|
279
279
|
server.addTool({
|
|
280
280
|
name: "get_tags",
|
|
281
|
-
description: "Get all unique tags with their usage counts from
|
|
281
|
+
description: "Get all unique tags with their usage counts from Reflect.",
|
|
282
282
|
parameters: z.object({
|
|
283
283
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
284
284
|
limit: z.number().default(50).describe("Maximum number of tags to return"),
|
|
@@ -334,7 +334,7 @@ export function registerTools(server, dbPath) {
|
|
|
334
334
|
// Tool: Get notes with a specific tag
|
|
335
335
|
server.addTool({
|
|
336
336
|
name: "get_notes_with_tag",
|
|
337
|
-
description: "Get notes that have a specific tag from
|
|
337
|
+
description: "Get notes that have a specific tag from Reflect.",
|
|
338
338
|
parameters: z.object({
|
|
339
339
|
tag: z.string().describe("The tag to search for"),
|
|
340
340
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
@@ -383,49 +383,116 @@ export function registerTools(server, dbPath) {
|
|
|
383
383
|
}
|
|
384
384
|
},
|
|
385
385
|
});
|
|
386
|
-
// Tool: Get a note by title
|
|
386
|
+
// Tool: Get a note by title (exact match first, then fuzzy fallback)
|
|
387
387
|
server.addTool({
|
|
388
388
|
name: "get_note",
|
|
389
|
-
description: "Get a note by its title (subject) from
|
|
389
|
+
description: "Get a note by its title (subject) from Reflect.",
|
|
390
390
|
parameters: z.object({
|
|
391
391
|
title: z.string().describe("The title/subject of the note to retrieve"),
|
|
392
392
|
graphId: z.string().default("rapheal-brain").describe("The graph ID to search in"),
|
|
393
393
|
}),
|
|
394
394
|
execute: async (args) => {
|
|
395
395
|
const { title, graphId } = args;
|
|
396
|
+
const FUZZY_LIMIT = 3;
|
|
396
397
|
try {
|
|
397
398
|
const dbFile = resolvedDbPath;
|
|
398
399
|
const db = new Database(dbFile, { readonly: true });
|
|
399
|
-
|
|
400
|
+
// Try exact match first
|
|
401
|
+
const exactStmt = db.prepare(`
|
|
400
402
|
SELECT id, subject, documentText, tags, editedAt, createdAt
|
|
401
403
|
FROM notes
|
|
402
404
|
WHERE isDeleted = 0 AND graphId = ? AND subject = ?
|
|
403
405
|
`);
|
|
404
|
-
const
|
|
406
|
+
const exactResult = exactStmt.get(graphId, title);
|
|
407
|
+
if (exactResult) {
|
|
408
|
+
db.close();
|
|
409
|
+
const note = {
|
|
410
|
+
id: exactResult.id,
|
|
411
|
+
subject: exactResult.subject,
|
|
412
|
+
documentText: exactResult.documentText,
|
|
413
|
+
tags: exactResult.tags ? JSON.parse(exactResult.tags) : [],
|
|
414
|
+
editedAt: formatDate(exactResult.editedAt),
|
|
415
|
+
createdAt: formatDate(exactResult.createdAt),
|
|
416
|
+
};
|
|
417
|
+
return {
|
|
418
|
+
content: [
|
|
419
|
+
{
|
|
420
|
+
type: "text",
|
|
421
|
+
text: JSON.stringify({ title, graphId, note }, null, 2),
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
// No exact match - try fuzzy search
|
|
427
|
+
const searchTerm = title.toLowerCase();
|
|
428
|
+
const fuzzyStmt = db.prepare(`
|
|
429
|
+
SELECT id, subject, documentText, tags, editedAt, createdAt,
|
|
430
|
+
CASE
|
|
431
|
+
WHEN LOWER(subject) LIKE ? THEN 2
|
|
432
|
+
WHEN LOWER(subject) LIKE ? THEN 1
|
|
433
|
+
ELSE 0
|
|
434
|
+
END as relevance
|
|
435
|
+
FROM notes
|
|
436
|
+
WHERE isDeleted = 0
|
|
437
|
+
AND graphId = ?
|
|
438
|
+
AND (LOWER(subject) LIKE ? OR LOWER(subject) LIKE ?)
|
|
439
|
+
ORDER BY relevance DESC, editedAt DESC
|
|
440
|
+
LIMIT ?
|
|
441
|
+
`);
|
|
442
|
+
const fuzzyResults = fuzzyStmt.all(`${searchTerm}%`, // starts with (score 2)
|
|
443
|
+
`%${searchTerm}%`, // contains (score 1)
|
|
444
|
+
graphId, `${searchTerm}%`, // WHERE starts with
|
|
445
|
+
`%${searchTerm}%`, // WHERE contains
|
|
446
|
+
FUZZY_LIMIT);
|
|
405
447
|
db.close();
|
|
406
|
-
if (
|
|
448
|
+
if (fuzzyResults.length === 0) {
|
|
407
449
|
return {
|
|
408
450
|
content: [
|
|
409
451
|
{
|
|
410
452
|
type: "text",
|
|
411
|
-
text: JSON.stringify({
|
|
453
|
+
text: JSON.stringify({
|
|
454
|
+
error: `No notes found matching '${title}'`,
|
|
455
|
+
query: title,
|
|
456
|
+
graphId
|
|
457
|
+
}),
|
|
412
458
|
},
|
|
413
459
|
],
|
|
414
460
|
};
|
|
415
461
|
}
|
|
416
|
-
const
|
|
462
|
+
const notes = fuzzyResults.map((result) => ({
|
|
417
463
|
id: result.id,
|
|
418
464
|
subject: result.subject,
|
|
419
465
|
documentText: result.documentText,
|
|
420
466
|
tags: result.tags ? JSON.parse(result.tags) : [],
|
|
421
467
|
editedAt: formatDate(result.editedAt),
|
|
422
468
|
createdAt: formatDate(result.createdAt),
|
|
423
|
-
};
|
|
469
|
+
}));
|
|
470
|
+
// If only one fuzzy match, return it directly
|
|
471
|
+
if (notes.length === 1) {
|
|
472
|
+
return {
|
|
473
|
+
content: [
|
|
474
|
+
{
|
|
475
|
+
type: "text",
|
|
476
|
+
text: JSON.stringify({
|
|
477
|
+
query: title,
|
|
478
|
+
graphId,
|
|
479
|
+
note: notes[0],
|
|
480
|
+
matchType: "fuzzy"
|
|
481
|
+
}, null, 2),
|
|
482
|
+
},
|
|
483
|
+
],
|
|
484
|
+
};
|
|
485
|
+
}
|
|
424
486
|
return {
|
|
425
487
|
content: [
|
|
426
488
|
{
|
|
427
489
|
type: "text",
|
|
428
|
-
text: JSON.stringify({
|
|
490
|
+
text: JSON.stringify({
|
|
491
|
+
query: title,
|
|
492
|
+
graphId,
|
|
493
|
+
matchCount: notes.length,
|
|
494
|
+
notes
|
|
495
|
+
}, null, 2),
|
|
429
496
|
},
|
|
430
497
|
],
|
|
431
498
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflect-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "MCP server for Reflect Notes - connect your notes to Claude Desktop. Just run: npx reflect-mcp",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/server.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"build": "tsc",
|
|
16
16
|
"dev": "tsx src/cli.ts",
|
|
17
17
|
"start": "node dist/cli.js",
|
|
18
|
-
"prepublishOnly": "npm run build"
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"postinstall": "npm rebuild better-sqlite3 || true"
|
|
19
20
|
},
|
|
20
21
|
"keywords": [
|
|
21
22
|
"mcp",
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
39
|
-
"better-sqlite3": "^11.
|
|
40
|
+
"better-sqlite3": "^11.10.0",
|
|
40
41
|
"fastmcp": "^3.25.4",
|
|
41
42
|
"zod": "^4.1.13"
|
|
42
43
|
},
|