@cachly-dev/mcp-server 0.5.2 → 0.5.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cachly-dev/mcp-server",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "MCP server – manage cachly.dev instances from any AI assistant (Copilot, Claude, Cursor, Windsurf)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@
9
9
  "main": "./dist/index.js",
10
10
  "scripts": {
11
11
  "build": "tsc",
12
+ "postinstall": "node scripts/postinstall.js",
12
13
  "dev": "tsx src/index.ts",
13
14
  "start": "node dist/index.js",
14
15
  "test": "vitest run",
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ // Shown once after: npm install @cachly-dev/mcp-server
3
+
4
+ const c = {
5
+ reset: "\x1b[0m",
6
+ bold: "\x1b[1m",
7
+ violet: "\x1b[35m",
8
+ green: "\x1b[32m",
9
+ cyan: "\x1b[36m",
10
+ dim: "\x1b[2m",
11
+ };
12
+
13
+ const line = `${c.dim}─────────────────────────────────────────────────────${c.reset}`;
14
+
15
+ console.log(`
16
+ ${line}
17
+ ${c.bold}${c.violet}🧠 Cachly Brain MCP Server${c.reset} ${c.dim}v${process.env.npm_package_version ?? ""}${c.reset}
18
+
19
+ ${c.bold}Give your AI assistant persistent memory in 30 seconds:${c.reset}
20
+
21
+ ${c.cyan}1.${c.reset} Get a free Brain instance at ${c.bold}cachly.dev/setup-ai${c.reset}
22
+ ${c.cyan}2.${c.reset} Add to Claude Code / Cursor / Copilot:
23
+ ${c.dim}npx @cachly-dev/mcp-server --key cky_live_... --instance <uuid>${c.reset}
24
+
25
+ ${c.green}✅ Free tier · GDPR · German servers · No credit card${c.reset}
26
+
27
+ ${line}`);
package/src/index.ts CHANGED
@@ -4114,8 +4114,75 @@ const server = new Server(
4114
4114
 
4115
4115
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
4116
4116
 
4117
+ // ── Auto-session management ───────────────────────────────────────────────────
4118
+ // Transparently starts a Brain session on the first tool call of a process
4119
+ // and saves a session_end summary on SIGTERM/exit so users never have to call
4120
+ // session_start/session_end manually.
4121
+
4122
+ let _autoSessionInstanceId: string | null = null;
4123
+ let _autoSessionStarted = false;
4124
+ let _autoSessionToolCount = 0;
4125
+
4126
+ async function autoStartSession(instanceId: string): Promise<void> {
4127
+ if (_autoSessionStarted) return;
4128
+ _autoSessionStarted = true;
4129
+ _autoSessionInstanceId = instanceId;
4130
+ try {
4131
+ await handleTool('session_start', { instance_id: instanceId, focus: 'auto (MCP session)' });
4132
+ } catch { /* non-fatal — session tracking is a best-effort feature */ }
4133
+
4134
+ // Auto-index the project if it hasn't been indexed in the last 24h.
4135
+ // This is the main lever for growing token savings: more indexed code →
4136
+ // more semantic cache hits → fewer LLM calls for repeated questions.
4137
+ if (process.env.CACHLY_AUTO_INDEX !== 'false') {
4138
+ try {
4139
+ const redis = await getConnection(instanceId);
4140
+ const lastIndexed = await redis.get(`cachly:index:last_indexed:${instanceId}`);
4141
+ const staleMs = 24 * 60 * 60 * 1000;
4142
+ const isStale = !lastIndexed || (Date.now() - parseInt(lastIndexed, 10)) > staleMs;
4143
+ if (isStale) {
4144
+ // Mark as indexing now to prevent concurrent re-runs.
4145
+ await redis.set(`cachly:index:last_indexed:${instanceId}`, String(Date.now()), 'EX', 90000);
4146
+ // Run in background — don't block the first tool call.
4147
+ handleTool('index_project', {
4148
+ instance_id: instanceId,
4149
+ dir: process.cwd(),
4150
+ max_files: 150,
4151
+ ttl: 86400 * 7, // cache for 7 days
4152
+ namespace: 'cachly:sem:code',
4153
+ }).catch(() => undefined);
4154
+ }
4155
+ } catch { /* never block the session on indexing errors */ }
4156
+ }
4157
+ }
4158
+
4159
+ async function autoEndSession(): Promise<void> {
4160
+ if (!_autoSessionStarted || !_autoSessionInstanceId) return;
4161
+ _autoSessionStarted = false;
4162
+ try {
4163
+ await handleTool('session_end', {
4164
+ instance_id: _autoSessionInstanceId,
4165
+ summary: `Auto-ended after ${_autoSessionToolCount} tool call(s). Session was started automatically.`,
4166
+ files_changed: [],
4167
+ lessons_learned: 0,
4168
+ });
4169
+ } catch { /* non-fatal */ }
4170
+ }
4171
+
4117
4172
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
4118
4173
  const { name, arguments: args } = request.params;
4174
+
4175
+ // Auto-start brain session on first tool call that has an instance_id.
4176
+ // Skip session management tools to avoid recursion.
4177
+ const sessionTools = new Set(['session_start', 'session_end', 'auto_learn_session']);
4178
+ if (!sessionTools.has(name) && !_autoSessionStarted) {
4179
+ const instanceId = (args as Record<string, unknown>)?.instance_id as string | undefined;
4180
+ if (instanceId) {
4181
+ await autoStartSession(instanceId).catch(() => undefined);
4182
+ }
4183
+ }
4184
+ if (!sessionTools.has(name)) _autoSessionToolCount++;
4185
+
4119
4186
  try {
4120
4187
  const text = await handleTool(name, (args ?? {}) as Record<string, unknown>);
4121
4188
  return { content: [{ type: 'text', text }] };
@@ -4125,8 +4192,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
4125
4192
  }
4126
4193
  });
4127
4194
 
4128
- // Graceful shutdown – close all Redis connections
4195
+ // Graceful shutdown – close all Redis connections + auto-end brain session
4129
4196
  process.on('SIGTERM', async () => {
4197
+ await autoEndSession().catch(() => undefined);
4198
+ for (const [, client] of pool) await client.quit().catch(() => undefined);
4199
+ process.exit(0);
4200
+ });
4201
+
4202
+ process.on('SIGINT', async () => {
4203
+ await autoEndSession().catch(() => undefined);
4130
4204
  for (const [, client] of pool) await client.quit().catch(() => undefined);
4131
4205
  process.exit(0);
4132
4206
  });
@@ -4179,26 +4253,26 @@ function buildClaudeMdBlock(instanceId: string): string {
4179
4253
  ## Cachly AI Brain
4180
4254
 
4181
4255
  The Cachly MCP server is available as tool \`cachly\`.
4256
+ Your instance ID: \`${instanceId}\`
4182
4257
 
4183
- ### At the START of every session (one call):
4184
- \`\`\`
4185
- session_start(
4186
- instance_id = "${instanceId}",
4187
- focus = "<what you plan to work on today>",
4188
- )
4189
- \`\`\`
4258
+ > **Sessions are fully automatic** (MCP ≥ 0.5.3).
4259
+ > The Brain starts tracking when you call any tool for the first time and saves a summary when your editor closes. You never need to call \`session_start\` or \`session_end\` manually.
4260
+
4261
+ ---
4190
4262
 
4191
- ### At the END of every session:
4263
+ ### Before editing any file — WIP-registry (prevents half-finished code across sessions):
4192
4264
  \`\`\`
4193
- session_end(
4194
- instance_id = "${instanceId}",
4195
- summary = "What was accomplished (2-3 sentences)",
4196
- files_changed = ["src/..."],
4197
- lessons_learned = 1,
4265
+ remember_context(
4266
+ instance_id = "${instanceId}",
4267
+ key = "wip-registry",
4268
+ content = "EDITING: <file:line> — goal: <what you are implementing>",
4269
+ category = "bug",
4270
+ ttl = 86400,
4198
4271
  )
4199
4272
  \`\`\`
4273
+ After the edit is complete, update \`content\` to \`"DONE: <file> — <what was completed>"\`.
4200
4274
 
4201
- ### After fixing any bug or learning something new:
4275
+ ### After fixing any bug or solving a tricky problem:
4202
4276
  \`\`\`
4203
4277
  learn_from_attempts(
4204
4278
  instance_id = "${instanceId}",
@@ -4209,9 +4283,21 @@ learn_from_attempts(
4209
4283
  severity = "critical" | "major" | "minor",
4210
4284
  file_paths = ["path/to/file"],
4211
4285
  commands = ["the command that worked"],
4212
- tags = ["tag1", "tag2"],
4286
+ tags = ["tag1"],
4287
+ )
4288
+ \`\`\`
4289
+
4290
+ ### Before starting any task — recall relevant lessons first:
4291
+ \`\`\`
4292
+ smart_recall(
4293
+ instance_id = "${instanceId}",
4294
+ query = "<describe what you are about to do>",
4213
4295
  )
4214
4296
  \`\`\`
4297
+
4298
+ ### Half-finished code rule:
4299
+ Never commit code that does not compile. Run \`tsc --noEmit\` / \`go build ./...\` before every commit.
4300
+ If a session ends mid-task, save the WIP-registry entry so the next session picks up exactly where you left off.
4215
4301
  ${CLAUDE_MD_MARKER_END}`;
4216
4302
  }
4217
4303