mcp-memory-keeper 0.10.2 → 0.12.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.
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DEFAULT_PROFILES = exports.ALL_TOOL_NAMES_SET = exports.ALL_TOOL_NAMES = void 0;
37
+ exports.loadConfigFile = loadConfigFile;
38
+ exports.validateToolNames = validateToolNames;
39
+ exports.resolveActiveProfile = resolveActiveProfile;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const os = __importStar(require("os"));
43
+ /**
44
+ * All known tool names - source of truth for validation.
45
+ * Update this list whenever a tool is added or removed from the
46
+ * ListToolsRequestSchema handler in src/index.ts.
47
+ */
48
+ exports.ALL_TOOL_NAMES = [
49
+ // Session Management
50
+ 'context_session_start',
51
+ 'context_session_list',
52
+ 'context_set_project_dir',
53
+ // Core Context
54
+ 'context_save',
55
+ 'context_get',
56
+ 'context_status',
57
+ // File Caching
58
+ 'context_cache_file',
59
+ 'context_file_changed',
60
+ // Checkpoints
61
+ 'context_checkpoint',
62
+ 'context_restore_checkpoint',
63
+ // Summarization & Compaction
64
+ 'context_summarize',
65
+ 'context_prepare_compaction',
66
+ // Git Integration
67
+ 'context_git_commit',
68
+ // Search
69
+ 'context_search',
70
+ 'context_search_all',
71
+ 'context_semantic_search',
72
+ // Export/Import
73
+ 'context_export',
74
+ 'context_import',
75
+ // Knowledge Graph
76
+ 'context_analyze',
77
+ 'context_find_related',
78
+ 'context_visualize',
79
+ // Multi-Agent
80
+ 'context_delegate',
81
+ // Session Branching/Merging
82
+ 'context_branch_session',
83
+ 'context_merge_sessions',
84
+ // Journal & Timeline
85
+ 'context_journal_entry',
86
+ 'context_timeline',
87
+ // Advanced Features
88
+ 'context_compress',
89
+ 'context_integrate_tool',
90
+ 'context_diff',
91
+ // Channel Management
92
+ 'context_list_channels',
93
+ 'context_channel_stats',
94
+ 'context_reassign_channel',
95
+ // Watch
96
+ 'context_watch',
97
+ // Batch Operations
98
+ 'context_batch_save',
99
+ 'context_batch_delete',
100
+ 'context_batch_update',
101
+ // Relationships
102
+ 'context_link',
103
+ 'context_get_related',
104
+ ];
105
+ /** Pre-computed Set for O(1) lookups — used internally and exported for index.ts */
106
+ exports.ALL_TOOL_NAMES_SET = new Set(exports.ALL_TOOL_NAMES);
107
+ /** Built-in default profiles */
108
+ exports.DEFAULT_PROFILES = {
109
+ minimal: [
110
+ 'context_session_start',
111
+ 'context_session_list',
112
+ 'context_save',
113
+ 'context_get',
114
+ 'context_search',
115
+ 'context_status',
116
+ 'context_checkpoint',
117
+ 'context_restore_checkpoint',
118
+ ],
119
+ standard: [
120
+ 'context_session_start',
121
+ 'context_session_list',
122
+ 'context_set_project_dir',
123
+ 'context_save',
124
+ 'context_get',
125
+ 'context_status',
126
+ 'context_checkpoint',
127
+ 'context_restore_checkpoint',
128
+ 'context_search',
129
+ 'context_search_all',
130
+ 'context_summarize',
131
+ 'context_prepare_compaction',
132
+ 'context_git_commit',
133
+ 'context_export',
134
+ 'context_import',
135
+ 'context_journal_entry',
136
+ 'context_timeline',
137
+ 'context_list_channels',
138
+ 'context_channel_stats',
139
+ 'context_batch_save',
140
+ 'context_batch_delete',
141
+ 'context_batch_update',
142
+ ],
143
+ full: [...exports.ALL_TOOL_NAMES],
144
+ };
145
+ const CONFIG_DIR = path.join(os.homedir(), '.mcp-memory-keeper');
146
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
147
+ /** Load config file, returning null if absent or invalid */
148
+ function loadConfigFile(configPath = CONFIG_FILE) {
149
+ try {
150
+ if (!fs.existsSync(configPath)) {
151
+ return null;
152
+ }
153
+ const raw = fs.readFileSync(configPath, 'utf-8');
154
+ const parsed = JSON.parse(raw);
155
+ if (!parsed ||
156
+ typeof parsed !== 'object' ||
157
+ Array.isArray(parsed) ||
158
+ !parsed.profiles ||
159
+ typeof parsed.profiles !== 'object' ||
160
+ Array.isArray(parsed.profiles)) {
161
+ console.warn(`[MCP-Memory-Keeper] Config file at ${configPath} is missing a valid "profiles" key. Ignoring file.`);
162
+ return null;
163
+ }
164
+ // Validated: parsed.profiles is a non-null, non-array object
165
+ return { profiles: parsed.profiles };
166
+ }
167
+ catch (error) {
168
+ const message = error instanceof Error ? error.message : String(error);
169
+ console.warn(`[MCP-Memory-Keeper] Failed to load config file at ${configPath}: ${message}. Ignoring file.`);
170
+ return null;
171
+ }
172
+ }
173
+ /** Validate tool names against ALL_TOOL_NAMES, returning unknown names */
174
+ function validateToolNames(tools) {
175
+ return tools.filter(name => !exports.ALL_TOOL_NAMES_SET.has(name));
176
+ }
177
+ /** Resolve the active profile based on env var and config file */
178
+ function resolveActiveProfile(configPath) {
179
+ const warnings = [];
180
+ let profileName = (process.env.TOOL_PROFILE || '').trim();
181
+ const hasEnvVar = profileName.length > 0;
182
+ if (!hasEnvVar) {
183
+ profileName = 'full';
184
+ }
185
+ const config = loadConfigFile(configPath);
186
+ let toolList;
187
+ let source = 'default';
188
+ // Resolution precedence: config file > built-in defaults
189
+ if (config && config.profiles[profileName] !== undefined) {
190
+ const candidate = config.profiles[profileName];
191
+ // Validate that the profile value is actually an array of strings
192
+ if (!Array.isArray(candidate) || !candidate.every(item => typeof item === 'string')) {
193
+ warnings.push(`Profile "${profileName}" in config file is not a valid array of strings. Falling back to built-in default.`);
194
+ }
195
+ else {
196
+ toolList = candidate;
197
+ source = hasEnvVar ? 'env+config' : 'config';
198
+ }
199
+ }
200
+ if (toolList === undefined && exports.DEFAULT_PROFILES[profileName] !== undefined) {
201
+ toolList = [...exports.DEFAULT_PROFILES[profileName]];
202
+ source = hasEnvVar ? 'env+builtin' : 'default';
203
+ }
204
+ if (toolList === undefined) {
205
+ // Profile not found anywhere
206
+ const allProfiles = {
207
+ ...exports.DEFAULT_PROFILES,
208
+ ...(config ? config.profiles : {}),
209
+ };
210
+ const profileList = Object.entries(allProfiles)
211
+ .map(([name, tools]) => `${name}(${Array.isArray(tools) ? tools.length : '?'})`)
212
+ .join(', ');
213
+ warnings.push(`Unknown TOOL_PROFILE "${profileName}". Available profiles: ${profileList}. Using "full".`);
214
+ profileName = 'full';
215
+ toolList = [...exports.DEFAULT_PROFILES.full];
216
+ source = 'default';
217
+ }
218
+ // Validate tool names
219
+ const unknownNames = validateToolNames(toolList);
220
+ if (unknownNames.length > 0) {
221
+ warnings.push(`Unknown tool names in profile "${profileName}": ${unknownNames.join(', ')}. These will be ignored.`);
222
+ }
223
+ // Filter to only valid tools
224
+ const validTools = toolList.filter(name => exports.ALL_TOOL_NAMES_SET.has(name));
225
+ // Guard against empty profile
226
+ if (validTools.length === 0) {
227
+ warnings.push(`Profile "${profileName}" has no valid tools after filtering. Using "full".`);
228
+ profileName = 'full';
229
+ return {
230
+ profileName,
231
+ tools: new Set(exports.ALL_TOOL_NAMES),
232
+ source: 'default',
233
+ warnings,
234
+ };
235
+ }
236
+ return {
237
+ profileName,
238
+ tools: new Set(validTools),
239
+ source,
240
+ warnings,
241
+ };
242
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "_comment": "Place this file at ~/.mcp-memory-keeper/config.json. Built-in profiles (minimal, standard, full) are available without configuration. Define custom profiles or override built-ins here.",
3
+ "profiles": {
4
+ "my_custom_workflow": [
5
+ "context_session_start",
6
+ "context_save",
7
+ "context_get",
8
+ "context_search",
9
+ "context_status",
10
+ "context_checkpoint",
11
+ "context_restore_checkpoint",
12
+ "context_diff",
13
+ "context_timeline",
14
+ "context_batch_save"
15
+ ],
16
+ "git_focused": [
17
+ "context_session_start",
18
+ "context_session_list",
19
+ "context_set_project_dir",
20
+ "context_save",
21
+ "context_get",
22
+ "context_search",
23
+ "context_status",
24
+ "context_checkpoint",
25
+ "context_restore_checkpoint",
26
+ "context_git_commit",
27
+ "context_diff",
28
+ "context_export"
29
+ ]
30
+ }
31
+ }
@@ -0,0 +1,114 @@
1
+ # Smart Project Directory Management
2
+
3
+ As of version 0.8.3, MCP Memory Keeper provides intelligent assistance for setting up project directories to enable git tracking. This enhancement helps users configure their project directory correctly, especially when starting Claude Code from parent directories.
4
+
5
+ ## How it Works
6
+
7
+ When you start a new session without providing a `projectDir`, the server will:
8
+
9
+ 1. Check if the current directory has a git repository
10
+ 2. Scan subdirectories for git repositories
11
+ 3. Provide smart suggestions for setting up the project directory
12
+ 4. Prompt for project directory when git operations are attempted
13
+
14
+ ## Examples
15
+
16
+ ### Starting from Parent Directory
17
+
18
+ ```typescript
19
+ // If you're in ~/workspace and your project is in ~/workspace/my-project
20
+ await mcp.call('context_session_start', {
21
+ name: 'My Feature Work',
22
+ description: 'Working on the new feature',
23
+ });
24
+
25
+ // Response will show:
26
+ // Started new session: <session-id>
27
+ // Name: My Feature Work
28
+ // Git branch: unknown
29
+ //
30
+ // 💡 Found git repositories in: my-project, another-project
31
+ // To enable git tracking, start a session with your project directory:
32
+ // context_session_start({ name: "My Feature Work", projectDir: "/Users/you/workspace/my-project" })
33
+ ```
34
+
35
+ ### Explicit Directory (Override)
36
+
37
+ ```typescript
38
+ // You can still explicitly set a different directory if needed
39
+ await mcp.call('context_session_start', {
40
+ name: 'Another Project',
41
+ projectDir: '/path/to/different/project',
42
+ });
43
+
44
+ // Response will show:
45
+ // Started new session: <session-id>
46
+ // Name: Another Project
47
+ // Working directory: /path/to/different/project (explicitly set)
48
+ // Git branch: develop
49
+ ```
50
+
51
+ ### Non-Git Directory
52
+
53
+ ```typescript
54
+ // If the directory is not a git repository
55
+ await mcp.call('context_session_start', {
56
+ name: 'Non-Git Project',
57
+ });
58
+
59
+ // Response will show:
60
+ // Started new session: <session-id>
61
+ // Name: Non-Git Project
62
+ // Working directory: /path/to/current/directory (auto-detected)
63
+ // Git: No repository found in working directory
64
+ ```
65
+
66
+ ### Git Operations Without Project Directory
67
+
68
+ ```typescript
69
+ // If you try to commit without setting project directory
70
+ await mcp.call('context_git_commit', {
71
+ message: 'feat: Add new feature',
72
+ });
73
+
74
+ // Response will show:
75
+ // ⚠️ No project directory set for git tracking!
76
+ //
77
+ // To enable git tracking for your project, use one of these methods:
78
+ //
79
+ // 1. For the current session:
80
+ // context_set_project_dir({ projectDir: "/path/to/your/project" })
81
+ //
82
+ // 2. When starting a new session:
83
+ // context_session_start({ name: "My Session", projectDir: "/path/to/your/project" })
84
+ ```
85
+
86
+ ## Benefits
87
+
88
+ 1. **Smart Suggestions**: Automatically detects git repositories and suggests the right paths
89
+ 2. **Clear Guidance**: Provides helpful messages when project directory is needed
90
+ 3. **Prevents Mistakes**: Avoids using wrong directories when started from parent folders
91
+ 4. **Context Preservation**: The working directory is saved with the session for future reference
92
+ 5. **Backward Compatible**: Existing code that provides `projectDir` continues to work as before
93
+
94
+ ## Database Schema
95
+
96
+ The sessions table now includes a `working_directory` column to persist this information:
97
+
98
+ ```sql
99
+ CREATE TABLE sessions (
100
+ id TEXT PRIMARY KEY,
101
+ name TEXT,
102
+ description TEXT,
103
+ branch TEXT,
104
+ working_directory TEXT, -- New column
105
+ parent_id TEXT,
106
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
107
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
108
+ FOREIGN KEY (parent_id) REFERENCES sessions(id)
109
+ );
110
+ ```
111
+
112
+ ## Migration Support
113
+
114
+ For existing databases, the schema is automatically updated when the server starts. The migration checks if the `working_directory` column exists and adds it if missing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-memory-keeper",
3
- "version": "0.10.2",
3
+ "version": "0.12.0",
4
4
  "description": "MCP server for persistent context management in AI coding assistants",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -45,19 +45,20 @@
45
45
  "files": [
46
46
  "dist/**/*",
47
47
  "bin/**/*",
48
+ "examples/**/*",
48
49
  "README.md",
49
50
  "LICENSE",
50
51
  "CHANGELOG.md"
51
52
  ],
52
53
  "engines": {
53
- "node": ">=18.0.0"
54
+ "node": ">=20.0.0"
54
55
  },
55
56
  "publishConfig": {
56
57
  "access": "public"
57
58
  },
58
59
  "dependencies": {
59
60
  "@modelcontextprotocol/sdk": "^1.12.3",
60
- "better-sqlite3": "^11.10.0",
61
+ "better-sqlite3": "^12.1.0",
61
62
  "simple-git": "^3.28.0",
62
63
  "uuid": "^11.1.0"
63
64
  },