reflect-mcp 1.0.8 → 1.0.10
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/dist/cli.js +95 -25
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +69 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,62 @@ import { DEFAULT_DB_PATH, expandPath } from "./utils.js";
|
|
|
10
10
|
import * as fs from "fs";
|
|
11
11
|
import * as path from "path";
|
|
12
12
|
import * as os from "os";
|
|
13
|
+
import * as net from "net";
|
|
13
14
|
import { execSync } from "child_process";
|
|
15
|
+
/**
|
|
16
|
+
* Check if a port is in use
|
|
17
|
+
*/
|
|
18
|
+
function isPortInUse(port) {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const server = net.createServer();
|
|
21
|
+
server.once("error", (err) => {
|
|
22
|
+
if (err.code === "EADDRINUSE") {
|
|
23
|
+
resolve(true);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
resolve(false);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
server.once("listening", () => {
|
|
30
|
+
server.close();
|
|
31
|
+
resolve(false);
|
|
32
|
+
});
|
|
33
|
+
server.listen(port, "127.0.0.1");
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Kill any process using the specified port
|
|
38
|
+
*/
|
|
39
|
+
function killProcessOnPort(port) {
|
|
40
|
+
try {
|
|
41
|
+
// Get PID(s) using the port
|
|
42
|
+
const pids = execSync(`lsof -ti:${port}`, { encoding: "utf-8" }).trim();
|
|
43
|
+
if (pids) {
|
|
44
|
+
console.log(`⚠️ Port ${port} in use by PID(s): ${pids.replace(/\n/g, ", ")}`);
|
|
45
|
+
execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: "ignore" });
|
|
46
|
+
console.log(`✅ Killed existing process(es) on port ${port}`);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// No process found on port, or kill failed - that's fine
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Ensure the port is free, killing any existing process if needed
|
|
57
|
+
*/
|
|
58
|
+
async function ensurePortFree(port) {
|
|
59
|
+
if (await isPortInUse(port)) {
|
|
60
|
+
killProcessOnPort(port);
|
|
61
|
+
// Wait a moment for the port to be released
|
|
62
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
63
|
+
// Check again
|
|
64
|
+
if (await isPortInUse(port)) {
|
|
65
|
+
throw new Error(`Port ${port} is still in use after attempting to free it`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
14
69
|
const REFLECT_CLIENT_ID = "55798f25d5a24efb95e4174fff3d219e";
|
|
15
70
|
const LAUNCH_AGENT_LABEL = "com.reflect-mcp";
|
|
16
71
|
const LAUNCH_AGENT_DIR = path.join(os.homedir(), "Library/LaunchAgents");
|
|
@@ -19,22 +74,24 @@ const LAUNCH_AGENT_PATH = path.join(LAUNCH_AGENT_DIR, `${LAUNCH_AGENT_LABEL}.pli
|
|
|
19
74
|
const args = process.argv.slice(2);
|
|
20
75
|
const command = args[0];
|
|
21
76
|
// Handle commands
|
|
22
|
-
|
|
23
|
-
install
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
uninstall
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
status
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
77
|
+
(async () => {
|
|
78
|
+
if (command === "install") {
|
|
79
|
+
await install(args.slice(1));
|
|
80
|
+
}
|
|
81
|
+
else if (command === "uninstall") {
|
|
82
|
+
uninstall();
|
|
83
|
+
}
|
|
84
|
+
else if (command === "status") {
|
|
85
|
+
status();
|
|
86
|
+
}
|
|
87
|
+
else if (command === "--help" || command === "-h") {
|
|
88
|
+
showHelp();
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Default: run the server
|
|
92
|
+
await runServer(args);
|
|
93
|
+
}
|
|
94
|
+
})();
|
|
38
95
|
function showHelp() {
|
|
39
96
|
console.log(`
|
|
40
97
|
Reflect MCP Server - Connect your Reflect notes to Claude
|
|
@@ -60,7 +117,7 @@ Examples:
|
|
|
60
117
|
`);
|
|
61
118
|
process.exit(0);
|
|
62
119
|
}
|
|
63
|
-
function install(installArgs) {
|
|
120
|
+
async function install(installArgs) {
|
|
64
121
|
let dbPath = DEFAULT_DB_PATH;
|
|
65
122
|
let port = 3000;
|
|
66
123
|
// Parse install arguments
|
|
@@ -88,6 +145,9 @@ function install(installArgs) {
|
|
|
88
145
|
catch {
|
|
89
146
|
// Ignore errors - service might not exist yet
|
|
90
147
|
}
|
|
148
|
+
// Kill any stale processes on the port
|
|
149
|
+
killProcessOnPort(port);
|
|
150
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
91
151
|
// Create plist content
|
|
92
152
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
93
153
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -189,7 +249,7 @@ function status() {
|
|
|
189
249
|
}
|
|
190
250
|
console.log(`\n📝 Logs: tail -f /tmp/reflect-mcp.log`);
|
|
191
251
|
}
|
|
192
|
-
function runServer(serverArgs) {
|
|
252
|
+
async function runServer(serverArgs) {
|
|
193
253
|
let dbPath = DEFAULT_DB_PATH;
|
|
194
254
|
let port = 3000;
|
|
195
255
|
for (let i = 0; i < serverArgs.length; i++) {
|
|
@@ -200,15 +260,25 @@ function runServer(serverArgs) {
|
|
|
200
260
|
dbPath = serverArgs[i];
|
|
201
261
|
}
|
|
202
262
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
port
|
|
206
|
-
|
|
207
|
-
|
|
263
|
+
// Ensure port is free before starting
|
|
264
|
+
try {
|
|
265
|
+
await ensurePortFree(port);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
console.error(`❌ ${err}`);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
await startReflectMCPServer({
|
|
273
|
+
clientId: REFLECT_CLIENT_ID,
|
|
274
|
+
port,
|
|
275
|
+
dbPath,
|
|
276
|
+
});
|
|
208
277
|
console.log(`Reflect MCP Server running on http://localhost:${port}`);
|
|
209
278
|
console.log(`Database: ${dbPath}`);
|
|
210
|
-
}
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
211
281
|
console.error("Failed to start server:", err);
|
|
212
282
|
process.exit(1);
|
|
213
|
-
}
|
|
283
|
+
}
|
|
214
284
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility functions for the Reflect MCP Server
|
|
3
3
|
*/
|
|
4
|
-
export declare const DEFAULT_DB_PATH = "~/Library/Application Support/Reflect/File System/000/t/00/00000000";
|
|
5
4
|
/**
|
|
6
5
|
* Expands ~ to the user's home directory
|
|
7
6
|
*/
|
|
8
7
|
export declare function expandPath(filePath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Searches for the Reflect local database file
|
|
10
|
+
* Returns the first valid database path found, or null if not found
|
|
11
|
+
*/
|
|
12
|
+
export declare function findLocalDatabase(): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Gets the default database path, searching for it if not provided
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDefaultDbPath(): string;
|
|
17
|
+
export declare const DEFAULT_DB_PATH: string;
|
|
9
18
|
/**
|
|
10
19
|
* Strips HTML tags from a string, converting <br> to newlines
|
|
11
20
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as os from "os";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
// Base path for Reflect local database
|
|
8
|
+
const REFLECT_BASE_PATH = "~/Library/Application Support/Reflect/File System";
|
|
8
9
|
/**
|
|
9
10
|
* Expands ~ to the user's home directory
|
|
10
11
|
*/
|
|
@@ -14,6 +15,72 @@ export function expandPath(filePath) {
|
|
|
14
15
|
}
|
|
15
16
|
return filePath;
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Searches for the Reflect local database file
|
|
20
|
+
* Returns the first valid database path found, or null if not found
|
|
21
|
+
*/
|
|
22
|
+
export function findLocalDatabase() {
|
|
23
|
+
const basePath = expandPath(REFLECT_BASE_PATH);
|
|
24
|
+
if (!fs.existsSync(basePath)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
// Search for database files in the File System directory
|
|
28
|
+
// Structure is typically: File System/XXX/t/XX/XXXXXXXX
|
|
29
|
+
try {
|
|
30
|
+
const entries = fs.readdirSync(basePath);
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const entryPath = path.join(basePath, entry);
|
|
33
|
+
const tPath = path.join(entryPath, "t");
|
|
34
|
+
if (fs.existsSync(tPath) && fs.statSync(tPath).isDirectory()) {
|
|
35
|
+
// Look for subdirectories in t/
|
|
36
|
+
const tEntries = fs.readdirSync(tPath);
|
|
37
|
+
for (const tEntry of tEntries) {
|
|
38
|
+
const subPath = path.join(tPath, tEntry);
|
|
39
|
+
if (fs.statSync(subPath).isDirectory()) {
|
|
40
|
+
// Look for database files (8-char hex names)
|
|
41
|
+
const dbFiles = fs.readdirSync(subPath);
|
|
42
|
+
for (const dbFile of dbFiles) {
|
|
43
|
+
const dbPath = path.join(subPath, dbFile);
|
|
44
|
+
// Check if it's a valid SQLite database (starts with SQLite header)
|
|
45
|
+
if (fs.statSync(dbPath).isFile()) {
|
|
46
|
+
try {
|
|
47
|
+
const header = Buffer.alloc(16);
|
|
48
|
+
const fd = fs.openSync(dbPath, 'r');
|
|
49
|
+
fs.readSync(fd, header, 0, 16, 0);
|
|
50
|
+
fs.closeSync(fd);
|
|
51
|
+
// SQLite files start with "SQLite format 3"
|
|
52
|
+
if (header.toString('utf8', 0, 15) === 'SQLite format 3') {
|
|
53
|
+
return dbPath;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Not a readable file, skip
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Gets the default database path, searching for it if not provided
|
|
73
|
+
*/
|
|
74
|
+
export function getDefaultDbPath() {
|
|
75
|
+
const found = findLocalDatabase();
|
|
76
|
+
if (found) {
|
|
77
|
+
return found;
|
|
78
|
+
}
|
|
79
|
+
// Fallback to a common path pattern
|
|
80
|
+
return expandPath("~/Library/Application Support/Reflect/File System/000/t/00/00000000");
|
|
81
|
+
}
|
|
82
|
+
// For backwards compatibility
|
|
83
|
+
export const DEFAULT_DB_PATH = getDefaultDbPath();
|
|
17
84
|
/**
|
|
18
85
|
* Strips HTML tags from a string, converting <br> to newlines
|
|
19
86
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflect-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
40
40
|
"better-sqlite3": "^11.10.0",
|
|
41
41
|
"fastmcp": "^3.25.4",
|
|
42
|
-
"reflect-mcp": "^1.0.
|
|
42
|
+
"reflect-mcp": "^1.0.9",
|
|
43
43
|
"zod": "^4.1.13"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|