mcp-memory-bucket 0.8.7 → 0.9.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/dist/client/index.html
CHANGED
package/dist/src/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
const FOLDERFOO_DEV_HOST = 'http://localhost:3000';
|
|
4
5
|
const FOLDERFOO_CLOUD_HOST = 'https://files.cuul.cc';
|
|
@@ -75,12 +76,23 @@ function resolveFolders(entries, baseDir) {
|
|
|
75
76
|
const deduped = folders.filter((f) => (seen.has(f.path) ? false : (seen.add(f.path), true)));
|
|
76
77
|
return { folders: deduped, remoteFolders };
|
|
77
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Default home for the cache DB, config file, credentials, and remote mirrors
|
|
81
|
+
* when nothing else is specified — centralized under the user's home directory
|
|
82
|
+
* so the same store is used regardless of which directory the tool is launched
|
|
83
|
+
* from. Overridable via --memory-dir/MEMORY_BUCKET_DIR for tests or anyone who
|
|
84
|
+
* still wants a per-project store.
|
|
85
|
+
*/
|
|
86
|
+
export function defaultBaseDir() {
|
|
87
|
+
return path.join(os.homedir(), '.mem-mcp');
|
|
88
|
+
}
|
|
78
89
|
export function loadConfig(cwd = process.cwd(), argv = process.argv) {
|
|
79
90
|
const explicitDir = memoryDirFlag(argv) ?? process.env.MEMORY_BUCKET_DIR;
|
|
80
|
-
const baseDir = explicitDir ? path.resolve(cwd, explicitDir) :
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
//
|
|
91
|
+
const baseDir = explicitDir ? path.resolve(cwd, explicitDir) : defaultBaseDir();
|
|
92
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
93
|
+
// The config file lives alongside the cache DB in baseDir (~/.mem-mcp unless
|
|
94
|
+
// --memory-dir/MEMORY_BUCKET_DIR points elsewhere) — this must match where
|
|
95
|
+
// saveFolder/removeFolder write back to.
|
|
84
96
|
const configPath = path.join(baseDir, 'memory-bucket.config.json');
|
|
85
97
|
const overrides = readConfigFile(configPath);
|
|
86
98
|
// Without an explicit config, only default to ./skills or ./docs when that
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-memory-bucket",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server exposing skill_* (reusable coding patterns) and memory_* (point-in-time working context) tools over a markdown+frontmatter source, cached into SQLite at runtime.",
|
|
6
6
|
"repository": {
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import { saveRoot, removeRoot as removeRootFromConfig, sanitizeRootName } from '../config.js';
|
|
5
|
-
import { initialScan } from '../store/sync.js';
|
|
6
|
-
const KIND = z.enum(['skill', 'memory']);
|
|
7
|
-
export function registerBucketRootTools(mcp, config, skillRepo, memoryRepo, db, skillSpec, memorySpec) {
|
|
8
|
-
mcp.tool('bucket_list_roots', 'Lists the configured skill and memory roots (the named source directories skills/memory docs live under, e.g. "super-skills", "demo-skills", "builtin") — use this to see what roots exist before passing a `root` argument to a create/list/search tool, or before adding/removing one.', {}, async () => {
|
|
9
|
-
const skill = skillRepo.listRoots().map((r) => ({ ...r, kind: 'skill' }));
|
|
10
|
-
const memory = memoryRepo.listRoots().map((r) => ({ ...r, kind: 'memory' }));
|
|
11
|
-
return { content: [{ type: 'text', text: JSON.stringify({ skill, memory }, null, 2) }] };
|
|
12
|
-
});
|
|
13
|
-
mcp.tool('bucket_create_root', 'Registers a new skill or memory root: an existing absolute directory path becomes a new named source that skill_create/memory_create can target via `root`. Scans it once and starts watching it live — never creates the directory itself, it must already exist.', {
|
|
14
|
-
kind: KIND,
|
|
15
|
-
path: z.string().describe('absolute path to an existing directory'),
|
|
16
|
-
name: z.string().optional().describe('name for the root; defaults to a sanitized version of the directory\'s basename'),
|
|
17
|
-
}, async ({ kind, path: dirPath, name }) => {
|
|
18
|
-
try {
|
|
19
|
-
if (!path.isAbsolute(dirPath)) {
|
|
20
|
-
return { content: [{ type: 'text', text: 'path must be an absolute directory path' }], isError: true };
|
|
21
|
-
}
|
|
22
|
-
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
23
|
-
return { content: [{ type: 'text', text: `not a directory: ${dirPath}` }], isError: true };
|
|
24
|
-
}
|
|
25
|
-
const rootName = sanitizeRootName(name || path.basename(dirPath));
|
|
26
|
-
if (!rootName) {
|
|
27
|
-
return { content: [{ type: 'text', text: 'could not derive a valid root name — provide one explicitly' }], isError: true };
|
|
28
|
-
}
|
|
29
|
-
const repo = kind === 'skill' ? skillRepo : memoryRepo;
|
|
30
|
-
repo.addRoot({ name: rootName, path: dirPath });
|
|
31
|
-
saveRoot(config, kind, { name: rootName, path: dirPath });
|
|
32
|
-
return { content: [{ type: 'text', text: JSON.stringify({ name: rootName, path: dirPath, kind }, null, 2) }] };
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
mcp.tool('bucket_delete_root', 'Unregisters a skill or memory root by name: stops watching it and drops its cached entries from the index. Never touches files on disk — the directory and its contents are left in place.', { kind: KIND, name: z.string() }, async ({ kind, name }) => {
|
|
39
|
-
try {
|
|
40
|
-
const repo = kind === 'skill' ? skillRepo : memoryRepo;
|
|
41
|
-
repo.removeRoot(name);
|
|
42
|
-
removeRootFromConfig(config, kind, name);
|
|
43
|
-
return { content: [{ type: 'text', text: `Removed ${kind} root "${name}"` }] };
|
|
44
|
-
}
|
|
45
|
-
catch (err) {
|
|
46
|
-
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
mcp.tool('bucket_rebuild_cache', 'EMERGENCY USE ONLY. Wipes the entire SQLite cache (all skills, memory docs, the full-text search index, and the date index) and rebuilds it from scratch by rescanning every configured root from disk. Source markdown files on disk are never touched — this only affects the derived cache, which is always safe to discard and regenerate. Use this only when other tools return results that contradict what you can see in the actual files (e.g. stale search hits, a doc that clearly exists on disk but skill_get/memory_get can\'t find, or search_by_date returning wrong dates) and a normal create/update/relocate call hasn\'t resolved it — this is a last resort, not a routine maintenance step. Takes a moment to complete on a large root; nothing else should be called until it returns.', {}, async () => {
|
|
50
|
-
try {
|
|
51
|
-
db.exec(`DELETE FROM skills; DELETE FROM memory_docs; DELETE FROM search_index; DELETE FROM doc_dates;`);
|
|
52
|
-
initialScan(db, skillSpec);
|
|
53
|
-
initialScan(db, memorySpec);
|
|
54
|
-
const skillCount = db.prepare(`SELECT COUNT(*) AS n FROM skills`).get().n;
|
|
55
|
-
const memoryCount = db.prepare(`SELECT COUNT(*) AS n FROM memory_docs`).get().n;
|
|
56
|
-
return {
|
|
57
|
-
content: [
|
|
58
|
-
{ type: 'text', text: `Cache rebuilt from disk: ${skillCount} skill(s), ${memoryCount} memory doc(s) reindexed.` },
|
|
59
|
-
],
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch (err) {
|
|
63
|
-
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|