@yugabytedb/meko-mcp 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +31 -6
  2. package/assets/hooks-handlers/codex-session-end.sh +78 -0
  3. package/assets/hooks-handlers/lib/capture.js +163 -14
  4. package/assets/hooks-handlers/lib/checkpoint-timer.js +44 -2
  5. package/assets/hooks-handlers/session-end.sh +10 -0
  6. package/assets/hooks-handlers/session-start.sh +8 -1
  7. package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
  8. package/assets/scripts/package-desktop-skill.sh +32 -1
  9. package/assets/skills/meko-mcp-tools/SKILL.md +47 -41
  10. package/assets/skills/meko-mcp-tools/references/_sections.md +2 -4
  11. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +29 -25
  12. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
  13. package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
  14. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +63 -46
  15. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -6
  16. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +4 -4
  17. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +17 -22
  18. package/assets/skills/meko-mcp-tools/references/tools-overview.md +40 -39
  19. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +1 -2
  20. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +4 -18
  21. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +9 -8
  22. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +49 -42
  23. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +6 -6
  24. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
  25. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +28 -24
  26. package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
  27. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +61 -36
  28. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +4 -4
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +16 -19
  30. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +40 -39
  31. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +1 -2
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -17
  33. package/assets/skills/meko-select-datapack-desktop/SKILL.md +31 -21
  34. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
  35. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
  36. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +1 -1
  37. package/bin/create-meko-setup.mjs +45 -6
  38. package/lib/clients/claude-code.mjs +8 -4
  39. package/lib/clients/claude-desktop.mjs +14 -0
  40. package/lib/clients/codex.mjs +23 -8
  41. package/lib/clients/common.mjs +2 -0
  42. package/lib/clients/cursor.mjs +7 -2
  43. package/lib/detect.mjs +7 -2
  44. package/lib/prompt.mjs +1 -1
  45. package/lib/url-selection.mjs +55 -0
  46. package/package.json +1 -1
  47. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -71
  48. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -71
@@ -77,14 +77,19 @@ const RC_FENCE_END = "# <<< meko mcp <<<";
77
77
  const SKILLS = [{ name: "meko-mcp-tools" }];
78
78
  // Codex hook timeouts are in SECONDS (Duration::from_secs in
79
79
  // codex-rs/hooks/src/engine/command_runner.rs), not milliseconds like Claude
80
- // Code / Cursor. Default is 600s if omitted; we cap SessionStart/SessionEnd
81
- // at 15s/30s to match the Claude Code values logically.
80
+ // Code / Cursor. Codex hard-caps SessionEnd at three seconds, so its dedicated
81
+ // handler only spools input and launches the actual capture in the background.
82
82
  const MEKO_HOOKS = [
83
83
  { event: "SessionStart", script: "session-start.sh", timeout: 15 },
84
84
  { event: "PreCompact", script: "pre-compact.sh" },
85
- { event: "SessionEnd", script: "session-end.sh", timeout: 30 },
85
+ { event: "SessionEnd", script: "codex-session-end.sh", timeout: 3 },
86
+ ];
87
+ // Include the former synchronous Codex SessionEnd handler so reinstall prunes
88
+ // it instead of leaving both old and new handlers active.
89
+ const MEKO_HOOK_SCRIPTS = [
90
+ ...MEKO_HOOKS.map((hook) => hook.script),
91
+ "session-end.sh",
86
92
  ];
87
- const MEKO_HOOK_SCRIPTS = MEKO_HOOKS.map((hook) => hook.script);
88
93
 
89
94
  /**
90
95
  * @param {{
@@ -196,10 +201,11 @@ export function createCodexAdapter(options = {}) {
196
201
  surfaces.app = app?.found ? app : null;
197
202
  }
198
203
 
204
+ let cliFound = false;
199
205
  if (surfaces.cli) {
200
206
  try {
201
207
  runCommand(`codex mcp get ${shellQuote(name)}`);
202
- return { found: true, status: "Configured" };
208
+ cliFound = true;
203
209
  } catch {
204
210
  // fall through to TOML grep — `codex mcp get` exits non-zero when
205
211
  // the entry isn't present, but might also fail for unrelated
@@ -209,8 +215,17 @@ export function createCodexAdapter(options = {}) {
209
215
  }
210
216
  const path = settingsPathFor(scope, null);
211
217
  const raw = safeReadFile(path);
212
- if (raw === null) return { found: false, status: "" };
213
- return parseCodexConfigForServer(raw, name).found
218
+ if (raw !== null) {
219
+ const parsed = parseCodexConfigForServer(raw, name);
220
+ if (parsed.found) {
221
+ return {
222
+ found: true,
223
+ status: "Configured",
224
+ ...(parsed.url ? { url: parsed.url } : {}),
225
+ };
226
+ }
227
+ }
228
+ return cliFound
214
229
  ? { found: true, status: "Configured" }
215
230
  : { found: false, status: "" };
216
231
  },
@@ -640,7 +655,7 @@ function upsertCodexMekoHooks(hooksPath, hooksRoot, { envFilePath } = {}) {
640
655
  function buildCodexHookCommand(scriptPath, { envFilePath } = {}) {
641
656
  const parts = [];
642
657
  if (envFilePath) parts.push(`. ${shellQuote(envFilePath)}`);
643
- parts.push(`bash ${shellQuote(scriptPath)}`);
658
+ parts.push(`MEKO_HOOK_CLIENT=codex bash ${shellQuote(scriptPath)}`);
644
659
  return parts.join(" && ");
645
660
  }
646
661
 
@@ -16,6 +16,8 @@ import { dirname, join, resolve } from "node:path";
16
16
  import { fileURLToPath } from "node:url";
17
17
 
18
18
  export const MEKO_MCP_USER_AGENT = "meko-mcp-installer/1.0";
19
+ export const MEKO_PRODUCTION_MCP_URL = "https://mcp.mekodata.ai/mcp";
20
+ export const MEKO_PRODUCTION_CONSOLE_URL = "https://cloud.mekodata.ai";
19
21
 
20
22
  /**
21
23
  * @returns {string} Absolute repository root path.
@@ -75,8 +75,13 @@ export function createCursorAdapter(customPaths = {}) {
75
75
  detectExisting(name, { scope, projectRoot }) {
76
76
  const path = paths.getMcpPath(scope, projectRoot);
77
77
  const cfg = readJsonFile(path);
78
- const found = Boolean(cfg?.mcpServers?.[name]);
79
- return { found, status: found ? "Configured" : "" };
78
+ const entry = cfg?.mcpServers?.[name];
79
+ const found = Boolean(entry);
80
+ return {
81
+ found,
82
+ status: found ? "Configured" : "",
83
+ ...(typeof entry?.url === "string" ? { url: entry.url } : {}),
84
+ };
80
85
  },
81
86
  removeRegistration(name, { scope, projectRoot }) {
82
87
  const mcpPath = paths.getMcpPath(scope, projectRoot);
package/lib/detect.mjs CHANGED
@@ -110,7 +110,7 @@ export function getClaudeCodeConfigPath() {
110
110
  * `scope` — "user" (default) or "project". Project scope looks under `projects[projectRoot].mcpServers`.
111
111
  * `projectRoot` — absolute path used as the key into `projects[...]` when `scope === "project"`.
112
112
  * Ignored for user scope. Must be supplied by the caller for project scope.
113
- * @returns {{ found: boolean, status: string }}
113
+ * @returns {{ found: boolean, status: string, url?: string }}
114
114
  * `found` - true if a matching MCP entry exists at the scope-appropriate location.
115
115
  * `status` - "Configured" when found, "" otherwise. (Kept as a string for
116
116
  * API compatibility with the prior implementation; callers use
@@ -129,5 +129,10 @@ export function detectExistingMeko(serverName = "meko", options = {}) {
129
129
  if (!entry) {
130
130
  return { found: false, status: "" };
131
131
  }
132
- return { found: true, status: "Configured" };
132
+ const url = typeof entry.url === "string" ? entry.url : undefined;
133
+ return {
134
+ found: true,
135
+ status: "Configured",
136
+ ...(url ? { url } : {}),
137
+ };
133
138
  }
package/lib/prompt.mjs CHANGED
@@ -50,7 +50,7 @@ function question(query) {
50
50
  *
51
51
  * @example
52
52
  * const choice = await askChoice('Connection type:', [
53
- * { label: 'Cloud Meko', description: 'Hosted at mekodev.com' },
53
+ * { label: 'Cloud Meko', description: 'Hosted at mekodata.ai' },
54
54
  * { label: 'Local Meko', description: 'docker-compose stack' },
55
55
  * ]);
56
56
  */
@@ -0,0 +1,55 @@
1
+ import { MEKO_PRODUCTION_MCP_URL } from "./clients/common.mjs";
2
+
3
+ function validHttpUrl(value) {
4
+ if (typeof value !== "string" || !value.trim()) return null;
5
+ const candidate = value.trim();
6
+ try {
7
+ const parsed = new URL(candidate);
8
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
9
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "") || "/";
10
+ return { value: candidate, comparisonKey: parsed.toString() };
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Select the URL offered by interactive/non-interactive setup.
18
+ * Explicit CLI URLs are resolved before this helper is called.
19
+ */
20
+ export function resolveSuggestedMcpUrl({
21
+ adapters,
22
+ clients,
23
+ name = "meko",
24
+ scope = "user",
25
+ projectRoot = process.cwd(),
26
+ }) {
27
+ const existingUrlsByKey = new Map();
28
+ for (const client of clients) {
29
+ const adapter = adapters[client];
30
+ if (!adapter?.detectExisting) continue;
31
+ try {
32
+ const existing = adapter.detectExisting(name, { scope, projectRoot });
33
+ const url = existing?.found ? validHttpUrl(existing.url) : null;
34
+ if (url && !existingUrlsByKey.has(url.comparisonKey)) {
35
+ existingUrlsByKey.set(url.comparisonKey, url.value);
36
+ }
37
+ } catch {
38
+ // Existing-config discovery is advisory. Installation performs its own
39
+ // prerequisite and config checks later with actionable errors.
40
+ }
41
+ }
42
+
43
+ const uniqueUrls = [...existingUrlsByKey.values()];
44
+ if (uniqueUrls.length === 1) {
45
+ return { url: uniqueUrls[0], source: "existing", existingUrls: uniqueUrls };
46
+ }
47
+ if (uniqueUrls.length > 1) {
48
+ return { url: null, source: "conflict", existingUrls: uniqueUrls };
49
+ }
50
+ return {
51
+ url: MEKO_PRODUCTION_MCP_URL,
52
+ source: "production-default",
53
+ existingUrls: [],
54
+ };
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yugabytedb/meko-mcp",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Single-line installer for Meko MCP Server across Claude and Cursor clients",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,71 +0,0 @@
1
- # Scope Permission Hierarchy and Per-Tool Requirements
2
-
3
- **WRONG:** `memory_add(scope="read", ...)` → PermissionError: requires 'write' or higher.
4
- **WRONG:** `memory_delete_all(scope="write", ...)` → PermissionError: requires 'admin'.
5
-
6
- ## Scope Hierarchy
7
-
8
- ```
9
- admin (level 2) -- can do everything
10
- ↓
11
- write (level 1) -- can read + write, not admin-only
12
- ↓
13
- read (level 0) -- can only read
14
- ```
15
-
16
- Higher scopes include lower scopes. An unrecognized scope string always fails.
17
-
18
- ## Per-Tool Requirements
19
-
20
- ### read scope (9 tools)
21
-
22
- | Tool | Group |
23
- |------|-------|
24
- | `knowledgebase_search` | RAG |
25
- | `memory_search` | Memory |
26
- | `memory_get_by_id` | Memory |
27
- | `memory_get_all` | Memory |
28
- | `flush_pending_memory_candidates` | Memory |
29
- | `conversation_get` | Conversation |
30
- | `conversation_list` | Conversation |
31
- | `datapack_list` | Datapack |
32
- | `datapack_describe` | Datapack |
33
-
34
- ### write scope (9 tools)
35
-
36
- | Tool | Group |
37
- |------|-------|
38
- | `memory_add` | Memory |
39
- | `memory_update` | Memory |
40
- | `memory_delete_by_id` | Memory |
41
- | `conversation_create` | Conversation |
42
- | `conversation_add_message` | Conversation |
43
- | `conversation_update` | Conversation |
44
- | `datapack_create` | Datapack |
45
- | `datapack_update` | Datapack |
46
- | `track_token_usage` | Observability |
47
-
48
- ### admin scope (3 tools — destructive, irreversible)
49
-
50
- | Tool | Group |
51
- |------|-------|
52
- | `memory_delete_all` | Memory |
53
- | `conversation_delete` | Conversation |
54
- | `datapack_delete` | Datapack |
55
-
56
- Agent and knowledge-base lifecycle tools are not MCP-exposed — see "Platform capabilities NOT exposed via MCP" in `tools-overview.md`.
57
-
58
- ## Best Practices
59
-
60
- 1. **Use the minimum scope needed.** `scope="read"` for reads documents intent and prevents accidental writes.
61
- 2. **The scope is a parameter, not an auth token.** When OAuth is enabled, the actual permission check happens against the OAuth token's claims. Both `scope` parameter and OAuth permissions must be satisfied.
62
-
63
- ## Common Mistakes
64
-
65
- **WRONG:** `scope="all"` — there is no "all" scope. Valid values are exactly: `"read"`, `"write"`, `"admin"`. Nothing else.
66
-
67
- Other invalid values that will fail: `"readwrite"`, `"rw"`, `"full"`, `"any"`.
68
-
69
- The error `Insufficient scope: 'all'. This tool requires 'read' or higher.` means the scope string was not recognized as a valid value. Always use one of the three valid strings.
70
-
71
- **Default choice:** Start with `scope="read"` unless you specifically need to write or delete.
@@ -1,71 +0,0 @@
1
- # Scope Permission Hierarchy and Per-Tool Requirements
2
-
3
- **WRONG:** `memory_add(scope="read", ...)` → PermissionError: requires 'write' or higher.
4
- **WRONG:** `memory_delete_all(scope="write", ...)` → PermissionError: requires 'admin'.
5
-
6
- ## Scope Hierarchy
7
-
8
- ```
9
- admin (level 2) -- can do everything
10
- ↓
11
- write (level 1) -- can read + write, not admin-only
12
- ↓
13
- read (level 0) -- can only read
14
- ```
15
-
16
- Higher scopes include lower scopes. An unrecognized scope string always fails.
17
-
18
- ## Per-Tool Requirements
19
-
20
- ### read scope (9 tools)
21
-
22
- | Tool | Group |
23
- |------|-------|
24
- | `knowledgebase_search` | RAG |
25
- | `memory_search` | Memory |
26
- | `memory_get_by_id` | Memory |
27
- | `memory_get_all` | Memory |
28
- | `flush_pending_memory_candidates` | Memory |
29
- | `conversation_get` | Conversation |
30
- | `conversation_list` | Conversation |
31
- | `datapack_list` | Datapack |
32
- | `datapack_describe` | Datapack |
33
-
34
- ### write scope (9 tools)
35
-
36
- | Tool | Group |
37
- |------|-------|
38
- | `memory_add` | Memory |
39
- | `memory_update` | Memory |
40
- | `memory_delete_by_id` | Memory |
41
- | `conversation_create` | Conversation |
42
- | `conversation_add_message` | Conversation |
43
- | `conversation_update` | Conversation |
44
- | `datapack_create` | Datapack |
45
- | `datapack_update` | Datapack |
46
- | `track_token_usage` | Observability |
47
-
48
- ### admin scope (3 tools — destructive, irreversible)
49
-
50
- | Tool | Group |
51
- |------|-------|
52
- | `memory_delete_all` | Memory |
53
- | `conversation_delete` | Conversation |
54
- | `datapack_delete` | Datapack |
55
-
56
- Agent and knowledge-base lifecycle tools are not MCP-exposed — see "Platform capabilities NOT exposed via MCP" in `tools-overview.md`.
57
-
58
- ## Best Practices
59
-
60
- 1. **Use the minimum scope needed.** `scope="read"` for reads documents intent and prevents accidental writes.
61
- 2. **The scope is a parameter, not an auth token.** When OAuth is enabled, the actual permission check happens against the OAuth token's claims. Both `scope` parameter and OAuth permissions must be satisfied.
62
-
63
- ## Common Mistakes
64
-
65
- **WRONG:** `scope="all"` — there is no "all" scope. Valid values are exactly: `"read"`, `"write"`, `"admin"`. Nothing else.
66
-
67
- Other invalid values that will fail: `"readwrite"`, `"rw"`, `"full"`, `"any"`.
68
-
69
- The error `Insufficient scope: 'all'. This tool requires 'read' or higher.` means the scope string was not recognized as a valid value. Always use one of the three valid strings.
70
-
71
- **Default choice:** Start with `scope="read"` unless you specifically need to write or delete.