note-mcp-server 2.4.1 → 2.4.2
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/index.js +59 -31
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -12,73 +12,101 @@ import {
|
|
|
12
12
|
import axios from "axios";
|
|
13
13
|
import FormData from "form-data";
|
|
14
14
|
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import { parse as parseEnv } from "dotenv";
|
|
17
|
+
|
|
15
18
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
19
|
|
|
17
|
-
// 優先載入專案目錄 (cwd) 的 .env,以支援不同專案自由切換
|
|
18
|
-
loadEnv({ path: path.join(process.cwd(), ".env") });
|
|
19
|
-
// 如果專案目錄沒有設定,則退回讀取全域的 .env
|
|
20
|
-
loadEnv({ path: path.join(__dirname, ".env") });
|
|
21
20
|
/**
|
|
22
21
|
* MCP 須由 Cursor 依 mcp.json 啟動;勿在終端機手動跑本檔當成「掛載 MCP」。
|
|
23
22
|
*
|
|
24
23
|
* 設定優先序:
|
|
25
|
-
* 1)
|
|
26
|
-
* 2)
|
|
24
|
+
* 1) 專案目錄 (cwd) 的 .env 優先(支援不同專案自由切換)
|
|
25
|
+
* 2) 全域的 note-mcp-server/.env 作為預設退路
|
|
26
|
+
*
|
|
27
|
+
* 變數組合:
|
|
28
|
+
* A) NOTES_API_BASE — 完整 API base(含 /api/notes/{socialite}/{key})
|
|
29
|
+
* B) notes_url + socialite + key(或 socialite_id,與 key 同義:加密路徑 token)
|
|
27
30
|
*
|
|
28
31
|
* 變數名支援常見大小寫(見 resolveNotesApiBase)。
|
|
29
32
|
*/
|
|
30
33
|
|
|
34
|
+
const cwdEnvPath = path.join(process.cwd(), ".env");
|
|
35
|
+
const cwdEnv = fs.existsSync(cwdEnvPath) ? parseEnv(fs.readFileSync(cwdEnvPath)) : {};
|
|
36
|
+
|
|
37
|
+
const globalEnvPath = path.join(__dirname, ".env");
|
|
38
|
+
const globalEnv = fs.existsSync(globalEnvPath) ? parseEnv(fs.readFileSync(globalEnvPath)) : {};
|
|
39
|
+
|
|
40
|
+
// 將載入的變數注入 process.env (cwd 優先蓋過 global)
|
|
41
|
+
for (const [k, v] of Object.entries(globalEnv)) {
|
|
42
|
+
if (process.env[k] === undefined) process.env[k] = v;
|
|
43
|
+
}
|
|
44
|
+
for (const [k, v] of Object.entries(cwdEnv)) {
|
|
45
|
+
process.env[k] = v; // cwd 總是能覆寫
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
function stripTrailingSlashes(value) {
|
|
32
49
|
return value.replace(/\/+$/, "");
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const trimmed = String(raw).trim();
|
|
42
|
-
if (trimmed !== "") {
|
|
43
|
-
return trimmed;
|
|
52
|
+
function extractBase(envObj) {
|
|
53
|
+
const get = (...keys) => {
|
|
54
|
+
for (const k of keys) {
|
|
55
|
+
if (envObj[k] !== undefined && String(envObj[k]).trim() !== "") {
|
|
56
|
+
return String(envObj[k]).trim();
|
|
57
|
+
}
|
|
44
58
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
59
|
+
return "";
|
|
60
|
+
};
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
const direct = firstEnv("NOTES_API_BASE");
|
|
62
|
+
const direct = get("NOTES_API_BASE");
|
|
51
63
|
if (direct) {
|
|
52
64
|
return stripTrailingSlashes(direct);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
|
-
const notesUrl = stripTrailingSlashes(
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
const socialite = firstEnv("socialite", "SOCIALITE");
|
|
59
|
-
const encryptedToken = firstEnv(
|
|
60
|
-
"key",
|
|
61
|
-
"KEY",
|
|
62
|
-
"socialite_id",
|
|
63
|
-
"SOCIALITE_ID"
|
|
64
|
-
);
|
|
67
|
+
const notesUrl = stripTrailingSlashes(get("notes_url", "NOTES_URL"));
|
|
68
|
+
const socialite = get("socialite", "SOCIALITE");
|
|
69
|
+
const encryptedToken = get("key", "KEY", "socialite_id", "SOCIALITE_ID");
|
|
65
70
|
|
|
66
71
|
if (notesUrl && socialite && encryptedToken) {
|
|
67
72
|
return `${notesUrl}/api/notes/${socialite}/${encryptedToken}`;
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function resolveNotesApiBase() {
|
|
79
|
+
let base = extractBase(cwdEnv);
|
|
80
|
+
if (base) return base;
|
|
81
|
+
|
|
82
|
+
base = extractBase(globalEnv);
|
|
83
|
+
if (base) return base;
|
|
84
|
+
|
|
85
|
+
base = extractBase(process.env);
|
|
86
|
+
if (base) return base;
|
|
87
|
+
|
|
70
88
|
throw new Error(
|
|
71
89
|
"note-mcp-server:請在專案目錄建立 .env,設定 notes_url、socialite、key(或 socialite_id),或設定 NOTES_API_BASE。詳見 .env.example。"
|
|
72
90
|
);
|
|
73
91
|
}
|
|
74
92
|
|
|
93
|
+
function firstEnv(...keys) {
|
|
94
|
+
for (const key of keys) {
|
|
95
|
+
if (process.env[key] !== undefined) {
|
|
96
|
+
const trimmed = String(process.env[key]).trim();
|
|
97
|
+
if (trimmed !== "") return trimmed;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
|
|
75
103
|
const BASE_URL = resolveNotesApiBase();
|
|
76
104
|
const APP_NAME = firstEnv("app_name", "APP_NAME", "notes_app_name", "NOTES_APP_NAME") || "Personal Note Assistant";
|
|
77
105
|
|
|
78
106
|
const server = new Server(
|
|
79
107
|
{
|
|
80
108
|
name: `note-mcp-server (${APP_NAME})`,
|
|
81
|
-
version: "2.4.
|
|
109
|
+
version: "2.4.2",
|
|
82
110
|
},
|
|
83
111
|
{
|
|
84
112
|
capabilities: {
|
package/package.json
CHANGED