@hu14/memos-mcp 1.0.0

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 ADDED
@@ -0,0 +1,129 @@
1
+ # Memos MCP Server
2
+
3
+ A Model Context Protocol (MCP) server for interacting with [Memos](https://usememos.com/) - a lightweight, open-source memo hub.
4
+
5
+ ## Features
6
+
7
+ - **Complete Memo Management**: Create, read, update, and delete memos
8
+ - **Tag Support**: List, create, and manage tags
9
+ - **Flexible Filtering**: Filter memos by creator, tags, visibility, and more
10
+ - **Pagination**: Efficiently handle large memo collections
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install -g memos-mcp
16
+ ```
17
+
18
+ Or run directly with npx:
19
+
20
+ ```bash
21
+ npx memos-mcp
22
+ ```
23
+
24
+ ## Configuration
25
+
26
+ ### Environment Variables
27
+
28
+ | Variable | Required | Description |
29
+ |----------|----------|-------------|
30
+ | `MEMOS_API_URL` | No | Your Memos instance URL (default: `http://localhost:5230`) |
31
+ | `MEMOS_API_TOKEN` | Yes | Your Memos API access token |
32
+
33
+ ### Getting an API Token
34
+
35
+ 1. Log in to your Memos instance
36
+ 2. Go to **Settings** → **Access Tokens**
37
+ 3. Create a new token with appropriate permissions
38
+
39
+ ### Claude Code Configuration
40
+
41
+ Add to your `~/.claude.json`:
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "memos": {
47
+ "command": "npx",
48
+ "args": ["-y", "memos-mcp"],
49
+ "env": {
50
+ "MEMOS_API_URL": "https://your-memos-instance.com",
51
+ "MEMOS_API_TOKEN": "your-api-token"
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ Or for local development:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "memos": {
64
+ "command": "node",
65
+ "args": ["/path/to/memos-mcp/dist/index.js"],
66
+ "env": {
67
+ "MEMOS_API_URL": "http://localhost:5230",
68
+ "MEMOS_API_TOKEN": "your-api-token"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ## Available Tools
76
+
77
+ ### Memos
78
+
79
+ - **`list_memos`** - List all memos with optional filtering and pagination
80
+ - `filter`: Filter expression (e.g., `creator == "users/1"`, `tag == "ideas"`)
81
+ - `limit`: Maximum number of memos to return (default: 10)
82
+ - `offset`: Number of memos to skip for pagination
83
+ - `sort`: Sort order (e.g., `create_time desc`, `update_time`)
84
+
85
+ - **`get_memo`** - Get a single memo by ID
86
+ - `name`: Memo name/ID (e.g., `memos/123`)
87
+
88
+ - **`create_memo`** - Create a new memo
89
+ - `content`: Memo content (supports Markdown)
90
+ - `visibility`: Visibility level (`PRIVATE`, `PROTECTED`, `PUBLIC`)
91
+ - `tags`: Array of tags to attach
92
+
93
+ - **`update_memo`** - Update an existing memo
94
+ - `name`: Memo name/ID
95
+ - `content`: New content
96
+ - `visibility`: New visibility
97
+ - `tags`: New tags (replaces existing)
98
+
99
+ - **`delete_memo`** - Delete a memo permanently
100
+ - `name`: Memo name/ID to delete
101
+
102
+ ### Tags
103
+
104
+ - **`list_tags`** - List all tags
105
+ - `creator`: Filter by creator
106
+ - `limit`: Maximum number of tags
107
+
108
+ - **`create_tag`** - Create a new tag
109
+ - `name`: Tag name (without # prefix)
110
+
111
+ - **`delete_tag`** - Delete a tag
112
+ - `name`: Tag name (e.g., `tags/ideas`)
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ # Install dependencies
118
+ npm install
119
+
120
+ # Build
121
+ npm run build
122
+
123
+ # Run locally
124
+ MEMOS_API_URL=http://localhost:5230 MEMOS_API_TOKEN=xxx npm run dev
125
+ ```
126
+
127
+ ## License
128
+
129
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,379 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ // Environment configuration
8
+ const MEMOS_API_URL = process.env.MEMOS_API_URL || "http://localhost:5230";
9
+ const MEMOS_API_TOKEN = process.env.MEMOS_API_TOKEN;
10
+ if (!MEMOS_API_TOKEN) {
11
+ console.error("Error: MEMOS_API_TOKEN environment variable is required");
12
+ process.exit(1);
13
+ }
14
+ // API client
15
+ async function memosApi(path, options = {}) {
16
+ const url = `${MEMOS_API_URL}${path}`;
17
+ const headers = {
18
+ "Authorization": `Bearer ${MEMOS_API_TOKEN}`,
19
+ "Content-Type": "application/json",
20
+ ...options.headers,
21
+ };
22
+ const response = await fetch(url, { ...options, headers });
23
+ if (!response.ok) {
24
+ const errorText = await response.text();
25
+ throw new Error(`API Error ${response.status}: ${errorText}`);
26
+ }
27
+ if (response.status === 204) {
28
+ return null;
29
+ }
30
+ return response.json();
31
+ }
32
+ // Tool definitions
33
+ const TOOLS = [
34
+ {
35
+ name: "list_memos",
36
+ description: "List all memos with optional filtering and pagination",
37
+ inputSchema: {
38
+ type: "object",
39
+ properties: {
40
+ filter: {
41
+ type: "string",
42
+ description: "Filter expression (e.g., 'creator == \"users/1\"', 'tag == \"ideas\"')",
43
+ },
44
+ limit: {
45
+ type: "number",
46
+ description: "Maximum number of memos to return (default: 10)",
47
+ default: 10,
48
+ },
49
+ offset: {
50
+ type: "number",
51
+ description: "Number of memos to skip for pagination",
52
+ default: 0,
53
+ },
54
+ sort: {
55
+ type: "string",
56
+ description: "Sort order (e.g., 'create_time desc', 'update_time')",
57
+ default: "create_time desc",
58
+ },
59
+ },
60
+ },
61
+ },
62
+ {
63
+ name: "get_memo",
64
+ description: "Get a single memo by ID",
65
+ inputSchema: {
66
+ type: "object",
67
+ properties: {
68
+ name: {
69
+ type: "string",
70
+ description: "Memo name/ID (e.g., 'memos/123')",
71
+ },
72
+ },
73
+ required: ["name"],
74
+ },
75
+ },
76
+ {
77
+ name: "create_memo",
78
+ description: "Create a new memo",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ content: {
83
+ type: "string",
84
+ description: "Memo content (supports Markdown)",
85
+ },
86
+ visibility: {
87
+ type: "string",
88
+ description: "Memo visibility: PRIVATE, PROTECTED, or PUBLIC",
89
+ enum: ["PRIVATE", "PROTECTED", "PUBLIC"],
90
+ default: "PRIVATE",
91
+ },
92
+ tags: {
93
+ type: "array",
94
+ items: { type: "string" },
95
+ description: "Tags to attach to the memo",
96
+ },
97
+ },
98
+ required: ["content"],
99
+ },
100
+ },
101
+ {
102
+ name: "update_memo",
103
+ description: "Update an existing memo",
104
+ inputSchema: {
105
+ type: "object",
106
+ properties: {
107
+ name: {
108
+ type: "string",
109
+ description: "Memo name/ID (e.g., 'memos/123')",
110
+ },
111
+ content: {
112
+ type: "string",
113
+ description: "New memo content",
114
+ },
115
+ visibility: {
116
+ type: "string",
117
+ description: "New visibility: PRIVATE, PROTECTED, or PUBLIC",
118
+ enum: ["PRIVATE", "PROTECTED", "PUBLIC"],
119
+ },
120
+ tags: {
121
+ type: "array",
122
+ items: { type: "string" },
123
+ description: "New tags to replace existing ones",
124
+ },
125
+ },
126
+ required: ["name"],
127
+ },
128
+ },
129
+ {
130
+ name: "delete_memo",
131
+ description: "Delete a memo permanently",
132
+ inputSchema: {
133
+ type: "object",
134
+ properties: {
135
+ name: {
136
+ type: "string",
137
+ description: "Memo name/ID to delete (e.g., 'memos/123')",
138
+ },
139
+ },
140
+ required: ["name"],
141
+ },
142
+ },
143
+ {
144
+ name: "list_tags",
145
+ description: "List all tags with optional filtering",
146
+ inputSchema: {
147
+ type: "object",
148
+ properties: {
149
+ creator: {
150
+ type: "string",
151
+ description: "Filter by creator (e.g., 'users/1')",
152
+ },
153
+ limit: {
154
+ type: "number",
155
+ description: "Maximum number of tags to return",
156
+ default: 100,
157
+ },
158
+ },
159
+ },
160
+ },
161
+ {
162
+ name: "create_tag",
163
+ description: "Create a new tag",
164
+ inputSchema: {
165
+ type: "object",
166
+ properties: {
167
+ name: {
168
+ type: "string",
169
+ description: "Tag name (without # prefix)",
170
+ },
171
+ },
172
+ required: ["name"],
173
+ },
174
+ },
175
+ {
176
+ name: "delete_tag",
177
+ description: "Delete a tag",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ name: {
182
+ type: "string",
183
+ description: "Tag name to delete (e.g., 'tags/ideas')",
184
+ },
185
+ },
186
+ required: ["name"],
187
+ },
188
+ },
189
+ ];
190
+ // Tool handlers
191
+ async function handleListMemos(args) {
192
+ const params = new URLSearchParams();
193
+ if (args.filter)
194
+ params.append("filter", args.filter);
195
+ if (args.limit)
196
+ params.append("pageSize", args.limit.toString());
197
+ if (args.offset)
198
+ params.append("offset", args.offset.toString());
199
+ if (args.sort)
200
+ params.append("orderBy", args.sort);
201
+ const result = await memosApi(`/api/v1/memos?${params.toString()}`);
202
+ return {
203
+ content: [
204
+ {
205
+ type: "text",
206
+ text: JSON.stringify(result, null, 2),
207
+ },
208
+ ],
209
+ };
210
+ }
211
+ async function handleGetMemo(args) {
212
+ const result = await memosApi(`/api/v1/${args.name}`);
213
+ return {
214
+ content: [
215
+ {
216
+ type: "text",
217
+ text: JSON.stringify(result, null, 2),
218
+ },
219
+ ],
220
+ };
221
+ }
222
+ async function handleCreateMemo(args) {
223
+ const body = {
224
+ content: args.content,
225
+ visibility: args.visibility || "PRIVATE",
226
+ tags: args.tags || [],
227
+ };
228
+ const result = await memosApi("/api/v1/memos", {
229
+ method: "POST",
230
+ body: JSON.stringify(body),
231
+ });
232
+ return {
233
+ content: [
234
+ {
235
+ type: "text",
236
+ text: `Memo created successfully:\n${JSON.stringify(result, null, 2)}`,
237
+ },
238
+ ],
239
+ };
240
+ }
241
+ async function handleUpdateMemo(args) {
242
+ const body = {};
243
+ if (args.content !== undefined)
244
+ body.content = args.content;
245
+ if (args.visibility !== undefined)
246
+ body.visibility = args.visibility;
247
+ if (args.tags !== undefined)
248
+ body.tags = args.tags;
249
+ const result = await memosApi(`/api/v1/${args.name}`, {
250
+ method: "PATCH",
251
+ body: JSON.stringify(body),
252
+ });
253
+ return {
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: `Memo updated successfully:\n${JSON.stringify(result, null, 2)}`,
258
+ },
259
+ ],
260
+ };
261
+ }
262
+ async function handleDeleteMemo(args) {
263
+ await memosApi(`/api/v1/${args.name}`, {
264
+ method: "DELETE",
265
+ });
266
+ return {
267
+ content: [
268
+ {
269
+ type: "text",
270
+ text: `Memo ${args.name} deleted successfully.`,
271
+ },
272
+ ],
273
+ };
274
+ }
275
+ async function handleListTags(args) {
276
+ const params = new URLSearchParams();
277
+ if (args.creator)
278
+ params.append("filter", `creator == "${args.creator}"`);
279
+ if (args.limit)
280
+ params.append("pageSize", args.limit.toString());
281
+ const result = await memosApi(`/api/v1/tags?${params.toString()}`);
282
+ return {
283
+ content: [
284
+ {
285
+ type: "text",
286
+ text: JSON.stringify(result, null, 2),
287
+ },
288
+ ],
289
+ };
290
+ }
291
+ async function handleCreateTag(args) {
292
+ const body = {
293
+ name: args.name,
294
+ };
295
+ const result = await memosApi("/api/v1/tags", {
296
+ method: "POST",
297
+ body: JSON.stringify(body),
298
+ });
299
+ return {
300
+ content: [
301
+ {
302
+ type: "text",
303
+ text: `Tag created successfully:\n${JSON.stringify(result, null, 2)}`,
304
+ },
305
+ ],
306
+ };
307
+ }
308
+ async function handleDeleteTag(args) {
309
+ await memosApi(`/api/v1/${args.name}`, {
310
+ method: "DELETE",
311
+ });
312
+ return {
313
+ content: [
314
+ {
315
+ type: "text",
316
+ text: `Tag ${args.name} deleted successfully.`,
317
+ },
318
+ ],
319
+ };
320
+ }
321
+ // Main server
322
+ const server = new index_js_1.Server({
323
+ name: "memos-mcp",
324
+ version: "1.0.0",
325
+ }, {
326
+ capabilities: {
327
+ tools: {},
328
+ },
329
+ });
330
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
331
+ return { tools: TOOLS };
332
+ });
333
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
334
+ const { name, arguments: args } = request.params;
335
+ try {
336
+ switch (name) {
337
+ case "list_memos":
338
+ return await handleListMemos(args);
339
+ case "get_memo":
340
+ return await handleGetMemo(args);
341
+ case "create_memo":
342
+ return await handleCreateMemo(args);
343
+ case "update_memo":
344
+ return await handleUpdateMemo(args);
345
+ case "delete_memo":
346
+ return await handleDeleteMemo(args);
347
+ case "list_tags":
348
+ return await handleListTags(args);
349
+ case "create_tag":
350
+ return await handleCreateTag(args);
351
+ case "delete_tag":
352
+ return await handleDeleteTag(args);
353
+ default:
354
+ throw new Error(`Unknown tool: ${name}`);
355
+ }
356
+ }
357
+ catch (error) {
358
+ const errorMessage = error instanceof Error ? error.message : String(error);
359
+ return {
360
+ content: [
361
+ {
362
+ type: "text",
363
+ text: `Error: ${errorMessage}`,
364
+ },
365
+ ],
366
+ isError: true,
367
+ };
368
+ }
369
+ });
370
+ // Start server
371
+ async function main() {
372
+ const transport = new stdio_js_1.StdioServerTransport();
373
+ await server.connect(transport);
374
+ console.error("Memos MCP server running on stdio");
375
+ }
376
+ main().catch((error) => {
377
+ console.error("Fatal error:", error);
378
+ process.exit(1);
379
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@hu14/memos-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Memos - A lightweight, open-source memo hub",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "memos-mcp": "dist/index.js"
8
+ },
9
+ "type": "module",
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "start": "node dist/index.js",
17
+ "dev": "npm run build && npm run start"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "memos",
22
+ "model-context-protocol"
23
+ ],
24
+ "author": "",
25
+ "license": "ISC",
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.29.0",
31
+ "zod": "^4.3.6"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^25.5.2",
35
+ "typescript": "^6.0.2"
36
+ }
37
+ }