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 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
- if (command === "install") {
23
- install(args.slice(1));
24
- }
25
- else if (command === "uninstall") {
26
- uninstall();
27
- }
28
- else if (command === "status") {
29
- status();
30
- }
31
- else if (command === "--help" || command === "-h") {
32
- showHelp();
33
- }
34
- else {
35
- // Default: run the server
36
- runServer(args);
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
- startReflectMCPServer({
204
- clientId: REFLECT_CLIENT_ID,
205
- port,
206
- dbPath,
207
- }).then(() => {
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
- }).catch((err) => {
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
- // Reflect local database path
7
- export const DEFAULT_DB_PATH = "~/Library/Application Support/Reflect/File System/000/t/00/00000000";
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.8",
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.3",
42
+ "reflect-mcp": "^1.0.9",
43
43
  "zod": "^4.1.13"
44
44
  },
45
45
  "devDependencies": {