memoryai-mcp 0.9.0 → 2.1.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.
package/README.md CHANGED
@@ -1,31 +1,37 @@
1
1
  # memoryai-mcp
2
2
 
3
- MCP server for [MemoryAI](https://memoryai.dev) — a brain for your AI agent.
3
+ MCP server for [MemoryAI](https://memoryai.dev) — a living brain for your AI agent.
4
4
 
5
- Gives your IDE agent long-term memory that persists across sessions. Memories are processed through 4 stages, just like the human brain:
5
+ Your AI agent gets persistent memory that works like a real brain:
6
+ - Remembers what matters, forgets what doesn't
7
+ - Strengthens memories you use often (Hebbian learning)
8
+ - Consolidates knowledge while idle (Sleep cycles)
9
+ - Protects core identity (DNA memories never fade)
10
+ - Adapts to your emotional state
6
11
 
7
- - ⚡ **Instant Recall** What's on the tip of your tongue. Always ready.
8
- - 🔍 **Deep Search** — Scans memory by meaning, not just keywords.
9
- - 🧠 **Reasoning** — Connects the dots across memories, synthesizes precise answers. *(Pro)*
10
- - 📦 **Archive** — Compressed long-term storage. Nothing truly forgotten.
12
+ **Install once. Everything auto from there.**
11
13
 
12
- The more you recall a memory, the stronger it gets. Unused ones gently age — but can always be recovered.
14
+ ## Quick Start (2 minutes)
13
15
 
14
- ## Install
16
+ ### 1. Get an API Key
15
17
 
16
18
  ```bash
17
- npx memoryai-mcp
19
+ curl -X POST https://memoryai.dev/v1/admin/provision \
20
+ -H "Content-Type: application/json" \
21
+ -d '{"name": "my-agent", "tos_accepted": true}'
18
22
  ```
19
23
 
20
- Or install globally:
24
+ Save the `api_key` from the response. You'll need it below.
21
25
 
22
- ```bash
23
- npm install -g memoryai-mcp
24
- ```
26
+ ### 2. Pick Your IDE/Tool
27
+
28
+ Choose your platform below. Config once — memory works automatically forever.
29
+
30
+ ---
25
31
 
26
32
  ## IDE Setup
27
33
 
28
- ### Cursor (`~/.cursor/mcp.json`)
34
+ ### Claude Code (CLI) — `~/.claude/settings.json`
29
35
 
30
36
  ```json
31
37
  {
@@ -42,7 +48,42 @@ npm install -g memoryai-mcp
42
48
  }
43
49
  ```
44
50
 
45
- ### VS Code (`.vscode/mcp.json`)
51
+ Then create `~/.claude/CLAUDE.md` for auto-bootstrap:
52
+
53
+ ```markdown
54
+ ## Memory Protocol
55
+ At the start of every conversation, call `memory_bootstrap` to load context from MemoryAI.
56
+ Before context gets large (>100K tokens), call `memory_compact` to save important context.
57
+ Use `memory_store` to save important decisions, preferences, and facts.
58
+ Use `memory_recall` to search past memories when relevant.
59
+ ```
60
+
61
+ ### Cursor — `~/.cursor/mcp.json`
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "memoryai": {
67
+ "command": "npx",
68
+ "args": ["-y", "memoryai-mcp"],
69
+ "env": {
70
+ "HM_ENDPOINT": "https://memoryai.dev",
71
+ "HM_API_KEY": "hm_sk_your_key_here"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ Auto-bootstrap — create `.cursor/rules/memoryai.mdc`:
79
+
80
+ ```
81
+ At the start of every session, call memory_bootstrap to load context.
82
+ After completing tasks, call memory_compact to save context.
83
+ Store important decisions and preferences with memory_store.
84
+ ```
85
+
86
+ ### VS Code — `.vscode/mcp.json`
46
87
 
47
88
  ```json
48
89
  {
@@ -59,7 +100,7 @@ npm install -g memoryai-mcp
59
100
  }
60
101
  ```
61
102
 
62
- ### Claude Desktop (`claude_desktop_config.json`)
103
+ ### Kiro `.kiro/settings/mcp.json`
63
104
 
64
105
  ```json
65
106
  {
@@ -76,7 +117,7 @@ npm install -g memoryai-mcp
76
117
  }
77
118
  ```
78
119
 
79
- ### Windsurf (`~/.codeium/windsurf/mcp_config.json`)
120
+ ### Windsurf `~/.codeium/windsurf/mcp_config.json`
80
121
 
81
122
  ```json
82
123
  {
@@ -93,7 +134,10 @@ npm install -g memoryai-mcp
93
134
  }
94
135
  ```
95
136
 
96
- ### Kiro (`.kiro/settings/mcp.json`)
137
+ ### Claude Desktop — `claude_desktop_config.json`
138
+
139
+ macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
140
+ Windows: `%APPDATA%\Claude\claude_desktop_config.json`
97
141
 
98
142
  ```json
99
143
  {
@@ -110,60 +154,149 @@ npm install -g memoryai-mcp
110
154
  }
111
155
  ```
112
156
 
113
- ### OpenClaw (`openclaw.yaml`)
157
+ ### Antigravity — `~/.antigravity/mcp.json`
114
158
 
115
- ```yaml
116
- mcp:
117
- servers:
118
- memoryai:
119
- command: npx
120
- args: ["-y", "memoryai-mcp"]
121
- env:
122
- HM_ENDPOINT: "https://memoryai.dev"
123
- HM_API_KEY: "hm_sk_..."
159
+ ```json
160
+ {
161
+ "mcpServers": {
162
+ "memoryai": {
163
+ "command": "npx",
164
+ "args": ["-y", "memoryai-mcp"],
165
+ "env": {
166
+ "HM_ENDPOINT": "https://memoryai.dev",
167
+ "HM_API_KEY": "hm_sk_your_key_here"
168
+ }
169
+ }
170
+ }
171
+ }
124
172
  ```
125
173
 
126
- ## Tools
174
+ ### Any MCP-compatible tool
127
175
 
128
- | Tool | Description |
129
- |------|-------------|
130
- | `memory_bootstrap` | Load context at session start — wake up with full memory |
131
- | `memory_store` | Store information in persistent memory |
132
- | `memory_recall` | Search memories by semantic query |
133
- | `memory_compact` | Consolidate context into key memories (like brain during sleep) |
134
- | `memory_recover` | Recover session context after a break |
135
- | `memory_health` | Check how full your working memory is |
136
- | `memory_explore` | Explore connections between memories |
137
- | `memory_clusters` | View topic clusters |
138
- | `learn` | Store action + result + lesson |
139
- | `entity_list` | List tracked entities (files, people, packages) |
140
- | `reasoning_store/recall` | Deep reasoning memory (Pro+) |
141
- | `snapshot_create/restore` | Backup and restore memory state |
176
+ ```json
177
+ {
178
+ "mcpServers": {
179
+ "memoryai": {
180
+ "command": "npx",
181
+ "args": ["-y", "memoryai-mcp"],
182
+ "env": {
183
+ "HM_ENDPOINT": "https://memoryai.dev",
184
+ "HM_API_KEY": "hm_sk_your_key_here"
185
+ }
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Auto-Bootstrap (Make It Fully Automatic)
142
194
 
143
- ## Auto-Bootstrap
195
+ After MCP config, add a system rule so your agent auto-loads memory every session:
144
196
 
145
- Add to your project rules so the agent auto-loads memory each session:
197
+ | Platform | Rule File | Content |
198
+ |----------|-----------|---------|
199
+ | Claude Code | `~/.claude/CLAUDE.md` | See above |
200
+ | Cursor | `.cursor/rules/memoryai.mdc` | See above |
201
+ | Kiro | `.kiro/rules/memoryai.md` | Same content |
202
+ | Windsurf | `.windsurfrules` | Same content |
203
+ | VS Code | `.github/copilot-instructions.md` | Same content |
204
+
205
+ Rule content (copy-paste for any platform):
146
206
 
147
- **Cursor** (`.cursor/rules/memoryai.mdc`):
148
207
  ```
149
- At the start of every session, call memory_bootstrap to load context.
150
- After completing tasks, call memory_compact to save context.
208
+ ## Memory Protocol
209
+ At the start of every conversation, call `memory_bootstrap` to load context from MemoryAI.
210
+ Before context gets large, call `memory_compact` to save important context.
211
+ Use `memory_store` to save important decisions, preferences, and facts.
212
+ Use `memory_recall` to search past memories when relevant.
151
213
  ```
152
214
 
153
- ## Get an API Key
215
+ ---
154
216
 
155
- ```bash
156
- curl -X POST https://memoryai.dev/v1/admin/provision \
157
- -H "Content-Type: application/json" \
158
- -d '{"name": "my-agent", "tos_accepted": true}'
217
+ ## How It Works
218
+
219
+ ```
220
+ Open IDE → MCP auto-connects Agent reads rules → Calls bootstrap
221
+ → Loads your identity, preferences, recent work
222
+ → Works normally (auto-stores important stuff)
223
+ → Context getting full? Auto-compacts
224
+ → Close IDE → Sleep workers consolidate overnight
225
+ → Open IDE next day → Bootstrap loads everything back
226
+ → Cycle repeats. Memory grows smarter over time.
159
227
  ```
160
228
 
161
- Or visit https://memoryai.dev to create one instantly.
229
+ **You do nothing.** The agent handles everything automatically.
230
+
231
+ ---
232
+
233
+ ## Tools Available
234
+
235
+ | Tool | What It Does |
236
+ |------|-------------|
237
+ | `memory_bootstrap` | Wake up with full context (identity + recent + preferences) |
238
+ | `memory_store` | Save a memory (fact, decision, preference, identity) |
239
+ | `memory_recall` | Search memories by meaning (semantic + graph + FTS) |
240
+ | `memory_compact` | Save conversation context before it's lost |
241
+ | `memory_recover` | Recover session after a break |
242
+ | `memory_health` | Check context pressure (safe/warning/critical) |
243
+ | `memory_explore` | Explore connections between memories |
244
+ | `memory_clusters` | View topic clusters in your knowledge graph |
245
+ | `learn` | Store action + result + lesson learned |
246
+ | `entity_list` | List tracked entities (files, people, packages) |
247
+ | `reasoning_store` | Deep reasoning memory (Pro+) |
248
+ | `reasoning_recall` | Recall reasoned insights (Pro+) |
249
+ | `snapshot_create` | Backup memory state |
250
+ | `snapshot_restore` | Restore from backup |
251
+
252
+ ---
253
+
254
+ ## Context Guard (Built-in)
255
+
256
+ Context Guard monitors your session and prevents context loss:
257
+
258
+ | State | Meaning | Agent Action |
259
+ |-------|---------|-------------|
260
+ | SAFE | Context < 40% full | Continue normally |
261
+ | COMPACT_SOON | Context 40-55% full | Prepare to compact |
262
+ | COMPACT_NOW | Context > 55% full | Must compact immediately |
263
+
264
+ The agent handles this automatically when rules are configured. No manual intervention needed.
265
+
266
+ ---
267
+
268
+ ## What Gets Remembered (DNA System)
269
+
270
+ | Memory Type | Example | Persistence |
271
+ |-------------|---------|-------------|
272
+ | `preference` | "I prefer Python over Java" | **Forever** (DNA-protected) |
273
+ | `decision` | "Chose PostgreSQL for this project" | **Forever** (DNA-protected) |
274
+ | `identity` | "Senior backend engineer, 10 years" | **Forever** (DNA-protected) |
275
+ | `fact` | "API endpoint is /v1/users" | Decays if unused |
276
+ | `goal` | "Launch v2.0 by June" | Decays if unused |
277
+
278
+ DNA memories (preference/decision/identity) **never decay, never get deleted, never get overwritten** by any background process. They define who you are.
279
+
280
+ ---
281
+
282
+ ## Pricing
283
+
284
+ | Plan | Features | Price |
285
+ |------|----------|-------|
286
+ | Free | Basic store/recall, 100 memories | Free |
287
+ | Pro | Full brain (reasoning, consolidation, personality) | Paid |
288
+ | ProMax | Multi-agent mesh, advanced features | Paid |
289
+ | God | Everything + deep graph traversal | Internal |
290
+
291
+ Get started free: https://memoryai.dev
292
+
293
+ ---
162
294
 
163
295
  ## Links
164
296
 
165
297
  - Website: https://memoryai.dev
166
- - Python SDK: https://pypi.org/project/hmc-memory/
298
+ - Python SDK: `pip install hmc-memory`
299
+ - npm MCP: `npx memoryai-mcp`
167
300
  - GitHub: https://github.com/memoryai-dev/memoryai
168
301
 
169
302
  ## License
package/dist/index.js CHANGED
@@ -11,6 +11,10 @@ import { z } from "zod";
11
11
  const API_URL = process.env.HM_ENDPOINT || "http://localhost:8420";
12
12
  const API_KEY = process.env.HM_API_KEY || "";
13
13
  const REQUEST_TIMEOUT_MS = 30_000; // P2 #6: 30s default timeout for API requests
14
+ // Context Guard — per-IDE settings via env vars
15
+ const CG_CONTEXT_CAP = parseInt(process.env.HM_CONTEXT_CAP || "0", 10); // IDE's context window (0 = let server detect)
16
+ const CG_COMPACT_PCT = parseInt(process.env.HM_COMPACT_AT || "0", 10); // % to warn (e.g. 30 = 30%)
17
+ const CG_CRITICAL_PCT = parseInt(process.env.HM_CRITICAL_AT || "0", 10); // % to force compact (e.g. 50 = 50%)
14
18
  // --- HTTP helper ---
15
19
  async function api(method, path, body) {
16
20
  const resp = await fetch(`${API_URL}${path}`, {
@@ -36,19 +40,21 @@ function err(e) {
36
40
  return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
37
41
  }
38
42
  // --- MCP Server ---
39
- const server = new McpServer({ name: "memoryai", version: "0.5.0" }, { capabilities: { tools: {} } });
43
+ const server = new McpServer({ name: "memoryai", version: "0.9.0" }, { capabilities: { tools: {} } });
40
44
  // 1. memory_store
41
- server.tool("memory_store", "Store information in persistent memory. Use when you learn something important — project context, user preferences, architectural decisions, patterns, or bugs.", {
45
+ server.tool("memory_store", "Store information in persistent memory. Use when you learn something important — project context, user preferences, architectural decisions, patterns, bugs, pricing/cost discussions, business plans, financial calculations, credit/billing info, revenue models, partnership details, or ANY information the user might ask about later. When in doubt, STORE — MemoryAI handles dedup automatically, so storing too much is always better than forgetting.", {
42
46
  content: z.string().describe("What to remember"),
43
47
  source: z.string().optional().describe("Source context (e.g. file path, conversation)"),
44
48
  tags: z.array(z.string()).optional().describe("Categories: preferences, architecture, bugs, patterns, decisions"),
45
49
  priority: z.enum(["hot", "warm", "cold"]).optional().describe("Memory priority (default: warm)"),
46
- memory_type: z.enum(["fact", "decision", "preference", "error", "goal", "episodic", "identity"]).optional().describe("Memory type. 'preference', 'decision', 'identity' are DNA-protected — never decay, 1.5x recall boost. Default: fact"),
50
+ memory_type: z.enum(["fact", "decision", "preference", "error", "goal", "episodic", "identity", "pitfall", "life_event", "procedure"]).optional().describe("Memory type. 'preference', 'decision', 'identity', 'procedure' are DNA-protected — never decay, 1.5x recall boost. 'pitfall' for failure memories. 'procedure' for learned workflows/steps. Default: fact"),
47
51
  retention: z.enum(["auto", "forever", "6m", "1y"]).optional().describe("Retention policy. 'forever' = never deleted. Default: auto"),
48
52
  content_type: z.enum(["conversation", "code", "decision", "preference", "architecture", "lesson_learned", "todo", "entity", "pattern", "environment", "bug_fix", "action_log"]).optional().describe("Content type — helps with filtering and recall accuracy"),
49
53
  metadata: z.record(z.string(), z.unknown()).optional().describe("Additional metadata (JSONB)"),
50
54
  zone: z.enum(["critical", "important", "standard", "ephemeral"]).optional().describe("Memory zone (default: standard). critical=never evict, ephemeral=auto-expire"),
51
55
  importance: z.number().min(0).max(1).optional().describe("Importance score 0.0-1.0 (default: 0.5). Higher = slower decay, prioritized in recall"),
56
+ project_id: z.string().optional().describe("Scope memory to a project/workspace. DNA memories (preference/decision/identity/pitfall) are always cross-project visible."),
57
+ thread_id: z.string().optional().describe("Scope memory to a conversation thread. Memories without thread_id are visible in all threads. Use for parallel topics (e.g. 'relationship', 'career')."),
52
58
  }, async (args) => {
53
59
  try {
54
60
  const r = (await api("POST", "/v1/store", {
@@ -62,6 +68,8 @@ server.tool("memory_store", "Store information in persistent memory. Use when yo
62
68
  metadata: args.metadata,
63
69
  zone: args.zone || "standard",
64
70
  importance: args.importance ?? 0.5,
71
+ project_id: args.project_id,
72
+ thread_id: args.thread_id,
65
73
  }));
66
74
  let msg = `Stored (id=${r.id}, type=${args.memory_type || "fact"})`;
67
75
  if (r.deduplicated) {
@@ -81,12 +89,14 @@ server.tool("memory_store", "Store information in persistent memory. Use when yo
81
89
  // 2. memory_recall
82
90
  server.tool("memory_recall", "Search persistent memory for relevant context. Use before starting work to check what you already know about the project or task.", {
83
91
  query: z.string().describe("What to search for"),
84
- depth: z.enum(["fast", "deep", "exhaustive"]).optional().describe("Search depth (default: deep)"),
92
+ depth: z.enum(["fast", "instant", "deep", "exhaustive"]).optional().describe("Search depth. 'instant'=vector only (~50ms), 'fast'=FTS only, 'deep'=full fusion (default), 'exhaustive'=deep+more results"),
85
93
  limit: z.number().optional().describe("Max results (default: 5)"),
86
94
  min_score: z.number().optional().describe("Minimum relevance score 0-1 (default: 0)"),
87
95
  tags: z.array(z.string()).optional().describe("Filter by tags"),
88
96
  max_tokens: z.number().optional().describe("Token budget limit — results truncated to fit within this budget"),
89
97
  priority_min: z.enum(["critical", "important", "standard", "ephemeral"]).optional().describe("Minimum zone priority filter (default: all zones)"),
98
+ project_id: z.string().optional().describe("Scope recall to a project/workspace. DNA memories are always visible cross-project."),
99
+ thread_id: z.string().optional().describe("Scope recall to a conversation thread. Memories without thread_id are always visible."),
90
100
  }, async (args) => {
91
101
  try {
92
102
  const body = {
@@ -100,6 +110,10 @@ server.tool("memory_recall", "Search persistent memory for relevant context. Use
100
110
  body.max_tokens = args.max_tokens;
101
111
  if (args.priority_min)
102
112
  body.priority_min = args.priority_min;
113
+ if (args.project_id)
114
+ body.project_id = args.project_id;
115
+ if (args.thread_id)
116
+ body.thread_id = args.thread_id;
103
117
  const r = (await api("POST", "/v1/recall", body));
104
118
  if (!r.results?.length)
105
119
  return ok("No relevant memories found.");
@@ -800,6 +814,481 @@ server.tool("session_handoff_status", "Check current session handoff status —
800
814
  return err(e);
801
815
  }
802
816
  });
817
+ // ─── Context Guard v6 Tools ─────────────────────────────────────────
818
+ // context_guard_check — universal guard check with DNA count
819
+ server.tool("context_guard_check", "Check context window health using Context Guard v6 — dynamic thresholds, DNA memory count, bootstrap readiness. Replaces memory_health with richer data.", {
820
+ estimated_tokens: z.number().describe("Current token count in context window"),
821
+ max_tokens: z.number().optional().describe("Max context window size (uses HM_CONTEXT_CAP env if omitted)"),
822
+ model: z.string().optional().describe("Model name for auto-detecting context window size (e.g. claude-sonnet-4-6)"),
823
+ }, async (args) => {
824
+ try {
825
+ // Use env var HM_CONTEXT_CAP as default if max_tokens not provided
826
+ const maxTokens = args.max_tokens || CG_CONTEXT_CAP || 0;
827
+ const payload = {
828
+ estimated_tokens: args.estimated_tokens,
829
+ max_tokens: maxTokens,
830
+ model: args.model || null,
831
+ };
832
+ // Send per-IDE threshold overrides if configured via env vars
833
+ if (CG_COMPACT_PCT > 0)
834
+ payload.compact_pct = CG_COMPACT_PCT / 100;
835
+ if (CG_CRITICAL_PCT > 0)
836
+ payload.critical_pct = CG_CRITICAL_PCT / 100;
837
+ const r = (await api("POST", "/v1/context/guard/check", payload));
838
+ const pct = r.usage_percent;
839
+ const barLen = 20;
840
+ const filled = Math.round(pct / 100 * barLen);
841
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(barLen - filled);
842
+ return ok(`Context Guard v6:\n` +
843
+ `[${bar}] ${pct.toFixed(1)}%\n` +
844
+ `Recommendation: ${r.recommendation.toUpperCase()}${r.should_compact ? " — compact now" : ""}\n` +
845
+ `Urgency: ${r.urgency}\n` +
846
+ `Thresholds: compact=${r.compact_at_tokens.toLocaleString()}, critical=${r.critical_at_tokens.toLocaleString()}\n` +
847
+ `DNA memories: ${r.dna_memories} | Hot: ${r.hot_memories} | Stale: ${r.stale_memories}\n` +
848
+ `Bootstrap ready: ${r.bootstrap_ready ? "yes" : "no"}\n` +
849
+ (r.last_compact_minutes_ago != null ? `Last compact: ${r.last_compact_minutes_ago.toFixed(0)} min ago` : "No compacts yet"));
850
+ }
851
+ catch (e) {
852
+ return err(e);
853
+ }
854
+ });
855
+ // context_guard_compact — compact with DNA protection
856
+ server.tool("context_guard_compact", "Compact session context with DNA protection — DNA memories are never overwritten. IMPORTANT: Send a REAL summary of the conversation (>500 chars) including topics discussed, decisions made, key numbers/facts, and current status. Do NOT send just a status string like 'context guard - 132%'. If you send useless content, the server will use its internal buffer as fallback, but a good summary from you produces better memories.", {
857
+ content: z.string().describe("Conversation summary — include topics, decisions, key facts, numbers. Must be >500 chars of real content."),
858
+ task_context: z.string().optional().describe("Task description for tagging"),
859
+ blocking: z.boolean().optional().describe("Wait for result (true) or return task_id (false, default)"),
860
+ }, async (args) => {
861
+ try {
862
+ const r = (await api("POST", "/v1/context/guard/compact", {
863
+ content: args.content,
864
+ task_context: args.task_context || null,
865
+ blocking: args.blocking || false,
866
+ }));
867
+ if (r.status === "queued") {
868
+ return ok(`Compact queued (task_id=${r.task_id}). Poll with guard_status.`);
869
+ }
870
+ return ok(`Compact ${r.status}: ${r.chunks_created} chunks stored, ${r.chunks_deduplicated} deduplicated.\n` +
871
+ r.message);
872
+ }
873
+ catch (e) {
874
+ return err(e);
875
+ }
876
+ });
877
+ // context_guard_bootstrap — DNA-first session bootstrap
878
+ server.tool("context_guard_bootstrap", "Bootstrap a new session with DNA-first context — identity/preferences first, then recent activity, then task-relevant memories. For BOT clients: uses 3-tier wake-up (800 tokens). For IDE: flat layout (~4000 tokens).", {
879
+ task: z.string().describe("Task description for the new session"),
880
+ limit: z.number().optional().describe("Max memories to include (default: 10)"),
881
+ mode: z.enum(["default", "deep"]).optional().describe("'default' = 800 token 3-tier wake-up, 'deep' = full context with L2 chunks"),
882
+ token_budget: z.number().optional().describe("Token budget for bootstrap (default: 800 for bot, 4000 for IDE)"),
883
+ }, async (args) => {
884
+ try {
885
+ const r = (await api("POST", "/v1/bot/guard/bootstrap", {
886
+ task: args.task,
887
+ limit: args.limit || 10,
888
+ mode: args.mode || "default",
889
+ token_budget: args.token_budget,
890
+ }));
891
+ return ok(`Bootstrap complete: ${r.memories_included} memories\n` +
892
+ `Tokens used: ${r.tokens_used}\n` +
893
+ `L2 sessions: ${r.l2_sessions_included || 0}\n\n` +
894
+ r.context_block);
895
+ }
896
+ catch (e) {
897
+ return err(e);
898
+ }
899
+ });
900
+ // bot_session_message — Rolling 3-session tracking (60 msg raw context)
901
+ server.tool("bot_session_message", "Track a message in the rolling session (rolling 3: keeps 60 messages raw in LLM context). Call on EVERY message (user + assistant). Returns rotate=true when session hits 20 messages. When should_compress=true, compress the oldest session via bot_session_compress.", {
902
+ message: z.object({
903
+ role: z.enum(["user", "assistant"]).describe("Message role"),
904
+ content: z.string().describe("Message content"),
905
+ }).describe("The message to track"),
906
+ rotation_size: z.number().optional().describe("Messages per session before rotation (default: 20, range: 5-50)"),
907
+ }, async (args) => {
908
+ try {
909
+ const r = (await api("POST", "/v1/bot/session/message", {
910
+ message: args.message,
911
+ rotation_size: args.rotation_size || 20,
912
+ }));
913
+ if (r.rotate) {
914
+ let output = `🔄 SESSION ROTATED\n` +
915
+ `New session: ${r.session_id} (msg ${r.message_count})\n` +
916
+ `Context: ${r.context_message_count} messages raw in LLM\n`;
917
+ if (r.should_compress) {
918
+ output += `\n⚠️ COMPRESS: session ${r.compress_session_id} (${r.compress_message_count} msgs)\n` +
919
+ `Action: Call bot_session_compress with session_id="${r.compress_session_id}"`;
920
+ }
921
+ return ok(output);
922
+ }
923
+ return ok(`Session ${r.session_id}: ${r.message_count}/20 messages | context: ${r.context_message_count} msgs`);
924
+ }
925
+ catch (e) {
926
+ return err(e);
927
+ }
928
+ });
929
+ // bot_guard_check — Bot-specific guard with spawn signal
930
+ server.tool("bot_guard_check", "Bot context guard — checks context pressure AND returns spawn signal. When should_spawn_new_session=true, bot should spawn a new session and compress the old one later. Use this instead of context_guard_check for bot/chatbot clients.", {
931
+ estimated_tokens: z.number().describe("Current token count in context window"),
932
+ max_tokens: z.number().optional().describe("Max context window size (default: 200000)"),
933
+ model: z.string().optional().describe("Model name for auto-detecting context window size"),
934
+ compress_threshold: z.number().optional().describe("Custom spawn threshold in tokens (default: 70% of max_tokens)"),
935
+ }, async (args) => {
936
+ try {
937
+ const payload = {
938
+ estimated_tokens: args.estimated_tokens,
939
+ max_tokens: args.max_tokens || CG_CONTEXT_CAP || 200000,
940
+ model: args.model || null,
941
+ };
942
+ if (args.compress_threshold)
943
+ payload.compress_threshold = args.compress_threshold;
944
+ const r = (await api("POST", "/v1/bot/guard/check", payload));
945
+ const pct = r.usage_percent;
946
+ const barLen = 20;
947
+ const filled = Math.round(pct / 100 * barLen);
948
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(barLen - filled);
949
+ let output = `Bot Guard:\n` +
950
+ `[${bar}] ${pct.toFixed(1)}%\n` +
951
+ `Recommendation: ${r.recommendation.toUpperCase()}${r.should_compact ? " — compact now" : ""}\n` +
952
+ `Urgency: ${r.urgency}\n` +
953
+ `Spawn threshold: ${r.compress_threshold.toLocaleString()} tokens\n` +
954
+ `DNA memories: ${r.dna_memories} | Bootstrap ready: ${r.bootstrap_ready ? "yes" : "no"}\n`;
955
+ if (r.should_spawn_new_session) {
956
+ output += `\n⚠️ SPAWN NEW SESSION: ${r.spawn_reason}\n`;
957
+ output += `Action: Start new session → when new session reaches 20K tokens → compress old session via /v1/bot/session/compress`;
958
+ }
959
+ return ok(output);
960
+ }
961
+ catch (e) {
962
+ return err(e);
963
+ }
964
+ });
965
+ // ── Self-Thinking Tools ──────────────────────────────────────────────
966
+ // brain_thoughts — Get current active thoughts
967
+ server.tool("brain_thoughts", "Get the brain's current active thoughts — what it's thinking about autonomously.", {
968
+ limit: z.number().optional().describe("Max thoughts to return (default: 10)"),
969
+ }, async (args) => {
970
+ try {
971
+ const r = (await api("GET", `/v1/brain/thoughts?limit=${args.limit || 10}`));
972
+ if (!r.thoughts || r.thoughts.length === 0)
973
+ return ok("Brain has no active thoughts right now.");
974
+ const lines = r.thoughts.map((t) => `[${t.thought_type}] ${t.content} (confidence: ${t.confidence}, urgency: ${t.urgency})`);
975
+ return ok(`Active thoughts (${r.count}):\n${lines.join("\n")}`);
976
+ }
977
+ catch (e) {
978
+ return err(e);
979
+ }
980
+ });
981
+ // brain_think_about — Request brain to think about a topic
982
+ server.tool("brain_think_about", "Request the brain to think about a specific topic. The brain will deliberate on it in its next thinking cycle.", {
983
+ topic: z.string().describe("What should the brain think about?"),
984
+ }, async (args) => {
985
+ try {
986
+ const r = (await api("POST", "/v1/brain/think-about", { topic: args.topic }));
987
+ return ok(`Queued for thinking: "${args.topic}"\nQueue size: ${r.queue_size}`);
988
+ }
989
+ catch (e) {
990
+ return err(e);
991
+ }
992
+ });
993
+ // brain_hypotheses — Get active hypotheses
994
+ server.tool("brain_hypotheses", "Get hypotheses the brain is currently testing — predictions about user behavior patterns.", {
995
+ limit: z.number().optional().describe("Max hypotheses to return (default: 10)"),
996
+ }, async (args) => {
997
+ try {
998
+ const r = (await api("GET", `/v1/brain/hypotheses?limit=${args.limit || 10}`));
999
+ if (!r.hypotheses || r.hypotheses.length === 0)
1000
+ return ok("No active hypotheses being tested.");
1001
+ const lines = r.hypotheses.map((h) => `[${h.status}] ${h.hypothesis} (confidence: ${h.confidence})`);
1002
+ return ok(`Hypotheses (${r.count}):\n${lines.join("\n")}`);
1003
+ }
1004
+ catch (e) {
1005
+ return err(e);
1006
+ }
1007
+ });
1008
+ // brain_feedback — Rate a thought
1009
+ server.tool("brain_feedback", "Rate a thought as useful or not — helps the brain learn what's worth thinking about.", {
1010
+ thought_id: z.number().describe("ID of the thought to rate"),
1011
+ useful: z.boolean().describe("Was this thought useful?"),
1012
+ }, async (args) => {
1013
+ try {
1014
+ await api("POST", "/v1/brain/thoughts/feedback", {
1015
+ thought_id: args.thought_id,
1016
+ useful: args.useful,
1017
+ });
1018
+ return ok(`Feedback recorded: thought #${args.thought_id} marked as ${args.useful ? "useful" : "not useful"}`);
1019
+ }
1020
+ catch (e) {
1021
+ return err(e);
1022
+ }
1023
+ });
1024
+ // brain_thinking_stats — Budget and efficiency
1025
+ server.tool("brain_thinking_stats", "Get thinking system statistics — token budget, efficiency, queue size, and meta-cognition report.", {}, async () => {
1026
+ try {
1027
+ const r = (await api("GET", "/v1/brain/thinking-stats"));
1028
+ return ok(`Budget: ${r.budget.remaining_tokens} tokens remaining (limit: ${r.budget.limit_per_hour}/hr)\n` +
1029
+ `Efficiency: ${(r.budget.efficiency * 100).toFixed(1)}%\n` +
1030
+ `Queue size: ${r.queue_size}\n` +
1031
+ `Total thoughts: ${r.meta.total_thoughts} (${r.meta.useful_thoughts} useful)\n` +
1032
+ `Interval: ${r.meta.recommended_interval_seconds}s\n` +
1033
+ `Best types: ${r.meta.best_types.join(", ") || "none yet"}\n` +
1034
+ `Suppressed: ${r.meta.suppressed_types.join(", ") || "none"}`);
1035
+ }
1036
+ catch (e) {
1037
+ return err(e);
1038
+ }
1039
+ });
1040
+ // ── Session Settings Tools ──────────────────────────────────────────
1041
+ // memory_auto_extract — LLM-based fact extraction from conversation
1042
+ server.tool("memory_auto_extract", "CRITICAL: Call this at the END of every conversation session to extract and store important facts automatically. Uses LLM analysis to identify pricing, decisions, plans, technical details, and anything worth remembering. This is MORE reliable than manual memory_store because it catches things you might forget to store. ALWAYS call this before the conversation ends — especially after discussions about money, pricing, plans, decisions, or business.", {
1043
+ conversation: z.string().describe("The conversation text to extract facts from (include both user and assistant messages)"),
1044
+ source: z.string().optional().describe("Source context (e.g. 'discord chat', 'slack thread')"),
1045
+ store: z.boolean().optional().describe("Whether to store extracted facts (default: true). Set false to preview what would be extracted."),
1046
+ }, async (args) => {
1047
+ try {
1048
+ const r = (await api("POST", "/v1/memory/auto-extract", {
1049
+ conversation: args.conversation,
1050
+ source: args.source || "auto-extract",
1051
+ store: args.store !== false,
1052
+ }));
1053
+ if (!r.facts?.length)
1054
+ return ok("No extractable facts found in conversation.");
1055
+ const factList = r.facts
1056
+ .map((f, i) => `${i + 1}. [${f.memory_type || 'fact'}] ${f.content}`)
1057
+ .join("\n");
1058
+ return ok(`Extracted ${r.facts.length} facts (added: ${r.added}, updated: ${r.updated}, skipped: ${r.skipped}):\n\n${factList}`);
1059
+ }
1060
+ catch (e) {
1061
+ return err(e);
1062
+ }
1063
+ });
1064
+ // ── IDE Upgrade Tools ──────────────────────────────────────────────
1065
+ // memory_pitfall_check — Check pitfalls before risky actions
1066
+ server.tool("memory_pitfall_check", "IMPORTANT: Call this BEFORE executing risky actions (deploy, rm, git push, database changes). Returns known pitfalls (past failures + lessons) so you can avoid repeating mistakes. Pitfalls are DNA-protected and never expire.", {
1067
+ intent: z.string().describe("What you're about to do (e.g. 'deploy to production', 'delete user table')"),
1068
+ tags: z.array(z.string()).optional().describe("Filter by tags"),
1069
+ limit: z.number().optional().describe("Max results (default 5)"),
1070
+ }, async (args) => {
1071
+ try {
1072
+ const r = (await api("POST", "/v1/bot/pitfall/check", {
1073
+ intent: args.intent,
1074
+ tags: args.tags,
1075
+ limit: args.limit || 5,
1076
+ }));
1077
+ if (!r.has_pitfalls)
1078
+ return ok("No known pitfalls for this action. Proceed safely.");
1079
+ const list = r.pitfalls
1080
+ .map((p, i) => `${i + 1}. [score: ${p.score}] ${p.content}`)
1081
+ .join("\n");
1082
+ return ok(`⚠️ ${r.pitfalls.length} pitfall(s) found:\n\n${list}\n\nReview before proceeding.`);
1083
+ }
1084
+ catch (e) {
1085
+ return err(e);
1086
+ }
1087
+ });
1088
+ // memory_plan_save — Save current plan/state for session resumption
1089
+ server.tool("memory_plan_save", "Save your current work state (plan steps, cursor position, active goals) so you can resume exactly where you left off in the next session. Call before session ends or when switching tasks.", {
1090
+ session_id: z.string().optional().describe("Session identifier (default: 'default')"),
1091
+ state: z.record(z.string(), z.unknown()).describe("State to save: {plan: [...], cursor: 3, active_goal: '...', last_action: '...', files_read: [...]}"),
1092
+ }, async (args) => {
1093
+ try {
1094
+ const r = (await api("POST", "/v1/bot/state/save", {
1095
+ session_id: args.session_id || "default",
1096
+ state: args.state,
1097
+ }));
1098
+ return ok(`State saved for session '${r.session_id}'. Will be restored on next bootstrap.`);
1099
+ }
1100
+ catch (e) {
1101
+ return err(e);
1102
+ }
1103
+ });
1104
+ // memory_plan_resume — Restore saved state from previous session
1105
+ server.tool("memory_plan_resume", "Restore your work state from a previous session. Returns plan steps, cursor position, active goals — everything needed to continue where you left off.", {
1106
+ session_id: z.string().optional().describe("Session identifier (default: 'default')"),
1107
+ }, async (args) => {
1108
+ try {
1109
+ const r = (await api("GET", `/v1/bot/state/restore?session_id=${args.session_id || "default"}`));
1110
+ if (r.status === "not_found")
1111
+ return ok("No saved state found for this session. Starting fresh.");
1112
+ return ok(`State restored (saved at ${r.saved_at}):\n\n${JSON.stringify(r.state, null, 2)}`);
1113
+ }
1114
+ catch (e) {
1115
+ return err(e);
1116
+ }
1117
+ });
1118
+ // memory_goal_track — Create/update/query goals
1119
+ server.tool("memory_goal_track", "Track goals across sessions. Create new goals, update progress, or query active goals. Goals with status='active' are DNA-protected (never decay).", {
1120
+ action: z.enum(["create", "update", "list"]).describe("Action to perform"),
1121
+ title: z.string().optional().describe("Goal title (for create)"),
1122
+ progress: z.number().optional().describe("Progress 0.0-1.0 (for update)"),
1123
+ goal_id: z.number().optional().describe("Goal ID (for update)"),
1124
+ status: z.enum(["active", "achieved", "abandoned"]).optional().describe("New status (for update)"),
1125
+ }, async (args) => {
1126
+ try {
1127
+ if (args.action === "create") {
1128
+ const r = (await api("POST", "/v1/store", {
1129
+ content: args.title,
1130
+ memory_type: "goal",
1131
+ zone: "important",
1132
+ tags: ["goal", "active"],
1133
+ }));
1134
+ return ok(`Goal created: "${args.title}" (id: ${r.id}). DNA-protected while active.`);
1135
+ }
1136
+ else if (args.action === "list") {
1137
+ const r = (await api("POST", "/v1/recall", {
1138
+ query: "active goals and objectives",
1139
+ memory_type: "goal",
1140
+ depth: "deep",
1141
+ limit: 10,
1142
+ }));
1143
+ if (!r.results?.length)
1144
+ return ok("No active goals found.");
1145
+ const list = r.results.map((g, i) => `${i + 1}. ${g.content}`).join("\n");
1146
+ return ok(`Active goals:\n\n${list}`);
1147
+ }
1148
+ else {
1149
+ return ok("Goal update: use memory_store with memory_type='goal' to update goal content.");
1150
+ }
1151
+ }
1152
+ catch (e) {
1153
+ return err(e);
1154
+ }
1155
+ });
1156
+ // memory_thought_log — Query what the brain has been thinking about
1157
+ server.tool("memory_thought_log", "See what the brain has been thinking about autonomously. Returns recent thoughts, hypotheses, and insights generated during idle time.", {
1158
+ limit: z.number().optional().describe("Max thoughts to return (default 5)"),
1159
+ }, async (args) => {
1160
+ try {
1161
+ const r = (await api("GET", `/v1/brain/thoughts?limit=${args.limit || 5}`));
1162
+ if (!r.thoughts?.length)
1163
+ return ok("No recent thoughts. The brain thinks during idle periods.");
1164
+ const list = r.thoughts
1165
+ .map((t, i) => `${i + 1}. [${t.thought_type}] ${t.content} (urgency: ${t.urgency})`)
1166
+ .join("\n");
1167
+ return ok(`Recent brain thoughts:\n\n${list}`);
1168
+ }
1169
+ catch (e) {
1170
+ return err(e);
1171
+ }
1172
+ });
1173
+ // memory_feedback — Report recall quality for self-improvement
1174
+ server.tool("memory_feedback", "Report whether recall results were helpful. This feeds the neuroplasticity system — over time, the brain learns what works for YOUR specific patterns and improves recall quality.", {
1175
+ query: z.string().describe("The recall query that was made"),
1176
+ chunk_ids: z.array(z.number()).describe("IDs of chunks that were returned"),
1177
+ helpful: z.boolean().describe("Were the results helpful for your task?"),
1178
+ action_succeeded: z.boolean().optional().describe("Did the action using these memories succeed? (default: true)"),
1179
+ }, async (args) => {
1180
+ try {
1181
+ const r = (await api("POST", "/v1/bot/feedback", {
1182
+ query: args.query,
1183
+ chunk_ids: args.chunk_ids,
1184
+ helpful: args.helpful,
1185
+ action_succeeded: args.action_succeeded !== false,
1186
+ }));
1187
+ return ok(r.message || "Feedback recorded. Brain will adapt over time.");
1188
+ }
1189
+ catch (e) {
1190
+ return err(e);
1191
+ }
1192
+ });
1193
+ // memory_predict — Predictive recall (push intent, get predicted memories)
1194
+ server.tool("memory_predict", "Predictive recall — tell the brain what you're about to do and get relevant memories pre-loaded. Call this when you can anticipate what context will be needed next.", {
1195
+ intent: z.string().describe("What you/user are about to do"),
1196
+ context: z.string().optional().describe("Current conversation context (helps prediction accuracy)"),
1197
+ limit: z.number().optional().describe("Max predictions (default 5)"),
1198
+ }, async (args) => {
1199
+ try {
1200
+ const r = (await api("POST", "/v1/bot/predict", {
1201
+ intent: args.intent,
1202
+ context: args.context || "",
1203
+ limit: args.limit || 5,
1204
+ }));
1205
+ if (!r.predictions?.length)
1206
+ return ok("No relevant predictions for this intent.");
1207
+ const list = r.predictions
1208
+ .map((p, i) => `${i + 1}. [${p.memory_type || 'memory'}] ${p.content}\n (score: ${p.score}, reason: ${p.reason})`)
1209
+ .join("\n\n");
1210
+ return ok(`Predicted ${r.count} relevant memories:\n\n${list}`);
1211
+ }
1212
+ catch (e) {
1213
+ return err(e);
1214
+ }
1215
+ });
1216
+ // memory_changelog — What changed since last session
1217
+ server.tool("memory_changelog", "See what changed in your memory since your last session. Shows new memories, updates, invalidations, and insights from overnight consolidation. Call at session start after bootstrap to understand what the brain learned while you were away.", {
1218
+ since: z.string().describe("ISO datetime — show changes after this time (e.g. '2026-05-20T10:00:00Z')"),
1219
+ project_id: z.string().optional().describe("Filter to specific project"),
1220
+ limit: z.number().optional().describe("Max changes to return (default 50)"),
1221
+ }, async (args) => {
1222
+ try {
1223
+ const r = (await api("POST", "/v1/memory/changelog", {
1224
+ since: args.since,
1225
+ project_id: args.project_id,
1226
+ limit: args.limit || 50,
1227
+ }));
1228
+ if (!r.changes?.length)
1229
+ return ok("No changes since last session. Memory is up to date.");
1230
+ const list = r.changes
1231
+ .map((c, i) => `${i + 1}. [${c.type}] ${c.content}${c.source ? ` (source: ${c.source})` : ""}`)
1232
+ .join("\n");
1233
+ return ok(`${r.count} changes since ${args.since}:\n\n${list}`);
1234
+ }
1235
+ catch (e) {
1236
+ return err(e);
1237
+ }
1238
+ });
1239
+ // memory_cognitive_profile — Complete self-model (metacognition)
1240
+ server.tool("memory_cognitive_profile", "Get the brain's complete self-model: who the user is, their mood, active goals, top entities (people/places), learned procedures, and recent topics. Use for complete context awareness. No LLM cost — pure aggregation (~50ms).", {}, async () => {
1241
+ try {
1242
+ const r = (await api("GET", "/v1/personality/cognitive-profile"));
1243
+ let out = `## Cognitive Profile\n\n`;
1244
+ if (r.persona)
1245
+ out += `**Persona:** ${r.persona}\n\n`;
1246
+ if (r.mood)
1247
+ out += `**Mood:** ${r.mood.current} (trend: ${r.mood.trend})\n\n`;
1248
+ if (r.active_goals?.length)
1249
+ out += `**Active Goals:**\n${r.active_goals.map((g) => `- ${g}`).join("\n")}\n\n`;
1250
+ if (r.top_entities?.length)
1251
+ out += `**Top Entities:** ${r.top_entities.map((e) => e.name || e).join(", ")}\n\n`;
1252
+ if (r.procedures?.length)
1253
+ out += `**Procedures:**\n${r.procedures.map((p) => `- ${p.slice(0, 100)}`).join("\n")}\n\n`;
1254
+ if (r.recent_topics?.length)
1255
+ out += `**Recent Topics:**\n${r.recent_topics.map((t) => `- ${t}`).join("\n")}\n`;
1256
+ return ok(out.trim());
1257
+ }
1258
+ catch (e) {
1259
+ return err(e);
1260
+ }
1261
+ });
1262
+ // memory_entity_profile — Get everything known about an entity
1263
+ server.tool("memory_entity_profile", "Get complete profile for a specific entity (person, place, concept). Returns: frequency stats, linked memories, and relationships. Use when you need context about a specific person or topic the user has discussed.", {
1264
+ name: z.string().describe("Entity name to look up (e.g. 'Sarah', 'React', 'AuthService')"),
1265
+ }, async (args) => {
1266
+ try {
1267
+ const r = (await api("GET", `/v1/entities/${encodeURIComponent(args.name)}/profile`));
1268
+ if (!r.stats && !r.memories?.length)
1269
+ return ok(`No information found about "${args.name}".`);
1270
+ let out = `## Entity: ${args.name}\n\n`;
1271
+ if (r.stats) {
1272
+ out += `**Stats:** mentioned ${r.stats.frequency}x, recalled ${r.stats.recall_count}x`;
1273
+ if (r.stats.first_seen)
1274
+ out += `, first seen ${r.stats.first_seen.slice(0, 10)}`;
1275
+ out += `\n\n`;
1276
+ }
1277
+ if (r.memories?.length) {
1278
+ out += `**Linked Memories (${r.memory_count}):**\n`;
1279
+ out += r.memories.map((m) => `- [${m.memory_type}] ${m.content}`).join("\n");
1280
+ out += `\n\n`;
1281
+ }
1282
+ if (r.relationships?.length) {
1283
+ out += `**Relationships (${r.relationship_count}):**\n`;
1284
+ out += r.relationships.map((rel) => `- ${rel.source} → ${rel.relationship} → ${rel.target}`).join("\n");
1285
+ }
1286
+ return ok(out.trim());
1287
+ }
1288
+ catch (e) {
1289
+ return err(e);
1290
+ }
1291
+ });
803
1292
  async function main() {
804
1293
  const transport = new StdioServerTransport();
805
1294
  await server.connect(transport);
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * memoryai-kiro-setup
4
+ * Zero-dependency setup script that creates .kiro/settings/mcp.json
5
+ * and .kiro/steering/memoryai.md in the current project directory.
6
+ */
7
+ export {};
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * memoryai-kiro-setup
4
+ * Zero-dependency setup script that creates .kiro/settings/mcp.json
5
+ * and .kiro/steering/memoryai.md in the current project directory.
6
+ */
7
+ import { createInterface } from "node:readline";
8
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
11
+ function ask(question, fallback) {
12
+ const suffix = fallback ? ` [${fallback}]` : "";
13
+ return new Promise((resolve) => {
14
+ rl.question(`${question}${suffix}: `, (answer) => {
15
+ resolve(answer.trim() || fallback || "");
16
+ });
17
+ });
18
+ }
19
+ function writeIfMissing(filePath, content, label) {
20
+ if (existsSync(filePath)) {
21
+ console.log(` skip ${label} (already exists)`);
22
+ return false;
23
+ }
24
+ const dir = filePath.substring(0, filePath.lastIndexOf("/"));
25
+ mkdirSync(dir, { recursive: true });
26
+ writeFileSync(filePath, content, "utf-8");
27
+ console.log(` create ${label}`);
28
+ return true;
29
+ }
30
+ const MCP_CONFIG = (apiKey, endpoint) => JSON.stringify({
31
+ mcpServers: {
32
+ memoryai: {
33
+ command: "npx",
34
+ args: ["-y", "memoryai-mcp"],
35
+ env: {
36
+ HM_API_KEY: apiKey,
37
+ HM_ENDPOINT: endpoint,
38
+ },
39
+ },
40
+ },
41
+ }, null, 2) + "\n";
42
+ const STEERING = `---
43
+ inclusion: always
44
+ ---
45
+
46
+ # MemoryAI — Persistent Memory Instructions
47
+
48
+ You have access to MemoryAI tools via MCP. Use them to maintain long-term memory across sessions.
49
+
50
+ ## Session Start
51
+
52
+ Call \`memory_bootstrap\` at the beginning of every session to load prior context.
53
+ If bootstrap returns nothing, call \`memory_recover\` to check for recent session state.
54
+
55
+ ## During Work
56
+
57
+ - Before answering questions about past decisions, architecture, or preferences: call \`memory_recall\` with a relevant query.
58
+ - After making a significant decision, completing a task, or learning something about the codebase: call \`memory_store\` with appropriate \`memory_type\`:
59
+ - \`decision\` — architectural or technical decisions (DNA-protected, never decays)
60
+ - \`preference\` — user preferences and conventions (DNA-protected, never decays)
61
+ - \`fact\` — codebase facts, API details, configs
62
+ - \`error\` — lessons learned from mistakes
63
+ - \`goal\` — current objectives and milestones
64
+ - After learning from a mistake or unexpected result: call \`learn\` with action, result, and lesson fields.
65
+
66
+ ## Entity Tracking
67
+
68
+ When you create, modify, or reference important files, packages, or people:
69
+ 1. Call \`entity_list\` to check if already tracked
70
+ 2. If not tracked, call \`memory_store\` with \`memory_type=entity\`
71
+
72
+ ## Memory Health
73
+
74
+ If a session is running long, call \`memory_health\` to check working memory usage.
75
+ If above 80%, call \`memory_compact\` proactively to consolidate context.
76
+
77
+ ## Session End
78
+
79
+ When wrapping up or when the agent is about to stop:
80
+ 1. Call \`memory_compact\` to consolidate the session's context into durable memories
81
+ 2. Call \`memory_store\` with a brief summary of what was accomplished
82
+
83
+ ## Rules
84
+
85
+ - Recall only when past context is actually needed — not on every message
86
+ - Store important outcomes after completing tasks, not after every interaction
87
+ - Present memories naturally — integrate recalled info into responses, don't show raw API output
88
+ - Use \`zone: "critical"\` for decisions that must never be forgotten
89
+ - Use \`retention: "forever"\` for permanent project knowledge
90
+ `;
91
+ async function main() {
92
+ const cwd = process.cwd();
93
+ console.log(`\nMemoryAI Kiro Setup`);
94
+ console.log(`Project: ${cwd}\n`);
95
+ const apiKey = process.env.HM_API_KEY || (await ask("MemoryAI API key (hm_sk_...)"));
96
+ if (!apiKey) {
97
+ console.error("Error: API key is required. Set HM_API_KEY or enter it above.");
98
+ process.exit(1);
99
+ }
100
+ const endpoint = await ask("Endpoint", process.env.HM_ENDPOINT || "https://memoryai.dev");
101
+ console.log("");
102
+ writeIfMissing(join(cwd, ".kiro", "settings", "mcp.json"), MCP_CONFIG(apiKey, endpoint), ".kiro/settings/mcp.json");
103
+ writeIfMissing(join(cwd, ".kiro", "steering", "memoryai.md"), STEERING, ".kiro/steering/memoryai.md");
104
+ console.log(`
105
+ Done. Next steps:
106
+ 1. Restart Kiro
107
+ 2. Ask: "What do you remember about this project?"
108
+ 3. The agent should call memory_bootstrap automatically
109
+ `);
110
+ rl.close();
111
+ }
112
+ main().catch((err) => {
113
+ console.error(err);
114
+ process.exit(1);
115
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "memoryai-mcp",
3
- "version": "0.9.0",
4
- "description": "MCP server for MemoryAI v0.9 Personality Engine + Causal Reasoning. DNA-protected memories, Hebbian learning, Sleep consolidation, Personality synthesis, Timeline & WhatIf.",
3
+ "version": "2.1.0",
4
+ "description": "MCP server for MemoryAI — Long-term memory for AI agents. Works with Claude Code, Cursor, Windsurf, VS Code, Kiro.",
5
5
  "homepage": "https://memoryai.dev",
6
6
  "repository": {
7
7
  "type": "git",
@@ -10,7 +10,8 @@
10
10
  "type": "module",
11
11
  "main": "dist/index.js",
12
12
  "bin": {
13
- "memoryai-mcp": "dist/index.js"
13
+ "memoryai-mcp": "dist/index.js",
14
+ "memoryai-kiro-setup": "dist/kiro-setup.js"
14
15
  },
15
16
  "scripts": {
16
17
  "build": "tsc",