@yugabytedb/meko-mcp 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +505 -0
  2. package/assets/hooks-handlers/lib/capture.js +863 -0
  3. package/assets/hooks-handlers/lib/checkpoint-timer.js +72 -0
  4. package/assets/hooks-handlers/pre-compact.sh +3 -0
  5. package/assets/hooks-handlers/session-end.sh +27 -0
  6. package/assets/hooks-handlers/session-start.sh +24 -0
  7. package/assets/hooks-handlers/test_single_conversation.sh +169 -0
  8. package/assets/skills/meko-mcp-tools/SKILL.md +192 -0
  9. package/assets/skills/meko-mcp-tools/references/_sections.md +31 -0
  10. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +39 -0
  11. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +49 -0
  12. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +373 -0
  13. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +56 -0
  14. package/assets/skills/meko-mcp-tools/references/tools-db-query-patterns.md +38 -0
  15. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +61 -0
  16. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +128 -0
  17. package/assets/skills/meko-mcp-tools/references/tools-overview.md +97 -0
  18. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +63 -0
  19. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +79 -0
  20. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +143 -0
  21. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +93 -0
  22. package/assets/skills/meko-mcp-tools/references/tools-write-guardrails.md +30 -0
  23. package/bin/create-meko-setup.mjs +499 -0
  24. package/lib/claude-code.mjs +14 -0
  25. package/lib/clients/claude-code.mjs +265 -0
  26. package/lib/clients/claude-desktop.mjs +256 -0
  27. package/lib/clients/common.mjs +107 -0
  28. package/lib/clients/cursor.mjs +332 -0
  29. package/lib/clients/index.mjs +14 -0
  30. package/lib/config.mjs +369 -0
  31. package/lib/detect.mjs +125 -0
  32. package/lib/installer.mjs +255 -0
  33. package/lib/logger.mjs +97 -0
  34. package/lib/mcp-transport.mjs +204 -0
  35. package/lib/migrate/adapters/claude-code.mjs +165 -0
  36. package/lib/migrate/adapters/cursor.mjs +221 -0
  37. package/lib/migrate/adapters/memory-md.mjs +230 -0
  38. package/lib/migrate/claude-parser.mjs +306 -0
  39. package/lib/migrate/daemon.mjs +67 -0
  40. package/lib/migrate/id.mjs +83 -0
  41. package/lib/migrate/lockfile.mjs +121 -0
  42. package/lib/migrate/logger.mjs +79 -0
  43. package/lib/migrate/mcp-client.mjs +224 -0
  44. package/lib/migrate/orchestrator.mjs +443 -0
  45. package/lib/migrate/progress.mjs +76 -0
  46. package/lib/migrate/state.mjs +177 -0
  47. package/lib/migrate.mjs +328 -0
  48. package/lib/prompt.mjs +212 -0
  49. package/lib/validate.mjs +259 -0
  50. package/package.json +49 -0
  51. package/scripts/bundle-assets.mjs +49 -0
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * checkpoint-timer.js — Background daemon for periodic conversation capture.
4
+ *
5
+ * Spawned by session-start.sh at session start. Runs capture.js in checkpoint
6
+ * mode every MEKO_CHECKPOINT_INTERVAL seconds (default: 600 = 10 minutes).
7
+ *
8
+ * Writes PID to ~/.claude/meko-capture/<session-id>.timer.pid for cleanup
9
+ * by session-end.sh.
10
+ *
11
+ * Usage: node checkpoint-timer.js <transcript_path>
12
+ *
13
+ * Environment:
14
+ * MEKO_CHECKPOINT_INTERVAL Seconds between ticks (default: 600)
15
+ * MEKO_WATERMARK_DIR Watermark directory (default: ~/.claude/meko-capture)
16
+ * MEKO_MCP_URL Inherited by capture.js
17
+ * MEKO_API_KEY Inherited by capture.js
18
+ */
19
+
20
+ const { execFileSync } = require("child_process");
21
+ const fs = require("fs");
22
+ const path = require("path");
23
+
24
+ const INTERVAL_SECS = parseInt(process.env.MEKO_CHECKPOINT_INTERVAL || "600", 10);
25
+ const WATERMARK_DIR =
26
+ process.env.MEKO_WATERMARK_DIR ||
27
+ path.join(process.env.HOME || "~", ".claude", "meko-capture");
28
+
29
+ const transcriptPath = process.argv[2];
30
+ if (!transcriptPath) {
31
+ process.stderr.write("[meko-timer] Usage: checkpoint-timer.js <transcript_path>\n");
32
+ process.exit(1);
33
+ }
34
+
35
+ const sessionId = path.basename(transcriptPath, ".jsonl");
36
+ const pidFile = path.join(WATERMARK_DIR, `${sessionId}.timer.pid`);
37
+ const captureScript = path.join(__dirname, "capture.js");
38
+
39
+ // Write PID file
40
+ fs.mkdirSync(WATERMARK_DIR, { recursive: true });
41
+ fs.writeFileSync(pidFile, String(process.pid));
42
+
43
+ function cleanup() {
44
+ try { fs.unlinkSync(pidFile); } catch { /* already gone */ }
45
+ process.exit(0);
46
+ }
47
+
48
+ process.on("SIGTERM", cleanup);
49
+ process.on("SIGINT", cleanup);
50
+
51
+ function tick() {
52
+ // Skip if transcript doesn't exist (session ended but we weren't killed yet)
53
+ if (!fs.existsSync(transcriptPath)) {
54
+ cleanup();
55
+ return;
56
+ }
57
+
58
+ const hookInput = JSON.stringify({ transcript_path: transcriptPath });
59
+
60
+ try {
61
+ execFileSync("node", [captureScript, "checkpoint"], {
62
+ input: hookInput,
63
+ timeout: 30000,
64
+ stdio: ["pipe", "pipe", "pipe"],
65
+ });
66
+ } catch (err) {
67
+ // Best-effort: log and continue
68
+ process.stderr.write(`[meko-timer] Checkpoint tick failed: ${err.message}\n`);
69
+ }
70
+ }
71
+
72
+ setInterval(tick, INTERVAL_SECS * 1000);
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # PreCompact hook — delegates to Node.js capture script.
3
+ exec node "$(dirname "$0")/lib/capture.js" pre-compact
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # SessionEnd hook — kills the checkpoint timer, then delegates to capture.js
3
+ # for a final transcript capture.
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+
7
+ # Read stdin into variable (need it for both timer cleanup and capture.js)
8
+ HOOK_INPUT="$(cat)"
9
+
10
+ # Extract transcript_path and kill checkpoint timer
11
+ TRANSCRIPT_PATH="$(printf '%s' "$HOOK_INPUT" | node -e '
12
+ const d = JSON.parse(require("fs").readFileSync(0,"utf-8"));
13
+ const p = d.transcript_path || (d.hookSpecificInput||{}).transcript_path || "";
14
+ process.stdout.write(p);
15
+ ' 2>/dev/null)"
16
+
17
+ if [ -n "$TRANSCRIPT_PATH" ]; then
18
+ SESSION_ID="$(basename "$TRANSCRIPT_PATH" .jsonl)"
19
+ PID_FILE="${MEKO_WATERMARK_DIR:-$HOME/.claude/meko-capture}/${SESSION_ID}.timer.pid"
20
+ if [ -f "$PID_FILE" ]; then
21
+ kill "$(cat "$PID_FILE")" 2>/dev/null || true
22
+ rm -f "$PID_FILE"
23
+ fi
24
+ fi
25
+
26
+ # Run final capture
27
+ printf '%s' "$HOOK_INPUT" | node "$SCRIPT_DIR/lib/capture.js" session-end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # SessionStart hook — creates Meko conversation + watermark via capture.js,
4
+ # injects additionalContext, and spawns the background checkpoint timer.
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+
8
+ # Read hook input from stdin (capture.js needs it, and we need transcript_path)
9
+ HOOK_INPUT="$(cat)"
10
+ TRANSCRIPT_PATH="$(printf '%s' "$HOOK_INPUT" | node -e '
11
+ const d = JSON.parse(require("fs").readFileSync(0,"utf-8"));
12
+ const p = d.transcript_path || (d.hookSpecificInput||{}).transcript_path || "";
13
+ process.stdout.write(p);
14
+ ' 2>/dev/null)"
15
+
16
+ # Spawn background checkpoint timer (periodic capture without interrupting the agent)
17
+ if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
18
+ nohup node "$SCRIPT_DIR/lib/checkpoint-timer.js" "$TRANSCRIPT_PATH" \
19
+ </dev/null >/dev/null 2>&1 &
20
+ disown 2>/dev/null || true
21
+ fi
22
+
23
+ # Create conversation + watermark via capture.js, output additionalContext
24
+ printf '%s' "$HOOK_INPUT" | node "$SCRIPT_DIR/lib/capture.js" session-start
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # test_single_conversation.sh — Verify that exactly ONE Meko conversation
4
+ # is created per session, regardless of how many hook modes fire.
5
+ #
6
+ # Simulates the full hook lifecycle: session-start → checkpoint → pre-compact → session-end.
7
+ # Asserts the watermark conversation_id stays the same throughout.
8
+ #
9
+ # Usage:
10
+ # ./test_single_conversation.sh [MCP_URL]
11
+ #
12
+ # Environment:
13
+ # MEKO_MCP_URL MCP server URL (default: http://localhost:8000/mcp)
14
+
15
+ set -euo pipefail
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
18
+ CAPTURE_JS="$SCRIPT_DIR/lib/capture.js"
19
+ MCP_URL="${1:-${MEKO_MCP_URL:-http://localhost:8000/mcp}}"
20
+ AGENT_ID="${MEKO_AGENT_ID:-claude_code}"
21
+
22
+ # Temp dirs for isolation
23
+ WATERMARK_DIR="$(mktemp -d -t meko-test-wm-XXXXXX)"
24
+ TRANSCRIPT_DIR="$(mktemp -d -t meko-test-tx-XXXXXX)"
25
+ SESSION_ID="test-dedup-$(uuidgen | tr '[:upper:]' '[:lower:]')"
26
+ TRANSCRIPT_PATH="$TRANSCRIPT_DIR/${SESSION_ID}.jsonl"
27
+ WATERMARK_PATH="$WATERMARK_DIR/${SESSION_ID}.watermark.json"
28
+
29
+ PASS=0
30
+ FAIL=0
31
+ CONV_IDS_SEEN=()
32
+
33
+ cleanup() {
34
+ rm -rf "$WATERMARK_DIR" "$TRANSCRIPT_DIR"
35
+ }
36
+ trap cleanup EXIT
37
+
38
+ log() { printf " %-50s" "$1"; }
39
+ pass() { printf "\033[32mPASS\033[0m %s\n" "${1:-}"; PASS=$((PASS + 1)); }
40
+ fail() { printf "\033[31mFAIL\033[0m %s\n" "${1:-}"; FAIL=$((FAIL + 1)); }
41
+
42
+ read_watermark_conv_id() {
43
+ if [ -f "$WATERMARK_PATH" ]; then
44
+ node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('$WATERMARK_PATH','utf-8')).conversation_id||'')"
45
+ fi
46
+ }
47
+
48
+ # Create mock transcript
49
+ USER_UUID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
50
+ cat > "$TRANSCRIPT_PATH" <<JSONL
51
+ {"type":"user","uuid":"$USER_UUID","message":{"content":"What is YugabyteDB?"}}
52
+ {"type":"assistant","uuid":"$(uuidgen | tr '[:upper:]' '[:lower:]')","message":{"content":"YugabyteDB is a distributed SQL database."}}
53
+ {"type":"user","uuid":"$(uuidgen | tr '[:upper:]' '[:lower:]')","message":{"content":"Does it support PostgreSQL extensions?"}}
54
+ {"type":"assistant","uuid":"$(uuidgen | tr '[:upper:]' '[:lower:]')","message":{"content":"Yes, including Apache AGE for graph queries."}}
55
+ JSONL
56
+
57
+ export MEKO_MCP_URL="$MCP_URL"
58
+ export MEKO_AGENT_ID="$AGENT_ID"
59
+ export MEKO_WATERMARK_DIR="$WATERMARK_DIR"
60
+
61
+ echo "============================================================"
62
+ echo "Test: Single Conversation Per Session (Dedup)"
63
+ echo "============================================================"
64
+ echo " MCP URL: $MCP_URL"
65
+ echo " Session ID: $SESSION_ID"
66
+ echo " Transcript: $TRANSCRIPT_PATH ($(wc -l < "$TRANSCRIPT_PATH") lines)"
67
+ echo " Watermark: $WATERMARK_DIR"
68
+ echo ""
69
+
70
+ # --- Step 1: session-start ---
71
+ echo "--- Step 1: session-start ---"
72
+
73
+ HOOK_INPUT=$(printf '{"transcript_path":"%s"}' "$TRANSCRIPT_PATH")
74
+ STDOUT=$(printf '%s' "$HOOK_INPUT" | node "$CAPTURE_JS" session-start 2>/dev/null || true)
75
+
76
+ log "Watermark file created"
77
+ if [ -f "$WATERMARK_PATH" ]; then
78
+ pass
79
+ else
80
+ fail "not found at $WATERMARK_PATH"
81
+ fi
82
+
83
+ CONV_A=$(read_watermark_conv_id)
84
+ log "Conversation ID assigned"
85
+ if [ -n "$CONV_A" ]; then
86
+ pass "$CONV_A"
87
+ CONV_IDS_SEEN+=("$CONV_A")
88
+ else
89
+ fail "empty conversation_id in watermark"
90
+ fi
91
+
92
+ log "Hook output contains conversation ID"
93
+ if echo "$STDOUT" | grep -q "$CONV_A" 2>/dev/null; then
94
+ pass
95
+ else
96
+ fail "stdout did not contain $CONV_A"
97
+ fi
98
+
99
+ # --- Step 2: checkpoint ---
100
+ echo ""
101
+ echo "--- Step 2: checkpoint ---"
102
+
103
+ printf '%s' "$HOOK_INPUT" | node "$CAPTURE_JS" checkpoint 2>/dev/null || true
104
+
105
+ CONV_B=$(read_watermark_conv_id)
106
+ log "Watermark conversation unchanged after checkpoint"
107
+ if [ "$CONV_B" = "$CONV_A" ]; then
108
+ pass "$CONV_B"
109
+ else
110
+ fail "expected $CONV_A, got $CONV_B"
111
+ CONV_IDS_SEEN+=("$CONV_B")
112
+ fi
113
+
114
+ # --- Step 3: pre-compact ---
115
+ echo ""
116
+ echo "--- Step 3: pre-compact ---"
117
+
118
+ printf '%s' "$HOOK_INPUT" | node "$CAPTURE_JS" pre-compact 2>/dev/null || true
119
+
120
+ CONV_C=$(read_watermark_conv_id)
121
+ log "Watermark conversation unchanged after pre-compact"
122
+ if [ "$CONV_C" = "$CONV_A" ]; then
123
+ pass "$CONV_C"
124
+ else
125
+ fail "expected $CONV_A, got $CONV_C"
126
+ CONV_IDS_SEEN+=("$CONV_C")
127
+ fi
128
+
129
+ # --- Step 4: session-end ---
130
+ echo ""
131
+ echo "--- Step 4: session-end ---"
132
+
133
+ printf '%s' "$HOOK_INPUT" | node "$CAPTURE_JS" session-end 2>/dev/null || true
134
+
135
+ CONV_D=$(read_watermark_conv_id)
136
+ log "Watermark conversation unchanged after session-end"
137
+ if [ "$CONV_D" = "$CONV_A" ]; then
138
+ pass "$CONV_D"
139
+ else
140
+ fail "expected $CONV_A, got $CONV_D"
141
+ CONV_IDS_SEEN+=("$CONV_D")
142
+ fi
143
+
144
+ # --- Step 5: Verify exactly one conversation in Meko ---
145
+ echo ""
146
+ echo "--- Step 5: Verify single conversation ---"
147
+
148
+ UNIQUE_IDS=($(printf '%s\n' "${CONV_IDS_SEEN[@]}" | sort -u))
149
+ log "Unique conversation IDs across all hooks"
150
+ if [ ${#UNIQUE_IDS[@]} -eq 1 ]; then
151
+ pass "1 (${UNIQUE_IDS[0]})"
152
+ else
153
+ fail "${#UNIQUE_IDS[@]} distinct IDs: ${UNIQUE_IDS[*]}"
154
+ fi
155
+
156
+ # --- Summary ---
157
+ echo ""
158
+ echo "============================================================"
159
+ TOTAL=$((PASS + FAIL))
160
+ echo " Total: $TOTAL | Passed: $PASS | Failed: $FAIL"
161
+ echo "============================================================"
162
+
163
+ if [ "$FAIL" -gt 0 ]; then
164
+ echo " RESULT: FAILED"
165
+ exit 1
166
+ else
167
+ echo " RESULT: ALL PASSED"
168
+ exit 0
169
+ fi
@@ -0,0 +1,192 @@
1
+ ---
2
+ name: meko-mcp-tools
3
+ description: Behavioral guide for AI agents using Meko MCP tools. Triggers when calling MCP tools, storing memories, persisting knowledge, managing datapacks, or working with YugabyteDB databases through Meko.
4
+ license: MIT
5
+ metadata:
6
+ author: Meko
7
+ version: "2.1.0"
8
+ tags: mcp, yugabytedb, tools, datapack, memory, conversation, rag, meko
9
+ ---
10
+
11
+ # Meko MCP Tools — Agent Behavioral Guide
12
+
13
+ Meko is agent-native data infrastructure that enables continuous learning from context windows through collective memory and shared knowledge. This skill teaches you how to use Meko's 31 MCP tools — and more importantly, **when to use them proactively** without waiting to be asked.
14
+
15
+ ## What Meko enables
16
+
17
+ Meko turns your volatile context window into persistent, shareable knowledge:
18
+
19
+ - **Personal memory** — Store who the user is, their preferences, role, and working style. Survives across sessions.
20
+ - **Team/org memory** — Store organizational conventions, coding standards, tooling choices. Shared across agents and team members.
21
+ - **Shared knowledge** — Persist domain knowledge (product specs, data dictionaries, research) into a searchable knowledge base via RAG.
22
+ - **Conversation history** — Preserve full dialog exchanges with reasoning traces for audit, replay, and learning transfer.
23
+ - **Decision traces** — Capture how and why decisions were made, enabling debugging and continuous improvement.
24
+ - **Structured data** — Store and query tabular data in a real database, not squeezed into memory.
25
+
26
+ ## When to use this skill
27
+
28
+ - You are calling tools on a Meko / YugabyteDB MCP server
29
+ - You need to decide what to store, where, and how
30
+ - You are constructing SQL queries for `db_run_read_only_query` or `db_run_write_query`
31
+ - You are setting up a RAG knowledge base pipeline
32
+ - You are managing datapacks, agents, or knowledge base sources
33
+ - You want to understand scope/permission requirements, `agent_id` constraints, or `datapack_id` routing
34
+
35
+ ## Discover the user's `agent_id` namespace — don't guess it
36
+
37
+ `agent_id` is currently overloaded: it doubles as a user-namespace key and an agent-type label. Treat it as the **user's namespace**, not as "which tool am I." See [issue #10](https://github.com/amiramm/meko-mcp-server/issues/10) for why this matters.
38
+
39
+ Defaulting to `claude_code` because you are Claude Code **fragments the user's memory across tools.** Don't do it.
40
+
41
+ ### The discovery protocol (run once per session, before any memory call)
42
+
43
+ 1. Call `db_summarize_database(scope="read", conversation_id="00000000-0000-0000-0000-000000000000")`.
44
+ 2. Inspect the returned tables. Mem0 stores memories in `<agent_id>_mem0_collection`. For each such table with `row_count > 0`, that's an `agent_id` the user is already using.
45
+ 3. Pick the namespace:
46
+ - **Exactly one `<x>_mem0_collection` has rows** → use `agent_id="<x>"`.
47
+ - **Multiple candidates with rows** → pick the one with the highest `row_count` (that's the user's primary namespace). Mention the other(s) briefly so the user can steer if they want memory written elsewhere.
48
+ - **No `<x>_mem0_collection` has rows** → use `agent_id="agent"`. This is the fallback for a fresh user.
49
+ 4. Cache the chosen value. Use it for every `memory_*` and `conversation_*` call in this session.
50
+
51
+ Never pick `claude_code` just because you're running in Claude Code. Pick what the user already uses. If you're wrong, the next `memory_search` returns nothing and you'll notice.
52
+
53
+ The SessionStart hook may seed a `conversation_id` in the watermark, but it does not pick `agent_id` for you — discovery still applies.
54
+
55
+ ## Critical: Use Meko tools, not local storage
56
+
57
+ **When Meko MCP tools are available, ALWAYS use them instead of local/built-in storage mechanisms.** Do not write to local memory files, markdown notes, or any file-based memory system. Meko's memory is persistent across all agents, sessions, and team members — local files are not.
58
+
59
+ - User shares personal info → call `memory_add` on the MCP server, NOT write to a local file
60
+ - User asks what you know → call `memory_search` on the MCP server, NOT read local files
61
+ - Conversation worth preserving → call `conversation_create`, NOT save to a local log
62
+
63
+ If a Meko tool call fails, you may fall back to local storage and tell the user — but Meko is always the first choice.
64
+
65
+ ## Core principle: Be Meko's persistent brain
66
+
67
+ **Do not wait for the user to say "save this to memory."** Proactively store context that would be valuable in future sessions. Think of Meko as your long-term memory that persists across conversations.
68
+
69
+ ### Proactive behavior rules
70
+
71
+ | Signal in conversation | What to do | Tool to use |
72
+ |---|---|---|
73
+ | User shares personal info ("I'm Amiram", "I'm a VP of Product") | Store as personal memory immediately | `memory_add` |
74
+ | User states a preference ("I prefer dark mode", "always use Python") | Store as personal preference | `memory_add` |
75
+ | User shares org convention ("we write in Go", "our standard is X") | Store as organizational memory | `memory_add` |
76
+ | User teaches domain knowledge ("Meko traces are decision traces") | Store as memory AND consider KB ingestion | `memory_add` |
77
+ | User corrects your behavior ("don't do X, do Y instead") | Store the correction as a learning | `memory_add` |
78
+ | User asks "what do you know about X?" | Search memory first, then DB | `memory_search` then `db_run_read_only_query` |
79
+ | Session produced a valuable multi-turn exchange | Preserve the full conversation | `conversation_create` + `conversation_add_message` |
80
+ | Significant learnings accumulated during session | Offer to persist key takeaways | Summarize and propose `memory_add` calls |
81
+ | User provides structured/tabular data (CSV, data dictionary) | Store as database table, NOT memory | `db_run_write_query` (CREATE TABLE + INSERT) |
82
+
83
+ ### Information classification
84
+
85
+ When the user shares information, classify it before storing:
86
+
87
+ ```
88
+ User says something → Classify:
89
+ ├── About themselves (name, role, preferences)
90
+ │ → memory_add — personal profile
91
+ ├── About how their team/org works (conventions, standards, policies)
92
+ │ → memory_add — organizational memory
93
+ ├── Domain knowledge (facts, definitions, specs, research)
94
+ │ → memory_add for quick recall + KB ingestion for search at scale
95
+ ├── A correction or learning ("don't do X", "always do Y")
96
+ │ → memory_add — behavioral feedback
97
+ ├── Full conversation worth preserving (multi-turn, reasoning traces)
98
+ │ → conversation_create + conversation_add_message — verbatim
99
+ └── Structured/tabular data (CSV rows, schemas, data dictionaries)
100
+ → db_run_write_query (CREATE TABLE + INSERT) — NOT memory_add
101
+ ```
102
+
103
+ **Why not memory_add for tabular data?** Mem0 extracts individual facts from text. Passing CSV rows through it loses columns, rows, and structural relationships. Use the database for structured data.
104
+
105
+ ## Automatic conversation capture
106
+
107
+ The Meko plugin automatically captures conversations via three mechanisms that coordinate through a shared watermark file:
108
+
109
+ 1. **Background checkpoint timer** — runs every 10 minutes, captures new exchanges without interrupting the agent
110
+ 2. **PreCompact hook** — fires before context compaction, captures everything before compaction discards context
111
+ 3. **SessionEnd hook** — fires at session end, captures remaining exchanges
112
+
113
+ All three are handled automatically. **Do NOT set up CronCreate for conversation capture** — it interrupts running tool calls and causes disruptive retry cycles.
114
+
115
+ ### What to do at session start
116
+
117
+ The SessionStart hook has already done the setup for you:
118
+
119
+ 1. **Created a Meko conversation** — `conversation_id` is injected into `additionalContext` on the first turn. Use that value for all subsequent MCP tool calls that accept `conversation_id`.
120
+ 2. **Discovered and cached `agent_id`** — also injected into `additionalContext`. Use the injected value as-is; do not re-run `db_summarize_database` unless `additionalContext` shows discovery failed (falls back to a default).
121
+ 3. **Preloaded recent memories** — `additionalContext` may include a `### Memories from prior sessions` block. Inspect it before acting so you don't re-ask questions the user has already answered.
122
+
123
+ If `additionalContext` is absent or empty (hook failed, MCP unavailable), fall back to the manual protocol: run discovery via `db_summarize_database` (see "Discover the user's `agent_id` namespace" above) and use a nil UUID for `conversation_id` until you can create a real one.
124
+
125
+ ### Before potentially destructive actions
126
+
127
+ Before any action that deletes, overwrites, or restructures user content — `Write` overwriting an existing file, large `Edit` deletions, `rm` / `rm -rf`, `git reset --hard`, destructive SQL (`DROP`, `TRUNCATE`, `DELETE` without `WHERE`) — run a `memory_search` for relevant feedback:
128
+
129
+ ```
130
+ memory_search(scope="read", query="destructive <action type> preferences feedback",
131
+ agent_id=<discovered>, conversation_id=<session_or_nil>)
132
+ ```
133
+
134
+ If a relevant feedback memory exists (e.g., "always ask before deleting content"), confirm with the user before proceeding. If the search is empty, proceed, but treat the action as irreversible and prefer a dry-run / preview when one is available.
135
+
136
+ ### Capture rules
137
+
138
+ - **Verbatim content only** — never summarize, rephrase, or condense. See `tools-memory-vs-conversation.md`.
139
+ - **Include tool calls and results** — store tool_use name + input in `reasoning`, tool results as follow-up reasoning entries. These are essential for session replay and compaction context.
140
+ - **Always use a seed** — enables dedup across the three capture mechanisms.
141
+ - **Graceful failure** — if `conversation_add_message` fails, log the error and continue. Do not retry more than once.
142
+
143
+ ## Calling tools correctly on the first attempt
144
+
145
+ **Use only the required parameters. Do not guess optional parameters.**
146
+
147
+ ### memory_add — correct call pattern
148
+ ```
149
+ memory_add(scope="write", text="User is VP of Product at YugabyteDB", agent_id="claude_code", conversation_id="00000000-0000-0000-0000-000000000000")
150
+ ```
151
+ Required parameters: `scope`, `text`, `agent_id`, `conversation_id`. Use a nil UUID (`"00000000-0000-0000-0000-000000000000"`) for `conversation_id` unless you have a real one from `conversation_create`. NEVER use strings like `"current"` or `""`.
152
+
153
+ ### memory_search — correct call pattern
154
+ ```
155
+ memory_search(scope="read", query="user role", agent_id="claude_code", conversation_id="00000000-0000-0000-0000-000000000000")
156
+ ```
157
+ Required parameters: `scope`, `query`, `agent_id`, `conversation_id`. Use a nil UUID for `conversation_id`.
158
+
159
+ ### Critical parameter rules
160
+
161
+ - **agent_id**: Use the value you discovered at session start (see "Discover the user's `agent_id` namespace" above), not a literal tool name. The reference examples below use `claude_code` for illustration only — substitute the discovered value. Must use underscores, never hyphens (hyphens break PostgreSQL table names and produce SQL syntax errors). If you haven't run discovery yet, do it now before any memory call.
162
+ - **conversation_id**: If required by the tool, use a nil UUID (`"00000000-0000-0000-0000-000000000000"`) unless you have a real one from `conversation_create`. NEVER use strings like `"current"`, `""`, or other non-UUID values.
163
+ - **scope**: Only `"read"`, `"write"`, or `"admin"`. Nothing else.
164
+ - **When in doubt about optional parameters, omit them.** The server has sensible defaults.
165
+
166
+ ## Key concepts
167
+
168
+ 1. **31 tools in 5 groups**: Database (3), RAG/Knowledge Base (3), Memory (7), Conversation (7), Datapack Management (11)
169
+ 2. **Scope hierarchy**: `read < write < admin` — every tool validates scope at entry. Only three valid values: `"read"`, `"write"`, `"admin"`. Using anything else (e.g., `"all"`) will fail.
170
+ 3. **datapack_id routing**: All DB, RAG, and memory tools accept optional `datapack_id` to target a specific datapack's database instead of the default
171
+ 4. **agent_id is a per-user namespace, not a per-tool label**: Memory and conversation tools use `agent_id` to isolate data. Discover the user's existing namespace via `db_summarize_database` at session start (see the section above) and use that value across every call — don't default to `claude_code` just because the current client is Claude Code. Must use underscores, never hyphens (hyphens are injected into PostgreSQL table names and cause SQL syntax errors). Issue [#10](https://github.com/amiramm/meko-mcp-server/issues/10) tracks the schema split that will eventually unbundle this.
172
+ 5. **Write guardrails**: `db_run_write_query` blocks dangerous SQL patterns and enforces configurable limits. One statement per call.
173
+ 6. **Conversation dedup**: `conversation_add_message` supports seed-based deterministic trace IDs to prevent duplicates
174
+ 7. **Known limitations**: Some tools have bugs or missing capabilities — see `tools-known-limitations.md` before attempting RAG cleanup or write operations
175
+ 8. **Error recovery**: Connection errors are common with memory tools — see `tools-troubleshooting.md` for retry strategies and fallbacks
176
+
177
+ ## Reference sections
178
+
179
+ | File | What it covers |
180
+ |------|---------------|
181
+ | `tools-overview.md` | Complete catalog of all 31 tools with decision tree |
182
+ | `tools-cookbook.md` | Per-tool examples with correct parameters, responses, and error cases |
183
+ | `tools-memory-vs-conversation.md` | When to use memory tools vs conversation tools |
184
+ | `tools-datapack-workflow.md` | Datapack lifecycle and datapack_id routing |
185
+ | `tools-rag-workflow.md` | End-to-end RAG pipeline flow |
186
+ | `tools-write-guardrails.md` | Blocked SQL patterns and configurable limits |
187
+ | `tools-scope-permissions.md` | read/write/admin permission hierarchy |
188
+ | `tools-agent-id-conventions.md` | Naming rules and constraints for agent_id |
189
+ | `tools-conversation-dedup.md` | Seed-based trace deduplication |
190
+ | `tools-db-query-patterns.md` | Read-only vs write query execution patterns |
191
+ | `tools-troubleshooting.md` | Error recovery, retry strategies, stuck pipeline diagnosis |
192
+ | `tools-known-limitations.md` | Broken tools, missing capabilities, permission gaps |
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Section Index
3
+ description: Maps reference files to their topics for the meko-mcp-tools skill
4
+ ---
5
+
6
+ # Reference Sections
7
+
8
+ ## Tool Selection & Catalog
9
+ - [tools-overview.md](tools-overview.md) — Complete catalog of all 31 tools with a decision tree for choosing the right tool
10
+
11
+ ## Tool-Specific Guidance
12
+ - [tools-memory-vs-conversation.md](tools-memory-vs-conversation.md) — Decision framework: memory_add vs conversation_create/conversation_add_message
13
+ - [tools-datapack-workflow.md](tools-datapack-workflow.md) — Datapack lifecycle, datapack_id routing, and multi-database patterns
14
+ - [tools-rag-workflow.md](tools-rag-workflow.md) — End-to-end RAG pipeline: source registration, index creation, status polling
15
+ - [tools-db-query-patterns.md](tools-db-query-patterns.md) — Read-only vs write query execution patterns and SQL conventions
16
+
17
+ ## Safety & Permissions
18
+ - [tools-write-guardrails.md](tools-write-guardrails.md) — Blocked SQL operations, bulk insert limits, WHERE clause enforcement
19
+ - [tools-scope-permissions.md](tools-scope-permissions.md) — read/write/admin permission hierarchy and per-tool requirements
20
+
21
+ ## Conventions & Deduplication
22
+ - [tools-agent-id-conventions.md](tools-agent-id-conventions.md) — agent_id naming rules, hyphen prohibition, and namespace isolation
23
+ - [tools-user-id-conventions.md](tools-user-id-conventions.md) — user_id vs agent_id: when to pass each, and how they scope memory
24
+ - [tools-conversation-dedup.md](tools-conversation-dedup.md) — Seed-based deterministic trace IDs for Langfuse deduplication
25
+
26
+ ## Practical Usage
27
+ - [tools-cookbook.md](tools-cookbook.md) — Per-tool examples with correct parameters, expected responses, and common errors
28
+
29
+ ## Troubleshooting & Limitations
30
+ - [tools-troubleshooting.md](tools-troubleshooting.md) — Error recovery, retry strategies, stuck pipeline diagnosis
31
+ - [tools-known-limitations.md](tools-known-limitations.md) — Broken tools, missing capabilities, permission gaps
@@ -0,0 +1,39 @@
1
+ # agent_id Naming Rules and Namespace Isolation
2
+
3
+ **WRONG:** `agent_id="my-support-agent"` → mem0 uses agent_id in table names (`my-support-agent_mem0_collection`), and hyphens are invalid PostgreSQL identifiers → table creation fails.
4
+
5
+ ## The Rule
6
+
7
+ **agent_id MUST NOT contain hyphens.** Use underscores. Stick to: lowercase letters, digits, and underscores.
8
+
9
+ ```
10
+ GOOD: "support_bot", "sales_agent_v2", "agent_001"
11
+ BAD: "support-bot", "sales-agent-v2", "my agent", "agent.one"
12
+ ```
13
+
14
+ ## Namespace Isolation
15
+
16
+ `agent_id` is the primary isolation boundary for both memory and conversation tools:
17
+
18
+ **Memory (mem0/pgvector + Apache AGE):**
19
+ - Each agent_id gets its own pgvector collection (`{agent_id}_mem0_collection`) and AGE graph (`{agent_id}_mem0_graph`)
20
+ - `memory_search` and `memory_get_all` only return data from the specified agent's namespace
21
+
22
+ **Conversations (Langfuse):**
23
+ - Traces tagged with `agent:{agent_id}`, names prefixed with `{agent_id}:message`, `{agent_id}:start`, `{agent_id}:update`
24
+ - `conversation_list` and `conversation_get` filter by and verify agent ownership
25
+
26
+ ## Consistency is Critical
27
+
28
+ **WRONG:** Using `agent_id="support_bot"` for memory and `agent_id="supportBot"` for conversations — these are separate namespaces that will never see each other's data.
29
+
30
+ Use the same `agent_id` string across all memory and conversation calls for the same logical agent.
31
+
32
+ ## Sub-Scoping
33
+
34
+ Within a single agent_id, further scope with optional parameters:
35
+ - `user_id` — per-user isolation
36
+ - `app_id` — per-application (e.g., "web_app" vs "mobile_app")
37
+ - `run_id` — per-execution run
38
+
39
+ Available on `memory_add`, `memory_search`, `memory_get_all`, `memory_delete_all`, `conversation_create`, `conversation_list`.
@@ -0,0 +1,49 @@
1
+ # Seed-Based Trace Deduplication for Conversations
2
+
3
+ ## The Problem
4
+
5
+ When MCP clients have built-in Langfuse hooks (Cursor, Claude Code), both the client hook and the MCP server may write a trace for the same message → duplicate traces, doubled message counts, corrupted conversation retrieval.
6
+
7
+ **WRONG:** Neither `seed` nor `trace_id` provided → both sides generate random IDs → two traces per message.
8
+
9
+ ## Solution: Use seed for deterministic trace IDs
10
+
11
+ ```
12
+ conversation_add_message(
13
+ scope="write", conversation_id="conv-uuid", agent_id="my_agent",
14
+ input="What is our Q3 revenue?",
15
+ output="Q3 revenue was $4.2M, up 15% from Q2.",
16
+ seed="conv-uuid:my_agent:What is our Q3 revenue?"
17
+ )
18
+ ```
19
+
20
+ Both sides hash the same seed string to produce the same trace ID. Langfuse treats the second write as an upsert → exactly one trace.
21
+
22
+ ## Priority Rules
23
+
24
+ 1. **`trace_id`** — if provided, used directly (highest precedence)
25
+ 2. **`seed`** — if provided, hashed to produce deterministic trace ID
26
+ 3. **Neither** — random trace ID generated
27
+
28
+ ## Choosing a Good Seed
29
+
30
+ The seed should be deterministic and unique per message:
31
+
32
+ ```
33
+ seed = f"{conversation_id}:{agent_id}:{input_text}"
34
+ -- or, if message order matters:
35
+ seed = f"{conversation_id}:{agent_id}:{message_index}"
36
+ ```
37
+
38
+ ## When to Use Each
39
+
40
+ | Scenario | Use |
41
+ |----------|-----|
42
+ | Client hook + MCP server both write to Langfuse | `seed` |
43
+ | Only the MCP server writes (no client hook) | Neither (random is fine) |
44
+ | Migrating from another system with existing IDs | `trace_id` |
45
+ | Replaying messages idempotently | `seed` |
46
+
47
+ ## session_id on conversation_create
48
+
49
+ Optional `session_id` serves a similar dedup purpose for the conversation container. If provided, the same session_id reconnects to an existing Langfuse session.