@yugabytedb/meko-mcp 2.3.0 → 2.5.1
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 +88 -35
- package/assets/hooks-handlers/lib/capture-cleanup-cli.js +735 -74
- package/assets/hooks-handlers/lib/capture-notices.js +94 -1
- package/assets/hooks-handlers/lib/capture-state.js +111 -0
- package/assets/hooks-handlers/lib/capture.js +130 -4
- package/assets/hooks-handlers/lib/checkpoint-timer.js +394 -8
- package/assets/hooks-handlers/lib/opencode-handler.js +29 -6
- package/assets/scripts/meko-statusline.sh +17 -1
- package/assets/skills/meko-mcp-tools/SKILL.md +6 -5
- package/assets/skills/meko-mcp-tools/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +194 -10
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -3
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +11 -6
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +4 -4
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +19 -14
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +69 -8
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +3 -1
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +8 -7
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +194 -10
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +10 -5
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +19 -14
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +68 -8
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -1
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +91 -12
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +39 -7
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +8 -6
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +13 -1
- package/bin/create-meko-setup.mjs +152 -35
- package/lib/autofix.mjs +100 -0
- package/lib/browser-login.mjs +495 -0
- package/lib/clients/codex.mjs +1 -24
- package/lib/clients/common.mjs +25 -0
- package/lib/clients/opencode.mjs +6 -1
- package/lib/migrate/datapack.mjs +254 -16
- package/lib/migrate/mcp-client.mjs +34 -0
- package/lib/migrate/orchestrator.mjs +1 -1
- package/lib/migrate.mjs +2 -6
- package/lib/validate.mjs +111 -22
- package/package.json +5 -5
|
@@ -68,7 +68,7 @@ memory_add(agent_id="<your-agent-id>",
|
|
|
68
68
|
|
|
69
69
|
**What NOT to store via memory_add:**
|
|
70
70
|
- Full conversations (use `conversation_create` + `conversation_add_message`)
|
|
71
|
-
- Large documents (use the UI's Datapack → Actions → Add Knowledge upload flow)
|
|
71
|
+
- Large documents (use `knowledgebase_upload_document`, or the UI's Datapack → Actions → Add Knowledge upload flow)
|
|
72
72
|
- Multi-topic dumps (transcripts, mixed logs + decisions) — store **one coherent fact per memory**, with the identifiers a later search will use
|
|
73
73
|
|
|
74
74
|
**Common errors:**
|
|
@@ -180,7 +180,7 @@ Get exact UUIDs from the `id` field of `memory_search` / `memory_get_all` result
|
|
|
180
180
|
```
|
|
181
181
|
conversation_create(agent_id="agent",
|
|
182
182
|
title="Debugging the auth middleware",
|
|
183
|
-
datapack_id="<uuid from
|
|
183
|
+
datapack_id="<uuid from datapack_search>")
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
`datapack_id` is required whenever no server-side default resolves for the caller. Omitting it in that state returns `{"error": "datapack_id_required"}` and persists nothing; the same contract applies to `conversation_add_message`, `conversation_get`, `conversation_update`, and `conversation_delete`.
|
|
@@ -225,8 +225,8 @@ conversation_get(conversation_id="conv-uuid-123", agent_id="agent",
|
|
|
225
225
|
### conversation_list
|
|
226
226
|
|
|
227
227
|
Target the datapack by `datapack_id` (UUID). It's optional — omit it to use the
|
|
228
|
-
pinned/default datapack, or pass the pinned `datapack_id`. Use
|
|
229
|
-
to look up the id.
|
|
228
|
+
pinned/default datapack, or pass the pinned `datapack_id`. Use
|
|
229
|
+
`datapack_search(query="<part of the name>")` to look up the id.
|
|
230
230
|
|
|
231
231
|
```
|
|
232
232
|
conversation_list(datapack_id="<datapack-uuid>", agent_id="agent", limit=20)
|
|
@@ -255,7 +255,7 @@ conversation_delete(conversation_id="conv-uuid-123", agent_id="agent")
|
|
|
255
255
|
|
|
256
256
|
## Knowledge Base Tools
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
Agents upload files via `knowledgebase_upload_document` and poll `knowledgebase_document_status` for indexing progress; a human uploading through the Cloud UI still uses the datapack's Actions → **Add Knowledge** dialog (PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) — both paths feed the same index. `knowledgebase_search` queries whatever the KB currently holds. MCP also exposes `knowledgebase_delete_document` for removing a single uploaded file.
|
|
259
259
|
|
|
260
260
|
See `tools-rag-workflow.md` for the decision table.
|
|
261
261
|
|
|
@@ -294,11 +294,178 @@ knowledgebase_delete_document(document_id="<uuid from a search hit>",
|
|
|
294
294
|
|
|
295
295
|
Returns `{"document_id", "chunks_deleted", "s3_deleted"}` — if `s3_deleted` is `false`, say so: the index entries are gone but the stored file may remain. Errors include a numeric `status`: `403` means the user is not the datapack owner, a maintainer, or the file's uploader — report it, don't retry; `409` (`DOCUMENT_PROCESSING`) means the file is still being indexed — wait for indexing to finish, then retry.
|
|
296
296
|
|
|
297
|
+
### knowledgebase_upload_document
|
|
298
|
+
|
|
299
|
+
**When to use:** Get a file's bytes into the datapack's KB for later `knowledgebase_search` retrieval — a file already on disk, or one generated mid-conversation. Use it when the content should be searchable by meaning; to keep a file exactly as-is and fetch it back whole, use `artifact_put`. Before calling it, check that you can reach S3 first: run `curl -sS -o /dev/null -m 10 -w '%{http_code}' https://s3.amazonaws.com`; in Windows PowerShell, run `curl.exe` with `NUL` in place of `/dev/null`. A 2xx or 3xx status means yes (S3's root normally answers 307). `000`, a connection, DNS or proxy error, or any other status, such as a proxy's 403 or 407, means no. A pass shows outbound HTTPS to S3 works, not that the presigned bucket host does, so if the POST still fails, report it and stop; a sandboxed session may have the file but no outbound network. If the check fails, don't call it — point the user at the UI. This tool never touches the file's bytes itself; it only requests a presigned S3 URL. Meko registers the file once it lands, so there's no separate confirm call. **The caller POSTs the file to the returned `url` directly** — multipart/form-data, every key in `fields` as a form field (in order), then the file's bytes last as a field named `"file"`.
|
|
300
|
+
|
|
301
|
+
**Confirm first.** The file goes into the datapack's shared knowledge base, which every member can read. Before calling the tool, tell the user which file and datapack, say the team will see it, and wait for a yes.
|
|
302
|
+
|
|
303
|
+
**You need a shell that can make the POST** (Python, curl, or PowerShell, below). Without one, as in Claude Desktop by default, don't call the tool: point the user at Datapack → Actions → **Add Knowledge**. An issued URL holds its `size` against the storage quota for up to 15 minutes even if nothing is uploaded.
|
|
304
|
+
|
|
305
|
+
**After the user confirms and the tool returns, POST the file in the same turn.** The upload is only half-done once you have `url`/`fields`; nothing else completes it for you.
|
|
306
|
+
|
|
307
|
+
**First, compute `content_hash` and `content_head_base64` — both required — *before* calling the tool at all. `content_head_base64` is compulsory: the tool refuses with `content_head_base64_required` if it's missing or blank, so there's no path that skips the sniff.**
|
|
308
|
+
|
|
309
|
+
Linux:
|
|
310
|
+
```bash
|
|
311
|
+
CONTENT_HASH=$(sha256sum report.pdf | cut -d' ' -f1)
|
|
312
|
+
CONTENT_HEAD_B64=$(head -c 3072 report.pdf | base64 -w0)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
macOS (no `sha256sum` by default — use `shasum`; BSD `base64` has no `-w0`, so strip newlines with `tr` instead):
|
|
316
|
+
```bash
|
|
317
|
+
CONTENT_HASH=$(shasum -a 256 report.pdf | cut -d' ' -f1)
|
|
318
|
+
CONTENT_HEAD_B64=$(head -c 3072 report.pdf | base64 | tr -d '\n')
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Windows PowerShell:
|
|
322
|
+
```powershell
|
|
323
|
+
$ContentHash = (Get-FileHash -Algorithm SHA256 -Path "report.pdf").Hash.ToLower()
|
|
324
|
+
$bytes = [System.IO.File]::ReadAllBytes("report.pdf")
|
|
325
|
+
$head = $bytes[0..([Math]::Min(3071, $bytes.Length - 1))]
|
|
326
|
+
$ContentHeadB64 = [Convert]::ToBase64String($head)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Windows cmd.exe (`certutil` ships built in for the hash — prints it on its own line, strip the header/footer lines before use; cmd.exe has **no** built-in way to take just the first 3072 bytes *and* base64-encode them in one step, so use the PowerShell or Python snippet for `content_head_base64` even in a cmd.exe-driven workflow):
|
|
330
|
+
```bat
|
|
331
|
+
certutil -hashfile report.pdf SHA256
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Python (cross-platform; streams the file so a large one isn't fully loaded into memory, and reuses the same read to build `content_head_base64` too):
|
|
335
|
+
```python
|
|
336
|
+
import hashlib, base64
|
|
337
|
+
|
|
338
|
+
h = hashlib.sha256()
|
|
339
|
+
with open(LOCAL_PATH, "rb") as f:
|
|
340
|
+
head = f.read(3072) # also the content_head_base64 sample
|
|
341
|
+
h.update(head)
|
|
342
|
+
for chunk in iter(lambda: f.read(1 << 20), b""):
|
|
343
|
+
h.update(chunk)
|
|
344
|
+
|
|
345
|
+
content_hash = h.hexdigest()
|
|
346
|
+
content_head_base64 = base64.b64encode(head).decode()
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Then, after the tool call returns `{url, fields}` — a portable snippet (identical on Linux/macOS/Windows, needs `python3` + `requests`), because it loops over whatever `fields` came back instead of hand-enumerating field names, so it can't drift out of sync with what the response actually contains:**
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
import json, requests
|
|
353
|
+
resp = json.loads(RESPONSE_JSON) # the tool's raw JSON string
|
|
354
|
+
if not resp.get("already_uploaded"):
|
|
355
|
+
with open(LOCAL_PATH, "rb") as f:
|
|
356
|
+
r = requests.post(resp["url"], data=resp["fields"], files={"file": (FILENAME, f)})
|
|
357
|
+
r.raise_for_status()
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Linux/macOS, curl (needs `jq`; builds the `-F` flags dynamically from whatever `fields` actually contains — a signer using temporary credentials adds `x-amz-security-token`, and extra policy conditions add their own fields, so a hardcoded field list drops them and S3 answers 403 on a form missing a signed field):**
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
if [ "$(echo "$RESPONSE_JSON" | jq -r '.already_uploaded')" != "true" ]; then
|
|
364
|
+
URL=$(echo "$RESPONSE_JSON" | jq -r '.url')
|
|
365
|
+
FIELDS=()
|
|
366
|
+
while IFS= read -r -d '' key && IFS= read -r -d '' value; do
|
|
367
|
+
FIELDS+=(-F "${key}=${value}")
|
|
368
|
+
done < <(echo "$RESPONSE_JSON" | jq -j '.fields | to_entries[] | (.key, "\u0000", .value, "\u0000")')
|
|
369
|
+
curl -sS --fail "${FIELDS[@]}" -F file=@/local/path/report.pdf "$URL"
|
|
370
|
+
fi
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Windows PowerShell 7+ (`Invoke-RestMethod -Form` takes the whole `fields` object as a hashtable — no per-field enumeration needed at all; use `[ordered]@{}`, not a plain `@{}`, since S3 requires `file` to be the *last* form field and a plain hashtable has no guaranteed enumeration order):**
|
|
374
|
+
|
|
375
|
+
```powershell
|
|
376
|
+
$resp = $json | ConvertFrom-Json
|
|
377
|
+
if (-not $resp.already_uploaded) {
|
|
378
|
+
$form = [ordered]@{}
|
|
379
|
+
$resp.fields.PSObject.Properties | ForEach-Object { $form[$_.Name] = $_.Value }
|
|
380
|
+
$form["file"] = Get-Item "C:\path\to\report.pdf"
|
|
381
|
+
Invoke-RestMethod -Uri $resp.url -Method Post -Form $form
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Windows cmd.exe:** cmd.exe has no built-in JSON parsing, so there's no safe way to build the `-F` flags dynamically from whatever `fields` contains without an extra tool. Rather than hardcode a field list that silently drops fields (e.g. `x-amz-security-token` on temporary credentials, or extra policy conditions) and fail with a confusing S3 403, use the PowerShell or Python snippet above even from a cmd.exe-driven workflow.
|
|
386
|
+
|
|
387
|
+
`size` must be the file's exact length in bytes, and the URL only accepts a body of exactly that size and SHA-256, for 5 minutes. Accepted extensions: pdf, txt, text, md, json, csv, xml, html, htm. `content_head_base64` — the file's first 3072 bytes, or the whole file if shorter, base64-encoded — is **required**: the tool sniffs it against the extension before requesting the URL and rejects an obvious mismatch (e.g. a renamed file) at once as `VALIDATION_ERROR`; a missing or blank one is `content_head_base64_required`. Text files must be UTF-8, because indexing reads UTF-8 only: a Latin-1 or Excel "CSV (Windows)" file is refused with a message to save it as UTF-8 (Excel: "CSV UTF-8"). Samples up to 4096 bytes are accepted and trimmed, so older snippets that send 4096 still work. A mismatch the server catches later surfaces as `state: "abandoned"` from `knowledgebase_document_status`. Idempotent — uploading the same content twice (by SHA-256) returns `already_uploaded: true` with an empty `url` and no `fields`; if that file's indexing never started or failed, the repeat queues it again.
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
knowledgebase_upload_document(
|
|
391
|
+
filename="report.pdf",
|
|
392
|
+
size=42000,
|
|
393
|
+
content_hash="<sha256 hex of the file's bytes>",
|
|
394
|
+
conversation_id="<uuid from conversation_create>",
|
|
395
|
+
content_head_base64="<base64 of the file's first 3072 bytes>",
|
|
396
|
+
agent_id="agent",
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Response (fresh upload):**
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"datapack_id": "...",
|
|
404
|
+
"url": "https://<bucket>.s3.amazonaws.com/",
|
|
405
|
+
"fields": {"key": "...", "policy": "...", "...": "..."},
|
|
406
|
+
"key": "user/datapack/hash/report.pdf",
|
|
407
|
+
"already_uploaded": false
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Response (identical content already uploaded):**
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"datapack_id": "...",
|
|
415
|
+
"url": "",
|
|
416
|
+
"key": "user/datapack/hash/report.pdf",
|
|
417
|
+
"already_uploaded": true,
|
|
418
|
+
"existing_filename": "report.pdf"
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
After a fresh upload, POST the file to `url` yourself (see above), then save `key` (as `document_key`) and poll `knowledgebase_document_status` until `state` is terminal. S3 answers a successful POST with `204`. `400 EntityTooSmall` or `EntityTooLarge` means `size` wasn't the file's exact byte count: call the tool again with the right size and upload through the new URL. The earlier URL can never succeed (it only accepts the wrong size) and expires on its own within 5 minutes.
|
|
423
|
+
|
|
424
|
+
**Common errors:**
|
|
425
|
+
- `conversation_id_required` — `conversation_id` was missing or blank.
|
|
426
|
+
- `datapack_id_required` — no `datapack_id` was given and no tenant default could be resolved.
|
|
427
|
+
- `content_head_base64_required` — `content_head_base64` was missing or blank. Checked after the `filename`/`size`/`content_hash` `VALIDATION_ERROR` checks, but always before a URL is requested — there is no way to skip it.
|
|
428
|
+
- `VALIDATION_ERROR` — missing filename, unsupported extension, missing/malformed `content_hash`, size ≤ 0, invalid or oversized `content_head_base64`, a sample shorter than `min(size, 3072)` bytes or longer than `size` (so `size` is wrong), or the sampled content doesn't match its extension.
|
|
429
|
+
- `FREE_TIER_KB_STORAGE_LIMIT` / `STANDARD_TIER_KB_STORAGE_LIMIT` (`status` 402) — no room left in the storage quota. Tell the user to free space or upgrade instead of retrying: every issued URL holds its `size` against the quota until the file is registered, or for up to 15 minutes if it is never uploaded.
|
|
430
|
+
|
|
431
|
+
Every error from the server also carries `status`, its HTTP status code.
|
|
432
|
+
- `knowledgebase_upload_document_failed` — unexpected error (see `detail`).
|
|
433
|
+
- The actual S3 POST isn't made through this tool, so its own failures (e.g. the body exceeding the cap the URL was signed under) surface to whatever made that call directly, not from this tool.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
### knowledgebase_document_status
|
|
438
|
+
|
|
439
|
+
**When to use:** Track a file uploaded via `knowledgebase_upload_document` from "waiting for bytes" through to indexed.
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
knowledgebase_document_status(
|
|
443
|
+
document_key="user/datapack/hash/report.pdf",
|
|
444
|
+
conversation_id="<uuid from conversation_create>",
|
|
445
|
+
agent_id="agent"
|
|
446
|
+
)
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Response (still indexing):**
|
|
450
|
+
```json
|
|
451
|
+
{
|
|
452
|
+
"document_key": "user/datapack/hash/report.pdf",
|
|
453
|
+
"filename": "report.pdf",
|
|
454
|
+
"state": "indexing",
|
|
455
|
+
"message": "The file is registered and being indexed.",
|
|
456
|
+
"document": {"status": "PROCESSING", "chunks_processed": 3}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Poll until `state` is `completed` or `failed` (or the pre-registration terminals `abandoned`/`oversized`). `NOT_FOUND` means `document_key` is unknown to this datapack — check it was copied verbatim from the upload response. `datapack_id_required` means no `datapack_id` was given and no tenant default could be resolved.
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
297
464
|
## Artifact Tools
|
|
298
465
|
|
|
299
466
|
### artifact_put
|
|
300
467
|
|
|
301
|
-
**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`.
|
|
468
|
+
**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. To make its content searchable by meaning instead, use `knowledgebase_upload_document`. 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`.
|
|
302
469
|
|
|
303
470
|
```
|
|
304
471
|
artifact_put(
|
|
@@ -378,14 +545,31 @@ For large files use the `local_path` value to read the file with normal file too
|
|
|
378
545
|
|
|
379
546
|
## Datapack Management Tools
|
|
380
547
|
|
|
381
|
-
### datapack_create / datapack_list / datapack_describe
|
|
548
|
+
### datapack_create / datapack_search / datapack_list / datapack_describe
|
|
382
549
|
|
|
383
550
|
```
|
|
384
551
|
datapack_create(name="analytics_prod", conversation_id="<conversation id>")
|
|
385
|
-
|
|
552
|
+
datapack_search(conversation_id="<session conversation id>", query="analytics") # find an id by part of the name
|
|
553
|
+
datapack_search(conversation_id="<session conversation id>", name="analytics_prod") # exact name
|
|
554
|
+
datapack_list(conversation_id="<session conversation id>") # small accounts: every datapack in one array
|
|
386
555
|
datapack_describe(datapack_id="<uuid>", include_status=True, conversation_id="<conversation id>")
|
|
387
556
|
```
|
|
388
557
|
|
|
558
|
+
Find a datapack id with `datapack_search(query=...)`. It returns one page:
|
|
559
|
+
`{"datapacks": [...], "has_more": true, "next_cursor": "<token>", "total": null}`.
|
|
560
|
+
To get the next page, call it again with the same filters and
|
|
561
|
+
`cursor="<next_cursor>"`. `next_cursor` is `""` on the last page, and also
|
|
562
|
+
when an older server has more matches than this page but cannot continue.
|
|
563
|
+
Do not send an empty cursor; ask for a narrower `query` instead. Treat the
|
|
564
|
+
cursor as opaque. Pass `include_total=True` only when you must show "N of M".
|
|
565
|
+
|
|
566
|
+
`datapack_list` still returns one array and is fine for an account with a
|
|
567
|
+
handful of datapacks. For an account that can see more than 1000 datapacks
|
|
568
|
+
(the server default limit) it returns `{"error": "too_many_datapacks", ...}`
|
|
569
|
+
instead; switch to `datapack_search`. If the server has no `datapack_search`
|
|
570
|
+
tool (an older server), use `datapack_list`.
|
|
571
|
+
|
|
572
|
+
|
|
389
573
|
`datapack_describe` returns these counts:
|
|
390
574
|
|
|
391
575
|
| Field | Meaning |
|
|
@@ -397,7 +581,7 @@ datapack_describe(datapack_id="<uuid>", include_status=True, conversation_id="<c
|
|
|
397
581
|
| `knowledge_chunk_count` | KB chunks across all documents (for debugging retrieval) |
|
|
398
582
|
| `shared_knowledge_count` | `collective_memory_count + knowledge_base_file_count`; `null` when the file count is `null` |
|
|
399
583
|
|
|
400
|
-
`knowledge_count` is a deprecated alias of `knowledge_chunk_count`. `datapack_list`
|
|
584
|
+
`knowledge_count` is a deprecated alias of `knowledge_chunk_count`. Neither `datapack_search` nor `datapack_list` computes counts; call `datapack_describe` for them.
|
|
401
585
|
|
|
402
586
|
### datapack_update / datapack_delete
|
|
403
587
|
|
|
@@ -420,4 +604,4 @@ Agent and KB lifecycle does not ship as MCP tools. If the user asks to create/li
|
|
|
420
604
|
- REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (agents), `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases` (KB sources).
|
|
421
605
|
- Or the Meko Cloud UI at `cloud.mekodata.ai` → Datapacks → agents / knowledge-bases.
|
|
422
606
|
|
|
423
|
-
KB
|
|
607
|
+
Uploading a *file* into an existing KB is not part of that lifecycle restriction — use `knowledgebase_upload_document` (see above) rather than the UI for anything driven from MCP, when you can POST the file's bytes yourself. Agents querying a populated index use `knowledgebase_search`, and can remove a single uploaded file with `knowledgebase_delete_document` — see `tools-rag-workflow.md`.
|
|
@@ -14,7 +14,8 @@ Datapacks are isolated workspaces — each has its own memory store and knowledg
|
|
|
14
14
|
## How to obtain a datapack_id
|
|
15
15
|
|
|
16
16
|
- From `datapack_create` response (`"datapack_id"` field; `"datapack_name"` is also returned)
|
|
17
|
-
- From `
|
|
17
|
+
- From `datapack_search(query="<part of the name>")` or `datapack_search(name="<exact name>")`: each row in `"datapacks"` has `"datapack_id"` and `"datapack_name"`. Page with `cursor="<next_cursor>"` only when that value is non-empty. An empty `next_cursor` means stop and narrow with `query`.
|
|
18
|
+
- From `datapack_list` on a small account, or on an older server without `datapack_search` (each entry has `"datapack_id"` and `"datapack_name"`). An account that can see more than 1000 datapacks (the server default limit) gets `too_many_datapacks` from an unfiltered `datapack_list`; use `datapack_search`.
|
|
18
19
|
- From `datapack_describe` response (same field names)
|
|
19
20
|
|
|
20
21
|
## Datapack lifecycle
|
|
@@ -27,13 +28,15 @@ datapack_create(name="sales_analytics",
|
|
|
27
28
|
-- Returns: {"datapack_id": "dp-uuid-123", "datapack_name": "sales_analytics", ...}
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
Provisioning agents and knowledge-base sources
|
|
31
|
+
Provisioning agents and knowledge-base *sources* (registering/indexing a new source against a datapack) is **not** MCP-exposed. Use the Meko control plane:
|
|
31
32
|
|
|
32
33
|
- **UI**: `app.mekodata.ai` → Datapacks → select datapack → Agents / Knowledge Bases
|
|
33
|
-
- **REST**: `POST /datapacks/:datapack_id/agents`, `POST /datapacks/:datapack_id/knowledge-bases`
|
|
34
|
+
- **REST**: `POST /datapacks/:datapack_id/agents`, `POST /datapacks/:datapack_id/knowledge-bases`
|
|
34
35
|
|
|
35
36
|
If the user asks to set those up mid-session, point them at the control plane rather than inventing an MCP call that will fail.
|
|
36
37
|
|
|
38
|
+
Uploading a *file* into an existing KB is a different, already-MCP-exposed operation — use `knowledgebase_upload_document` (see `tools-cookbook.md`) rather than routing the user to the Add Knowledge UI, when you can POST the file's bytes yourself.
|
|
39
|
+
|
|
37
40
|
### Targeting a specific datapack on subsequent calls
|
|
38
41
|
|
|
39
42
|
```
|
|
@@ -12,7 +12,7 @@ These are current limitations of the Meko MCP tools. Know them upfront to avoid
|
|
|
12
12
|
| Standard | 5,000 | 5,000 | 30,000 |
|
|
13
13
|
| Pro / Enterprise | uncapped | uncapped | uncapped |
|
|
14
14
|
|
|
15
|
-
The Free tier also caps `context_search` and `conversation_add_message` at 1,000 calls each. Embedding turns into the conversation-search cache has its own cap
|
|
15
|
+
The Free tier also caps `context_search` and `conversation_add_message` at 1,000 calls each. Embedding turns into the conversation-search cache has its own cap: 2,000 turns on Free and 10,000 on Pro; Standard and Enterprise are uncapped. When that cap is reached, `conversation_add_message` still stores the turn and reports `conversation_search_skipped: "quota_exceeded"`; the turn just won't appear in `context_search`'s conversation bucket.
|
|
16
16
|
|
|
17
17
|
A quota error can arrive with HTTP 403. It is not an authentication failure; don't reconfigure credentials because of it.
|
|
18
18
|
|
|
@@ -36,6 +36,10 @@ One call returns roughly the **20 most recent rows**; the response's `total` rep
|
|
|
36
36
|
|
|
37
37
|
`memory_search` and `memory_get_all` return every agent's rows for the user. `memory_delete_all` deletes only rows in the `agent_id` you pass, and an omitted `agent_id` means the `meko_agent` bucket. A `memory_search(run_id=X)` preview can therefore list rows that `memory_delete_all(run_id=X)` leaves in place. To clear rows written by several agents, delete them by id with `memory_delete_by_id`, or call `memory_delete_all` once per `agent_id` shown in the preview.
|
|
38
38
|
|
|
39
|
+
## Viewers can read but not write
|
|
40
|
+
|
|
41
|
+
On a datapack shared with you as a viewer, every conversation and memory write returns `read_only_access` and writes nothing: `conversation_create`, `conversation_add_message`, `conversation_update`, `memory_add`, `memory_update`, `memory_promote`, `artifact_put`, and `track_token_usage`. You can still delete your own memories with `memory_delete_by_id` and `memory_delete_all`, and delete a conversation you started. Searches work as for any other role. `context_search` covers every member's conversations, but for a viewer its conversation results and `conversation_get` return `user_id: null`, so they don't say who wrote a turn. Automatic capture holds a viewer's session and reports `read_only_access` at the next session start.
|
|
42
|
+
|
|
39
43
|
## Promoted memories are read-only through MCP
|
|
40
44
|
|
|
41
45
|
`memory_update` and `memory_delete_by_id` return `memory_is_promoted` for a memory that has been promoted to shared knowledge. Edit or remove promoted content in the Cloud UI Learnings tab.
|
|
@@ -52,9 +56,11 @@ The one exception is a single uploaded **file**: `knowledgebase_delete_document`
|
|
|
52
56
|
|
|
53
57
|
**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.
|
|
54
58
|
|
|
55
|
-
##
|
|
59
|
+
## KB index/source management is UI-only
|
|
60
|
+
|
|
61
|
+
Manually creating a vector index, adding a source to an existing one, or polling raw build status is not exposed via MCP. Use the Cloud UI for those (Datapack → Actions → Add Knowledge).
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
**Adding a file** is a registered MCP tool: if you can send the file's bytes in an HTTPS POST to an external URL yourself (a sandboxed session may have the file but no outbound network), call `knowledgebase_upload_document` directly (accepted extensions PDF/TXT/MD/JSON/CSV/XML/HTML, up to 5 MB Free / 50 MB Standard / 60 MB Pro+ per file) to get a presigned URL, then POST the bytes to it yourself; Meko registers and indexes the file once it lands, so no separate index-management call is needed. Confirm with the user first, because every datapack member can read the knowledge base. The Cloud UI's **Add Knowledge** flow (10 files per batch) remains the human-facing path for the same upload.
|
|
58
64
|
|
|
59
65
|
To **query** a built index, use `knowledgebase_search` — it returns both uploaded documents and memories the user promoted from the Learnings tab.
|
|
60
66
|
|
|
@@ -70,7 +76,7 @@ It works **poorly** for:
|
|
|
70
76
|
- Data dictionaries — only partial information extracted
|
|
71
77
|
- Structured schemas — relationships between fields lost
|
|
72
78
|
|
|
73
|
-
**
|
|
79
|
+
**Don't store structured data as memories.** The options are:
|
|
74
80
|
|
|
75
81
|
1. **Write a single narrative summary** as a memory — one call, not row-by-row:
|
|
76
82
|
```
|
|
@@ -79,8 +85,7 @@ It works **poorly** for:
|
|
|
79
85
|
conversation_id="<session conversation_id>",
|
|
80
86
|
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)")
|
|
81
87
|
```
|
|
82
|
-
2. **Upload the
|
|
83
|
-
3. **Tell the user** that structured-data storage via MCP isn't supported and let them decide how to proceed.
|
|
88
|
+
2. **Upload the file itself to the knowledge base** with `knowledgebase_upload_document`, if you can POST its bytes yourself — `.csv`, `.json` and the other accepted types go in as they are — and query it with `knowledgebase_search`. (The Cloud UI's **Add Knowledge** flow does the same for a person.)
|
|
84
89
|
|
|
85
90
|
Never ingest CSV row-by-row into memory — each row becomes a fragmented fact with lost context.
|
|
86
91
|
|
|
@@ -27,11 +27,11 @@ Conversations are backed by Langfuse sessions and traces. They preserve full str
|
|
|
27
27
|
|
|
28
28
|
```
|
|
29
29
|
conversation_create(agent_id="support_bot", title="Pricing discussion",
|
|
30
|
-
datapack_id="<uuid from
|
|
30
|
+
datapack_id="<uuid from datapack_search>")
|
|
31
31
|
-- Returns: {"id": "conv-uuid-here"}
|
|
32
32
|
|
|
33
33
|
conversation_add_message(conversation_id="conv-uuid-here", agent_id="support_bot",
|
|
34
|
-
datapack_id="<uuid from
|
|
34
|
+
datapack_id="<uuid from datapack_search>",
|
|
35
35
|
input="What are your pricing tiers?",
|
|
36
36
|
output="We offer Starter ($10/mo), Pro ($50/mo), and Enterprise (custom).",
|
|
37
37
|
reasoning="Retrieved pricing page data. No special discounts apply.")
|
|
@@ -85,7 +85,7 @@ Agents on Cloud Meko have two distinct read surfaces. Pick the right one for the
|
|
|
85
85
|
- **Personal memories** — written by `memory_add`. The `agent_id` records the writer but does not restrict reads; memories are scoped **per-user**, so any of that user's agents can read them via MCP, and no other user can.
|
|
86
86
|
- **Team-shared Shared Knowledge** — arrives two ways:
|
|
87
87
|
1. An agent calls `memory_promote` for exact, user-confirmed memory UUIDs, or the user promotes them from the Cloud UI's Learnings tab. Promotion moves the memories into shared knowledge, strips `user_id`, preserves originating `agent_id` as provenance, and evicts the private mem0 records.
|
|
88
|
-
2.
|
|
88
|
+
2. A file is uploaded — by an agent with `knowledgebase_upload_document`, or by the user via Datapack → Actions → **Add Knowledge** in the Cloud UI. PDF/TXT/MD/JSON/CSV/XML/HTML up to 5MB (Free) / 50MB (Standard) / 60MB (Pro+) each.
|
|
89
89
|
|
|
90
90
|
Both show up in `knowledgebase_search`, tagged `metadata_filters.source: "memory"` vs other values so the agent can distinguish provenance in responses.
|
|
91
91
|
|
|
@@ -102,7 +102,7 @@ Call `context_search`. One call returns your personal memories (every agent, no
|
|
|
102
102
|
There is no MCP-side "just put it in a database table" option — raw SQL access isn't part of the MCP surface. Workarounds:
|
|
103
103
|
|
|
104
104
|
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.
|
|
105
|
-
2. **
|
|
105
|
+
2. **Upload the file** with `knowledgebase_upload_document` if you have it and can POST its bytes to an external URL yourself, or suggest the user upload it via the Cloud UI's Add Knowledge flow, if it's a document (PDF/TXT/MD/JSON/CSV/XML/HTML are supported).
|
|
106
106
|
3. **Never ingest CSV row-by-row** into memory — each row becomes a fragmented fact with lost context.
|
|
107
107
|
|
|
108
108
|
## Memory Storage: automatic, not proactive
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Complete Tool Catalog and Decision Tree
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**28 Meko data tools covered by this skill.** These are the tools available in production, grouped as: Retrieval (1), Memory (8), Conversation (6), Knowledge Base (4), Datapack (6), Artifacts (2), Observability (1). Combined Meko + AMP endpoints may expose additional infrastructure tools; those are outside this skill's scope.
|
|
4
4
|
|
|
5
5
|
## Quick health check before using tools
|
|
6
6
|
|
|
7
7
|
Before starting a session, verify that the Meko MCP tools are working:
|
|
8
8
|
|
|
9
9
|
1. `memory_search(query="test", agent_id="<your-session-agent-id>", conversation_id="<session-conversation-id>")` — Confirms memory subsystem is up. Use the `agent_id` and `conversation_id` from the SessionStart `additionalContext`. May fail with "connection already closed" — see `tools-troubleshooting.md`.
|
|
10
|
-
2. `
|
|
10
|
+
2. `datapack_search(conversation_id="<session-conversation-id>", limit=1)`: confirms Meko API connectivity and returns one datapack your token has access to. On a server without `datapack_search`, call `datapack_list(conversation_id="<session-conversation-id>")` instead.
|
|
11
11
|
|
|
12
12
|
## Decision tree: which tool do I need?
|
|
13
13
|
|
|
@@ -16,7 +16,8 @@ User wants to...
|
|
|
16
16
|
├── Ask "what do you know about X?" --------> context_search (read; memory + KB + past conversations in one call)
|
|
17
17
|
├── Search personal context? ---------------> memory_search (read)
|
|
18
18
|
├── Search shared datapack knowledge? ------> knowledgebase_search (read)
|
|
19
|
-
├── Add
|
|
19
|
+
├── Add a file to a knowledge base? --------> knowledgebase_upload_document (write)
|
|
20
|
+
│ └── Check its indexing progress? -------> knowledgebase_document_status (read)
|
|
20
21
|
├── Delete ONE knowledge-base file? --------> knowledgebase_delete_document (destructive — confirm with the user first)
|
|
21
22
|
├── Store or recall information?
|
|
22
23
|
│ ├── Store a fact/preference/entity? -----------> memory_add (write)
|
|
@@ -28,10 +29,11 @@ User wants to...
|
|
|
28
29
|
│ ├── Upload a generated file (report, CSV, PDF)? -> artifact_put (write)
|
|
29
30
|
│ └── Retrieve a previously uploaded file? -------> artifact_get (read)
|
|
30
31
|
└── Manage datapacks?
|
|
32
|
+
├── Find a datapack id by name? -------> datapack_search(query=...) (read)
|
|
31
33
|
└── CRUD datapack? --------------------> datapack_create/list/describe/update/delete
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
Agent lifecycle and KB **
|
|
36
|
+
Agent lifecycle and KB **index / source lifecycle** (creating indexes, adding sources, re-indexing) are managed outside the MCP surface — typically in the Meko control-plane UI. Single KB files are handled here: adding one (`knowledgebase_upload_document`, then `knowledgebase_document_status`) and deleting one (`knowledgebase_delete_document`).
|
|
35
37
|
|
|
36
38
|
## Retrieval Tools (1)
|
|
37
39
|
|
|
@@ -39,12 +41,14 @@ Agent lifecycle and KB **ingestion / index lifecycle** (adding sources, uploads,
|
|
|
39
41
|
|------|---------|
|
|
40
42
|
| `context_search(query, conversation_id, agent_id=None, datapack_id=None, limit=10, force_source="auto")` | Default first call for open-ended recall. Queries memory, the knowledge base, and the conversation-history cache in parallel and returns each source in its own bucket: `{"results": {"memory": [...], "knowledge_base": [...], "conversation": {"hits": [...], "thread": [...]}}, "token_savings": {...}}`. A bucket is `null` only when that source wasn't queried: `force_source` excluded it, or the server couldn't build a query vector for it. An empty bucket is ambiguous: either that source found nothing relevant, or it failed. `context_search` turns a failed source into an empty list and records the error only in the trace. Before you tell the user nothing is stored about X, confirm with `memory_search` or `knowledgebase_search`, which return errors. `force_source` is `"auto"` (all three), `"memory"`, `"knowledge_base"`, or `"conversation"`; any other value returns `invalid_force_source`. `limit` bounds the memory and KB buckets only; the conversation bucket returns up to 10 hits plus a thread of whole turns. The conversation bucket is datapack-wide. It returns embedded turns from every user and agent on the datapack, and each hit carries its author's `user_id`. Don't present a hit as this user's own history. |
|
|
41
43
|
|
|
42
|
-
## Knowledge Base Tools (
|
|
44
|
+
## Knowledge Base Tools (4)
|
|
43
45
|
|
|
44
46
|
| Tool | Purpose |
|
|
45
47
|
|------|---------|
|
|
46
48
|
| `knowledgebase_search(query, conversation_id, datapack_id, agent_id=None, limit=10)` | Hybrid (semantic + keyword) search across KB chunks and promoted memories. `datapack_id` is REQUIRED (no default). Each hit has `id`, `chunk_text`, `document_id`, `metadata_filters`, `distance`, and `match_type` (`semantic`, `keyword`, or `hybrid`). |
|
|
47
49
|
| `knowledgebase_delete_document(document_id, conversation_id, datapack_id="")` | Permanently delete ONE KB file (chunks + metadata; stored-file delete is best-effort — check `s3_deleted`). Irreversible: confirm with the user first. `document_id` comes from `knowledgebase_search` hits (no filename in hits — echo the id + chunk text). Owner/maintainer/uploader only (status 403 otherwise); status 409 while still indexing — wait and retry. |
|
|
50
|
+
| `knowledgebase_upload_document(filename, size, content_hash, conversation_id, content_head_base64, datapack_id=None, agent_id=None)` | Requests a presigned S3 URL for a file (does not upload bytes itself — the caller POSTs to the returned `url`/`fields`). Returns `{datapack_id, url, fields, key, already_uploaded}` (fresh upload) or `{datapack_id, url: "", key, already_uploaded: true, existing_filename}` (dedup). Accepted extensions: pdf/txt/text/md/json/csv/xml/html/htm; `content_head_base64` (base64 of the file's first 3072 bytes, or the whole file if shorter) is **required** and is always sniffed against the extension before requesting the URL — a missing/blank value is rejected as `content_head_base64_required`, this check cannot be skipped. Idempotent by content hash. |
|
|
51
|
+
| `knowledgebase_document_status(document_key, conversation_id, datapack_id=None, agent_id=None)` | Poll indexing progress for a file uploaded via `knowledgebase_upload_document`, using its returned `key` (passed here as `document_key`). `state` is one of `awaiting_upload`/`indexing` (non-terminal) or `completed`/`failed`/`abandoned`/`oversized` (terminal). |
|
|
48
52
|
|
|
49
53
|
## Memory Tools (8)
|
|
50
54
|
|
|
@@ -66,21 +70,22 @@ Agent lifecycle and KB **ingestion / index lifecycle** (adding sources, uploads,
|
|
|
66
70
|
| `conversation_create(agent_id=None, run_id=None, title=None, metadata=None, session_id="", datapack_id=None)` | Create conversation container (Langfuse session) |
|
|
67
71
|
| `conversation_add_message(conversation_id, input, output, agent_id=None, reasoning=None, metadata=None, seed=None, datapack_id=None, plan=None)` | Add a message turn (Langfuse trace). `output` is required. The response may include `extracted_memories` and, when the turn wasn't embedded for conversation search, `conversation_search_skipped` (`quota_exceeded` or `datapack_opted_out`). |
|
|
68
72
|
| `conversation_get(conversation_id, agent_id=None, include_messages=False, limit=100, offset=0, datapack_id=None)` | Retrieve conversation, optionally with messages |
|
|
69
|
-
| `conversation_list(agent_id=None, limit=20, offset=0, conversation_id="", datapack_id=None)` | List the user's conversations within a datapack (`agent_id` does not filter — trace attribution only). `datapack_id` (UUID) is optional — defaults to the pinned/tenant datapack; use `
|
|
73
|
+
| `conversation_list(agent_id=None, limit=20, offset=0, conversation_id="", datapack_id=None)` | List the user's conversations within a datapack (`agent_id` does not filter — trace attribution only). `datapack_id` (UUID) is optional — defaults to the pinned/tenant datapack; use `datapack_search(query=...)` to look it up. `conversation_id` optional (omit for browse). |
|
|
70
74
|
| `conversation_update(conversation_id, agent_id=None, title=None, metadata=None, datapack_id=None)` | Update title or metadata |
|
|
71
75
|
| `conversation_delete(conversation_id, agent_id=None, datapack_id=None)` | Delete entire conversation (destructive) |
|
|
72
76
|
|
|
73
|
-
## Datapack Management Tools (
|
|
77
|
+
## Datapack Management Tools (6)
|
|
74
78
|
|
|
75
79
|
| Tool | Purpose |
|
|
76
80
|
|------|---------|
|
|
77
81
|
| `datapack_create(name, conversation_id)` | Create new datapack |
|
|
78
|
-
| `
|
|
82
|
+
| `datapack_search(conversation_id, query="", name="", limit=20, cursor="", grant="", sort="created", include_total=False, datapack_id=None)` | Find datapacks and page through them. Returns `{datapacks, has_more, next_cursor, total}`. Use `query` for part of a name, `name` for an exact name, and `cursor` (the previous page's `next_cursor`) for the next page. `limit` is 1-100. `grant` is `owner` or `shared`; `sort` is `created` (newest first) or `name`. Pass `include_total=True` only when you must show "N of M". Rows carry no connection fields and no counts. Servers older than this tool don't have it; use `datapack_list` there. |
|
|
83
|
+
| `datapack_list(conversation_id, datapack_id=None, query="", limit=0)` | Return datapacks as one array. Fine for a small account. `query` filters by part of a name; more than 100 matches return a `too_many_datapacks` error. `limit` returns the first matches (at most 100) without saying whether more exist. With neither, an account that can see more than 1000 datapacks (the server default limit) gets a `too_many_datapacks` error; use `datapack_search` then. `conversation_id` is required for trace nesting. |
|
|
79
84
|
| `datapack_describe(conversation_id, datapack_id="", include_status=False)` | Describe a datapack by UUID (default datapack if omitted). Returns `memory_count`, `collective_memory_count` (promoted), `learnings_count` (awaiting a promotion decision), `knowledge_base_file_count`, `knowledge_chunk_count`, and `shared_knowledge_count`. `knowledge_base_file_count` and `shared_knowledge_count` are `null` when the status endpoint is unreachable; `knowledge_count` is a deprecated alias of `knowledge_chunk_count`. |
|
|
80
85
|
| `datapack_update(datapack_id, conversation_id, name=None, description=None, conversation_search_opt_out=None)` | Rename a datapack, update its description, and/or opt out of (or back into) conversation-search caching. Pass at least one field. Opt-out is owner/maintainer only. |
|
|
81
86
|
| `datapack_delete(datapack_id, conversation_id)` | Delete datapack by UUID (irreversible) |
|
|
82
87
|
|
|
83
|
-
All
|
|
88
|
+
All six datapack tools reject an empty `conversation_id` with `conversation_id_required`.
|
|
84
89
|
|
|
85
90
|
## Artifact Tools (2)
|
|
86
91
|
|
|
@@ -103,14 +108,14 @@ Some things the Meko platform can do are not wired into the MCP tool surface tod
|
|
|
103
108
|
|
|
104
109
|
| Capability | Where it lives | How to reach it |
|
|
105
110
|
|---|---|---|
|
|
106
|
-
| Create / list / delete **agents** within a datapack |
|
|
107
|
-
| Add / list / delete **knowledge-base sources** on a datapack |
|
|
108
|
-
| Langfuse project-key generation |
|
|
111
|
+
| Create / list / delete **agents** within a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/agents` (`POST/GET/DELETE /agents/:agent` for targeted deletes), or the Meko control-plane UI |
|
|
112
|
+
| Add / list / delete **knowledge-base sources** on a datapack | Meko API server | REST: `POST/GET/DELETE /datapacks/:datapack_id/knowledge-bases`, plus `upload-url`, `upload-complete`, `create`, `status` subroutes. Also available in the Meko UI. |
|
|
113
|
+
| Langfuse project-key generation | Meko API server | REST: `POST /datapacks/:datapack_id/langfuse/project-keys` |
|
|
109
114
|
| Account / billing / tier management | Meko UI only | Not available via MCP or public REST |
|
|
110
115
|
|
|
111
|
-
The MCP-exposed `datapack_create` / `datapack_list` / `datapack_describe` / `datapack_update` / `datapack_delete` tools above are a deliberate subset — the common CRUD that an agent reasonably needs mid-conversation. Anything involving agent or KB lifecycle is control-plane territory.
|
|
116
|
+
The MCP-exposed `datapack_create` / `datapack_search` / `datapack_list` / `datapack_describe` / `datapack_update` / `datapack_delete` tools above are a deliberate subset — the common CRUD that an agent reasonably needs mid-conversation. Anything involving agent or KB lifecycle is control-plane territory.
|
|
112
117
|
|
|
113
|
-
For
|
|
118
|
+
For a file already on disk or generated mid-conversation, and when you can send the file's bytes in an HTTPS POST to an external URL yourself (a sandboxed session may have the file but no outbound network), requesting a URL with `knowledgebase_upload_document` and POSTing to it gets it into the KB without leaving MCP for a human's help. The UI upload path (Datapack → Actions → **Add Knowledge**, PDF/TXT/MD/JSON/CSV/XML/HTML, 5MB Free / 50MB Standard / 60MB Pro+ each, 10/batch) remains the way for a human to add files directly. `knowledgebase_search` queries the resulting index either way.
|
|
114
119
|
|
|
115
120
|
## Common Parameter Patterns
|
|
116
121
|
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# Knowledge Base / RAG workflow
|
|
2
2
|
|
|
3
|
-
MCP exposes
|
|
4
|
-
`
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
MCP exposes four KB tools: `knowledgebase_search` (retrieval),
|
|
4
|
+
`knowledgebase_upload_document` and `knowledgebase_document_status` (add a
|
|
5
|
+
file and track its indexing), and `knowledgebase_delete_document` (remove ONE
|
|
6
|
+
uploaded file). Creating, listing or renaming a knowledge base itself still
|
|
7
|
+
happens out of band — through the **Meko UI** (`cloud.mekodata.ai`).
|
|
7
8
|
|
|
8
9
|
## Decision table
|
|
9
10
|
|
|
10
11
|
| Situation | Use this | Why |
|
|
11
12
|
|---|---|---|
|
|
12
13
|
| Search an existing KB | `knowledgebase_search` | Retrieval over the indexed chunks |
|
|
13
|
-
| Add
|
|
14
|
+
| Add a file to a KB | `knowledgebase_upload_document` + one direct S3 POST | Requests a presigned URL, then you POST the file to it; no need to leave MCP |
|
|
15
|
+
| Track a file's indexing progress | `knowledgebase_document_status` | Poll with the `key` from the upload response, passed here as `document_key`, until `state` is terminal |
|
|
16
|
+
| Add documents to a KB from the Cloud UI instead | **Meko UI** — Datapack → Actions → **Add Knowledge** | File-upload dialog (PDF/TXT/MD/JSON/CSV/XML/HTML, 5 MB Free / 50 MB Standard / 60 MB Pro+ each, 10/batch). Same index either way — this is the human-facing path, not required when an agent can upload directly |
|
|
14
17
|
| Delete ONE uploaded file | `knowledgebase_delete_document` | Destructive; `document_id` from search hits; confirm with the user first |
|
|
15
18
|
| Anything else (list / rename / re-index / source lifecycle) | **UI** | No MCP tools for the rest of KB lifecycle |
|
|
16
19
|
|
|
@@ -58,6 +61,59 @@ Lower `distance` is closer. Promoted memories appear as hits whose `metadata_fil
|
|
|
58
61
|
Empty or nonexistent KB: `{"results": [], "count": 0}` (no error,
|
|
59
62
|
just an empty array).
|
|
60
63
|
|
|
64
|
+
## knowledgebase_upload_document — putting a file in
|
|
65
|
+
|
|
66
|
+
This tool never touches the file's bytes itself — it only requests a
|
|
67
|
+
presigned S3 URL. **You POST the file to that URL yourself**, as a
|
|
68
|
+
second step:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
knowledgebase_upload_document(
|
|
72
|
+
filename="report.pdf",
|
|
73
|
+
size=42000,
|
|
74
|
+
content_hash="<sha256 hex of the file's bytes>",
|
|
75
|
+
conversation_id="<uuid from conversation_create>",
|
|
76
|
+
agent_id="<your agent_id>",
|
|
77
|
+
content_head_base64="<base64 of the file's first ~4KB>")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Build the POST from every key in the response's `fields`, not a hand-picked list:
|
|
81
|
+
a missing signed field such as `x-amz-security-token` makes S3 answer 403. Use
|
|
82
|
+
the Python, curl, or PowerShell snippet under `knowledgebase_upload_document`
|
|
83
|
+
in `tools-cookbook.md`. Confirm with the user first: the file becomes visible to
|
|
84
|
+
every datapack member.
|
|
85
|
+
|
|
86
|
+
Required: `filename`, `size` (the exact byte count — the URL accepts no
|
|
87
|
+
other length), `content_hash`, `conversation_id`, `content_head_base64`. `content_hash` is the SHA-256 hex digest of the
|
|
88
|
+
file's bytes, computed by you (e.g. `sha256sum`) — it becomes part of
|
|
89
|
+
the S3 key, so it also drives the dedup check. A response with
|
|
90
|
+
`already_uploaded: true` means identical content already exists; skip
|
|
91
|
+
the S3 POST entirely, there is nothing left to upload. Otherwise POST
|
|
92
|
+
as above: every key in `fields` as a form field (in order), then the
|
|
93
|
+
bytes last as a field named `"file"`. Meko registers the object once
|
|
94
|
+
it lands, so no separate confirm call is needed after the POST. Accepted extensions:
|
|
95
|
+
pdf, txt, text, md, json, csv, xml, html, htm; `content_head_base64` is
|
|
96
|
+
always sniffed against the extension before requesting the URL,
|
|
97
|
+
rejecting an obvious mismatch immediately instead of waiting for the
|
|
98
|
+
watcher — a missing/blank value is rejected as
|
|
99
|
+
`content_head_base64_required`, this sniff cannot be skipped.
|
|
100
|
+
Ingestion is asynchronous — save the response's `key` (as
|
|
101
|
+
`document_key`) and poll `knowledgebase_document_status`.
|
|
102
|
+
|
|
103
|
+
## knowledgebase_document_status — tracking it
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
knowledgebase_document_status(
|
|
107
|
+
document_key="<the upload response's `key`>",
|
|
108
|
+
conversation_id="<uuid from conversation_create>",
|
|
109
|
+
agent_id="<your agent_id>")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`state` covers the whole lifecycle: `awaiting_upload` and `indexing`
|
|
113
|
+
are non-terminal (poll again); `completed`, `failed`, `abandoned`, and
|
|
114
|
+
`oversized` are terminal. `NOT_FOUND` means the `document_key` doesn't
|
|
115
|
+
belong to this datapack.
|
|
116
|
+
|
|
61
117
|
## UI ingestion — what the user sees
|
|
62
118
|
|
|
63
119
|
From `cloud.mekodata.ai`:
|
|
@@ -65,11 +121,16 @@ From `cloud.mekodata.ai`:
|
|
|
65
121
|
1. Open a datapack (`/datapacks/<name>`).
|
|
66
122
|
2. Click **Actions** → **Add Knowledge**.
|
|
67
123
|
3. Drag-and-drop or browse for files. Supported: PDF, TXT, MD, JSON,
|
|
68
|
-
|
|
124
|
+
CSV, XML, HTML. Per-file limit 5 MB (Free) / 50 MB (Standard) / 60 MB (Pro+). Up to 10 files per batch.
|
|
69
125
|
4. The UI handles upload, storage, and index build. The user does not
|
|
70
126
|
pick a bucket or provide credentials.
|
|
71
127
|
5. Search results from `knowledgebase_search` become available once
|
|
72
128
|
indexing completes.
|
|
73
129
|
|
|
74
|
-
If a
|
|
75
|
-
point them at this flow.
|
|
130
|
+
If a *human* asks you "how do I add a document to my knowledge base?",
|
|
131
|
+
point them at this flow. If *you* (the agent) have the file's bytes —
|
|
132
|
+
already on disk, or generated mid-conversation — and can send them in an
|
|
133
|
+
HTTPS POST to an external URL yourself, call
|
|
134
|
+
`knowledgebase_upload_document` directly instead of describing the UI
|
|
135
|
+
flow to yourself. A sandboxed session may have the file but no outbound
|
|
136
|
+
network; point the user at the UI then.
|