@yugabytedb/meko-mcp 1.0.8 → 1.2.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 (51) hide show
  1. package/README.md +242 -44
  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 +457 -107
  5. package/assets/hooks-handlers/lib/package.json +1 -0
  6. package/assets/hooks-handlers/test_single_conversation.sh +1 -1
  7. package/assets/scripts/package-desktop-skill.sh +36 -0
  8. package/assets/skills/meko-mcp-tools/SKILL.md +167 -53
  9. package/assets/skills/meko-mcp-tools/references/_sections.md +1 -1
  10. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +84 -22
  11. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +89 -56
  12. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +15 -7
  13. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +17 -9
  14. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +94 -5
  15. package/assets/skills/meko-mcp-tools/references/tools-overview.md +52 -37
  16. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +108 -37
  17. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +6 -10
  18. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +30 -18
  19. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +55 -69
  20. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +251 -0
  21. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +150 -0
  22. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +24 -0
  23. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +99 -0
  24. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +406 -0
  25. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +69 -0
  26. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +217 -0
  27. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +112 -0
  28. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +134 -0
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +75 -0
  30. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +155 -0
  31. package/bin/create-meko-setup.mjs +151 -22
  32. package/lib/clients/claude-code.mjs +378 -68
  33. package/lib/clients/claude-desktop.mjs +45 -8
  34. package/lib/clients/codex.mjs +1209 -0
  35. package/lib/clients/common.mjs +223 -1
  36. package/lib/clients/cursor.mjs +118 -13
  37. package/lib/clients/index.mjs +2 -0
  38. package/lib/config.mjs +56 -0
  39. package/lib/detect.mjs +52 -44
  40. package/lib/installer.mjs +11 -4
  41. package/lib/mcp-transport.mjs +61 -2
  42. package/lib/migrate/adapters/memory-md.mjs +13 -6
  43. package/lib/migrate/datapack.mjs +167 -0
  44. package/lib/migrate/id.mjs +127 -9
  45. package/lib/migrate/orchestrator.mjs +68 -10
  46. package/lib/migrate.mjs +346 -3
  47. package/lib/prompt.mjs +22 -4
  48. package/lib/validate.mjs +313 -9
  49. package/lib/version-check.mjs +178 -0
  50. package/package.json +2 -1
  51. package/scripts/bundle-assets.mjs +8 -0
@@ -2,7 +2,9 @@
2
2
 
3
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
4
 
5
- > **Note on `agent_id` in the examples below.** The examples use `agent_id="claude_code"` for readability, but `agent_id` is a **per-user namespace**, not a per-tool label. At runtime, use the value you discovered via `db_summarize_database` at session start (see the main SKILL.md). Substitute it anywhere you see `claude_code` in the examples. Issue [#10](https://github.com/amiramm/meko-mcp-server/issues/10) tracks the eventual schema fix.
5
+ > **Note on `agent_id` in the examples below.** Where you see `agent_id="agent"` in an example, substitute **your** session's `agent_id` — the value the SessionStart hook injected into `additionalContext`. For Claude Code that's `claude_code:<repo-basename>` (e.g. `claude_code:meko-mcp-server`); for Cursor, `cursor:<repo-basename>`; for Claude Desktop, the bare client name `claude_desktop`. 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
+ > **Note on availability on Cloud.** The `db_*` tools and the three KB ingestion tools (`knowledgebase_trigger_index_creation`, `knowledgebase_add_source_to_index`, `knowledgebase_check_index_status`) return `{"error": "not_available"}` on Cloud Meko today. This cookbook keeps their examples for reference but you can't call them from a Cloud client.
6
8
 
7
9
  ---
8
10
 
@@ -97,14 +99,14 @@ Split into two separate calls.
97
99
 
98
100
  ## Memory Tools
99
101
 
100
- **Critical:** `agent_id` must not contain hyphens. Use `"claude_code"`, not `"claude-code"`.
102
+ **Critical:** Pass your session's `agent_id` on every memory call (the value from the SessionStart `additionalContext`, e.g. `claude_code:meko-mcp-server`). 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. For genuinely cross-project facts, write with `agent_id="meko_agent"` so any agent can pick them up.
101
103
 
102
104
  ### memory_add
103
105
 
104
106
  **When to use:** Store facts, preferences, user profile info, org conventions, corrections, learnings. Use proactively — don't wait for the user to ask.
105
107
 
106
108
  ```
107
- memory_add(scope="write", agent_id="claude_code",
109
+ memory_add(scope="write", agent_id="agent",
108
110
  text="User Amiram is VP of Product at YugabyteDB. Prefers concise responses.")
109
111
  ```
110
112
 
@@ -115,7 +117,7 @@ memory_add(scope="write", agent_id="claude_code",
115
117
 
116
118
  **With user scoping:**
117
119
  ```
118
- memory_add(scope="write", agent_id="claude_code", user_id="amiram",
120
+ memory_add(scope="write", agent_id="agent", user_id="amiram",
119
121
  text="Prefers Python for backend, Go for infrastructure.")
120
122
  ```
121
123
 
@@ -125,7 +127,7 @@ memory_add(scope="write", agent_id="claude_code", user_id="amiram",
125
127
  - Large documents (use knowledge base ingestion)
126
128
 
127
129
  **Common errors:**
128
- - `syntax error at or near "-"` — Your `agent_id` contains a hyphen. Use underscores.
130
+ - `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.
129
131
  - `connection already closed` — Retry once. If it fails again, the memory subsystem is down.
130
132
 
131
133
  ---
@@ -135,7 +137,7 @@ memory_add(scope="write", agent_id="claude_code", user_id="amiram",
135
137
  **When to use:** Find relevant memories by meaning. Always try this before asking the user to repeat information.
136
138
 
137
139
  ```
138
- memory_search(scope="read", query="What programming language does the team use?", agent_id="claude_code")
140
+ memory_search(scope="read", query="What programming language does the team use?", agent_id="agent")
139
141
  ```
140
142
 
141
143
  **Response:**
@@ -145,7 +147,7 @@ memory_search(scope="read", query="What programming language does the team use?"
145
147
 
146
148
  **With limit:**
147
149
  ```
148
- memory_search(scope="read", query="user preferences", agent_id="claude_code", limit=5)
150
+ memory_search(scope="read", query="user preferences", agent_id="agent", limit=5)
149
151
  ```
150
152
 
151
153
  ---
@@ -155,12 +157,12 @@ memory_search(scope="read", query="user preferences", agent_id="claude_code", li
155
157
  **When to use:** List everything stored for an agent. Useful at session start to load context.
156
158
 
157
159
  ```
158
- memory_get_all(scope="read", agent_id="claude_code")
160
+ memory_get_all(scope="read", agent_id="agent")
159
161
  ```
160
162
 
161
163
  **With user scoping:**
162
164
  ```
163
- memory_get_all(scope="read", agent_id="claude_code", user_id="amiram")
165
+ memory_get_all(scope="read", agent_id="agent", user_id="amiram")
164
166
  ```
165
167
 
166
168
  ---
@@ -168,7 +170,7 @@ memory_get_all(scope="read", agent_id="claude_code", user_id="amiram")
168
170
  ### memory_get_by_id
169
171
 
170
172
  ```
171
- memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="claude_code")
173
+ memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="agent")
172
174
  ```
173
175
 
174
176
  ---
@@ -178,7 +180,7 @@ memory_get_by_id(scope="read", memory_id="mem-uuid-123", agent_id="claude_code")
178
180
  **When to use:** Overwrite a specific memory's text. Requires the memory UUID.
179
181
 
180
182
  ```
181
- memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="claude_code")
183
+ memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses Go for all new services", agent_id="agent")
182
184
  ```
183
185
 
184
186
  ---
@@ -186,7 +188,7 @@ memory_update(scope="write", memory_id="mem-uuid-123", text="Updated: Team uses
186
188
  ### memory_delete_by_id
187
189
 
188
190
  ```
189
- memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="claude_code")
191
+ memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="agent")
190
192
  ```
191
193
 
192
194
  ---
@@ -196,7 +198,7 @@ memory_delete_by_id(scope="write", memory_id="mem-uuid-123", agent_id="claude_co
196
198
  **Destructive. Requires admin scope.** Deletes all memories for the agent.
197
199
 
198
200
  ```
199
- memory_delete_all(scope="admin", agent_id="claude_code")
201
+ memory_delete_all(scope="admin", agent_id="agent")
200
202
  ```
201
203
 
202
204
  ---
@@ -208,7 +210,7 @@ memory_delete_all(scope="admin", agent_id="claude_code")
208
210
  **When to use:** Start storing a multi-turn exchange. Do this when the session contains valuable dialog worth preserving.
209
211
 
210
212
  ```
211
- conversation_create(scope="write", agent_id="claude_code", user_id="amiram",
213
+ conversation_create(scope="write", agent_id="agent", user_id="amiram",
212
214
  title="Debugging the auth middleware")
213
215
  ```
214
216
 
@@ -224,7 +226,7 @@ conversation_create(scope="write", agent_id="claude_code", user_id="amiram",
224
226
  **When to use:** Add a user/assistant exchange to an existing conversation. **All fields must be verbatim** — never summarize or rephrase.
225
227
 
226
228
  ```
227
- conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
229
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
228
230
  input="Why is the auth middleware returning 401?",
229
231
  output="The token validation is checking the wrong issuer claim...",
230
232
  reasoning="Checked the middleware source, found issuer mismatch between config and JWT...")
@@ -232,10 +234,10 @@ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_i
232
234
 
233
235
  **With dedup seed (use when client hooks also write to Langfuse):**
234
236
  ```
235
- conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
237
+ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
236
238
  input="Why is the auth middleware returning 401?",
237
239
  output="The token validation is checking the wrong issuer claim...",
238
- seed="conv-uuid-123:claude_code:Why is the auth middleware returning 401?")
240
+ seed="conv-uuid-123:agent:Why is the auth middleware returning 401?")
239
241
  ```
240
242
 
241
243
  ---
@@ -243,7 +245,7 @@ conversation_add_message(scope="write", conversation_id="conv-uuid-123", agent_i
243
245
  ### conversation_get
244
246
 
245
247
  ```
246
- conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="claude_code",
248
+ conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="agent",
247
249
  include_messages=True, limit=50)
248
250
  ```
249
251
 
@@ -252,7 +254,7 @@ conversation_get(scope="read", conversation_id="conv-uuid-123", agent_id="claude
252
254
  ### conversation_list
253
255
 
254
256
  ```
255
- conversation_list(scope="read", agent_id="claude_code", limit=20)
257
+ conversation_list(scope="read", agent_id="agent", limit=20)
256
258
  ```
257
259
 
258
260
  ---
@@ -260,48 +262,65 @@ conversation_list(scope="read", agent_id="claude_code", limit=20)
260
262
  ### conversation_update
261
263
 
262
264
  ```
263
- conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="claude_code",
265
+ conversation_update(scope="write", conversation_id="conv-uuid-123", agent_id="agent",
264
266
  title="Resolved: Auth middleware issuer mismatch")
265
267
  ```
266
268
 
267
269
  ---
268
270
 
269
- ### conversation_delete_message
271
+ ### conversation_delete
272
+
273
+ **Destructive. Requires admin scope.**
270
274
 
271
275
  ```
272
- conversation_delete_message(scope="write", conversation_id="conv-uuid-123",
273
- agent_id="claude_code", trace_id="trace-uuid-456")
276
+ conversation_delete(scope="admin", conversation_id="conv-uuid-123", agent_id="agent")
274
277
  ```
275
278
 
276
279
  ---
277
280
 
278
- ### conversation_delete
281
+ ## RAG / Knowledge Base Tools
279
282
 
280
- **Destructive. Requires admin scope.**
283
+ **On cloud Meko today, 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). The three ingestion-side MCP tools below are Free-Tier-gated on cloud and brittle even when ungated. `knowledgebase_search` is the one KB tool to reach for.
284
+
285
+ See `tools-rag-workflow.md` for the decision table and why.
286
+
287
+ ### knowledgebase_search
288
+
289
+ **When to use:** Retrieve chunks from a populated KB. Works on cloud today.
281
290
 
282
291
  ```
283
- conversation_delete(scope="admin", conversation_id="conv-uuid-123", agent_id="claude_code")
292
+ knowledgebase_search(
293
+ scope="read",
294
+ query="natural-language question",
295
+ agent_id="agent",
296
+ conversation_id="<uuid from conversation_create>",
297
+ datapack_id="<datapack UUID — REQUIRED here, no default>",
298
+ limit=10)
284
299
  ```
285
300
 
286
- ---
301
+ Unlike memory tools, `datapack_id` has no default — you must pass it explicitly.
287
302
 
288
- ## RAG / Knowledge Base Tools
303
+ **Response (empty KB, verified 2026-05-07):**
304
+ ```json
305
+ {"results": [], "count": 0}
306
+ ```
307
+
308
+ Populated KBs return results with chunk content and similarity scores. An empty/nonexistent KB is not an error — just `count: 0`.
309
+
310
+ ---
289
311
 
290
312
  ### knowledgebase_trigger_index_creation
291
313
 
292
- **When to use:** Create a new vector index from source URIs. This is the only way to start a RAG pipeline.
314
+ **When to use:** Self-hosted deployments where the ingestion worker has IAM access to the target S3 bucket. **Not available on cloud Free Tier** (returns `{"error": "not_available", "detail": "Vector index creation is not available on the free tier."}`).
293
315
 
294
316
  ```
295
- knowledgebase_trigger_index_creation(scope="write",
317
+ knowledgebase_trigger_index_creation(
318
+ scope="write",
319
+ conversation_id="<uuid from conversation_create>",
296
320
  source_uris="s3://my-bucket/docs/,s3://my-bucket/reports/",
297
321
  index_name="company_docs")
298
322
  ```
299
323
 
300
- **Response:**
301
- ```json
302
- {"source_ids": ["src-uuid-1", "src-uuid-2"], "index_name": "company_docs", "status": "build_triggered"}
303
- ```
304
-
305
324
  **Optional parameters:**
306
325
  - `ai_provider="OPENAI"` (default)
307
326
  - `embedding_model="text-embedding-3-large"` (default)
@@ -310,31 +329,54 @@ knowledgebase_trigger_index_creation(scope="write",
310
329
  - `chunk_overlap=256` (default)
311
330
  - `datapack_id=None`
312
331
 
313
- **Warning:** Each call creates a new index. Do NOT retry on failure — you'll get duplicate indexes (e.g., `docs_v1`, `docs_v2`, `docs_v3`).
332
+ **Success response:**
333
+ ```json
334
+ {"source_ids": ["<uuid>", ...], "index_id": "<uuid>", "index_name": "company_docs",
335
+ "status": "build_triggered", "message": "... registered, index '...' initialised, and build triggered."}
336
+ ```
337
+
338
+ **Critical caveats:**
339
+ - URIs must start with `s3://`. The worker (`aws_source_processor.py:86-117`) rejects any other scheme with `ValueError("Invalid source URI")` — async, not surfaced through the MCP response.
340
+ - The worker uses the boto3 default credential chain (env vars, IAM role, `~/.aws/credentials` on the worker host). There is no way for the user to pass AWS credentials through the MCP tool. If the worker's identity can't read the bucket, the build stalls at INIT.
341
+ - Each call creates a new index. Do NOT retry on failure — you'll get duplicate indexes.
342
+ - Tracked as a gap: [yugabyte/meko-mcp-server#89](https://github.com/yugabyte/meko-mcp-server/issues/89) / MEKO-96.
314
343
 
315
344
  ---
316
345
 
317
346
  ### knowledgebase_check_index_status
318
347
 
319
- **When to use:** Poll for build completion after triggering creation.
348
+ **When to use:** Poll a self-hosted build for completion. **Not available on cloud Free Tier** (returns `{"error": "not_available"}`).
320
349
 
321
350
  ```
322
- knowledgebase_check_index_status(scope="read", index_name="company_docs")
351
+ knowledgebase_check_index_status(
352
+ scope="read",
353
+ conversation_id="<uuid from conversation_create>",
354
+ index_name="company_docs",
355
+ datapack_id=None)
323
356
  ```
324
357
 
325
- **Polling strategy:** Check every 1-2 minutes. If `pipeline_details` is empty or documents remain at `INIT` for more than 5 minutes, the pipeline is likely stuck. Stop polling after 3 consecutive no-progress checks — see `tools-troubleshooting.md`.
358
+ Check `completion_rate_percent` in `pipeline_stats` and `document_status` in `pipeline_details`. If documents stay at `INIT` for >5 minutes, the worker probably can't reach the bucket. Stop polling after 3 consecutive no-progress checks.
326
359
 
327
360
  ---
328
361
 
329
362
  ### knowledgebase_add_source_to_index
330
363
 
331
- **Known bug:** This tool has a parameter mismatch (`r_index_name` vs `r_index_id`) and may fail. Prefer `knowledgebase_trigger_index_creation` with all sources at once instead.
364
+ **When to use:** Grow an existing index with a new source URI (self-hosted / paid). **Not available on cloud Free Tier** (same "Vector index creation is not available" gate as `trigger_index_creation`).
332
365
 
333
366
  ```
334
- knowledgebase_add_source_to_index(scope="write", index_name="company_docs",
335
- source_id="src-uuid-new")
367
+ knowledgebase_add_source_to_index(
368
+ scope="write",
369
+ conversation_id="<uuid from conversation_create>",
370
+ index_name="company_docs",
371
+ source_uri="s3://my-bucket/new-docs/")
336
372
  ```
337
373
 
374
+ Param is **`source_uri`** (URI string), not `source_id` — older docs had this wrong.
375
+
376
+ The historical `r_index_name` vs `r_index_id` parameter-mismatch bug (reported in 2026-03) is **fixed** on main. The tool now resolves `index_name → index_id` internally via `SELECT id FROM dist_rag.vector_indexes WHERE index_name = %s` before calling the dist_rag function. If the name doesn't exist you get `{"error": "index_not_found", "detail": "No vector index found with name '...'"}`.
377
+
378
+ Same S3-only / worker-credentials caveats as `trigger_index_creation` apply.
379
+
338
380
  ---
339
381
 
340
382
  ## Datapack Management Tools
@@ -354,20 +396,11 @@ datapack_update(scope="write", name="analytics_prod", connection_string="postgre
354
396
  datapack_delete(scope="admin", name="analytics_prod") # Irreversible!
355
397
  ```
356
398
 
357
- ### Agent management within datapacks
399
+ ### Agent and knowledge-base management (NOT MCP — control-plane only)
358
400
 
359
- ```
360
- datapack_create_agent(scope="write", datapack_name="analytics_prod", agent_name="analytics_bot")
361
- datapack_list_agents(scope="read", datapack_name="analytics_prod")
362
- datapack_delete_agent(scope="admin", datapack_name="analytics_prod", agent_name="analytics_bot")
363
- ```
401
+ 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:
364
402
 
365
- ### Knowledge base source management within datapacks
366
-
367
- ```
368
- datapack_add_knowledge_base(scope="write", datapack_name="analytics_prod", url="s3://data/reports/")
369
- datapack_list_knowledge_bases(scope="read", datapack_name="analytics_prod")
370
- datapack_delete_knowledge_base(scope="admin", datapack_name="analytics_prod", url="s3://data/reports/")
371
- ```
403
+ - REST: `POST/GET/DELETE /datapacks/:name/agents` (agents), `POST/GET/DELETE /datapacks/:name/knowledge-bases` (KB sources).
404
+ - Or the Meko UI at `app.mekodev.com` → Datapacks → agents / knowledge-bases.
372
405
 
373
- **Note:** `datapack_delete_knowledge_base` removes the source registration from the Meko API. It does NOT delete the actual vector index, source records, or vector data from the database.
406
+ To build a RAG index from inside a session (which IS MCP-exposed), use `knowledgebase_trigger_index_creation` / `knowledgebase_add_source_to_index` / `knowledgebase_check_index_status` — those operate on `dist_rag` tables inside the datapack's database.
@@ -32,23 +32,31 @@ All **Database**, **RAG**, and **Memory** tools accept `datapack_id`.
32
32
 
33
33
  ## Datapack lifecycle
34
34
 
35
- ### Creation and setup
35
+ ### Creation and setup (MCP)
36
36
 
37
37
  ```
38
38
  datapack_create(scope="write", name="sales_analytics")
39
- datapack_create_agent(scope="write", datapack_name="sales_analytics", agent_name="sales_agent")
40
- datapack_add_knowledge_base(scope="write", datapack_name="sales_analytics", url="s3://company-docs/sales/")
41
39
  db_run_write_query(scope="write", query="CREATE TABLE leads (...)", datapack_id="dp-uuid-from-step-1")
42
40
  ```
43
41
 
42
+ Provisioning agents and knowledge-base sources on the datapack is **not** MCP-exposed — do that in the Meko control plane (UI at `app.mekodev.com` → Datapacks, or directly via the REST API:
43
+ `POST /datapacks/:name/agents`, `POST /datapacks/:name/knowledge-bases`). If the user asks the agent to set those up mid-session, tell them where to go rather than inventing an MCP call that will fail.
44
+
45
+ For RAG indexes inside the datapack's database, use the MCP-exposed RAG tools:
46
+
47
+ ```
48
+ knowledgebase_trigger_index_creation(scope="write", source_uris=[...], index_name="leads_docs", datapack_id="dp-uuid-from-step-1")
49
+ knowledgebase_check_index_status(scope="read", index_name="leads_docs", datapack_id="dp-uuid-from-step-1")
50
+ ```
51
+
44
52
  ### Teardown (requires admin scope)
45
53
 
46
- Delete child resources before the datapack:
54
+ Delete child resources first (agents and KB sources via the control plane), then the datapack:
47
55
 
48
56
  ```
49
- datapack_delete_knowledge_base(scope="admin", datapack_name="sales_analytics", url="s3://company-docs/sales/")
50
- datapack_delete_agent(scope="admin", datapack_name="sales_analytics", agent_name="sales_agent")
51
- datapack_delete(scope="admin", name="sales_analytics")
57
+ # Control-plane (REST or UI): DELETE /datapacks/sales_analytics/knowledge-bases
58
+ # Control-plane (REST or UI): DELETE /datapacks/sales_analytics/agents/sales_agent
59
+ datapack_delete(scope="admin", name="sales_analytics") # MCP-exposed, destructive
52
60
  ```
53
61
 
54
62
  ## Common mistake: mixing default and datapack databases
@@ -10,7 +10,7 @@ There are no MCP tools to:
10
10
  - Clear stuck work queue entries
11
11
  - Reset a failed pipeline
12
12
 
13
- The `datapack_delete_knowledge_base` tool only removes the KB source **registration** from the Meko API. It does NOT touch the actual `dist_rag` index, source records, or vector data in the database.
13
+ KB-source deletion happens via the Meko control plane (REST: `DELETE /datapacks/:name/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
14
 
15
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
16
 
@@ -18,7 +18,7 @@ The `datapack_delete_knowledge_base` tool only removes the KB source **registrat
18
18
 
19
19
  The RAG tools (`knowledgebase_trigger_index_creation`, `knowledgebase_add_source_to_index`, `knowledgebase_check_index_status`) handle index **creation and monitoring** only.
20
20
 
21
- To actually **query** a built index, use `db_run_read_only_query` with `dist_rag` SQL functions directly. The specific query syntax depends on the `dist_rag` extension API.
21
+ To actually **query** a built index on Cloud, use `knowledgebase_search` — it returns both uploaded documents (UI "Add Knowledge" flow) and memories the user promoted from the Learnings tab. The `db_run_read_only_query` direct-DB path is Free-Tier-gated on Cloud.
22
22
 
23
23
  ## Memory tools unreliable for structured/tabular data
24
24
 
@@ -32,13 +32,19 @@ It works **poorly** for:
32
32
  - Data dictionaries — only partial information extracted
33
33
  - Structured schemas — relationships between fields lost
34
34
 
35
- **Use instead:** `db_run_write_query` to CREATE TABLE and INSERT the data as proper database rows. Then query it with `db_run_read_only_query`.
35
+ **On Cloud, structured data is not MCP-supported today.** `db_run_write_query` / `db_run_read_only_query` / `db_summarize_database` all return `{"error": "not_available", "detail": "Free Tier: DB Tools access is not enabled. coming soon."}`. The options are:
36
36
 
37
- If you must store a schema overview in memory, write a single narrative summary:
38
- ```
39
- memory_add(scope="write", agent_id="claude_code",
40
- 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)")
41
- ```
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 a Cloud feature today 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.
42
48
 
43
49
  ## MCP user permission gaps
44
50
 
@@ -52,7 +58,9 @@ If `db_run_read_only_query` returns "permission denied", this is a server-side c
52
58
 
53
59
  **`db_run_write_query`** — May fail with `'dict' object has no attribute 'guardrail_config'` in some deployments. When this happens, all write operations are blocked for the session.
54
60
 
55
- **`knowledgebase_add_source_to_index`** — SQL parameter mismatch: tool passes `r_index_name` (string) but the DB function expects `r_index_id` (UUID). Workaround: use `knowledgebase_trigger_index_creation` with all sources at once.
61
+ **Knowledge-base ingestion tools on cloud Meko** (`knowledgebase_trigger_index_creation`, `knowledgebase_add_source_to_index`, `knowledgebase_check_index_status`) return `{"error": "not_available"}` on Free Tier. Even when ungated, the async worker only reads `s3://` URIs and uses its own boto3 credential chain — it cannot read buckets the user provides credentials for. Tracked: [yugabyte/meko-mcp-server#89](https://github.com/yugabyte/meko-mcp-server/issues/89) / MEKO-96. Use the Meko UI's **Add Knowledge** file-upload dialog for ingestion on cloud. `knowledgebase_search` works on cloud today.
62
+
63
+ (Historical note: `knowledgebase_add_source_to_index` used to have a `r_index_name` vs `r_index_id` SQL-signature bug. That specific bug was fixed on main in commit `3ae724a` — the tool now resolves `index_name → index_id` internally.)
56
64
 
57
65
  ## No conversation search
58
66
 
@@ -65,14 +65,57 @@ All three fields — `input`, `output`, and `reasoning` — must contain the **e
65
65
 
66
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
67
 
68
- ## Memory Limitations for Structured Data
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 project memories | Memories you wrote under this `agent_id`, filtered by `(datapack_id, user_id, agent_id)` | `memory_search(agent_id="<your agent_id>", 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 multiple specific agent_ids (e.g. also see what was written from `claude_code:other-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="<your-agent-id>", 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 project 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 specific buckets (e.g. also see what was written from `claude_code:other-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
69
111
 
70
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.
71
113
 
72
- For tabular data, prefer:
73
- 1. **Create a table** via `db_run_write_query` and insert the data as rows — preserves all structure
74
- 2. **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
75
- 3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context
114
+ On Cloud Meko today the `db_run_write_query` path isn't available (returns `{"error": "not_available"}`), so there's no MCP-side "just put it in a database table" option. 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.
76
119
 
77
120
  ## Proactive Memory Storage
78
121
 
@@ -126,3 +169,49 @@ Automatic capture handles the raw exchange. You should still manually use `conve
126
169
  ### Watermark coordination
127
170
 
128
171
  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.
172
+
173
+ ## Observability: conversation_id IS the Langfuse trace ID
174
+
175
+ This is the feature agents tend to miss. Verified live 2026-05-07 in the Meko UI's Observe hub.
176
+
177
+ - `conversation_create` returns a `conversation_id` (e.g. `d71fc8b61a7f45d585eea9a6436e0c3f`).
178
+ - That ID is also the **Langfuse trace_id** for the conversation. Not a separate trace — literally the same identifier.
179
+ - 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.
180
+ - Child spans reveal internals. Observed structure:
181
+ - `memory_add`: `Memory Add (Meko MCP)` → `Create a new memory in Mem0` → `Bulk Payload Update (yugabytedb / vector)` → `Execute Query (yugabytedb / vector)`
182
+ - `memory_search`: `Memory Search (Meko MCP)` → `Search for memories based on a query in Mem0` (Retriever)
183
+ - `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)
184
+ - `knowledgebase_search`: `Knowledgebase Search (Meko MCP)` → multiple `Execute Query (yugabytedb)` child spans
185
+ - Trace tags include `agent:<agent_id>` and the Meko org UUID. Both are searchable/filterable in Langfuse.
186
+ - 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).
187
+
188
+ ### Finding a trace in the UI
189
+
190
+ Two navigation paths, both verified in the Meko UI:
191
+
192
+ 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.
193
+ 2. **Observe hub** — browse all traces across a datapack. URL shape: `/observe-hub?project=<langfuse_project_id>&session=<conversation_id>`.
194
+
195
+ 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.
196
+
197
+ ### Observed latencies on prod (2026-05-07)
198
+
199
+ From real traces, not the docstring happy path:
200
+
201
+ | Tool | Latency per call |
202
+ |---|---|
203
+ | `memory_add` | 12-21 seconds (calls OpenAI for extraction, then writes to vector + graph) |
204
+ | `memory_search` | 1.8-5.9 seconds |
205
+ | `knowledgebase_search` | 0.6 seconds (empty index; will grow with index size) |
206
+ | `conversation_add_message` | 0.11 seconds (fire-and-forget; queued to Langfuse) |
207
+
208
+ `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.
209
+
210
+ ### Proactive diagnostic pattern
211
+
212
+ 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:
213
+
214
+ - 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).
215
+ - No span at all → the call never reached the server. Likely a transport / auth / `conversation_id` mismatch issue.
216
+
217
+ 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.