note-mcp-server 2.2.4 → 2.2.6
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 +21 -2
- package/index.js +70 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,8 +105,8 @@ socialite_id=eyJpdiI6I…
|
|
|
105
105
|
|
|
106
106
|
| 工具 | 說明 |
|
|
107
107
|
|------|------|
|
|
108
|
-
| `list_notes` | GET 列表,支援 `search`
|
|
109
|
-
| `read_note` | GET 單筆,支援 `c_id` 或 `last` |
|
|
108
|
+
| `list_notes` | GET 列表,支援 `search` / `tag` / `page` / `limit`(預設 10),每筆附 `note_url` |
|
|
109
|
+
| `read_note` | GET 單筆,支援 `c_id` 或 `last`,回傳附 `note_url` |
|
|
110
110
|
| `create_note` | POST 新增,`content` 必填,`title` 可選 |
|
|
111
111
|
| `update_note` | POST 修改,`c_id` 必填,支援 `content`、`title`、`append`、`prepend` |
|
|
112
112
|
| `delete_note` | POST 刪除,`c_id` + `action=delete` |
|
|
@@ -115,6 +115,25 @@ socialite_id=eyJpdiI6I…
|
|
|
115
115
|
|
|
116
116
|
完整 REST 行為請對你的 API 網址加上 **`/help`** 查官方說明。
|
|
117
117
|
|
|
118
|
+
前台筆記網址格式:
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
{notes_url}/app/notes/content/{c_id}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Agent 安全流程(重要)
|
|
127
|
+
|
|
128
|
+
- 只要使用者貼出或提到敏感設定(例如 `key`、`token`、`NOTES_API_BASE`、`socialite_id`),完成設定或操作後,代理必須主動執行:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
echo -n "" | pbcopy
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- 回覆中必須明確告知「剪貼簿已清空」。
|
|
135
|
+
- 此流程屬於預設安全規範,不需等待使用者額外提醒。
|
|
136
|
+
|
|
118
137
|
---
|
|
119
138
|
|
|
120
139
|
## 常見問題
|
package/index.js
CHANGED
|
@@ -109,12 +109,40 @@ function normalizeListPayload(data) {
|
|
|
109
109
|
return [];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
function resolveNotesSiteBase() {
|
|
113
|
+
const fromEnv = firstEnv("notes_url", "NOTES_URL");
|
|
114
|
+
if (fromEnv) {
|
|
115
|
+
return stripTrailingSlashes(fromEnv);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// BASE_URL = {site}/api/notes/{socialite}/{token}
|
|
119
|
+
return stripTrailingSlashes(BASE_URL.replace(/\/api\/notes\/.*$/i, ""));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const NOTES_SITE_BASE = resolveNotesSiteBase();
|
|
123
|
+
const SECURITY_NOTICE =
|
|
124
|
+
"安全規範:若使用者訊息或設定包含 key、token、NOTES_API_BASE、socialite_id 等敏感資訊,完成操作後必須主動清空 macOS 剪貼簿(echo -n \"\" | pbcopy),並在回覆中明確告知已清空。";
|
|
125
|
+
const NOTE_URL_NOTICE = `前台連結格式:${NOTES_SITE_BASE}/app/notes/content/{c_id}。`;
|
|
126
|
+
|
|
127
|
+
function withSecurityNotice(description) {
|
|
128
|
+
return `${description}\n${NOTE_URL_NOTICE}\n${SECURITY_NOTICE}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function buildNoteUrl(cId) {
|
|
132
|
+
if (cId === undefined || cId === null || String(cId).trim() === "") {
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
return `${NOTES_SITE_BASE}/app/notes/content/${encodeURIComponent(String(cId))}`;
|
|
136
|
+
}
|
|
137
|
+
|
|
112
138
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
113
139
|
return {
|
|
114
140
|
tools: [
|
|
115
141
|
{
|
|
116
142
|
name: "list_notes",
|
|
117
|
-
description:
|
|
143
|
+
description: withSecurityNotice(
|
|
144
|
+
`列出或搜尋 ${APP_NAME} 中的筆記。支援關鍵字、標籤搜尋及分頁(預設每頁 10 筆)。回傳資料會附上 note_url。`
|
|
145
|
+
),
|
|
118
146
|
inputSchema: {
|
|
119
147
|
type: "object",
|
|
120
148
|
properties: {
|
|
@@ -127,7 +155,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
127
155
|
},
|
|
128
156
|
{
|
|
129
157
|
name: "read_note",
|
|
130
|
-
description:
|
|
158
|
+
description: withSecurityNotice(
|
|
159
|
+
`從 ${APP_NAME} 讀取單筆筆記(GET ?c_id=)。亦可傳 c_id=last 讀取最新一筆。回傳資料會附上 note_url。`
|
|
160
|
+
),
|
|
131
161
|
inputSchema: {
|
|
132
162
|
type: "object",
|
|
133
163
|
properties: {
|
|
@@ -141,9 +171,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
141
171
|
},
|
|
142
172
|
{
|
|
143
173
|
name: "create_note",
|
|
144
|
-
description:
|
|
145
|
-
`在 ${APP_NAME} 中新增筆記。內容請優先使用簡潔的 AdminLTE 4 card
|
|
146
|
-
|
|
174
|
+
description: withSecurityNotice(
|
|
175
|
+
`在 ${APP_NAME} 中新增筆記。內容請優先使用簡潔的 AdminLTE 4 card 結構。`
|
|
176
|
+
),
|
|
147
177
|
inputSchema: {
|
|
148
178
|
type: "object",
|
|
149
179
|
properties: {
|
|
@@ -155,7 +185,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
155
185
|
},
|
|
156
186
|
{
|
|
157
187
|
name: "update_note",
|
|
158
|
-
description:
|
|
188
|
+
description: withSecurityNotice(
|
|
189
|
+
`在 ${APP_NAME} 中修改筆記。內容請優先使用簡潔的 AdminLTE 4 card 結構,避免嵌套破版,支援以 append/prepend 追加內容。`
|
|
190
|
+
),
|
|
159
191
|
inputSchema: {
|
|
160
192
|
type: "object",
|
|
161
193
|
properties: {
|
|
@@ -170,7 +202,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
170
202
|
},
|
|
171
203
|
{
|
|
172
204
|
name: "delete_note",
|
|
173
|
-
description: "刪除筆記(POST:c_id + action=delete)。",
|
|
205
|
+
description: withSecurityNotice("刪除筆記(POST:c_id + action=delete)。"),
|
|
174
206
|
inputSchema: {
|
|
175
207
|
type: "object",
|
|
176
208
|
properties: {
|
|
@@ -181,8 +213,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
181
213
|
},
|
|
182
214
|
{
|
|
183
215
|
name: "upload_image",
|
|
184
|
-
description:
|
|
185
|
-
`將圖片上傳至 ${APP_NAME}。此工具會回傳圖片的永久網址(URL)。若用戶要求生成圖片及內容,請務必分兩步執行:1. 先呼叫此工具傳圖獲取網址;2. 將獲取的網址以 <img> 標籤補進筆記內容(create_note 或 update_note
|
|
216
|
+
description: withSecurityNotice(
|
|
217
|
+
`將圖片上傳至 ${APP_NAME}。此工具會回傳圖片的永久網址(URL)。若用戶要求生成圖片及內容,請務必分兩步執行:1. 先呼叫此工具傳圖獲取網址;2. 將獲取的網址以 <img> 標籤補進筆記內容(create_note 或 update_note)中。`
|
|
218
|
+
),
|
|
186
219
|
inputSchema: {
|
|
187
220
|
type: "object",
|
|
188
221
|
properties: {
|
|
@@ -200,7 +233,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
200
233
|
},
|
|
201
234
|
{
|
|
202
235
|
name: "send_push",
|
|
203
|
-
description:
|
|
236
|
+
description: withSecurityNotice(
|
|
237
|
+
"發送 Web Push(POST:action=push、message;可選 title、url)。"
|
|
238
|
+
),
|
|
204
239
|
inputSchema: {
|
|
205
240
|
type: "object",
|
|
206
241
|
properties: {
|
|
@@ -229,9 +264,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
229
264
|
params.limit = args.limit || 10;
|
|
230
265
|
|
|
231
266
|
const response = await axios.get(BASE_URL, { params });
|
|
267
|
+
const payload =
|
|
268
|
+
response.data && typeof response.data === "object"
|
|
269
|
+
? { ...response.data }
|
|
270
|
+
: response.data;
|
|
271
|
+
|
|
272
|
+
const notes = normalizeListPayload(payload);
|
|
273
|
+
if (Array.isArray(notes)) {
|
|
274
|
+
for (const note of notes) {
|
|
275
|
+
if (note && typeof note === "object" && note.c_id !== undefined) {
|
|
276
|
+
note.note_url = buildNoteUrl(note.c_id);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
232
281
|
return {
|
|
233
282
|
content: [
|
|
234
|
-
{ type: "text", text: JSON.stringify(
|
|
283
|
+
{ type: "text", text: JSON.stringify(payload, null, 2) },
|
|
235
284
|
],
|
|
236
285
|
};
|
|
237
286
|
}
|
|
@@ -241,8 +290,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
241
290
|
const response = await axios.get(BASE_URL, {
|
|
242
291
|
params: { c_id: cId },
|
|
243
292
|
});
|
|
293
|
+
const payload =
|
|
294
|
+
response.data && typeof response.data === "object"
|
|
295
|
+
? { ...response.data }
|
|
296
|
+
: response.data;
|
|
297
|
+
if (payload && typeof payload === "object") {
|
|
298
|
+
const effectiveCid =
|
|
299
|
+
payload.c_id !== undefined ? payload.c_id : cId === "last" ? "" : cId;
|
|
300
|
+
payload.note_url = buildNoteUrl(effectiveCid);
|
|
301
|
+
}
|
|
244
302
|
return {
|
|
245
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
303
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
246
304
|
};
|
|
247
305
|
}
|
|
248
306
|
|
package/package.json
CHANGED