memory-journal-mcp 4.4.2 → 4.5.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.
Files changed (73) hide show
  1. package/.github/workflows/lint-and-test.yml +1 -1
  2. package/.github/workflows/security-update.yml +1 -1
  3. package/CHANGELOG.md +81 -1
  4. package/DOCKER_README.md +57 -7
  5. package/Dockerfile +17 -17
  6. package/README.md +65 -6
  7. package/SECURITY.md +27 -35
  8. package/dist/cli.js +10 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/constants/ServerInstructions.d.ts +5 -1
  11. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  12. package/dist/constants/ServerInstructions.js +137 -83
  13. package/dist/constants/ServerInstructions.js.map +1 -1
  14. package/dist/database/SqliteAdapter.d.ts +2 -1
  15. package/dist/database/SqliteAdapter.d.ts.map +1 -1
  16. package/dist/database/SqliteAdapter.js +15 -8
  17. package/dist/database/SqliteAdapter.js.map +1 -1
  18. package/dist/handlers/resources/index.d.ts +3 -1
  19. package/dist/handlers/resources/index.d.ts.map +1 -1
  20. package/dist/handlers/resources/index.js +5 -2
  21. package/dist/handlers/resources/index.js.map +1 -1
  22. package/dist/handlers/tools/index.d.ts.map +1 -1
  23. package/dist/handlers/tools/index.js +63 -16
  24. package/dist/handlers/tools/index.js.map +1 -1
  25. package/dist/server/McpServer.d.ts +2 -0
  26. package/dist/server/McpServer.d.ts.map +1 -1
  27. package/dist/server/McpServer.js +43 -2
  28. package/dist/server/McpServer.js.map +1 -1
  29. package/dist/server/Scheduler.d.ts +91 -0
  30. package/dist/server/Scheduler.d.ts.map +1 -0
  31. package/dist/server/Scheduler.js +201 -0
  32. package/dist/server/Scheduler.js.map +1 -0
  33. package/dist/utils/logger.d.ts.map +1 -1
  34. package/dist/utils/logger.js +6 -3
  35. package/dist/utils/logger.js.map +1 -1
  36. package/dist/utils/security-utils.d.ts +0 -21
  37. package/dist/utils/security-utils.d.ts.map +1 -1
  38. package/dist/utils/security-utils.js +0 -47
  39. package/dist/utils/security-utils.js.map +1 -1
  40. package/hooks/README.md +107 -0
  41. package/hooks/cursor/hooks.json +10 -0
  42. package/hooks/cursor/memory-journal.mdc +22 -0
  43. package/hooks/cursor/session-end.sh +19 -0
  44. package/hooks/kilo-code/session-end-mode.json +11 -0
  45. package/hooks/kiro/session-end.md +13 -0
  46. package/package.json +8 -8
  47. package/releases/v4.5.0.md +116 -0
  48. package/scripts/generate-server-instructions.ts +176 -0
  49. package/scripts/server-instructions-function-body.ts +77 -0
  50. package/server.json +3 -3
  51. package/src/cli.ts +26 -0
  52. package/src/constants/ServerInstructions.ts +137 -83
  53. package/src/constants/server-instructions.md +262 -0
  54. package/src/database/SqliteAdapter.ts +22 -8
  55. package/src/handlers/resources/index.ts +8 -2
  56. package/src/handlers/tools/index.ts +70 -20
  57. package/src/server/McpServer.ts +60 -2
  58. package/src/server/Scheduler.ts +278 -0
  59. package/src/utils/logger.ts +6 -3
  60. package/src/utils/security-utils.ts +0 -52
  61. package/tests/constants/server-instructions.test.ts +26 -0
  62. package/tests/database/sqlite-adapter.test.ts +84 -0
  63. package/tests/filtering/tool-filter.test.ts +46 -0
  64. package/tests/handlers/github-resource-handlers.test.ts +453 -0
  65. package/tests/handlers/github-tool-handlers.test.ts +899 -0
  66. package/tests/handlers/prompt-handlers.test.ts +40 -0
  67. package/tests/handlers/resource-handlers.test.ts +32 -0
  68. package/tests/handlers/tool-handlers.test.ts +13 -2
  69. package/tests/security/sql-injection.test.ts +3 -54
  70. package/tests/server/mcp-server.test.ts +491 -5
  71. package/tests/server/scheduler.test.ts +400 -0
  72. package/tests/vector/vector-search-manager.test.ts +60 -0
  73. package/.vscode/settings.json +0 -84
@@ -0,0 +1,107 @@
1
+ # IDE Hook & Rule Configurations
2
+
3
+ Ready-to-use configurations for automatic session management with memory-journal-mcp.
4
+
5
+ ## How It Works
6
+
7
+ Memory Journal bridges AI sessions with two behaviors:
8
+
9
+ - **Session start** — Agent reads `memory://briefing` and shows the user a project context summary
10
+ - **Session end** — Agent creates a `retrospective` entry tagged `session-summary` capturing what was done, what's pending, and context for the next session
11
+
12
+ The next session's briefing automatically includes the previous session's summary.
13
+
14
+ ## Progressive Enhancement
15
+
16
+ ```
17
+ ┌─────────────────────────────────────────────────────┐
18
+ │ Cursor Rule (most reliable for agent behavior) │
19
+ │ .cursor/rules/memory-journal.mdc │
20
+ │ ↓ always-apply rule instructs agent directly │
21
+ ├─────────────────────────────────────────────────────┤
22
+ │ Server Instructions (fallback for any MCP client) │
23
+ │ Embedded in MCP server initialization │
24
+ │ ↓ agent follows Session Start / Session End steps │
25
+ ├─────────────────────────────────────────────────────┤
26
+ │ IDE Hooks (audit & logging) │
27
+ │ Cursor sessionEnd · Kiro hooks · Kilo Code modes │
28
+ │ ↓ fire-and-forget observation on session close │
29
+ ├─────────────────────────────────────────────────────┤
30
+ │ User opt-out │
31
+ │ User says "skip the summary" → agent skips │
32
+ └─────────────────────────────────────────────────────┘
33
+ ```
34
+
35
+ ## Setup by IDE
36
+
37
+ ### Cursor
38
+
39
+ #### Step 1: Cursor Rule (handles session start + end behavior)
40
+
41
+ Copy `cursor/memory-journal.mdc` to your project's `.cursor/rules/`:
42
+
43
+ ```powershell
44
+ # From your project root
45
+ mkdir -p .cursor/rules
46
+ cp <path-to-memory-journal-mcp>/hooks/cursor/memory-journal.mdc .cursor/rules/memory-journal.mdc
47
+ ```
48
+
49
+ This `alwaysApply` rule instructs the agent to:
50
+
51
+ - Read `memory://briefing` and show project context at session start
52
+ - Create a session summary entry when the conversation wraps up
53
+
54
+ **Requirements**: Cursor with Rules support (`.cursor/rules/` directory).
55
+
56
+ #### Step 2: sessionEnd Hook (optional — audit logging)
57
+
58
+ Copy `cursor/hooks.json` and `cursor/session-end.sh` to your project's `.cursor/`:
59
+
60
+ ```powershell
61
+ cp <path-to-memory-journal-mcp>/hooks/cursor/hooks.json .cursor/hooks.json
62
+ mkdir -p .cursor/hooks
63
+ cp <path-to-memory-journal-mcp>/hooks/cursor/session-end.sh .cursor/hooks/session-end.sh
64
+ chmod +x .cursor/hooks/session-end.sh
65
+ ```
66
+
67
+ The `sessionEnd` hook is **fire-and-forget** — Cursor does not use its output. It logs session metadata to `/tmp/memory-journal-sessions.log`. Customize the script for your own auditing needs.
68
+
69
+ > **Note:** Cursor's `sessionEnd` hook cannot inject messages or trigger agent actions. Session summary creation is handled by the Cursor rule and server instructions, not the hook.
70
+
71
+ **Requirements**: Cursor v1.7+ with Hooks enabled.
72
+
73
+ ### Kiro (AWS)
74
+
75
+ Copy `kiro/session-end.md` to your project's `.kiro/hooks/` directory:
76
+
77
+ ```powershell
78
+ mkdir -p .kiro/hooks
79
+ cp <path-to-memory-journal-mcp>/hooks/kiro/session-end.md .kiro/hooks/
80
+ ```
81
+
82
+ Kiro hooks use markdown files with YAML frontmatter. The `manual` trigger means you activate it from the Kiro hook panel when ending a session.
83
+
84
+ ### Kilo Code
85
+
86
+ Copy `kilo-code/session-end-mode.json` to your Kilo Code settings:
87
+
88
+ ```powershell
89
+ # Import via Kilo Code settings UI, or add to your modes configuration
90
+ cp <path-to-memory-journal-mcp>/hooks/kilo-code/session-end-mode.json ~/.kilocode/modes/
91
+ ```
92
+
93
+ This creates a `session-end` custom mode. Switch to it at the end of a session and Kilo Code will create the summary entry using MCP tools.
94
+
95
+ ### VS Code + GitHub Copilot
96
+
97
+ Agent hooks are in **preview** (early 2026). When stabilized, a configuration will be added here. In the meantime, the server instructions fallback handles session management.
98
+
99
+ ### AntiGravity
100
+
101
+ Does not currently support hooks or rules. The server instructions fallback handles session management automatically. For session-start behavior, add to your user rules: "At session start, read `memory://briefing` from memory-journal-mcp."
102
+
103
+ ## No Rules or Hooks? No Problem
104
+
105
+ The `server-instructions.md` in this project includes **Session Start** and **Session End** behavior sections that instruct any MCP-connected agent to manage sessions automatically. This works in **every** MCP client, regardless of rule or hook support — though reliability varies by client.
106
+
107
+ To **disable** session-end entries, tell the agent: "Skip the session summary" or "Don't create an end-of-session entry."
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "sessionEnd": [
5
+ {
6
+ "command": ".cursor/hooks/session-end.sh"
7
+ }
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: Memory Journal MCP - session start briefing and session end summary
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Memory Journal MCP
7
+
8
+ ## Session Start
9
+
10
+ Before responding to the first user message in every conversation:
11
+
12
+ 1. Fetch `memory://briefing` from the memory-journal-mcp server
13
+ 2. Show the `userMessage` field to the user (it contains a formatted project context summary)
14
+ 3. Then proceed with the user's request
15
+
16
+ ## Session End
17
+
18
+ When the conversation is wrapping up (user says "thanks," final deliverable complete, no more work planned):
19
+
20
+ 1. Create a journal entry summarizing: what was accomplished, what's unfinished, and context for the next session
21
+ 2. Use `entry_type: "retrospective"` and tag with `session-summary`
22
+ 3. This is opt-out — ALWAYS create the entry, even for short/trivial sessions, unless the user explicitly says to skip it
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ # session-end.sh — Fire-and-forget sessionEnd hook for memory-journal-mcp
4
+ #
5
+ # Cursor's sessionEnd hook is observational only (output is not used).
6
+ # Session summary creation is handled by the Cursor rule + server instructions,
7
+ # not this hook. Customize this script for logging or cleanup.
8
+ #
9
+ # Input (JSON via stdin): session_id, reason, duration_ms, is_background_agent, etc.
10
+
11
+ input=$(cat)
12
+
13
+ timestamp=$(date '+%Y-%m-%d %H:%M:%S')
14
+ session_id=$(echo "$input" | grep -o '"session_id":"[^"]*"' | head -1 | cut -d'"' -f4)
15
+ reason=$(echo "$input" | grep -o '"reason":"[^"]*"' | head -1 | cut -d'"' -f4)
16
+
17
+ echo "[$timestamp] session=$session_id reason=$reason" >> /tmp/memory-journal-sessions.log 2>/dev/null
18
+
19
+ exit 0
@@ -0,0 +1,11 @@
1
+ {
2
+ "customModes": [
3
+ {
4
+ "slug": "session-end",
5
+ "name": "Session End",
6
+ "roleDefinition": "You are wrapping up a coding session. Create a memory-journal-mcp entry summarizing the session.",
7
+ "customInstructions": "Create a memory-journal-mcp entry summarizing this session:\n- What was accomplished (key changes, decisions, files modified)\n- What's unfinished or blocked (pending items, open questions)\n- Context for next session (relevant entry IDs, branch names, PR numbers)\n\nUse entry_type 'retrospective' and tag with 'session-summary'.",
8
+ "groups": ["mcp"]
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Session End Journal Entry
3
+ description: Creates a session summary journal entry via memory-journal-mcp
4
+ trigger: manual
5
+ ---
6
+
7
+ Create a memory-journal-mcp entry summarizing this session:
8
+
9
+ - **What was accomplished** (key changes, decisions, files modified)
10
+ - **What's unfinished or blocked** (pending items, open questions)
11
+ - **Context for next session** (relevant entry IDs, branch names, PR numbers)
12
+
13
+ Use `entry_type: "retrospective"` and tag with `session-summary`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-journal-mcp",
3
- "version": "4.4.2",
3
+ "version": "4.5.0",
4
4
  "description": "Project context management for AI-assisted development - Persistent knowledge graphs and intelligent context recall across fragmented AI threads",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,8 @@
18
18
  "test": "vitest run",
19
19
  "test:watch": "vitest",
20
20
  "test:coverage": "vitest run --coverage",
21
- "bench": "vitest bench --run"
21
+ "bench": "vitest bench --run",
22
+ "generate:instructions": "node scripts/generate-server-instructions.ts"
22
23
  },
23
24
  "keywords": [
24
25
  "mcp",
@@ -55,8 +56,8 @@
55
56
  "@octokit/rest": "^22.0.1",
56
57
  "@xenova/transformers": "^2.17.2",
57
58
  "commander": "^14.0.3",
58
- "cors": "^2.8.6",
59
59
  "express": "^5.2.1",
60
+ "express-rate-limit": "^8.2.1",
60
61
  "simple-git": "^3.32.3",
61
62
  "sql.js": "^1.14.0",
62
63
  "vectra": "^0.12.3",
@@ -64,12 +65,11 @@
64
65
  },
65
66
  "devDependencies": {
66
67
  "@eslint/js": "^10.0.1",
67
- "@types/cors": "^2.8.19",
68
68
  "@types/express": "^5.0.6",
69
- "@types/node": "^25.3.2",
69
+ "@types/node": "^25.3.3",
70
70
  "@vitest/coverage-v8": "^4.0.18",
71
71
  "eslint": "^10.0.2",
72
- "globals": "^17.3.0",
72
+ "globals": "^17.4.0",
73
73
  "typescript": "^5.9.3",
74
74
  "typescript-eslint": "^8.56.1",
75
75
  "vitest": "^4.0.17"
@@ -78,8 +78,8 @@
78
78
  "axios": "^1.13.5",
79
79
  "brace-expansion": "^2.0.2",
80
80
  "glob": "^11.1.0",
81
- "minimatch": "^10.2.3",
82
- "tar": "^7.5.8",
81
+ "minimatch": "^10.2.4",
82
+ "tar": "^7.5.9",
83
83
  "tmp": "^0.2.4"
84
84
  }
85
85
  }
@@ -0,0 +1,116 @@
1
+ # v4.5.0 - Automated Scheduling, Security Hardening & Quality Improvements
2
+
3
+ **Released: March 2, 2026**
4
+
5
+ ## Highlights
6
+
7
+ ### ⏰ Automated Scheduler (HTTP/SSE Only)
8
+
9
+ New in-process scheduler runs periodic maintenance jobs for long-running HTTP/SSE server processes:
10
+
11
+ - `--backup-interval <minutes>` — Automated database backups with cleanup
12
+ - `--keep-backups <count>` — Max backups to retain (default: 5)
13
+ - `--vacuum-interval <minutes>` — Database optimization (`PRAGMA optimize`)
14
+ - `--rebuild-index-interval <minutes>` — Full vector index rebuild
15
+
16
+ Each job is error-isolated. Status visible via `memory://health`.
17
+
18
+ ### 🔒 Security Hardening
19
+
20
+ Comprehensive security improvements across the entire stack:
21
+
22
+ - **HTTP Transport** — Rate limiting (100 req/min), CSP headers, Cache-Control, Referrer-Policy, CORS wildcard warning
23
+ - **Input Validation** — `entry_type` and `significance_type` now constrained to Zod enums; date format validation via regex
24
+ - **Dead Code Wiring** — `sanitizeSearchQuery()` and `assertNoPathTraversal()` now active in code paths
25
+ - **Foreign Keys** — `PRAGMA foreign_keys = ON` enforced at database initialization
26
+ - **Path Traversal** — `exportToFile()` now protected with `assertNoPathTraversal()`
27
+ - **Logger Hardening** — `LOG_LEVEL` validated; `setLevel()` guarded against invalid values
28
+ - **Removed dead code** — SQL injection detection functions that provided false sense of security
29
+ - **CI** — Blocking `npm audit` and TruffleHog steps; Node.js test matrix aligned to `>=24.0.0`
30
+
31
+ ### ✅ Test Coverage → 92%
32
+
33
+ Expanded test suite from 549 → 590 tests, raising line coverage from 88.59% → 92.06%:
34
+
35
+ - SIGINT shutdown handlers for all three transport modes
36
+ - Prompt handlers with proper arguments
37
+ - `SqliteAdapter` backup edge cases
38
+ - GitHub integration error paths
39
+
40
+ ### 📝 Cursor Rule for Session Management
41
+
42
+ Added `hooks/cursor/memory-journal.mdc` — an `alwaysApply` Cursor rule that instructs agents to read `memory://briefing` at session start and create a retrospective at session end. This is the most reliable mechanism for session behavior in Cursor.
43
+
44
+ ## Added
45
+
46
+ - **Automated Scheduler** — `Scheduler.ts` module with CLI flags for backup, vacuum, and index rebuild intervals
47
+ - **Cursor Rule** — `hooks/cursor/memory-journal.mdc` for reliable session management
48
+ - **Cursor `sessionEnd` Hook** — `hooks/cursor/hooks.json` + `session-end.sh` audit script
49
+
50
+ ## Improved
51
+
52
+ - **Test Coverage** — 88.59% → 92.06% line coverage (549 → 590 tests)
53
+ - **Database I/O** — Debounced `scheduleSave()` reduces disk writes on rapid mutations
54
+ - **Vector Index Rebuild** — Paginated fetching (200/page) + parallel batch embedding (5 at a time)
55
+ - **Server Startup** — Eliminated duplicate `getTools()` call
56
+ - **GitHub API** — TTL response cache (5 min) with automatic invalidation on mutations
57
+
58
+ ## Fixed
59
+
60
+ - **Session Start briefing in Cursor** — Added `user-memory-journal-mcp` server name for Cursor compatibility
61
+ - **`deleteOldBackups` Test Isolation** — Fixed flaky test by cleaning up pre-existing backups
62
+ - **`share_with_team` Not Setting `isPersonal`** — `create_entry` with `share_with_team: true` now correctly sets `isPersonal: false`
63
+ - **Path Traversal Test Assertion** — Updated to assert `PathTraversalError` type
64
+ - **Tool Handler Test Fix** — Updated to use valid `entry_type` enum value
65
+
66
+ ## Security
67
+
68
+ - Wire dead-code security utilities (F-001, F-002)
69
+ - HTTP security headers: CSP, Cache-Control, Referrer-Policy (F-003)
70
+ - `PRAGMA foreign_keys = ON` (F-005)
71
+ - CORS wildcard warning (F-006)
72
+ - `entry_type` / `significance_type` enum constraints
73
+ - Date format validation on all date string fields
74
+ - HTTP rate limiting (100 req/min per IP)
75
+ - Remove dead SQL injection detection code
76
+ - `exportToFile()` path traversal protection
77
+ - `getRawDb()` safety documentation
78
+ - Logger `LOG_LEVEL` validation (L1) and `setLevel()` guard (L2)
79
+ - CI `security-scan` Node version alignment (L3)
80
+
81
+ ## Changed
82
+
83
+ - `@types/node`: 25.3.2 → 25.3.3 (patch)
84
+ - `globals`: 17.3.0 → 17.4.0 (minor)
85
+ - `minimatch` override: 10.2.3 → 10.2.4 (patch)
86
+ - `tar` override: 7.5.8 → 7.5.9 (patch)
87
+
88
+ ## Removed
89
+
90
+ - **Unused `cors` dependency** — CORS handled by custom middleware
91
+
92
+ ## CI/CD
93
+
94
+ - Removed Dependabot auto-merge workflow
95
+ - Trivy Action updated to 0.34.0
96
+ - Node.js test matrix aligned: `[24.x, 25.x]`
97
+ - Blocking `npm audit` in CI pipeline
98
+ - Blocking TruffleHog secret scanning
99
+
100
+ ## Documentation
101
+
102
+ - Revised `hooks/README.md` with progressive enhancement model
103
+ - Updated Session Management in README.md and DOCKER_README.md
104
+ - SECURITY.md rewrite for TypeScript era
105
+ - Team collaboration in READMEs with wiki links
106
+ - Rate limiting documentation
107
+
108
+ ---
109
+
110
+ ```bash
111
+ # npm
112
+ npm install -g memory-journal-mcp@4.5.0
113
+
114
+ # Docker
115
+ docker pull writenotenow/memory-journal-mcp:v4.5.0
116
+ ```
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Generates src/constants/ServerInstructions.ts from src/constants/server-instructions.md
3
+ *
4
+ * Reads the markdown source file, splits it by section delimiters,
5
+ * escapes for template literals, and produces the full TypeScript module
6
+ * with types, constants, and the generateInstructions function.
7
+ *
8
+ * Usage: node scripts/generate-server-instructions.ts
9
+ */
10
+
11
+ import { readFileSync, writeFileSync } from 'node:fs'
12
+ import { dirname, resolve } from 'node:path'
13
+ import { fileURLToPath } from 'node:url'
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url))
16
+ const projectRoot = resolve(__dirname, '..')
17
+
18
+ const mdPath = resolve(projectRoot, 'src/constants/server-instructions.md')
19
+ const tsPath = resolve(projectRoot, 'src/constants/ServerInstructions.ts')
20
+
21
+ // Read plain markdown source
22
+ const markdown = readFileSync(mdPath, 'utf-8')
23
+
24
+ // Section names in order
25
+ const SECTION_NAMES = ['ESSENTIAL', 'GITHUB', 'SERVER_ACCESS', 'TOOL_PARAMETER_REFERENCE']
26
+
27
+ /**
28
+ * Parse sections from markdown using <!-- SECTION:NAME --> delimiters
29
+ */
30
+ function parseSections(content) {
31
+ const sections = {}
32
+
33
+ for (let i = 0; i < SECTION_NAMES.length; i++) {
34
+ const name = SECTION_NAMES[i]
35
+ const startMarker = '<!-- SECTION:' + name + ' -->'
36
+ const startIdx = content.indexOf(startMarker)
37
+
38
+ if (startIdx === -1) {
39
+ throw new Error('Missing section marker: ' + startMarker)
40
+ }
41
+
42
+ const contentStart = startIdx + startMarker.length
43
+
44
+ // Find next section marker or end of file
45
+ let contentEnd
46
+ if (i + 1 < SECTION_NAMES.length) {
47
+ const nextMarker = '<!-- SECTION:' + SECTION_NAMES[i + 1] + ' -->'
48
+ contentEnd = content.indexOf(nextMarker)
49
+ if (contentEnd === -1) {
50
+ throw new Error('Missing section marker: ' + nextMarker)
51
+ }
52
+ } else {
53
+ contentEnd = content.length
54
+ }
55
+
56
+ // Trim leading/trailing whitespace but preserve internal structure
57
+ sections[name] = content.slice(contentStart, contentEnd).trim()
58
+ }
59
+
60
+ return sections
61
+ }
62
+
63
+ /**
64
+ * Escape content for use inside a JS/TS template literal
65
+ */
66
+ function escapeForTemplateLiteral(content) {
67
+ return content.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${')
68
+ }
69
+
70
+ const sections = parseSections(markdown)
71
+
72
+ // Read the function body template (static TypeScript code after the constants)
73
+ const FUNCTION_BODY = readFileSync(
74
+ resolve(projectRoot, 'scripts/server-instructions-function-body.ts'),
75
+ 'utf-8'
76
+ )
77
+
78
+ // Build the TypeScript file using string concatenation to avoid nested escaping
79
+ const lines = []
80
+
81
+ lines.push('/**')
82
+ lines.push(' * Server instructions for Memory Journal MCP.')
83
+ lines.push(' *')
84
+ lines.push(' * ⚠️ AUTO-GENERATED — DO NOT EDIT THIS FILE DIRECTLY')
85
+ lines.push(' * Edit src/constants/server-instructions.md instead,')
86
+ lines.push(' * then run: npm run generate:instructions')
87
+ lines.push(' *')
88
+ lines.push(' * These instructions are automatically sent to MCP clients during initialization,')
89
+ lines.push(' * providing guidance for AI agents on tool usage.')
90
+ lines.push(' *')
91
+ lines.push(' * Optimized for token efficiency with tiered instruction levels.')
92
+ lines.push(' */')
93
+ lines.push('')
94
+ lines.push("import type { ToolGroup } from '../types/index.js'")
95
+ lines.push("import { TOOL_GROUPS } from '../filtering/ToolFilter.js'")
96
+ lines.push('')
97
+ lines.push('/**')
98
+ lines.push(' * Resource definition for instruction generation')
99
+ lines.push(' */')
100
+ lines.push('export interface ResourceDefinition {')
101
+ lines.push(' uri: string')
102
+ lines.push(' name: string')
103
+ lines.push(' description?: string')
104
+ lines.push('}')
105
+ lines.push('')
106
+ lines.push('/**')
107
+ lines.push(' * Prompt definition for instruction generation')
108
+ lines.push(' */')
109
+ lines.push('export interface PromptDefinition {')
110
+ lines.push(' name: string')
111
+ lines.push(' description?: string')
112
+ lines.push('}')
113
+ lines.push('')
114
+ lines.push('/**')
115
+ lines.push(' * Latest entry snapshot for initial briefing')
116
+ lines.push(' */')
117
+ lines.push('export interface LatestEntrySnapshot {')
118
+ lines.push(' id: number')
119
+ lines.push(' timestamp: string')
120
+ lines.push(' entryType: string')
121
+ lines.push(' content: string')
122
+ lines.push('}')
123
+ lines.push('')
124
+ lines.push('/**')
125
+ lines.push(' * Instruction detail level for token efficiency')
126
+ lines.push(' * - essential: ~200 tokens - Core behaviors only (for token-constrained clients)')
127
+ lines.push(' * - standard: ~400 tokens - + GitHub patterns (default)')
128
+ lines.push(' * - full: ~600 tokens - + tool/resource listings')
129
+ lines.push(' */')
130
+ lines.push("export type InstructionLevel = 'essential' | 'standard' | 'full'")
131
+ lines.push('')
132
+ lines.push('/**')
133
+ lines.push(' * Essential behavioral guidance (~200 tokens)')
134
+ lines.push(' * Core patterns every AI agent should follow.')
135
+ lines.push(' */')
136
+ lines.push(
137
+ 'const ESSENTIAL_INSTRUCTIONS = `' + escapeForTemplateLiteral(sections.ESSENTIAL) + '\n`'
138
+ )
139
+ lines.push('')
140
+ lines.push('/**')
141
+ lines.push(' * GitHub integration patterns (~150 additional tokens)')
142
+ lines.push(' */')
143
+ lines.push('const GITHUB_INSTRUCTIONS = `\n' + escapeForTemplateLiteral(sections.GITHUB) + '\n`')
144
+ lines.push('')
145
+ lines.push('/**')
146
+ lines.push(' * Server access instructions - critical for AI agents to call tools correctly')
147
+ lines.push(' */')
148
+ lines.push(
149
+ 'const SERVER_ACCESS_INSTRUCTIONS = `\n' +
150
+ escapeForTemplateLiteral(sections.SERVER_ACCESS) +
151
+ '\n`'
152
+ )
153
+ lines.push('')
154
+ lines.push('/**')
155
+ lines.push(' * Tool parameter reference - essential for correct tool invocation')
156
+ lines.push(' */')
157
+ lines.push(
158
+ 'const TOOL_PARAMETER_REFERENCE = `\n' +
159
+ escapeForTemplateLiteral(sections.TOOL_PARAMETER_REFERENCE) +
160
+ '\n`'
161
+ )
162
+ lines.push('')
163
+ lines.push(FUNCTION_BODY)
164
+ lines.push('')
165
+
166
+ const tsContent = lines.join('\n')
167
+
168
+ writeFileSync(tsPath, tsContent, 'utf-8')
169
+
170
+ process.stderr.write(
171
+ '✅ Generated ServerInstructions.ts (' +
172
+ tsContent.length.toLocaleString() +
173
+ ' bytes) from server-instructions.md (' +
174
+ markdown.length.toLocaleString() +
175
+ ' bytes)\n'
176
+ )
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Generate dynamic instructions based on enabled tools, resources, prompts, and latest entry
3
+ *
4
+ * @param enabledTools - Set of enabled tool names
5
+ * @param resources - Available resource definitions
6
+ * @param prompts - Available prompt definitions
7
+ * @param latestEntry - Optional latest entry for context snapshot
8
+ * @param level - Instruction detail level (default: 'standard')
9
+ */
10
+ export function generateInstructions(
11
+ enabledTools: Set<string>,
12
+ _resources: ResourceDefinition[],
13
+ prompts: PromptDefinition[],
14
+ latestEntry?: LatestEntrySnapshot,
15
+ level: InstructionLevel = 'standard'
16
+ ): string {
17
+ let instructions = ESSENTIAL_INSTRUCTIONS
18
+
19
+ // Add latest entry snapshot for immediate context (compact format)
20
+ if (latestEntry) {
21
+ const preview = latestEntry.content.slice(0, 120)
22
+ instructions += `\n**Latest**: #${String(latestEntry.id)} (${latestEntry.timestamp}) ${latestEntry.entryType}\n> ${preview}${latestEntry.content.length > 120 ? '...' : ''}\n`
23
+ }
24
+
25
+ // Standard and full levels include GitHub patterns
26
+ if (level === 'standard' || level === 'full') {
27
+ instructions += GITHUB_INSTRUCTIONS
28
+ }
29
+
30
+ // Full level includes server access instructions and tool parameter reference
31
+ if (level === 'full') {
32
+ instructions += SERVER_ACCESS_INSTRUCTIONS
33
+ instructions += TOOL_PARAMETER_REFERENCE
34
+
35
+ // Add active tools summary
36
+ const activeGroups = getActiveToolGroups(enabledTools)
37
+ if (activeGroups.length > 0) {
38
+ instructions += `\n## Active Tools (${String(enabledTools.size)})\n`
39
+ for (const { group, tools } of activeGroups) {
40
+ instructions += `**${group}**: ${tools.map((t) => `\`${t}\``).join(', ')}\n`
41
+ }
42
+ }
43
+
44
+ // Add prompts section
45
+ if (prompts.length > 0) {
46
+ instructions += `\n## Prompts (${String(prompts.length)})\n`
47
+ instructions += 'Pre-built templates and guided workflows:\n'
48
+ for (const prompt of prompts) {
49
+ instructions += `- \`${prompt.name}\` - ${prompt.description ?? ''}\n`
50
+ }
51
+ }
52
+ }
53
+
54
+ return instructions
55
+ }
56
+
57
+ /**
58
+ * Get active tool groups with their enabled tools
59
+ */
60
+ function getActiveToolGroups(enabledTools: Set<string>): { group: ToolGroup; tools: string[] }[] {
61
+ const activeGroups: { group: ToolGroup; tools: string[] }[] = []
62
+
63
+ for (const [group, allTools] of Object.entries(TOOL_GROUPS) as [ToolGroup, string[]][]) {
64
+ const enabledInGroup = allTools.filter((tool) => enabledTools.has(tool))
65
+ if (enabledInGroup.length > 0) {
66
+ activeGroups.push({ group, tools: enabledInGroup })
67
+ }
68
+ }
69
+
70
+ return activeGroups
71
+ }
72
+
73
+ /**
74
+ * Static instructions for backward compatibility
75
+ * @deprecated Use generateInstructions() instead for dynamic content
76
+ */
77
+ export const SERVER_INSTRUCTIONS = ESSENTIAL_INSTRUCTIONS + GITHUB_INSTRUCTIONS
package/server.json CHANGED
@@ -3,12 +3,12 @@
3
3
  "name": "io.github.neverinfamous/memory-journal-mcp",
4
4
  "title": "Memory Journal MCP",
5
5
  "description": "MCP server– Project memory system with GitHub-aware context, knowledge graphs, and CI/PR timelines",
6
- "version": "4.4.2",
6
+ "version": "4.5.0",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "oci",
10
- "identifier": "docker.io/writenotenow/memory-journal-mcp:v4.4.2",
11
- "version": "4.4.2",
10
+ "identifier": "docker.io/writenotenow/memory-journal-mcp:v4.5.0",
11
+ "version": "4.5.0",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  }
package/src/cli.ts CHANGED
@@ -23,6 +23,22 @@ program
23
23
  .option('--auto-rebuild-index', 'Rebuild vector index on server startup')
24
24
  .option('--cors-origin <origin>', 'CORS allowed origin for HTTP transport (default: *)')
25
25
  .option('--log-level <level>', 'Log level: debug, info, warning, error', 'info')
26
+ .option(
27
+ '--backup-interval <minutes>',
28
+ 'Automated backup interval in minutes, HTTP only (0 = disabled)',
29
+ '0'
30
+ )
31
+ .option('--keep-backups <count>', 'Max backups to retain during automated cleanup', '5')
32
+ .option(
33
+ '--vacuum-interval <minutes>',
34
+ 'Database optimize interval in minutes, HTTP only (0 = disabled)',
35
+ '0'
36
+ )
37
+ .option(
38
+ '--rebuild-index-interval <minutes>',
39
+ 'Vector index rebuild interval in minutes, HTTP only (0 = disabled)',
40
+ '0'
41
+ )
26
42
  .action(
27
43
  async (options: {
28
44
  transport: string
@@ -35,6 +51,10 @@ program
35
51
  autoRebuildIndex?: boolean
36
52
  corsOrigin?: string
37
53
  logLevel: string
54
+ backupInterval: string
55
+ keepBackups: string
56
+ vacuumInterval: string
57
+ rebuildIndexInterval: string
38
58
  }) => {
39
59
  // Set log level
40
60
  logger.setLevel(options.logLevel as 'debug' | 'info' | 'warning' | 'error')
@@ -67,6 +87,12 @@ program
67
87
  autoRebuildIndex:
68
88
  options.autoRebuildIndex ?? process.env['AUTO_REBUILD_INDEX'] === 'true',
69
89
  corsOrigin: options.corsOrigin,
90
+ scheduler: {
91
+ backupIntervalMinutes: parseInt(options.backupInterval, 10),
92
+ keepBackups: parseInt(options.keepBackups, 10),
93
+ vacuumIntervalMinutes: parseInt(options.vacuumInterval, 10),
94
+ rebuildIndexIntervalMinutes: parseInt(options.rebuildIndexInterval, 10),
95
+ },
70
96
  })
71
97
  } catch (error) {
72
98
  logger.error('Failed to start server', {