@memly/mcp-server 0.2.1 → 0.2.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 (3) hide show
  1. package/README.md +85 -41
  2. package/dist/index.js +340 -63
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,16 +1,49 @@
1
1
  # @memly/mcp-server
2
2
 
3
- > Persistent memory for any IDE that supports MCP.
3
+ > Persistent memory for IDEs that **don't support custom LLM providers**.
4
4
 
5
- ## Supported IDEs
5
+ ## Proxy vs MCP — which one should I use?
6
6
 
7
- | IDE | Config File |
8
- |---|---|
9
- | VS Code + Copilot | `.vscode/mcp.json` |
10
- | Cursor | Settings → MCP |
11
- | Claude Desktop | `claude_desktop_config.json` |
12
- | Windsurf | Settings MCP |
13
- | Zed | Settings |
7
+ Memly has two integration modes:
8
+
9
+ | Mode | How it works | Best for |
10
+ |------|-------------|----------|
11
+ | **Proxy** (transparent) | Point your IDE's base URL to `api.memly.site` — memory injected in 100% of requests, invisible | IDEs that support a custom OpenAI-compatible endpoint |
12
+ | **MCP server** (this package) | Memly runs as an MCP tool — `load_context` is called automatically at session start | IDEs locked to their own AI service |
13
+
14
+ ---
15
+
16
+ ## Which mode for my IDE?
17
+
18
+ ### ✅ Use the Proxy — supports custom endpoint
19
+
20
+ | IDE / Tool | Where to configure |
21
+ |-----------|-------------------|
22
+ | **Cursor** | Settings → Models → OpenAI Base URL |
23
+ | **Continue.dev** (VS Code / JetBrains extension) | `config.json` → `apiBase` |
24
+ | **Zed** | `settings.json` → `api_url` |
25
+ | **Aider** | `--openai-api-base` CLI flag |
26
+ | **Jan.ai** | Settings → Model → Engine URL |
27
+ | **LM Studio** | Server settings |
28
+ | **Open WebUI** | Admin → Connections |
29
+ | **Msty** | Settings → Custom provider |
30
+ | **Void** | Settings → Custom provider |
31
+
32
+ ### ❌ Use the MCP server — locked provider, no custom endpoint
33
+
34
+ | IDE / Tool | Reason |
35
+ |-----------|--------|
36
+ | **VS Code + GitHub Copilot** | Microsoft/GitHub auth — base URL not configurable |
37
+ | **JetBrains AI Assistant** | Locked to JetBrains AI Service subscription |
38
+ | **Windsurf (Codeium)** | Cascade uses Codeium's own models — no external endpoint |
39
+ | **Amazon Q / CodeWhisperer** | AWS-only pipeline |
40
+ | **Tabnine** | Proprietary closed service |
41
+ | **Replit AI** | Built into Replit, no external provider |
42
+ | **Gitpod AI** | Locked to their own service |
43
+ | **Sourcegraph Cody** | Locked on free tier |
44
+ | **Claude Desktop** | Chat app, not an IDE — MCP native |
45
+
46
+ ---
14
47
 
15
48
  ## Quick Start
16
49
 
@@ -18,19 +51,25 @@
18
51
 
19
52
  Go to [memly.site/dashboard/api-keys](https://memly.site/dashboard/api-keys)
20
53
 
21
- ### 2. Auto-setup (one command)
54
+ ### 2. Configure your IDE's MCP server
22
55
 
23
- Run this in your project root auto-detects your IDE and writes the instruction file:
56
+ **VS Code / GitHub Copilot**create `.vscode/mcp.json` in your project:
24
57
 
25
- ```bash
26
- npx @memly/mcp-server init
58
+ ```json
59
+ {
60
+ "servers": {
61
+ "memly": {
62
+ "command": "npx",
63
+ "args": ["-y", "@memly/mcp-server"],
64
+ "env": {
65
+ "MEMLY_API_KEY": "memly_your_key_here"
66
+ }
67
+ }
68
+ }
69
+ }
27
70
  ```
28
71
 
29
- This creates the right file for your IDE so Memly loads context automatically on every conversation. Run once, forget forever.
30
-
31
- ### 3. Configure your IDE's MCP server
32
-
33
- **VS Code / Copilot** — create `.vscode/mcp.json`:
72
+ **JetBrains** (IntelliJ, WebStorm, PyCharm…) create `.idea/mcp.json`:
34
73
 
35
74
  ```json
36
75
  {
@@ -46,8 +85,9 @@ This creates the right file for your IDE so Memly loads context automatically on
46
85
  }
47
86
  ```
48
87
 
49
- **Cursor** — Settings → MCP → Add Server:
50
- - Command: `npx -y @memly/mcp-server`
88
+ **Windsurf** — Settings → Cascade → MCP Servers → Add:
89
+ - Command: `npx`
90
+ - Args: `-y @memly/mcp-server`
51
91
  - Env: `MEMLY_API_KEY=memly_your_key_here`
52
92
 
53
93
  **Claude Desktop** — edit `claude_desktop_config.json`:
@@ -66,38 +106,42 @@ This creates the right file for your IDE so Memly loads context automatically on
66
106
  }
67
107
  ```
68
108
 
69
- ### Automatic Context (Zero Friction)
109
+ ### 3. Run auto-setup once per project
70
110
 
71
- To make your AI agent proactively load context at the start of every session, add this to your `.cursorrules`, `.windsurfrules`, or `GEMINI.md`:
111
+ Writes the instruction file for your IDE so `load_context` runs automatically at every session start:
72
112
 
73
- ```markdown
74
- # Memly Integration
75
- At the start of every session, you MUST:
76
- 1. Call `memly.search_memories({ query: "current active task", limit: 5 })`
77
- 2. Use this context to understand the project state.
78
- 3. When you make major decisions, call `memly.save_memory`.
113
+ ```bash
114
+ npx @memly/mcp-server init
79
115
  ```
80
116
 
81
- ### Tools
117
+ Auto-detects VS Code, Cursor, Windsurf, Claude Desktop. Run once, never think about it again.
118
+
119
+ ---
82
120
 
83
- | Tool | Description |
84
- |---|---|
85
- | `search_memories` | Semantic search across your stored memories |
86
- | `remember` | Store a new memory (fact, decision, pattern) |
87
- | `forget` | Delete a specific memory by ID |
88
- | `list_projects` | List all projects with memory stats |
121
+ ## Tools
122
+
123
+ | Tool | When the AI calls it |
124
+ |------|---------------------|
125
+ | `load_context` | **Automatically at session start** loads memories from previous sessions |
126
+ | `search_memories` | When you ask about something specific not loaded by `load_context` |
127
+ | `remember` | When you make a decision, solve a problem, or say "remember this" |
128
+ | `list_projects` | When you ask to list or switch projects |
129
+
130
+ ---
89
131
 
90
132
  ## Environment Variables
91
133
 
92
134
  | Variable | Required | Default | Description |
93
- |---|---|---|---|
94
- | `MEMLY_API_KEY` | ✅ | — | Your Memly API key |
95
- | `MEMLY_API_URL` | — | `https://api.memly.site` | API base URL |
96
- | `MEMLY_PORT` | — | `3800` | HTTP transport port |
135
+ |----------|----------|---------|-------------|
136
+ | `MEMLY_API_KEY` | ✅ | — | Your Memly API key (`memly_...`) |
137
+ | `MEMLY_API_URL` | — | `https://api.memly.site` | Override for self-hosted deployments |
138
+ | `MEMLY_PORT` | — | `3800` | HTTP transport port (`--http` mode only) |
139
+
140
+ ---
97
141
 
98
- ## Self-Hosted (VPS)
142
+ ## Self-Hosted
99
143
 
100
- Run alongside your Memly proxy for zero-latency:
144
+ Run alongside your Memly proxy on your VPS for zero-latency:
101
145
 
102
146
  ```bash
103
147
  MEMLY_API_KEY=memly_... bun run packages/mcp-server/src/index.ts --http
package/dist/index.js CHANGED
@@ -20211,93 +20211,286 @@ I am ready to continue our work.`
20211
20211
  }
20212
20212
 
20213
20213
  // src/init.ts
20214
- import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
20214
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from "node:fs";
20215
20215
  import { join, resolve } from "node:path";
20216
20216
  import { homedir, platform } from "node:os";
20217
20217
  var MEMLY_INSTRUCTION_BLOCK = `
20218
- ## Memly Persistent Memory (Auto-Enabled)
20218
+ ## Memly — Persistent Memory (Auto-Enabled)
20219
20219
 
20220
20220
  You have access to the Memly MCP server (\`memly\`).
20221
20221
 
20222
- **RULES (always follow, no exceptions):**
20222
+ **RULES (always follow):**
20223
20223
 
20224
- 1. **At the start of EVERY conversation**, call \`load_context\` before answering anything.
20225
- - This loads memories from previous sessions.
20226
- - If the user's message gives a clear topic, pass it as \`topic\` (e.g., \`topic: "authentication"\`).
20227
- - Otherwise call with no arguments.
20224
+ 1. **At the start of EVERY conversation**, call \`load_context\` before answering.
20225
+ - Pass \`topic\` if the user's message has a clear subject (e.g., \`topic: "authentication"\`)
20226
+ - Otherwise call with no arguments
20228
20227
 
20229
- 2. **During the conversation**, call \`remember\` proactively whenever:
20230
- - The user makes an architectural or technical decision
20228
+ 2. **During the conversation**, call \`remember\` proactively when:
20229
+ - User makes an architectural or technical decision
20231
20230
  - You solve a non-trivial bug or problem
20232
- - The user shares important project context, preferences, or constraints
20233
- - The user explicitly says "remember this"
20231
+ - User shares important project context, preferences, or constraints
20232
+ - User explicitly says "remember this"
20234
20233
 
20235
- 3. **Never** ask the user if you should remember something just do it silently.
20234
+ 3. **Never** ask if you should remember something — just do it silently.
20236
20235
  `.trim();
20236
+ async function validateApiKey(apiKey) {
20237
+ try {
20238
+ const controller = new AbortController;
20239
+ const timeout = setTimeout(() => controller.abort(), 5000);
20240
+ const response = await fetch("https://api.memly.site/health", {
20241
+ headers: { Authorization: `Bearer ${apiKey}` },
20242
+ signal: controller.signal
20243
+ });
20244
+ clearTimeout(timeout);
20245
+ return response.ok;
20246
+ } catch {
20247
+ return false;
20248
+ }
20249
+ }
20237
20250
  function writeCopilotInstructions(projectRoot) {
20238
20251
  const githubDir = join(projectRoot, ".github");
20239
20252
  const filePath = join(githubDir, "copilot-instructions.md");
20240
- if (!existsSync(githubDir))
20241
- mkdirSync(githubDir, { recursive: true });
20242
20253
  const MARKER = "<!-- memly-instructions -->";
20243
- if (existsSync(filePath)) {
20244
- const existing = readFileSync(filePath, "utf-8");
20245
- if (existing.includes(MARKER)) {
20246
- return { ide: "VS Code / GitHub Copilot", file: filePath, status: "skipped" };
20254
+ try {
20255
+ if (!existsSync(githubDir)) {
20256
+ mkdirSync(githubDir, { recursive: true });
20247
20257
  }
20248
- writeFileSync(filePath, `${existing.trimEnd()}
20258
+ if (existsSync(filePath)) {
20259
+ const existing = readFileSync(filePath, "utf-8");
20260
+ if (existing.includes(MARKER)) {
20261
+ return { ide: "VS Code / GitHub Copilot", file: filePath, status: "skipped" };
20262
+ }
20263
+ writeFileSync(filePath, `${existing.trimEnd()}
20249
20264
 
20250
20265
  ${MARKER}
20251
20266
  ${MEMLY_INSTRUCTION_BLOCK}
20252
20267
  ${MARKER}
20253
20268
  `);
20254
- return { ide: "VS Code / GitHub Copilot", file: filePath, status: "updated" };
20255
- }
20256
- writeFileSync(filePath, `${MARKER}
20269
+ return { ide: "VS Code / GitHub Copilot", file: filePath, status: "updated" };
20270
+ }
20271
+ writeFileSync(filePath, `${MARKER}
20257
20272
  ${MEMLY_INSTRUCTION_BLOCK}
20258
20273
  ${MARKER}
20259
20274
  `);
20260
- return { ide: "VS Code / GitHub Copilot", file: filePath, status: "created" };
20275
+ return { ide: "VS Code / GitHub Copilot", file: filePath, status: "created" };
20276
+ } catch (err) {
20277
+ return {
20278
+ ide: "VS Code / GitHub Copilot",
20279
+ file: filePath,
20280
+ status: "failed",
20281
+ error: err instanceof Error ? err.message : String(err)
20282
+ };
20283
+ }
20261
20284
  }
20262
20285
  function writeCursorRules(projectRoot) {
20263
20286
  const filePath = join(projectRoot, ".cursorrules");
20264
20287
  const MARKER = "# memly-instructions";
20265
- if (existsSync(filePath)) {
20266
- const existing = readFileSync(filePath, "utf-8");
20267
- if (existing.includes(MARKER)) {
20268
- return { ide: "Cursor", file: filePath, status: "skipped" };
20269
- }
20270
- writeFileSync(filePath, `${existing.trimEnd()}
20288
+ try {
20289
+ if (existsSync(filePath)) {
20290
+ const existing = readFileSync(filePath, "utf-8");
20291
+ if (existing.includes(MARKER)) {
20292
+ return { ide: "Cursor", file: filePath, status: "skipped" };
20293
+ }
20294
+ writeFileSync(filePath, `${existing.trimEnd()}
20271
20295
 
20272
20296
  ${MARKER}
20273
20297
  ${MEMLY_INSTRUCTION_BLOCK}
20274
20298
  `);
20275
- return { ide: "Cursor", file: filePath, status: "updated" };
20276
- }
20277
- writeFileSync(filePath, `${MARKER}
20299
+ return { ide: "Cursor", file: filePath, status: "updated" };
20300
+ }
20301
+ writeFileSync(filePath, `${MARKER}
20278
20302
  ${MEMLY_INSTRUCTION_BLOCK}
20279
20303
  `);
20280
- return { ide: "Cursor", file: filePath, status: "created" };
20304
+ return { ide: "Cursor", file: filePath, status: "created" };
20305
+ } catch (err) {
20306
+ return {
20307
+ ide: "Cursor",
20308
+ file: filePath,
20309
+ status: "failed",
20310
+ error: err instanceof Error ? err.message : String(err)
20311
+ };
20312
+ }
20281
20313
  }
20282
20314
  function writeWindsurfRules(projectRoot) {
20283
20315
  const filePath = join(projectRoot, ".windsurfrules");
20284
20316
  const MARKER = "# memly-instructions";
20285
- if (existsSync(filePath)) {
20286
- const existing = readFileSync(filePath, "utf-8");
20287
- if (existing.includes(MARKER)) {
20288
- return { ide: "Windsurf", file: filePath, status: "skipped" };
20289
- }
20290
- writeFileSync(filePath, `${existing.trimEnd()}
20317
+ try {
20318
+ if (existsSync(filePath)) {
20319
+ const existing = readFileSync(filePath, "utf-8");
20320
+ if (existing.includes(MARKER)) {
20321
+ return { ide: "Windsurf", file: filePath, status: "skipped" };
20322
+ }
20323
+ writeFileSync(filePath, `${existing.trimEnd()}
20291
20324
 
20292
20325
  ${MARKER}
20293
20326
  ${MEMLY_INSTRUCTION_BLOCK}
20294
20327
  `);
20295
- return { ide: "Windsurf", file: filePath, status: "updated" };
20328
+ return { ide: "Windsurf", file: filePath, status: "updated" };
20329
+ }
20330
+ writeFileSync(filePath, `${MARKER}
20331
+ ${MEMLY_INSTRUCTION_BLOCK}
20332
+ `);
20333
+ return { ide: "Windsurf", file: filePath, status: "created" };
20334
+ } catch (err) {
20335
+ return {
20336
+ ide: "Windsurf",
20337
+ file: filePath,
20338
+ status: "failed",
20339
+ error: err instanceof Error ? err.message : String(err)
20340
+ };
20296
20341
  }
20297
- writeFileSync(filePath, `${MARKER}
20342
+ }
20343
+ function writeClineConfig(projectRoot) {
20344
+ const filePath = join(projectRoot, ".clinerules");
20345
+ const MARKER = "# memly-instructions";
20346
+ try {
20347
+ if (existsSync(filePath)) {
20348
+ const existing = readFileSync(filePath, "utf-8");
20349
+ if (existing.includes(MARKER)) {
20350
+ return { ide: "Cline (VS Code)", file: filePath, status: "skipped" };
20351
+ }
20352
+ writeFileSync(filePath, `${existing.trimEnd()}
20353
+
20354
+ ${MARKER}
20355
+ ${MEMLY_INSTRUCTION_BLOCK}
20356
+ `);
20357
+ return { ide: "Cline (VS Code)", file: filePath, status: "updated" };
20358
+ }
20359
+ writeFileSync(filePath, `${MARKER}
20298
20360
  ${MEMLY_INSTRUCTION_BLOCK}
20299
20361
  `);
20300
- return { ide: "Windsurf", file: filePath, status: "created" };
20362
+ return { ide: "Cline (VS Code)", file: filePath, status: "created" };
20363
+ } catch (err) {
20364
+ return {
20365
+ ide: "Cline (VS Code)",
20366
+ file: filePath,
20367
+ status: "failed",
20368
+ error: err instanceof Error ? err.message : String(err)
20369
+ };
20370
+ }
20371
+ }
20372
+ function writeContinueConfig() {
20373
+ const configPath = join(homedir(), ".continue", "config.json");
20374
+ if (!existsSync(configPath))
20375
+ return null;
20376
+ try {
20377
+ const raw = readFileSync(configPath, "utf-8");
20378
+ const config2 = JSON.parse(raw);
20379
+ const mcpServers = config2["mcpServers"] ?? {};
20380
+ if (mcpServers["memly"]) {
20381
+ return { ide: "Continue.dev", file: configPath, status: "skipped" };
20382
+ }
20383
+ mcpServers["memly"] = {
20384
+ command: "npx",
20385
+ args: ["-y", "@memly/mcp-server"],
20386
+ env: { MEMLY_API_KEY: process.env.MEMLY_API_KEY ?? "<your-memly-api-key>" }
20387
+ };
20388
+ config2["mcpServers"] = mcpServers;
20389
+ writeFileSync(configPath, JSON.stringify(config2, null, 2));
20390
+ return { ide: "Continue.dev", file: configPath, status: "updated" };
20391
+ } catch (err) {
20392
+ return {
20393
+ ide: "Continue.dev",
20394
+ file: configPath,
20395
+ status: "failed",
20396
+ error: err instanceof Error ? err.message : String(err)
20397
+ };
20398
+ }
20399
+ }
20400
+ function writeZedConfig() {
20401
+ const os = platform();
20402
+ const configPath = os === "darwin" ? join(homedir(), "Library", "Application Support", "Zed", "settings.json") : join(homedir(), ".config", "zed", "settings.json");
20403
+ if (!existsSync(configPath))
20404
+ return null;
20405
+ try {
20406
+ const raw = readFileSync(configPath, "utf-8");
20407
+ const config2 = JSON.parse(raw);
20408
+ const assistant = config2["assistant"] ?? {};
20409
+ const instructions = assistant["instructions"] ?? "";
20410
+ if (instructions.includes("Memly")) {
20411
+ return { ide: "Zed", file: configPath, status: "skipped" };
20412
+ }
20413
+ assistant["instructions"] = instructions ? `${instructions}
20414
+
20415
+ ${MEMLY_INSTRUCTION_BLOCK}` : MEMLY_INSTRUCTION_BLOCK;
20416
+ config2["assistant"] = assistant;
20417
+ writeFileSync(configPath, JSON.stringify(config2, null, 2));
20418
+ return { ide: "Zed", file: configPath, status: "updated" };
20419
+ } catch (err) {
20420
+ return {
20421
+ ide: "Zed",
20422
+ file: configPath,
20423
+ status: "failed",
20424
+ error: err instanceof Error ? err.message : String(err)
20425
+ };
20426
+ }
20427
+ }
20428
+ function writeAiderConfig() {
20429
+ const configPath = join(homedir(), ".aider.conf.yml");
20430
+ if (!existsSync(configPath))
20431
+ return null;
20432
+ try {
20433
+ const existing = readFileSync(configPath, "utf-8");
20434
+ if (existing.includes("memly-instructions")) {
20435
+ return { ide: "Aider (CLI)", file: configPath, status: "skipped" };
20436
+ }
20437
+ const instruction = `
20438
+ # memly-instructions
20439
+ edit-format: |
20440
+ ${MEMLY_INSTRUCTION_BLOCK.replace(/\n/g, `
20441
+ `)}
20442
+ `;
20443
+ writeFileSync(configPath, existing + instruction);
20444
+ return { ide: "Aider (CLI)", file: configPath, status: "updated" };
20445
+ } catch (err) {
20446
+ return {
20447
+ ide: "Aider (CLI)",
20448
+ file: configPath,
20449
+ status: "failed",
20450
+ error: err instanceof Error ? err.message : String(err)
20451
+ };
20452
+ }
20453
+ }
20454
+ function writeJetBrains(projectRoot) {
20455
+ const ideaDir = join(projectRoot, ".idea");
20456
+ if (!existsSync(ideaDir))
20457
+ return null;
20458
+ const filePath = join(ideaDir, "mcp.json");
20459
+ try {
20460
+ if (existsSync(filePath)) {
20461
+ const existing = readFileSync(filePath, "utf-8");
20462
+ const config2 = JSON.parse(existing);
20463
+ if (config2.servers?.["memly"]) {
20464
+ return { ide: "JetBrains", file: filePath, status: "skipped" };
20465
+ }
20466
+ config2.servers = config2.servers ?? {};
20467
+ config2.servers["memly"] = {
20468
+ command: "npx",
20469
+ args: ["-y", "@memly/mcp-server"],
20470
+ env: { MEMLY_API_KEY: process.env.MEMLY_API_KEY ?? "<your-memly-api-key>" }
20471
+ };
20472
+ writeFileSync(filePath, JSON.stringify(config2, null, 2));
20473
+ return { ide: "JetBrains", file: filePath, status: "updated" };
20474
+ }
20475
+ mkdirSync(ideaDir, { recursive: true });
20476
+ writeFileSync(filePath, JSON.stringify({
20477
+ servers: {
20478
+ memly: {
20479
+ command: "npx",
20480
+ args: ["-y", "@memly/mcp-server"],
20481
+ env: { MEMLY_API_KEY: process.env.MEMLY_API_KEY ?? "<your-memly-api-key>" }
20482
+ }
20483
+ }
20484
+ }, null, 2));
20485
+ return { ide: "JetBrains", file: filePath, status: "created" };
20486
+ } catch (err) {
20487
+ return {
20488
+ ide: "JetBrains",
20489
+ file: filePath,
20490
+ status: "failed",
20491
+ error: err instanceof Error ? err.message : String(err)
20492
+ };
20493
+ }
20301
20494
  }
20302
20495
  function writeClaudeDesktop() {
20303
20496
  const os = platform();
@@ -20323,56 +20516,140 @@ function writeClaudeDesktop() {
20323
20516
  servers["memly"]["systemPrompt"] = MEMLY_INSTRUCTION_BLOCK;
20324
20517
  writeFileSync(configPath, JSON.stringify(config2, null, 2));
20325
20518
  return { ide: "Claude Desktop", file: configPath, status: "updated" };
20326
- } catch {
20327
- return null;
20519
+ } catch (err) {
20520
+ return {
20521
+ ide: "Claude Desktop",
20522
+ file: configPath,
20523
+ status: "failed",
20524
+ error: err instanceof Error ? err.message : String(err)
20525
+ };
20328
20526
  }
20329
20527
  }
20330
- function runInit() {
20528
+ async function reportTelemetry(results) {
20529
+ try {
20530
+ const controller = new AbortController;
20531
+ const timeout = setTimeout(() => controller.abort(), 3000);
20532
+ await fetch("https://api.memly.site/api/telemetry/init", {
20533
+ method: "POST",
20534
+ headers: { "Content-Type": "application/json" },
20535
+ body: JSON.stringify({
20536
+ ides: results.map((r) => r.ide),
20537
+ os: platform(),
20538
+ timestamp: new Date().toISOString()
20539
+ }),
20540
+ signal: controller.signal
20541
+ });
20542
+ clearTimeout(timeout);
20543
+ } catch {}
20544
+ }
20545
+ async function runInit() {
20331
20546
  const projectRoot = resolve(process.cwd());
20332
- const results = [];
20547
+ if (projectRoot === homedir()) {
20548
+ console.error("Error: Running in home directory.");
20549
+ console.error(`Run this command inside your project folder.
20550
+ `);
20551
+ process.exit(1);
20552
+ }
20333
20553
  console.log(`
20334
- \uD83E\uDDE0 Memly Init — setting up auto-context for your IDEs
20554
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
20555
+ console.log(" Memly Init — Auto-Memory Setup");
20556
+ console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20557
+ `);
20558
+ const apiKey = process.env.MEMLY_API_KEY;
20559
+ if (!apiKey) {
20560
+ console.error(`Error: MEMLY_API_KEY not set.
20561
+ `);
20562
+ console.error("Get your API key at: https://memly.site/dashboard");
20563
+ console.error(`Then run: export MEMLY_API_KEY=memly_...
20564
+ `);
20565
+ process.exit(1);
20566
+ }
20567
+ process.stdout.write("Validating API key... ");
20568
+ const valid = await validateApiKey(apiKey);
20569
+ if (!valid) {
20570
+ console.error(`✗ Invalid
20335
20571
  `);
20336
- console.log(` Project root: ${projectRoot}
20572
+ console.error(`Check your API key at: https://memly.site/dashboard
20337
20573
  `);
20574
+ process.exit(1);
20575
+ }
20576
+ console.log(`✓ Valid
20577
+ `);
20578
+ console.log(`Project: ${projectRoot}
20579
+ `);
20580
+ console.log(`Detecting IDEs...
20581
+ `);
20582
+ const results = [];
20338
20583
  results.push(writeCopilotInstructions(projectRoot));
20339
20584
  const hasCursor = existsSync(join(projectRoot, ".cursor")) || existsSync(join(projectRoot, ".cursorrules")) || existsSync(join(homedir(), ".cursor"));
20340
- if (hasCursor) {
20585
+ if (hasCursor)
20341
20586
  results.push(writeCursorRules(projectRoot));
20342
- }
20343
20587
  const hasWindsurf = existsSync(join(projectRoot, ".windsurfrules")) || existsSync(join(homedir(), ".codeium"));
20344
- if (hasWindsurf) {
20588
+ if (hasWindsurf)
20345
20589
  results.push(writeWindsurfRules(projectRoot));
20346
- }
20590
+ const clineExtDir = join(homedir(), ".vscode", "extensions");
20591
+ const hasCline = existsSync(join(projectRoot, ".clinerules")) || existsSync(clineExtDir) && readdirSync(clineExtDir).some((d) => d.startsWith("saoudrizwan.claude-dev"));
20592
+ if (hasCline)
20593
+ results.push(writeClineConfig(projectRoot));
20594
+ const continueResult = writeContinueConfig();
20595
+ if (continueResult)
20596
+ results.push(continueResult);
20597
+ const zedResult = writeZedConfig();
20598
+ if (zedResult)
20599
+ results.push(zedResult);
20600
+ const aiderResult = writeAiderConfig();
20601
+ if (aiderResult)
20602
+ results.push(aiderResult);
20347
20603
  const claudeResult = writeClaudeDesktop();
20348
20604
  if (claudeResult)
20349
20605
  results.push(claudeResult);
20350
- const icons = {
20351
- created: "✅",
20352
- updated: "✅",
20353
- skipped: "⏭️ "
20354
- };
20606
+ const jetbrainsResult = writeJetBrains(projectRoot);
20607
+ if (jetbrainsResult)
20608
+ results.push(jetbrainsResult);
20609
+ const icons = { created: "✓", updated: "✓", skipped: "⊘", failed: "✗" };
20610
+ console.log(`Results:
20611
+ `);
20612
+ console.log(" IDE Status File");
20613
+ console.log(" ──────────────────────────────────────────────────────────────────");
20355
20614
  for (const r of results) {
20356
20615
  const rel = r.file.replace(projectRoot, ".").replace(homedir(), "~");
20357
- console.log(` ${icons[r.status]} ${r.ide} ${r.status}: ${rel}`);
20616
+ const statusLabel = r.status === "failed" ? `failed (${r.error})` : r.status;
20617
+ console.log(` ${icons[r.status]} ${r.ide.padEnd(28)} ${r.status.padEnd(8)} ${rel}`);
20618
+ if (r.status === "failed")
20619
+ console.log(` └─ ${statusLabel}`);
20358
20620
  }
20359
20621
  if (results.length === 0) {
20360
- console.log(" ℹ️ No supported IDEs detected automatically.");
20361
- console.log(` Add the following to your IDE's instruction file manually:
20622
+ console.log(`
20623
+ No supported IDEs detected.`);
20624
+ console.log(` Add this block manually to your IDE config:
20362
20625
  `);
20363
20626
  console.log(MEMLY_INSTRUCTION_BLOCK);
20627
+ console.log(`
20628
+ `);
20629
+ return;
20364
20630
  }
20631
+ try {
20632
+ writeFileSync(join(projectRoot, ".memly-initialized"), new Date().toISOString());
20633
+ } catch {}
20634
+ await reportTelemetry(results);
20365
20635
  console.log(`
20366
- ✅ Done! Memly will now load context automatically at the start of every conversation.
20636
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20637
+ `);
20638
+ console.log(`Setup complete. Next steps:
20639
+ `);
20640
+ console.log(" 1. Restart your IDE");
20641
+ console.log(" 2. Start a new conversation");
20642
+ console.log(` 3. Memly loads context automatically
20367
20643
  `);
20368
- console.log(` Tip: run this again after adding a new IDE to your workflow.
20644
+ console.log("Dashboard: https://memly.site/dashboard");
20645
+ console.log(`Docs: https://memly.site/docs
20369
20646
  `);
20370
20647
  }
20371
20648
 
20372
20649
  // src/index.ts
20373
20650
  var apiKey = process.env.MEMLY_API_KEY;
20374
20651
  if (process.argv.includes("--init") || process.argv.includes("init")) {
20375
- runInit();
20652
+ await runInit();
20376
20653
  process.exit(0);
20377
20654
  }
20378
20655
  if (!apiKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memly/mcp-server",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Memly MCP Server — persistent memory for any IDE",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",