@prih/mcp-graph-memory 1.0.3

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.
Files changed (111) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +512 -0
  3. package/dist/api/index.js +473 -0
  4. package/dist/api/rest/code.js +78 -0
  5. package/dist/api/rest/docs.js +80 -0
  6. package/dist/api/rest/files.js +64 -0
  7. package/dist/api/rest/graph.js +56 -0
  8. package/dist/api/rest/index.js +117 -0
  9. package/dist/api/rest/knowledge.js +238 -0
  10. package/dist/api/rest/skills.js +284 -0
  11. package/dist/api/rest/tasks.js +272 -0
  12. package/dist/api/rest/tools.js +126 -0
  13. package/dist/api/rest/validation.js +191 -0
  14. package/dist/api/rest/websocket.js +65 -0
  15. package/dist/api/tools/code/get-file-symbols.js +30 -0
  16. package/dist/api/tools/code/get-symbol.js +22 -0
  17. package/dist/api/tools/code/list-files.js +18 -0
  18. package/dist/api/tools/code/search-code.js +27 -0
  19. package/dist/api/tools/code/search-files.js +22 -0
  20. package/dist/api/tools/context/get-context.js +19 -0
  21. package/dist/api/tools/docs/cross-references.js +76 -0
  22. package/dist/api/tools/docs/explain-symbol.js +55 -0
  23. package/dist/api/tools/docs/find-examples.js +52 -0
  24. package/dist/api/tools/docs/get-node.js +24 -0
  25. package/dist/api/tools/docs/get-toc.js +22 -0
  26. package/dist/api/tools/docs/list-snippets.js +46 -0
  27. package/dist/api/tools/docs/list-topics.js +18 -0
  28. package/dist/api/tools/docs/search-files.js +22 -0
  29. package/dist/api/tools/docs/search-snippets.js +43 -0
  30. package/dist/api/tools/docs/search.js +27 -0
  31. package/dist/api/tools/file-index/get-file-info.js +21 -0
  32. package/dist/api/tools/file-index/list-all-files.js +28 -0
  33. package/dist/api/tools/file-index/search-all-files.js +24 -0
  34. package/dist/api/tools/knowledge/add-attachment.js +31 -0
  35. package/dist/api/tools/knowledge/create-note.js +20 -0
  36. package/dist/api/tools/knowledge/create-relation.js +29 -0
  37. package/dist/api/tools/knowledge/delete-note.js +19 -0
  38. package/dist/api/tools/knowledge/delete-relation.js +23 -0
  39. package/dist/api/tools/knowledge/find-linked-notes.js +25 -0
  40. package/dist/api/tools/knowledge/get-note.js +20 -0
  41. package/dist/api/tools/knowledge/list-notes.js +18 -0
  42. package/dist/api/tools/knowledge/list-relations.js +17 -0
  43. package/dist/api/tools/knowledge/remove-attachment.js +19 -0
  44. package/dist/api/tools/knowledge/search-notes.js +25 -0
  45. package/dist/api/tools/knowledge/update-note.js +34 -0
  46. package/dist/api/tools/skills/add-attachment.js +31 -0
  47. package/dist/api/tools/skills/bump-usage.js +19 -0
  48. package/dist/api/tools/skills/create-skill-link.js +25 -0
  49. package/dist/api/tools/skills/create-skill.js +26 -0
  50. package/dist/api/tools/skills/delete-skill-link.js +23 -0
  51. package/dist/api/tools/skills/delete-skill.js +20 -0
  52. package/dist/api/tools/skills/find-linked-skills.js +25 -0
  53. package/dist/api/tools/skills/get-skill.js +21 -0
  54. package/dist/api/tools/skills/link-skill.js +23 -0
  55. package/dist/api/tools/skills/list-skills.js +20 -0
  56. package/dist/api/tools/skills/recall-skills.js +18 -0
  57. package/dist/api/tools/skills/remove-attachment.js +19 -0
  58. package/dist/api/tools/skills/search-skills.js +25 -0
  59. package/dist/api/tools/skills/update-skill.js +58 -0
  60. package/dist/api/tools/tasks/add-attachment.js +31 -0
  61. package/dist/api/tools/tasks/create-task-link.js +25 -0
  62. package/dist/api/tools/tasks/create-task.js +25 -0
  63. package/dist/api/tools/tasks/delete-task-link.js +23 -0
  64. package/dist/api/tools/tasks/delete-task.js +20 -0
  65. package/dist/api/tools/tasks/find-linked-tasks.js +25 -0
  66. package/dist/api/tools/tasks/get-task.js +20 -0
  67. package/dist/api/tools/tasks/link-task.js +23 -0
  68. package/dist/api/tools/tasks/list-tasks.js +24 -0
  69. package/dist/api/tools/tasks/move-task.js +38 -0
  70. package/dist/api/tools/tasks/remove-attachment.js +19 -0
  71. package/dist/api/tools/tasks/search-tasks.js +25 -0
  72. package/dist/api/tools/tasks/update-task.js +55 -0
  73. package/dist/cli/index.js +451 -0
  74. package/dist/cli/indexer.js +277 -0
  75. package/dist/graphs/attachment-types.js +74 -0
  76. package/dist/graphs/code-types.js +10 -0
  77. package/dist/graphs/code.js +172 -0
  78. package/dist/graphs/docs.js +198 -0
  79. package/dist/graphs/file-index-types.js +10 -0
  80. package/dist/graphs/file-index.js +310 -0
  81. package/dist/graphs/file-lang.js +119 -0
  82. package/dist/graphs/knowledge-types.js +32 -0
  83. package/dist/graphs/knowledge.js +764 -0
  84. package/dist/graphs/manager-types.js +87 -0
  85. package/dist/graphs/skill-types.js +10 -0
  86. package/dist/graphs/skill.js +1013 -0
  87. package/dist/graphs/task-types.js +17 -0
  88. package/dist/graphs/task.js +960 -0
  89. package/dist/lib/embedder.js +101 -0
  90. package/dist/lib/events-log.js +400 -0
  91. package/dist/lib/file-import.js +327 -0
  92. package/dist/lib/file-mirror.js +446 -0
  93. package/dist/lib/frontmatter.js +17 -0
  94. package/dist/lib/mirror-watcher.js +637 -0
  95. package/dist/lib/multi-config.js +254 -0
  96. package/dist/lib/parsers/code.js +246 -0
  97. package/dist/lib/parsers/codeblock.js +66 -0
  98. package/dist/lib/parsers/docs.js +196 -0
  99. package/dist/lib/project-manager.js +418 -0
  100. package/dist/lib/promise-queue.js +22 -0
  101. package/dist/lib/search/bm25.js +167 -0
  102. package/dist/lib/search/code.js +103 -0
  103. package/dist/lib/search/docs.js +108 -0
  104. package/dist/lib/search/file-index.js +31 -0
  105. package/dist/lib/search/files.js +61 -0
  106. package/dist/lib/search/knowledge.js +101 -0
  107. package/dist/lib/search/skills.js +104 -0
  108. package/dist/lib/search/tasks.js +103 -0
  109. package/dist/lib/watcher.js +67 -0
  110. package/package.json +83 -0
  111. package/ui/README.md +54 -0
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchTasks = searchTasks;
4
+ const embedder_1 = require("../../lib/embedder");
5
+ const bm25_1 = require("../../lib/search/bm25");
6
+ /**
7
+ * Semantic search over the task graph.
8
+ *
9
+ * 1. Score every node by cosine similarity to the query embedding.
10
+ * 2. Filter seeds below `minScore`, take top `topK`.
11
+ * 3. BFS expansion via relation edges up to `bfsDepth` hops with score decay.
12
+ * 4. De-duplicate, re-filter, sort, cap at `maxResults`.
13
+ */
14
+ function searchTasks(graph, queryEmbedding, options = {}) {
15
+ const { topK = 5, bfsDepth = 1, maxResults = 20, minScore = 0.5, bfsDecay = 0.8, queryText, bm25Index, searchMode = 'hybrid', rrfK = 60 } = options;
16
+ const useVector = searchMode !== 'keyword';
17
+ const useBm25 = searchMode !== 'vector' && !!queryText && !!bm25Index;
18
+ // --- 1. Score all nodes (skip proxy nodes) ---
19
+ const scored = [];
20
+ if (useVector) {
21
+ graph.forEachNode((id, attrs) => {
22
+ if (attrs.proxyFor)
23
+ return;
24
+ if (attrs.embedding.length === 0)
25
+ return;
26
+ scored.push({ id, score: (0, embedder_1.cosineSimilarity)(queryEmbedding, attrs.embedding) });
27
+ });
28
+ }
29
+ if (useBm25) {
30
+ const bm25Scores = bm25Index.score(queryText);
31
+ const positiveScored = useVector ? scored.filter(s => s.score > 0) : [];
32
+ if (positiveScored.length > 0) {
33
+ const vectorMap = new Map(positiveScored.map(s => [s.id, s.score]));
34
+ const fused = (0, bm25_1.rrfFuse)(vectorMap, bm25Scores, rrfK);
35
+ scored.length = 0;
36
+ for (const [id, score] of fused)
37
+ scored.push({ id, score });
38
+ }
39
+ else {
40
+ scored.length = 0;
41
+ for (const [id, score] of bm25Scores)
42
+ scored.push({ id, score });
43
+ }
44
+ // Normalize scores to 0–1 so minScore threshold works uniformly
45
+ const maxScore = scored.reduce((m, s) => Math.max(m, s.score), 0);
46
+ if (maxScore > 0) {
47
+ for (const s of scored)
48
+ s.score /= maxScore;
49
+ }
50
+ }
51
+ if (scored.length === 0)
52
+ return [];
53
+ scored.sort((a, b) => b.score - a.score);
54
+ // --- 2. Filter seeds ---
55
+ const minS = minScore;
56
+ const seeds = scored.filter(s => s.score >= minS).slice(0, topK);
57
+ if (seeds.length === 0)
58
+ return [];
59
+ // --- 3. BFS expansion ---
60
+ const scoreMap = new Map(seeds.map(s => [s.id, s.score]));
61
+ function bfs(startId, seedScore) {
62
+ const queue = [
63
+ { id: startId, depth: 0, score: seedScore },
64
+ ];
65
+ const visited = new Set();
66
+ while (queue.length > 0) {
67
+ const item = queue.shift();
68
+ if (visited.has(item.id))
69
+ continue;
70
+ visited.add(item.id);
71
+ const prev = scoreMap.get(item.id) ?? -Infinity;
72
+ if (item.score > prev)
73
+ scoreMap.set(item.id, item.score);
74
+ if (item.depth >= bfsDepth)
75
+ continue;
76
+ if (item.score * bfsDecay < minS)
77
+ continue;
78
+ const nextScore = item.score * bfsDecay;
79
+ graph.outNeighbors(item.id).forEach(n => queue.push({ id: n, depth: item.depth + 1, score: nextScore }));
80
+ graph.inNeighbors(item.id).forEach(n => queue.push({ id: n, depth: item.depth + 1, score: nextScore }));
81
+ }
82
+ }
83
+ for (const seed of seeds) {
84
+ bfs(seed.id, seed.score);
85
+ }
86
+ // --- 4. Build results (exclude proxy nodes) ---
87
+ return [...scoreMap.entries()]
88
+ .filter(([id, score]) => score >= minS && !graph.getNodeAttribute(id, 'proxyFor'))
89
+ .map(([id, score]) => {
90
+ const attrs = graph.getNodeAttributes(id);
91
+ return {
92
+ id,
93
+ title: attrs.title,
94
+ description: attrs.description,
95
+ status: attrs.status,
96
+ priority: attrs.priority,
97
+ tags: attrs.tags,
98
+ score,
99
+ };
100
+ })
101
+ .sort((a, b) => b.score - a.score)
102
+ .slice(0, maxResults);
103
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startWatcher = startWatcher;
7
+ const chokidar_1 = __importDefault(require("chokidar"));
8
+ const micromatch_1 = __importDefault(require("micromatch"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /** Directories that are always excluded from watching (heavy, never useful). */
11
+ const ALWAYS_IGNORED = ['.git', 'node_modules', '.next', '.nuxt', '.turbo', 'dist', 'build', '.graph-memory', '.notes', '.tasks', '.skills'];
12
+ // chokidar 5: watch the directory directly — glob patterns don't fire 'add' for existing files
13
+ function startWatcher(dir, handlers, pattern = '**/*.md', excludePatterns) {
14
+ const matches = (filePath) => {
15
+ const rel = path_1.default.relative(dir, filePath);
16
+ if (excludePatterns && excludePatterns.length > 0 && micromatch_1.default.isMatch(rel, excludePatterns))
17
+ return false;
18
+ return micromatch_1.default.isMatch(rel, pattern);
19
+ };
20
+ // chokidar 5 `ignored` accepts a function — use micromatch for glob exclude patterns
21
+ // plus always skip heavy directories (.git, node_modules, etc.)
22
+ const alwaysIgnoredSet = new Set(ALWAYS_IGNORED.map(d => path_1.default.join(dir, d)));
23
+ const ignored = (filePath) => {
24
+ // Always ignore heavy directories by exact basename match
25
+ if (alwaysIgnoredSet.has(filePath))
26
+ return true;
27
+ // User-defined exclude patterns (glob-based)
28
+ if (excludePatterns && excludePatterns.length > 0) {
29
+ const rel = path_1.default.relative(dir, filePath);
30
+ if (micromatch_1.default.isMatch(rel, excludePatterns))
31
+ return true;
32
+ }
33
+ return false;
34
+ };
35
+ let resolveReady;
36
+ const whenReady = new Promise(resolve => {
37
+ resolveReady = resolve;
38
+ });
39
+ const watcher = chokidar_1.default.watch(dir, {
40
+ ignoreInitial: false,
41
+ persistent: true,
42
+ ignored,
43
+ });
44
+ watcher.on('add', (filePath) => {
45
+ if (matches(filePath))
46
+ handlers.onAdd(filePath);
47
+ });
48
+ watcher.on('change', (filePath) => {
49
+ if (matches(filePath))
50
+ handlers.onChange(filePath);
51
+ });
52
+ watcher.on('unlink', (filePath) => {
53
+ if (matches(filePath))
54
+ handlers.onUnlink(filePath);
55
+ });
56
+ watcher.on('ready', () => {
57
+ process.stderr.write(`[watcher] Ready. Watching ${dir}\n`);
58
+ resolveReady();
59
+ });
60
+ watcher.on('error', (err) => {
61
+ process.stderr.write(`[watcher] Watch error: ${err}\n`);
62
+ });
63
+ return {
64
+ whenReady,
65
+ close: () => watcher.close(),
66
+ };
67
+ }
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "@prih/mcp-graph-memory",
3
+ "version": "1.0.3",
4
+ "description": "MCP server for semantic graph memory from markdown files",
5
+ "main": "dist/cli/index.js",
6
+ "bin": {
7
+ "mcp-graph-memory": "dist/cli/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "npm run build:server && npm run build:ui",
11
+ "build:server": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
12
+ "build:ui": "cd ui && npm run build",
13
+ "start": "node dist/index.js",
14
+ "dev": "tsc --watch",
15
+ "cli": "node dist/cli/index.js",
16
+ "cli:dev": "tsx src/cli/index.ts",
17
+ "test": "jest",
18
+ "test:watch": "jest --watch"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/prih/mcp-graph-memory.git"
23
+ },
24
+ "homepage": "https://github.com/prih/mcp-graph-memory",
25
+ "bugs": "https://github.com/prih/mcp-graph-memory/issues",
26
+ "keywords": [
27
+ "mcp",
28
+ "model-context-protocol",
29
+ "graph",
30
+ "memory",
31
+ "semantic-search",
32
+ "knowledge-graph",
33
+ "embeddings",
34
+ "documentation",
35
+ "code-indexing"
36
+ ],
37
+ "author": "prih <prihmail@gmail.com>",
38
+ "license": "ISC",
39
+ "engines": {
40
+ "node": ">=20"
41
+ },
42
+ "files": [
43
+ "dist/",
44
+ "ui/dist/",
45
+ "README.md"
46
+ ],
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "dependencies": {
51
+ "@huggingface/transformers": "^3.8.1",
52
+ "@modelcontextprotocol/sdk": "^1.27.1",
53
+ "chokidar": "^5.0.0",
54
+ "commander": "^14.0.3",
55
+ "cors": "^2.8.6",
56
+ "dotenv": "^17.3.1",
57
+ "express": "^5.2.1",
58
+ "graphology": "^0.26.0",
59
+ "micromatch": "^4.0.8",
60
+ "mime": "^4.1.0",
61
+ "multer": "^2.1.1",
62
+ "ts-morph": "^27.0.2",
63
+ "ws": "^8.19.0",
64
+ "yaml": "^2.8.2",
65
+ "zod": "^4.3.6"
66
+ },
67
+ "devDependencies": {
68
+ "@types/cors": "^2.8.19",
69
+ "@types/express": "^5.0.6",
70
+ "@types/jest": "^30.0.0",
71
+ "@types/micromatch": "^4.0.10",
72
+ "@types/multer": "^2.1.0",
73
+ "@types/node": "^25.4.0",
74
+ "@types/supertest": "^7.2.0",
75
+ "@types/ws": "^8.18.1",
76
+ "jest": "^30.3.0",
77
+ "supertest": "^7.2.2",
78
+ "ts-jest": "^29.4.6",
79
+ "tsc-alias": "^1.8.16",
80
+ "tsx": "^4.21.0",
81
+ "typescript": "^5.9.3"
82
+ }
83
+ }
package/ui/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Graph Memory — Web UI
2
+
3
+ React web interface for browsing and managing graph memory data.
4
+
5
+ ## Tech Stack
6
+
7
+ | Library | Version | Purpose |
8
+ |---------|---------|---------|
9
+ | React | 19 | UI framework |
10
+ | Material UI (MUI) | 7 | Component library |
11
+ | React Router DOM | 7 | Client-side routing |
12
+ | Cytoscape.js | 3.33 | Graph visualization |
13
+ | Vite | 8 | Build tool + dev server |
14
+
15
+ ## Architecture
16
+
17
+ Feature-Sliced Design (FSD):
18
+
19
+ ```
20
+ src/
21
+ ├── app/ # Routes, theme, global styles
22
+ ├── pages/ # Dashboard, Knowledge, Tasks, Skills, Docs, Files, Prompts, Search, Graph, Tools, Help
23
+ ├── widgets/ # Layout (sidebar + project selector + theme toggle)
24
+ ├── features/ # note-crud, task-crud, skill-crud
25
+ ├── entities/ # project, note, task, skill, file, doc, code, graph
26
+ ├── shared/ # API client, WebSocket hook, theme context
27
+ └── content/ # Help articles + prompt templates (markdown, bundled via ?raw)
28
+ ```
29
+
30
+ ## Development
31
+
32
+ ```bash
33
+ npm install
34
+ npm run dev # Vite dev server on :5173, proxies /api → http://localhost:3000
35
+ npm run build # Production build → dist/
36
+ ```
37
+
38
+ The backend (`serve` command) must be running on port 3000 for the API proxy to work.
39
+
40
+ ## Pages
41
+
42
+ | Route | Description |
43
+ |-------|-------------|
44
+ | `/:projectId/dashboard` | Stats cards + recent notes/tasks |
45
+ | `/:projectId/knowledge` | Notes CRUD, search, relations, cross-graph links |
46
+ | `/:projectId/tasks` | Kanban board: configurable columns, drag-drop with highlights, inline creation, filters, due date/estimate badges, quick actions |
47
+ | `/:projectId/docs` | Browse indexed documentation, TOC |
48
+ | `/:projectId/files` | File browser, directory navigation, metadata |
49
+ | `/:projectId/skills` | Skill/recipe management with triggers, steps, usage tracking |
50
+ | `/:projectId/prompts` | AI prompt generator: scenarios, role/style/graph selection, live preview, export as skill |
51
+ | `/:projectId/search` | Unified search across all 6 graphs |
52
+ | `/:projectId/graph` | Interactive force-directed graph (Cytoscape.js) |
53
+ | `/:projectId/tools` | MCP tools explorer with live execution |
54
+ | `/:projectId/help` | Built-in searchable documentation |