@cachly-dev/mcp-server 0.9.0 → 0.9.1
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/CHANGELOG.md +12 -0
- package/README.md +33 -1
- package/dist/index.js +106 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +117 -4
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cachly-dev/mcp-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"mcpName": "io.github.cachly-dev/cachly-mcp",
|
|
5
|
-
"description": "The world's first Cognitive Cache — AI memory that thinks.
|
|
5
|
+
"description": "The world's first Cognitive Cache — AI memory that thinks. 68 MCP tools: sessions, lessons, semantic search, team brain, knowledge syndication, causal tracing, memory consolidation, compact recovery. Claude Code, Cursor, Copilot, Windsurf.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"cachly-mcp": "./dist/index.js"
|
package/server.json
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
"url": "https://github.com/cachly-dev/cachly-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"name": "@cachly-dev/mcp-server",
|
|
14
14
|
"identifier": "@cachly-dev/mcp-server",
|
|
15
|
-
"version": "0.9.
|
|
15
|
+
"version": "0.9.1",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|
package/src/index.ts
CHANGED
|
@@ -3037,6 +3037,22 @@ const TOOLS = [
|
|
|
3037
3037
|
required: ['instance_id'],
|
|
3038
3038
|
},
|
|
3039
3039
|
},
|
|
3040
|
+
// ── crystal_view — inspect current Memory Crystal ──────────────────────
|
|
3041
|
+
{
|
|
3042
|
+
name: 'crystal_view',
|
|
3043
|
+
description:
|
|
3044
|
+
'View the current Memory Crystal — the distilled snapshot of everything your AI brain has learned. ' +
|
|
3045
|
+
'Shows all top patterns grouped by category, lesson count, crystal age, and when to refresh. ' +
|
|
3046
|
+
'A crystal is created by memory_crystalize and injected into every session_start automatically. ' +
|
|
3047
|
+
'Call this to review what institutional knowledge is preserved, or to decide if a refresh is due.',
|
|
3048
|
+
inputSchema: {
|
|
3049
|
+
type: 'object',
|
|
3050
|
+
properties: {
|
|
3051
|
+
instance_id: { type: 'string', description: 'UUID of the cache instance' },
|
|
3052
|
+
},
|
|
3053
|
+
required: ['instance_id'],
|
|
3054
|
+
},
|
|
3055
|
+
},
|
|
3040
3056
|
// ── Roadmap — Persistent project plan tracker ───────────────────────────
|
|
3041
3057
|
{
|
|
3042
3058
|
name: 'roadmap_add',
|
|
@@ -5589,6 +5605,21 @@ async function handleTool(name: string, args: Record<string, unknown>): Promise<
|
|
|
5589
5605
|
} catch { /* git not available or not a repo — silent skip */ }
|
|
5590
5606
|
}
|
|
5591
5607
|
|
|
5608
|
+
// ── Crystal age check — remind if > 30 days old or missing ──────────────
|
|
5609
|
+
let crystalReminder = '';
|
|
5610
|
+
try {
|
|
5611
|
+
const crystalRaw = await redis.get('cachly:crystal:latest');
|
|
5612
|
+
if (!crystalRaw) {
|
|
5613
|
+
crystalReminder = `💎 **Memory Crystal:** None exists yet. Run \`memory_crystalize(instance_id="${instance_id}")\` to distill your brain into a permanent snapshot — injected into every future session automatically.`;
|
|
5614
|
+
} else {
|
|
5615
|
+
const crystal = JSON.parse(crystalRaw) as { ts: string; label?: string; lesson_count?: number };
|
|
5616
|
+
const crystalAgeDays = Math.round((Date.now() - new Date(crystal.ts).getTime()) / 86_400_000);
|
|
5617
|
+
if (crystalAgeDays >= 30) {
|
|
5618
|
+
crystalReminder = `💎 **Memory Crystal is ${crystalAgeDays} days old** (${crystal.label ?? 'unnamed'}). Run \`memory_crystalize(instance_id="${instance_id}")\` to refresh it with your latest ${crystal.lesson_count ?? '?'} lessons.`;
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
} catch { /* non-critical */ }
|
|
5622
|
+
|
|
5592
5623
|
const durationStr = durationMin !== undefined ? ` · ${durationMin} min` : '';
|
|
5593
5624
|
return [
|
|
5594
5625
|
`✅ **Session saved**${durationStr}`,
|
|
@@ -5598,6 +5629,7 @@ async function handleTool(name: string, args: Record<string, unknown>): Promise<
|
|
|
5598
5629
|
lessons_learned !== undefined ? `🧠 **Lessons stored:** ${lessons_learned}` : '',
|
|
5599
5630
|
autoLearned.length > 0 ? `🤖 **Auto-learned:** ${autoLearned.length} lessons extracted from summary (${autoLearned.slice(0, 3).map(t => `\`${t}\``).join(', ')}${autoLearned.length > 3 ? '…' : ''})` : '',
|
|
5600
5631
|
ambientLearned.length > 0 ? `🌿 **Ambient git learning:** ${ambientLearned.length} commit${ambientLearned.length > 1 ? 's' : ''} auto-learned (${ambientLearned.slice(0, 3).map(t => `\`${t}\``).join(', ')}${ambientLearned.length > 3 ? '…' : ''})` : '',
|
|
5632
|
+
crystalReminder,
|
|
5601
5633
|
``,
|
|
5602
5634
|
`💡 Next session: \`session_start(focus="...")\` to see this summary.`,
|
|
5603
5635
|
].filter(l => l !== '').join('\n');
|
|
@@ -6077,6 +6109,63 @@ async function handleTool(name: string, args: Record<string, unknown>): Promise<
|
|
|
6077
6109
|
return lines.join('\n');
|
|
6078
6110
|
}
|
|
6079
6111
|
|
|
6112
|
+
// ── crystal_view — show current Memory Crystal ───────────────────────────
|
|
6113
|
+
case 'crystal_view': {
|
|
6114
|
+
const { instance_id } = args as { instance_id: string };
|
|
6115
|
+
const redis = await getConnection(instance_id);
|
|
6116
|
+
|
|
6117
|
+
const crystalRaw = await redis.get('cachly:crystal:latest');
|
|
6118
|
+
if (!crystalRaw) {
|
|
6119
|
+
return [
|
|
6120
|
+
`💎 **No Memory Crystal yet**`,
|
|
6121
|
+
``,
|
|
6122
|
+
`Your brain has no crystal — all knowledge lives in raw lessons only.`,
|
|
6123
|
+
``,
|
|
6124
|
+
`Run \`memory_crystalize(instance_id="${instance_id}")\` to:`,
|
|
6125
|
+
` • Distill everything learned into a permanent, compact snapshot`,
|
|
6126
|
+
` • Inject it into every future \`session_start\` automatically`,
|
|
6127
|
+
` • Preserve team knowledge even after lesson TTLs expire`,
|
|
6128
|
+
``,
|
|
6129
|
+
`💡 Recommended: run monthly or after any major milestone.`,
|
|
6130
|
+
].join('\n');
|
|
6131
|
+
}
|
|
6132
|
+
|
|
6133
|
+
const crystal = JSON.parse(crystalRaw) as {
|
|
6134
|
+
label: string; ts: string; session_count: number; lesson_count: number;
|
|
6135
|
+
top_patterns: Array<{ category: string; insight: string; count: number }>;
|
|
6136
|
+
categories: string[]; created_from: string;
|
|
6137
|
+
};
|
|
6138
|
+
|
|
6139
|
+
const ageDays = Math.round((Date.now() - new Date(crystal.ts).getTime()) / 86_400_000);
|
|
6140
|
+
const ageStr = ageDays === 0 ? 'today' : ageDays === 1 ? '1 day ago' : `${ageDays} days ago`;
|
|
6141
|
+
const freshness = ageDays < 14 ? '🟢 Fresh' : ageDays < 30 ? '🟡 Aging' : '🔴 Stale — refresh recommended';
|
|
6142
|
+
|
|
6143
|
+
const lines: string[] = [
|
|
6144
|
+
`💎 **Memory Crystal: ${crystal.label}**`,
|
|
6145
|
+
``,
|
|
6146
|
+
`📅 Created: **${ageStr}** · Freshness: ${freshness}`,
|
|
6147
|
+
`📊 Compressed: **${crystal.session_count} sessions** + **${crystal.lesson_count} lessons** → ${crystal.top_patterns.length} patterns`,
|
|
6148
|
+
`🗂️ Categories: ${crystal.categories.slice(0, 10).join(', ')}${crystal.categories.length > 10 ? `… +${crystal.categories.length - 10}` : ''}`,
|
|
6149
|
+
``,
|
|
6150
|
+
`**Top patterns by category:**`,
|
|
6151
|
+
``,
|
|
6152
|
+
];
|
|
6153
|
+
|
|
6154
|
+
for (const p of crystal.top_patterns) {
|
|
6155
|
+
lines.push(`**${p.category}** (${p.count} lesson${p.count > 1 ? 's' : ''})`);
|
|
6156
|
+
lines.push(` → ${p.insight.slice(0, 150)}${p.insight.length > 150 ? '…' : ''}`);
|
|
6157
|
+
lines.push('');
|
|
6158
|
+
}
|
|
6159
|
+
|
|
6160
|
+
if (ageDays >= 30) {
|
|
6161
|
+
lines.push(`---`, `⚠️ Crystal is ${ageDays} days old. Run \`memory_crystalize(instance_id="${instance_id}")\` to refresh with your latest lessons.`);
|
|
6162
|
+
} else {
|
|
6163
|
+
lines.push(`---`, `💡 This crystal is injected automatically into every \`session_start\`. Refresh monthly with \`memory_crystalize\`.`);
|
|
6164
|
+
}
|
|
6165
|
+
|
|
6166
|
+
return lines.filter(l => l !== undefined).join('\n');
|
|
6167
|
+
}
|
|
6168
|
+
|
|
6080
6169
|
case 'brain_doctor': {
|
|
6081
6170
|
const { instance_id, workspace_path: drWorkspacePath = '' } = args as { instance_id: string; workspace_path?: string };
|
|
6082
6171
|
const redis = await getConnection(instance_id);
|
|
@@ -7593,9 +7682,11 @@ async function handleBulkLockStream(name: string, args: Record<string, unknown>)
|
|
|
7593
7682
|
> Sessions are fully automatic. The Brain starts when you call any tool and saves a summary when you close.
|
|
7594
7683
|
|
|
7595
7684
|
### MANDATORY hooks (always fire, no exceptions):
|
|
7685
|
+
- **Context compacted** → call \`compact_recover(instance_id="${instance_id}", focus="<current task>")\` FIRST
|
|
7596
7686
|
- **Window opens** → call \`session_start(instance_id="${instance_id}", focus="<today's goal>")\`
|
|
7597
7687
|
- **Bug fixed / deployed / discovered** → call \`learn_from_attempts(instance_id="${instance_id}", topic="fix:<area>", outcome="success", what_worked="...")\`
|
|
7598
7688
|
- **Window closes** → call \`session_end(instance_id="${instance_id}", summary="...", files_changed=[...])\`
|
|
7689
|
+
- **Monthly** → call \`memory_crystalize(instance_id="${instance_id}")\` to distill knowledge into a permanent Crystal
|
|
7599
7690
|
`;
|
|
7600
7691
|
|
|
7601
7692
|
const full = `## Cachly AI Brain — Autopilot for ${project_name}
|
|
@@ -7656,18 +7747,40 @@ smart_recall(
|
|
|
7656
7747
|
|
|
7657
7748
|
---
|
|
7658
7749
|
|
|
7659
|
-
## ⚡
|
|
7750
|
+
## ⚡ Context Recovery (MANDATORY after compaction)
|
|
7751
|
+
|
|
7752
|
+
**If your context window was compacted**, call this FIRST — before reading any file:
|
|
7753
|
+
\`\`\`
|
|
7754
|
+
compact_recover(
|
|
7755
|
+
instance_id = "${instance_id}",
|
|
7756
|
+
focus = "<what you were working on>",
|
|
7757
|
+
)
|
|
7758
|
+
\`\`\`
|
|
7759
|
+
Returns: last checkpoint, pending tasks, top lessons. Instant — no full brain scan.
|
|
7760
|
+
|
|
7761
|
+
---
|
|
7762
|
+
|
|
7763
|
+
## 🔁 Scheduled Maintenance (run on schedule)
|
|
7764
|
+
|
|
7765
|
+
| When | Call |
|
|
7766
|
+
|---|---|
|
|
7767
|
+
| **Monthly** | \`memory_crystalize(instance_id="${instance_id}")\` — distill brain into a permanent snapshot |
|
|
7768
|
+
| Weekly review | \`brain_diff(instance_id="${instance_id}", since="7d")\` — see what your AI learned this week |
|
|
7769
|
+
| Before big refactor | \`knowledge_decay(instance_id="${instance_id}")\` — see which lessons to still trust |
|
|
7770
|
+
| After major milestone | \`memory_crystalize(instance_id="${instance_id}", label="v2 launch")\` — preserve milestone knowledge |
|
|
7771
|
+
|
|
7772
|
+
## 🧠 Cognitive Tools (use anytime)
|
|
7660
7773
|
|
|
7661
7774
|
| When | Call |
|
|
7662
7775
|
|---|---|
|
|
7663
7776
|
| Brain feeling cluttered | \`memory_consolidate(instance_id="${instance_id}")\` |
|
|
7664
|
-
| Weekly review | \`brain_diff(instance_id="${instance_id}", since="7d")\` |
|
|
7665
7777
|
| Weird bug, no idea why | \`causal_trace(instance_id="${instance_id}", problem="<symptom>")\` |
|
|
7666
|
-
|
|
|
7778
|
+
| Unknown error | \`syndicate_search(q="<error message>")\` — global community solutions |
|
|
7779
|
+
| Unknown error that you solved | \`syndicate(instance_id="${instance_id}", topic="fix:<area>", what_worked="...")\` |
|
|
7667
7780
|
|
|
7668
7781
|
---
|
|
7669
7782
|
|
|
7670
|
-
*Cachly v0.
|
|
7783
|
+
*Cachly v0.9 · Generated ${new Date().toISOString().slice(0, 10)}*
|
|
7671
7784
|
`;
|
|
7672
7785
|
|
|
7673
7786
|
const content = style === 'minimal' ? minimal : full;
|