@yugabytedb/meko-mcp 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +81 -23
  2. package/assets/hooks-handlers/before-submit-prompt.sh +44 -0
  3. package/assets/hooks-handlers/cursor-session-start.sh +42 -0
  4. package/assets/hooks-handlers/lib/capture.js +404 -88
  5. package/assets/hooks-handlers/lib/checkpoint-timer.js +23 -11
  6. package/assets/hooks-handlers/session-start.sh +6 -2
  7. package/assets/scripts/meko-statusline.sh +119 -0
  8. package/assets/scripts/package-desktop-skill.sh +39 -0
  9. package/assets/skills/meko-mcp-tools/SKILL.md +42 -50
  10. package/assets/skills/meko-mcp-tools/references/_sections.md +1 -1
  11. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +75 -150
  12. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +30 -36
  13. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +6 -22
  14. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +9 -8
  15. package/assets/skills/meko-mcp-tools/references/tools-overview.md +35 -42
  16. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +28 -92
  17. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +5 -9
  18. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +1 -81
  19. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +244 -0
  20. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +180 -0
  21. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +24 -0
  22. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +99 -0
  23. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +327 -0
  24. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +63 -0
  25. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +214 -0
  26. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +105 -0
  27. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +70 -0
  28. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +71 -0
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +75 -0
  30. package/assets/skills/meko-select-datapack-desktop/SKILL.md +198 -0
  31. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +121 -0
  32. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +66 -0
  33. package/bin/create-meko-setup.mjs +33 -4
  34. package/lib/clients/claude-code.mjs +133 -6
  35. package/lib/clients/claude-desktop.mjs +48 -20
  36. package/lib/clients/codex.mjs +538 -5
  37. package/lib/clients/common.mjs +122 -1
  38. package/lib/clients/cursor.mjs +120 -27
  39. package/lib/config.mjs +52 -0
  40. package/lib/installer.mjs +26 -2
  41. package/lib/mcp-transport.mjs +5 -0
  42. package/lib/validate.mjs +0 -1
  43. package/package.json +1 -1
  44. package/scripts/bundle-assets.mjs +16 -0
  45. package/assets/skills/meko-mcp-tools/references/tools-db-query-patterns.md +0 -38
  46. package/assets/skills/meko-mcp-tools/references/tools-write-guardrails.md +0 -30
@@ -0,0 +1,327 @@
1
+ # Tool Cookbook — Complete Usage Examples
2
+
3
+ Every tool example below shows the correct parameters, expected response, and common errors. Use `scope="read"` for reads and `scope="write"` for writes — never `"all"` or any other value.
4
+
5
+ > **Note on `agent_id` in the examples below.** The string `"agent"` appears in these examples as a placeholder shorthand; it is NOT a required constant. Substitute **your** client's bucket: for Claude Desktop, the bare client name `claude_desktop`; for Claude Code/Cursor, `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). For genuinely cross-project facts (user identity, global preferences) write/read with `agent_id="meko_agent"` — the common bucket the server stores empty/missing values into. See `tools-agent-id-conventions.md`.
6
+
7
+ ---
8
+
9
+ ## Memory Tools
10
+
11
+ **Critical:** Pass your session's `agent_id` on every memory call. For Claude Desktop that's `claude_desktop` for client-personal context, or `meko_agent` for genuinely cross-project facts (user identity, global preferences). Personal writes are scoped strictly by `agent_id` — other agents won't see your writes on personal reads unless they pass the same exact value.
12
+
13
+ ### memory_add
14
+
15
+ **When to use:** NOT for facts the user states — those are captured when you post the turn with `conversation_add_message` and the server extracts them. Reserve `memory_add` for the three cases per-turn capture can't reach: (1) the user explicitly says "remember this"; (2) a durable fact only in your output or a tool result, never in a user turn; (3) overwriting a negated/corrected fact (pair with `memory_delete_by_id`, since extraction is additive).
16
+
17
+ ```
18
+ memory_add(scope="write", agent_id="claude_desktop",
19
+ text="Remember: deploy scripts must be run from the repo root, never a subdir.")
20
+ ```
21
+
22
+ **Response:**
23
+ ```json
24
+ {"results": [{"id": "mem-uuid-123", "memory": "User Amiram is VP of Product at YugabyteDB. Prefers concise responses."}]}
25
+ ```
26
+
27
+ **With user scoping:**
28
+ ```
29
+ memory_add(scope="write", agent_id="agent", user_id="amiram",
30
+ text="Prefers Python for backend, Go for infrastructure.")
31
+ ```
32
+
33
+ **What NOT to store via memory_add:**
34
+ - Full conversations (use `conversation_create` + `conversation_add_message`)
35
+ - Large documents (use the UI's Datapack → Actions → Add Knowledge upload flow)
36
+
37
+ **Common errors:**
38
+ - `syntax error at or near "-"` — legacy error from the pre-multi-tenancy schema when `agent_id` became part of a PostgreSQL identifier. No longer applies on Cloud (agent_id is a TEXT column value, any string is accepted). If you hit it on a deployment that still uses the old schema, use underscores instead of hyphens.
39
+ - `connection already closed` — Retry once. If it fails again, the memory subsystem is down.
40
+
41
+ ---
42
+
43
+ ### memory_search
44
+
45
+ **When to use:** Find relevant memories by meaning. Always try this before asking the user to repeat information.
46
+
47
+ ```
48
+ memory_search(scope="read", query="What programming language does the team use?", agent_id="agent")
49
+ ```
50
+
51
+ **Response:**
52
+ ```json
53
+ {"results": [{"id": "mem-uuid-123", "memory": "Team uses Python for backend", "score": 0.89}]}
54
+ ```
55
+
56
+ **With limit:**
57
+ ```
58
+ memory_search(scope="read", query="user preferences", agent_id="agent", limit=5)
59
+ ```
60
+
61
+ ---
62
+
63
+ ### memory_get_all
64
+
65
+ **When to use:** List everything stored for an agent. Useful at session start to load context.
66
+
67
+ ```
68
+ memory_get_all(scope="read", agent_id="agent")
69
+ ```
70
+
71
+ **With user scoping:**
72
+ ```
73
+ memory_get_all(scope="read", agent_id="agent", user_id="amiram")
74
+ ```
75
+
76
+ ---
77
+
78
+ ### memory_get_by_id
79
+
80
+ ```
81
+ memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="agent")
82
+ ```
83
+
84
+ ---
85
+
86
+ ### memory_update
87
+
88
+ **When to use:** Overwrite a specific memory's text. Requires the memory UUID.
89
+
90
+ ```
91
+ memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="agent")
92
+ ```
93
+
94
+ ---
95
+
96
+ ### memory_delete_by_id
97
+
98
+ ```
99
+ memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="agent")
100
+ ```
101
+
102
+ ---
103
+
104
+ ### memory_delete_all
105
+
106
+ **Destructive. Requires admin scope.** Deletes all memories for the agent.
107
+
108
+ ```
109
+ memory_delete_all(scope="admin", agent_id="agent")
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Conversation Tools
115
+
116
+ ### conversation_create
117
+
118
+ **When to use:** Start storing a multi-turn exchange. Do this when the session contains valuable dialog worth preserving.
119
+
120
+ ```
121
+ conversation_create(scope="write", agent_id="agent", user_id="amiram",
122
+ title="Debugging the auth middleware")
123
+ ```
124
+
125
+ **Response:**
126
+ ```json
127
+ {"id": "conv-uuid-123", "title": "Debugging the auth middleware"}
128
+ ```
129
+
130
+ ---
131
+
132
+ ### conversation_add_message
133
+
134
+ **When to use:** Add a user/assistant exchange to an existing conversation. **All fields must be verbatim** — never summarize or rephrase.
135
+
136
+ Pass `index_for_search=True` on substantive turns so this conversation is embedded into the shared conversation-history cache (searchable later via `conversation_search` / `contextual_prominence_search`). This isn't limited to WorkbenchLM — pass it for agent-harness conversations too.
137
+
138
+ ```
139
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
140
+ input="Why is the auth middleware returning 401?",
141
+ output="The token validation is checking the wrong issuer claim...",
142
+ reasoning="Checked the middleware source, found issuer mismatch between config and JWT...",
143
+ index_for_search=True)
144
+ ```
145
+
146
+ **With dedup seed (use when client hooks also write to Langfuse):**
147
+ ```
148
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
149
+ input="Why is the auth middleware returning 401?",
150
+ output="The token validation is checking the wrong issuer claim...",
151
+ seed="conv-uuid-123:agent:Why is the auth middleware returning 401?",
152
+ index_for_search=True)
153
+ ```
154
+
155
+ ---
156
+
157
+ ### conversation_get
158
+
159
+ ```
160
+ conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="agent",
161
+ include_messages=True, limit=50)
162
+ ```
163
+
164
+ ---
165
+
166
+ ### conversation_list
167
+
168
+ ```
169
+ conversation_list(scope="read", agent_id="agent", limit=20)
170
+ ```
171
+
172
+ ---
173
+
174
+ ### conversation_update
175
+
176
+ ```
177
+ conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
178
+ title="Resolved: Auth middleware issuer mismatch")
179
+ ```
180
+
181
+ ---
182
+
183
+ ### conversation_delete
184
+
185
+ **Destructive. Requires admin scope.**
186
+
187
+ ```
188
+ conversation_delete(scope="admin", conversation_id="conv-uuid-123", agent_id="agent")
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Knowledge Base Tools
194
+
195
+ **KB ingestion is a UI-only activity.** Users upload files via the datapack's Actions → **Add Knowledge** dialog (PDF/TXT/MD/JSON/MP4, 5MB each, 10/batch). `knowledgebase_search` is the one KB tool exposed via MCP.
196
+
197
+ See `tools-rag-workflow.md` for the decision table.
198
+
199
+ ### knowledgebase_search
200
+
201
+ **When to use:** Retrieve chunks from a populated KB. Works on cloud today.
202
+
203
+ ```
204
+ knowledgebase_search(
205
+ scope="read",
206
+ query="natural-language question",
207
+ agent_id="agent",
208
+ conversation_id="<uuid from conversation_create>",
209
+ datapack_id="<datapack UUID — REQUIRED here, no default>",
210
+ limit=10)
211
+ ```
212
+
213
+ Unlike memory tools, `datapack_id` has no default — you must pass it explicitly.
214
+
215
+ **Response (empty KB, verified 2026-05-07):**
216
+ ```json
217
+ {"results": [], "count": 0}
218
+ ```
219
+
220
+ Populated KBs return results with chunk content and similarity scores. An empty/nonexistent KB is not an error — just `count: 0`.
221
+
222
+ ---
223
+
224
+ ## Artifact Tools
225
+
226
+ ### artifact_put
227
+
228
+ **When to use:** An agent has generated a file (report, CSV, PDF, code output, image) and wants to persist it in Meko for later retrieval or cross-agent sharing. Files < 1 MB are stored inline in the DB; files ≥ 1 MB go to the datapack's S3 bucket. Idempotent — uploading the same bytes twice returns the same `content_hash`.
229
+
230
+ ```
231
+ artifact_put(
232
+ scope="write",
233
+ filename="analysis_report.csv",
234
+ content_type="text/csv",
235
+ content_base64="<base64-encoded bytes>",
236
+ conversation_id="<uuid from conversation_create>",
237
+ agent_id="claude_desktop"
238
+ )
239
+ ```
240
+
241
+ **Response:**
242
+ ```json
243
+ {
244
+ "artifact_id": "550e8400-e29b-41d4-a716-446655440000",
245
+ "content_hash": "a665a45920422f9d417e4867efdc4fb8a5f1f89ea5b8440b1ad4c4c6b8a7e4d3",
246
+ "filename": "analysis_report.csv",
247
+ "content_type": "text/csv",
248
+ "size_bytes": 4096,
249
+ "stored_in": "db"
250
+ }
251
+ ```
252
+
253
+ Save the `content_hash` — it's the retrieval key for `artifact_get`.
254
+
255
+ **Common errors:**
256
+ - `invalid_base64` — `content_base64` is not valid base64.
257
+ - `artifact_too_large` — file exceeds 5 MiB (default). Set `MEKO_MAX_ARTIFACT_UPLOAD_BYTES` to raise the limit.
258
+
259
+ ---
260
+
261
+ ### artifact_get
262
+
263
+ **When to use:** Retrieve a file previously uploaded with `artifact_put`.
264
+
265
+ **Small files (< 1 MB) — content returned inline:**
266
+ ```
267
+ artifact_get(
268
+ scope="read",
269
+ content_hash="a665a45920422f9d417e4867efdc4fb8a5f1f89ea5b8440b1ad4c4c6b8a7e4d3",
270
+ conversation_id="<uuid from conversation_create>",
271
+ agent_id="claude_desktop"
272
+ )
273
+ ```
274
+
275
+ **Response (inline):**
276
+ ```json
277
+ {
278
+ "content_hash": "a665a45920422f9d417e4867efdc4fb8...",
279
+ "filename": "analysis_report.csv",
280
+ "stored_in": "db",
281
+ "content_base64": "<base64-encoded bytes>"
282
+ }
283
+ ```
284
+
285
+ **Large files (≥ 1 MB) — written to local disk:**
286
+ ```json
287
+ {
288
+ "content_hash": "a665a45920422f9d417e4867efdc4fb8...",
289
+ "filename": "dataset.parquet",
290
+ "stored_in": "s3",
291
+ "local_path": "/Users/you/.meko/artifacts/a665a4.../dataset.parquet"
292
+ }
293
+ ```
294
+
295
+ For large files use `local_path` to read the file. S3 URLs are never exposed.
296
+
297
+ **Common errors:**
298
+ - `ARTIFACT_NOT_FOUND` — no artifact with that hash in this datapack.
299
+ - `ARTIFACT_EXPIRED` — free-tier TTL has elapsed (30 days of no access).
300
+
301
+ ---
302
+
303
+ ## Datapack Management Tools
304
+
305
+ ### datapack_create / datapack_list / datapack_describe
306
+
307
+ ```
308
+ datapack_create(scope="write", name="analytics_prod")
309
+ datapack_list(scope="read") # returns datapack_id for each datapack
310
+ datapack_describe(scope="read", datapack_id="<uuid>", include_status=True)
311
+ ```
312
+
313
+ ### datapack_update / datapack_delete
314
+
315
+ ```
316
+ datapack_update(scope="write", datapack_id="<uuid>", connection_string="postgresql://...")
317
+ datapack_delete(scope="admin", datapack_id="<uuid>") # Irreversible!
318
+ ```
319
+
320
+ ### Agent and knowledge-base management (NOT MCP — control-plane only)
321
+
322
+ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/list/delete agents or KB sources, don't invent a tool call — point them at the control plane:
323
+
324
+ - REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
325
+ - Or the Meko UI at `app.mekodev.com` → Datapacks → agents / knowledge-bases.
326
+
327
+ KB ingestion specifically lives in the UI today: Datapack → Actions → **Add Knowledge** (PDF/TXT/MD/JSON/MP4, 5 MB each, 10/batch). Agents querying a populated index use `knowledgebase_search` — see `tools-rag-workflow.md`.
@@ -0,0 +1,63 @@
1
+ # Known Limitations
2
+
3
+ These are current limitations of the Meko MCP tools. Know them upfront to avoid wasted tool calls.
4
+
5
+ ## No delete tools for RAG artifacts
6
+
7
+ There are no MCP tools to:
8
+ - Delete a vector index
9
+ - Remove a source from an index
10
+ - Clear stuck work queue entries
11
+ - Reset a failed pipeline
12
+
13
+ KB-source deletion happens via the Meko control plane (REST: `DELETE /datapacks/:datapack_id/knowledge-bases`, or the UI), which removes the registration from the Meko API — but does **not** touch the actual `dist_rag` index, source records, or vector data in the datapack's database.
14
+
15
+ **Workaround:** For stuck or failed indexes, create a new index with a different name. Stale indexes remain in the database until manually cleaned up by an admin.
16
+
17
+ ## RAG ingestion is UI-only
18
+
19
+ KB ingestion (creating an index, adding sources, polling build status) is not exposed via MCP. Documents go in through the Cloud UI's **Add Knowledge** flow (Datapack → Actions → Add Knowledge) — PDF/TXT/MD/JSON/MP4 up to 5 MB each, 10 per batch.
20
+
21
+ To **query** a built index, use `knowledgebase_search` — it returns both uploaded documents and memories the user promoted from the Learnings tab.
22
+
23
+ ## Memory tools unreliable for structured/tabular data
24
+
25
+ `memory_add` passes text through Mem0's fact extraction pipeline. This works well for:
26
+ - Facts: "Alice works at Acme Corp"
27
+ - Preferences: "User prefers dark mode"
28
+ - Entity relationships: "Amiram reports to Karthik"
29
+
30
+ It works **poorly** for:
31
+ - CSV rows or tabular data — columns and rows get dropped
32
+ - Data dictionaries — only partial information extracted
33
+ - Structured schemas — relationships between fields lost
34
+
35
+ **Structured data is not natively supported via MCP.** The options are:
36
+
37
+ 1. **Write a single narrative summary** as a memory — one call, not row-by-row:
38
+ ```
39
+ memory_add(scope="write",
40
+ agent_id="<your session agent_id>",
41
+ conversation_id="<session conversation_id>",
42
+ text="Customer Complaints dataset has fields: Complaint ID (int PK), Date Submitted (date), Product (text, e.g. Mortgage/Credit Card), Sub-product (text), Issue (text), Company Response (text), State (text, 2-letter code), ZIP Code (text)")
43
+ ```
44
+ 2. **Upload the schema doc** through the Cloud UI's **Add Knowledge** flow (Datapack → Actions → Add Knowledge). Accepts PDF/TXT/MD/JSON — convert CSV to MD or JSON first. That makes it queryable via `knowledgebase_search`.
45
+ 3. **Tell the user** that structured-data storage via MCP isn't supported and let them decide how to proceed.
46
+
47
+ Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
48
+
49
+ ## Activation is model-judged on Desktop (no hooks)
50
+
51
+ Claude Desktop has no lifecycle hooks, so this skill activates only when the model judges it relevant from the skill's `description`. Reliable triggers: recall questions ("what do you know about me"), explicit save requests ("remember this"), and mentions of memory/Meko/datapacks. **Best-effort** triggers: task-shaped prompts where a durable fact appears only in passing ("I'm evaluating pnpm; I already use Turborepo") — the skill may not fire and the turn goes uncaptured. Also, when the model resolves a tool directly via tool search it may call `memory_add`/`memory_search` without reading this skill at all.
52
+
53
+ The skill description is tuned to its 1024-char ceiling; broadening it further does not close the task-shaped-prompt gap (empirically confirmed in Phase-9 testing). Mitigations, in order of leverage:
54
+
55
+ 1. **Personal-preferences snippet** (always-on) — paste the snippet from the Desktop setup README's "Make Desktop proactive" step into Claude's profile preferences; it is injected into every conversation regardless of prompt shape. This is the only true fix for task-shaped misses.
56
+ 2. **Server-side guidance** — the `agent_id` tool docstrings and the server's connect-time instructions name `claude_desktop` as this client's bucket, so even a skill-less tool-search call avoids the wrong-bucket (`claude_code`) write.
57
+ 3. Nothing is lost when the *user* explicitly recalls or saves — only passive capture of in-passing facts is best-effort.
58
+
59
+ ## No conversation search
60
+
61
+ `conversation_list` returns conversations by agent, but there is no semantic search across conversation content. To find a specific past exchange, you need to list conversations and inspect them individually with `conversation_get`.
62
+
63
+ For finding past knowledge by meaning, use `memory_search` instead — which is why storing key facts via `memory_add` alongside conversations is important.
@@ -0,0 +1,214 @@
1
+ # When to Use Memory Tools vs Conversation Tools
2
+
3
+ **WRONG:** `memory_add(text="User asked about pricing. I explained tiers. User chose Pro.")` — mem0 extracts facts, discarding conversational structure, turn ordering, and reasoning traces.
4
+
5
+ ## Use `memory_add` when storing:
6
+
7
+ - A **fact**: "User prefers dark mode"
8
+ - A **preference**: "Customer budget is $50k"
9
+ - An **entity relationship**: "Alice works at Acme Corp"
10
+
11
+ Memory is backed by pgvector (semantic search) and Apache AGE (entity-relationship graph). It retrieves relevant facts by meaning, not by conversation order.
12
+
13
+ ```
14
+ memory_add(scope="write", agent_id="support_bot",
15
+ text="Customer Alice (alice@acme.com) prefers email, has Pro plan.", user_id="alice_123")
16
+
17
+ memory_search(scope="read", query="What plan does Alice have?", agent_id="support_bot")
18
+ ```
19
+
20
+ ## Use `conversation_create` + `conversation_add_message` when storing:
21
+
22
+ - A **full dialog exchange** with input/output pairs
23
+ - A **chain-of-thought** reasoning trace alongside the response
24
+ - A **multi-turn chat** where turn order matters
25
+
26
+ Conversations are backed by Langfuse sessions and traces. They preserve full structure: who said what, in what order, with what reasoning.
27
+
28
+ ```
29
+ conversation_create(scope="write", agent_id="support_bot", user_id="alice_123", title="Pricing discussion")
30
+ -- Returns: {"id": "conv-uuid-here"}
31
+
32
+ conversation_add_message(scope="write", conversation_id="conv-uuid-here", agent_id="support_bot",
33
+ input="What are your pricing tiers?",
34
+ output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
35
+ reasoning="Retrieved pricing page data. No special discounts apply.")
36
+ ```
37
+
38
+ ## Decision Matrix
39
+
40
+ | Signal | Tool |
41
+ |--------|------|
42
+ | "remember that...", "note that...", "keep in mind..." | `memory_add` |
43
+ | "store this conversation", "save this chat" | `conversation_create` + `conversation_add_message` |
44
+ | "what do you know about X?", "recall..." | `memory_search` |
45
+ | "show me our past conversation about..." | `conversation_list` + `conversation_get` |
46
+ | "the user prefers...", "their budget is..." | `memory_add` |
47
+ | "save my query and your response" | `conversation_add_message` |
48
+
49
+ ## Verbatim Content Rules for conversation_add_message
50
+
51
+ **WRONG:** Summarizing or rephrasing content before storing:
52
+ ```
53
+ conversation_add_message(...,
54
+ input="User inquired about database performance", -- rephrased
55
+ output="I provided optimization suggestions", -- summarized
56
+ reasoning="Analyzed the query and suggested improvements" -- condensed
57
+ )
58
+ ```
59
+
60
+ All three fields — `input`, `output`, and `reasoning` — must contain the **exact, verbatim text**. Never summarize, rephrase, editorialize, or condense any field:
61
+
62
+ - **`input`**: The user's exact prompt, word for word
63
+ - **`output`**: The assistant's complete response, word for word — including code blocks, formatting, and all detail
64
+ - **`reasoning`**: The full chain-of-thought or internal reasoning trace, unedited
65
+
66
+ The purpose of conversation storage is to create a faithful, replayable record. A rephrased summary loses the original wording, tone, and detail — making the stored conversation useless for review, debugging, or audit.
67
+
68
+ ## Personal memory vs. team-shared knowledge — the three read paths
69
+
70
+ Agents on Cloud Meko have three distinct read surfaces. Pick the right one for the question.
71
+
72
+ | Read path | What it returns | How to call |
73
+ |---|---|---|
74
+ | Your own desktop memories | Memories you wrote under this `agent_id`, filtered by `(datapack_id, user_id, agent_id)` | `memory_search(agent_id="claude_desktop", query="...", ...)` |
75
+ | Cross-project common bucket | Memories any agent (including this one) wrote with `agent_id="meko_agent"` — the empty-default bucket for genuinely cross-project facts | `memory_search(agent_id="meko_agent", query="...", ...)` |
76
+ | Team's shared knowledge | Promoted memories + uploaded documents, visible to every member of the datapack | `knowledgebase_search(agent_id="<anything>", datapack_id="<datapack UUID>", query="...")` — `agent_id` is ignored |
77
+
78
+ For a true fan-out across other clients' buckets (e.g. also see what was written from `claude_code:some-repo` or `cursor:foo`), call `memory_search` once per agent_id — there's no single-call shortcut. Empty string is rewritten to `meko_agent` server-side; it does not drop the filter.
79
+
80
+ ### How content gets into each surface
81
+
82
+ - **Personal memories** — written by `memory_add`. Scoped per-user and per-agent from the moment of write. Only the writer sees them via MCP reads.
83
+ - **Team-shared Shared Knowledge** — arrives two ways:
84
+ 1. The **user** (never the agent) promotes a personal memory to Knowledge via the Cloud UI's Learnings tab. That copies the row into the shared `knowledge_base` table with the `user_id` stripped, making it team-wide. Originating `agent_id` is preserved in metadata for provenance.
85
+ 2. The user uploads a file via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/MP4 up to 5MB each.
86
+
87
+ Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
88
+
89
+ **No MCP tool promotes to Shared Knowledge.** The agent can flag memories it thinks are worth promoting and suggest the user do it from the UI — but the action is user-initiated.
90
+
91
+ ### When the user asks "what do you know about X?"
92
+
93
+ A full sweep is three calls (budget for it — each is 2-6 seconds):
94
+
95
+ ```
96
+ memory_search(agent_id="claude_desktop", query="X", conversation_id=..., ...)
97
+ memory_search(agent_id="meko_agent", query="X", conversation_id=..., ...) # cross-project common bucket
98
+ knowledgebase_search(agent_id="<anything>", datapack_id="<uuid>", query="X", conversation_id=..., ...)
99
+ ```
100
+
101
+ When you answer, be explicit about scope so the user knows why something is or isn't there:
102
+
103
+ - "I found this in your own desktop memories…"
104
+ - "I found this in your common cross-project bucket (something you or another agent wrote under `meko_agent`)…"
105
+ - "I found this in your team's Shared Knowledge — someone (you or a teammate) promoted it earlier…"
106
+ - "I couldn't find anything in your personal memories. You might want to check the Cloud UI's Memory Summary tab for a cross-agent view."
107
+
108
+ For a true fan-out across other clients' buckets (e.g. also see what was written from `claude_code:some-repo` or `cursor:foo`), call `memory_search` once per known agent_id — empty string just resolves to `meko_agent`, not a fan-out.
109
+
110
+ ## Memory limitations for structured data
111
+
112
+ **WRONG:** Using `memory_add` to ingest CSV rows, data dictionaries, or tabular schemas — Mem0 extracts individual facts and may drop columns, rows, or structural relationships.
113
+
114
+ There is no MCP-side "just put it in a database table" option — raw SQL access isn't part of the MCP surface. Workarounds:
115
+
116
+ 1. **Write a single narrative summary** as a memory: `"The Customer Complaints dataset has fields: Complaint ID (int), Date Submitted (date), Product (text), Sub-product (text), Issue (text)..."` — one call, not row-by-row.
117
+ 2. **Suggest the user upload the file** via the Cloud UI's Add Knowledge flow if it's a document (CSV files aren't in the supported list — PDF/TXT/MD/JSON/MP4 are; for CSV, convert to MD or JSON first).
118
+ 3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context.
119
+
120
+ ## Memory Storage: capture the turn, don't proactively memory_add
121
+
122
+ Do **not** proactively `memory_add` facts the user states. On Claude Desktop, post each substantive turn with `conversation_add_message` and the server extracts durable memories from it automatically — personal info, team conventions, domain knowledge, and corrections the user states are all captured that way. A separate `memory_add` just duplicates what extraction produces.
123
+
124
+ Explicit `memory_add` is reserved for the three cases per-turn capture can't reach:
125
+
126
+ - **Explicit request** → the user says "remember this" / "save this."
127
+ - **Output-only / tool-derived fact** → a durable fact only in your output or a tool result, never in a user turn (extraction reads the user side of the turn).
128
+ - **Overwriting correction** → a prior fact was negated and the stale memory must not survive. Extraction is additive, so `memory_search` for the old memory and `memory_update` / `memory_delete_by_id`.
129
+
130
+ Use `memory_search` at the start of sessions to recall what you already know before asking the user to repeat themselves.
131
+
132
+ ## Using Both Together
133
+
134
+ Posting the turn does both jobs: it preserves the full conversation (structure) and feeds the extractor (searchable memory). Add an explicit `memory_add` only for the three cases above.
135
+
136
+ ## Key Retrieval Difference
137
+
138
+ - `memory_search`: **semantic similarity** across all memories via pgvector. Returns relevant facts regardless of when stored.
139
+ - `conversation_get`: **ordered list of message turns** for a specific conversation. No semantic search. Requires `conversation_id`.
140
+
141
+ ## Conversation Capture (Desktop: agent-driven)
142
+
143
+ Claude Desktop has **no capture hooks** — you are the capture mechanism. Post each substantive turn with `conversation_add_message`, and the server extracts memories from the posted turns automatically (extraction runs inside `conversation_add_message`). Coding clients like Claude Code get the same effect from SessionStart / PreCompact / SessionEnd hooks; on Desktop it's your responsibility per turn.
144
+
145
+ ### What to capture
146
+
147
+ The full transcript including:
148
+ - **User prompts** — verbatim text (the `input` field)
149
+ - **Assistant responses** — all text blocks (the `output` field)
150
+ - **Tool calls** — tool name + input parameters (the `reasoning` field)
151
+ - **Tool results** — output from tool executions (appended to `reasoning`)
152
+
153
+ This is more than just text — tool calls and results are critical context for session replay, cross-agent sharing, and compaction.
154
+
155
+ ### Seed-based deduplication
156
+
157
+ Each message's seed is `<conversation_id>:<user_message_uuid>`. All three capture mechanisms generate the same seed for the same exchange, producing the same deterministic trace ID via `sha256(seed)[:16].hex()`. This means duplicate writes from overlapping captures are idempotent.
158
+
159
+ ### When to manually store conversations
160
+
161
+ Automatic capture handles the raw exchange. You should still manually use `conversation_create` + `conversation_add_message` when:
162
+ - The user explicitly asks to "save this conversation"
163
+ - You want to add curated `reasoning` traces beyond raw tool calls
164
+ - You want to store a selected subset of the conversation with a descriptive title
165
+
166
+ ### Watermark coordination
167
+
168
+ A shared watermark file at `~/.claude/meko-capture/<session-id>.watermark.json` tracks what has been saved. Both hooks and the agent's periodic checkpoint use this to avoid reprocessing already-captured exchanges.
169
+
170
+ ## Observability: conversation_id IS the Langfuse trace ID
171
+
172
+ This is the feature agents tend to miss. Verified live 2026-05-07 in the Meko UI's Observe hub.
173
+
174
+ - `conversation_create` returns a `conversation_id` (e.g. `d71fc8b61a7f45d585eea9a6436e0c3f`).
175
+ - That ID is also the **Langfuse trace_id** for the conversation. Not a separate trace — literally the same identifier.
176
+ - Every subsequent MCP tool call made while passing that `conversation_id` becomes a **span under that trace**, named after the tool: `Memory Add (Meko MCP)`, `Memory Search (Meko MCP)`, `Knowledgebase Search (Meko MCP)`, `Conversation Add Message (Meko MCP)`, etc.
177
+ - Child spans reveal internals. Observed structure:
178
+ - `memory_add`: `Memory Add (Meko MCP)` → `Create a new memory in Mem0` → `Bulk Payload Update (yugabytedb / vector)` → `Execute Query (yugabytedb / vector)`
179
+ - `memory_search`: `Memory Search (Meko MCP)` → `Search for memories based on a query in Mem0` (Retriever)
180
+ - `conversation_add_message`: `Conversation Add Message (Meko MCP)` → `Conversation Message Added` span → `Reasoning` generation (the `reasoning` field is stored as a Langfuse *generation*-typed span, not a plain text field)
181
+ - `knowledgebase_search`: `Knowledgebase Search (Meko MCP)` → multiple `Execute Query (yugabytedb)` child spans
182
+ - Trace tags include `agent:<agent_id>` and the Meko org UUID. Both are searchable/filterable in Langfuse.
183
+ - Each datapack has its own Langfuse project — traces for a tool call land in the project for whichever `datapack_id` was on the call (or the default datapack if omitted).
184
+
185
+ ### Finding a trace in the UI
186
+
187
+ Two navigation paths, both verified in the Meko UI:
188
+
189
+ 1. **Datapack → Conversations tab** — every row has an **Open in Observe** button that deep-links to the trace with `session=<conversation_id>` pre-filled. Fastest when you know which conversation to inspect.
190
+ 2. **Observe hub** — browse all traces across a datapack. URL shape: `/observe-hub?project=<langfuse_project_id>&session=<conversation_id>`.
191
+
192
+ The Conversations-tab row preview shows the first user turn verbatim, plus the agent_id tag, message count, and started-at timestamp. If you want a conversation to be recognizable in the UI, call `conversation_add_message` with a clean first-turn `input` early in the session.
193
+
194
+ ### Observed latencies on prod (2026-05-07)
195
+
196
+ From real traces, not the docstring happy path:
197
+
198
+ | Tool | Latency per call |
199
+ |---|---|
200
+ | `memory_add` | 12-21 seconds (calls OpenAI for extraction, then writes to vector + graph) |
201
+ | `memory_search` | 1.8-5.9 seconds |
202
+ | `knowledgebase_search` | 0.6 seconds (empty index; will grow with index size) |
203
+ | `conversation_add_message` | 0.11 seconds (fire-and-forget; queued to Langfuse) |
204
+
205
+ `memory_add` is the expensive one. If you're capturing a long conversation, batch through `conversation_add_message` (cheap, queued) and let the server-side Mem0 extractor handle the heavy lifting on its own schedule, rather than firing `memory_add(messages=...)` per turn.
206
+
207
+ ### Proactive diagnostic pattern
208
+
209
+ If a user reports "my memory_add didn't seem to save", open the Observe hub for their datapack, filter on their `conversation_id`, and look at the span tree. You will see either:
210
+
211
+ - A `Memory Add (Meko MCP)` span with `Create a new memory in Mem0` child → the call reached Mem0. The fact extractor may have returned `"results": []` (common on short or non-fact-shaped text; not a bug, but lossy).
212
+ - No span at all → the call never reached the server. Likely a transport / auth / `conversation_id` mismatch issue.
213
+
214
+ The mem0 extractor is lossy — it extracts atomic facts and graph triples, and may drop prose that doesn't look fact-shaped to it. Observed 2026-05-07: 2 of 5 `memory_add` calls returned `"results": []` and only the graph side landed. When preserving authoritative text matters, store it via `conversation_add_message` (verbatim in `input`/`output`/`reasoning`) — the conversation path preserves text without LLM re-extraction.