@yugabytedb/meko-mcp 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +183 -33
  2. package/assets/hooks-handlers/codex-session-end.sh +13 -0
  3. package/assets/hooks-handlers/cursor-session-start.sh +19 -1
  4. package/assets/hooks-handlers/lib/capture-notices.js +321 -0
  5. package/assets/hooks-handlers/lib/capture-state.js +2079 -0
  6. package/assets/hooks-handlers/lib/capture-status-cli.js +82 -0
  7. package/assets/hooks-handlers/lib/capture.js +1653 -225
  8. package/assets/hooks-handlers/lib/checkpoint-timer.js +455 -50
  9. package/assets/hooks-handlers/lib/kiro-handler.js +738 -0
  10. package/assets/hooks-handlers/lib/terminal-handoff.js +418 -0
  11. package/assets/hooks-handlers/session-end.sh +3 -24
  12. package/assets/hooks-handlers/session-start.sh +8 -1
  13. package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
  14. package/assets/scripts/meko-statusline.sh +41 -1
  15. package/assets/scripts/package-desktop-skill.sh +32 -1
  16. package/assets/skills/meko-mcp-tools/SKILL.md +90 -137
  17. package/assets/skills/meko-mcp-tools/references/_sections.md +3 -5
  18. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +31 -28
  19. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
  20. package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
  21. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +69 -49
  22. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -6
  23. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -5
  24. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +29 -92
  25. package/assets/skills/meko-mcp-tools/references/tools-overview.md +42 -40
  26. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +1 -2
  27. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +18 -11
  28. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +10 -9
  29. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +51 -44
  30. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +6 -6
  31. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +34 -25
  33. package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
  34. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +63 -37
  35. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +4 -4
  36. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +19 -22
  37. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +42 -40
  38. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +1 -2
  39. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -17
  40. package/assets/skills/meko-select-datapack-desktop/SKILL.md +31 -21
  41. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
  42. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
  43. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +1 -1
  44. package/bin/create-meko-setup.mjs +93 -16
  45. package/lib/capture-status.mjs +67 -0
  46. package/lib/clients/aliases.mjs +5 -0
  47. package/lib/clients/claude-code.mjs +8 -4
  48. package/lib/clients/claude-desktop.mjs +133 -4
  49. package/lib/clients/codex.mjs +29 -11
  50. package/lib/clients/common.mjs +2 -0
  51. package/lib/clients/cursor.mjs +7 -2
  52. package/lib/clients/index.mjs +2 -0
  53. package/lib/clients/kiro.mjs +705 -0
  54. package/lib/config.mjs +90 -0
  55. package/lib/detect.mjs +7 -2
  56. package/lib/installer.mjs +1 -0
  57. package/lib/migrate/adapters/codex.mjs +490 -0
  58. package/lib/migrate/id.mjs +28 -3
  59. package/lib/migrate/orchestrator.mjs +34 -7
  60. package/lib/migrate.mjs +4 -2
  61. package/lib/prompt.mjs +17 -2
  62. package/lib/url-selection.mjs +55 -0
  63. package/package.json +4 -4
  64. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -71
  65. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -71
package/README.md CHANGED
@@ -1,12 +1,34 @@
1
1
  # Meko Setup Installer
2
2
 
3
- A zero-dependency Node.js CLI that configures [Meko MCP Server](https://mekodata.netlify.app/) for Claude Code, Claude Desktop, Cursor, and OpenAI Codex (CLI + Desktop App) in one command. It registers MCP server settings, configures hook/runtime environment where supported, installs skills support, and validates the setup.
3
+ A zero-dependency Node.js CLI that configures [Meko MCP Server](https://mekodata.netlify.app/) for Claude Code, Claude Desktop, Cursor, OpenAI Codex (CLI + Desktop App), and Kiro (IDE + CLI) in one command. It registers MCP server settings, configures hook/runtime environment where supported, installs skills support, and validates the setup.
4
4
 
5
5
  Reduces manual setup to a single command.
6
6
 
7
+ ## What this installer authenticates with
8
+
9
+ The installer configures **API-key authentication only**. Every supported
10
+ client sends `Authorization: Bearer <your-api-key>` on the wire, plus the
11
+ `User-Agent` the Cloud WAF requires. Most adapters store the header value in
12
+ client config. Codex stores `bearer_token_env_var = "MEKO_API_KEY"` and resolves
13
+ the key from its runtime environment; Claude Desktop passes the same variable
14
+ through `mcp-remote` header interpolation.
15
+
16
+ Cloud Meko also accepts a browser **OAuth** flow, but that path is out of scope
17
+ here: you turn it on inside a client's own UI, and it uses no API key. Don't
18
+ configure both against the same client — see [Two authentication
19
+ modes](../README.md#two-authentication-modes--pick-one-dont-mix-them) for the
20
+ comparison and the failure modes, including why OAuth isn't currently usable from
21
+ clients that register a loopback callback.
22
+
23
+ **Note:** The server accepts the key only as `Authorization: Bearer …` on the
24
+ wire. An `API_KEY` or `MEKO_API_KEY` environment variable does nothing unless
25
+ the client config references it. The installer creates that reference for
26
+ Codex and Claude Desktop; installer-managed capture hooks also read
27
+ `MEKO_API_KEY` when they send data directly.
28
+
7
29
  ## Prerequisites
8
30
 
9
- - **Node.js 18 or newer** on your PATH. Get it from [nodejs.org](https://nodejs.org/) or via a version manager (`nvm`, `fnm`, `asdf`). `npx`, which comes bundled with Node, is how you invoke the installer.
31
+ - **Node.js 20.18.1 or newer** on your PATH. Get it from [nodejs.org](https://nodejs.org/) or via a version manager (`nvm`, `fnm`, `asdf`). `npx`, which comes bundled with Node, is how you invoke the installer. (The Claude Desktop `mcp-remote` bridge depends on `undici@^7`, whose every release declares `engines.node >= 20.18.1`; the installer enforces that exact floor so the bridge can start.)
10
32
 
11
33
  ## Quick Start
12
34
 
@@ -62,7 +84,7 @@ You can also combine both: install via `.mcpb` for the MCP wiring, then run Opti
62
84
  4. Quit and relaunch Claude Desktop.
63
85
  5. Verify in chat: *"Is Claude configured with an MCP Server for Meko?"*
64
86
 
65
- Prerequisite: Node 18+ on `PATH` (the bundle launches `npx mcp-remote` under the hood). See [`mcpb/README.md`](../mcpb/README.md) for what's in the bundle.
87
+ Prerequisite: Node 20.18.1+ on `PATH` (the bundle launches `npx mcp-remote` under the hood). See [`mcpb/README.md`](../mcpb/README.md) for what's in the bundle.
66
88
 
67
89
  **Option B — `create-meko-setup` installer:**
68
90
 
@@ -98,7 +120,7 @@ Re-run the installer to refresh the bundles when skill content updates; you'll n
98
120
  # Target two clients in one run:
99
121
  npx @yugabytedb/meko-mcp --client claude-code,claude-desktop --local --yes
100
122
 
101
- # Target every supported client (claude-code, claude-desktop, cursor):
123
+ # Target every supported client (claude-code, claude-desktop, cursor, codex, kiro):
102
124
  npx @yugabytedb/meko-mcp --client all --local --yes
103
125
  ```
104
126
 
@@ -108,7 +130,7 @@ Each client is installed sequentially. A failure on one does not abort the other
108
130
 
109
131
  ```bash
110
132
  npx @yugabytedb/meko-mcp \
111
- --url https://your-mcp.mekodev.com/mcp \
133
+ --url https://mcp.mekodata.ai/mcp \
112
134
  --api-key "$MEKO_API_KEY" \
113
135
  --yes
114
136
  ```
@@ -121,7 +143,7 @@ The installer performs up to 5 steps (some are skippable via flags):
121
143
  |------|--------|------------------------|
122
144
  | 1 | Register MCP server | `claude mcp add meko <url> --transport http --scope user` (with `-H "Authorization: Bearer <key>"` for cloud) |
123
145
  | 2 | Set hook environment vars | Writes `MEKO_MCP_URL` and `MEKO_API_KEY` into `~/.claude/settings.json` under the `env` key. Also prunes any stale Meko hook entries in `settings.json.hooks` that point at a prior install path (e.g. a previous `npx` cache or homebrew-global copy) so only the current install's hooks fire. |
124
- | 3 | Register plugin marketplace | `claude plugin marketplace add yugabyte/meko-mcp-server --scope user` |
146
+ | 3 | Register public plugin marketplace | `claude plugin marketplace add https://github.com/yugabyte/meko-skills.git --scope user` |
125
147
  | 4 | Install skills plugin | `claude plugin install meko-agent-skills --scope user` |
126
148
  | 5 | Validate setup | Config check via `claude mcp list`, MCP `initialize` handshake, `tools/list` verification, and a canary `datapack_list` call |
127
149
 
@@ -159,9 +181,16 @@ The canary used to do a `memory_add` → `memory_get_by_id` → `memory_delete_b
159
181
  ```
160
182
  This is **scoped to the Meko server block only** — it affects requests Codex makes to the Meko MCP server and nothing else (other MCP servers, other Codex traffic are untouched). The installer **merges** rather than clobbers: it reads whatever headers you already have — in either the inline `http_headers = { … }` form or the table form `[mcp_servers.meko.http_headers]` — keeps every one of them, and only *adds* a `User-Agent` if you don't already have one (a custom User-Agent is left exactly as you set it). If you had the table form, it's folded into the single inline line so there's never a conflicting duplicate definition. This holds **across a reinstall** too: re-registration deletes and rewrites the whole server block, so the installer snapshots your headers beforehand and merges them back. It **backs up `config.toml` to `config.toml.bak`** before writing. Local installs skip this (no WAF in front of `localhost`). Related: the capture-hook side of the same WAF issue is [#174](https://github.com/yugabyte/meko-mcp-server/issues/174).
161
183
  - **No project scope**: Codex has no per-project config. `--scope project --client codex` warns and degrades to user scope.
162
- - **Auto-capture hooks**: when Codex hooks are available, the installer copies the Meko hook scripts to `~/.codex/meko-hooks/hooks-handlers/`, writes Meko lifecycle hooks to `~/.codex/hooks.json` pointing at that copy, and prunes stale Meko hook entries from deleted install paths. The scripts live under `$CODEX_HOME` (not the shipped package) on purpose: under `npx @yugabytedb/meko-mcp` the package unpacks into an ephemeral `~/.npm/_npx/<hash>/` cache dir that npx later garbage-collects, so a `hooks.json` pinned there would become a dangling `bash '<missing>'` and Codex would report `SessionStart hook (failed) — hook exited with code 127`. Copying under `$CODEX_HOME` gives the hook a home-dir-stable target; re-running the installer refreshes the copy and auto-heals any stale npx-pinned entry. `memory_search` still handles recall; capture is driven by the hooks (and, where hooks are unavailable, by AGENTS.md-prompted per-turn `conversation_add_message` posting that the server extracts memories from). Explicit `memory_add` is reserved for the narrow cases — the user says "remember this", a fact lives only in the assistant's output or a tool result, or a negated/corrected fact needs overwriting.
184
+ - **Auto-capture hooks**: the installer copies the Meko hook scripts to `~/.codex/meko-hooks/hooks-handlers/`, writes Meko lifecycle hooks to `~/.codex/hooks.json` pointing at that copy, and prunes stale Meko hook entries from deleted install paths. The scripts live under `$CODEX_HOME` (not the shipped package) on purpose: under `npx @yugabytedb/meko-mcp` the package unpacks into an ephemeral `~/.npm/_npx/<hash>/` cache dir that npx later garbage-collects, so a `hooks.json` pinned there would become a dangling `bash '<missing>'` and Codex would report `SessionStart hook (failed) — hook exited with code 127`. Copying under `$CODEX_HOME` gives the hook a home-dir-stable target; re-running the installer refreshes the copy and auto-heals any stale npx-pinned entry. `memory_search` still handles recall; capture is driven by the hooks (and, where hooks are unavailable, by AGENTS.md-prompted per-turn `conversation_add_message` posting that the server extracts memories from). Explicit `memory_add` is reserved for the narrow cases — the user says "remember this", a fact lives only in the assistant's output or a tool result, or a negated/corrected fact needs overwriting.
163
185
  - **API key storage** (security note): Codex's hooks.json schema rejects a top-level `env` block and provides no per-command env field. The installer writes `MEKO_MCP_URL` and (when supplied) `MEKO_API_KEY` to `~/.codex/meko-env.sh` at mode 0600 (user read/write only); each hook's `command` field sources that file before invoking bash, e.g. `. '/Users/you/.codex/meko-env.sh' && bash '/Users/you/.codex/meko-hooks/hooks-handlers/session-start.sh'`. The key never appears in process arguments, so `ps -ef` from another user can't lift it while a hook is running. Trust boundary is the same as `~/.aws/credentials` or `~/.netrc` — file-system permissions on the user's home directory. If your threat model precludes even that, install for the local Meko URL (no API key prompt), or skip hook installation by deleting the Meko entries from `~/.codex/hooks.json` and removing `~/.codex/meko-env.sh` and `~/.codex/meko-hooks/` after install.
164
186
  - **Restart Codex.app** after install so it picks up the new MCP server registration.
187
+ - **Kiro (IDE + `kiro-cli`)** — one install configures both surfaces (they share the same config tree). `$KIRO_HOME` overrides the global root, matching how Kiro resolves every global surface.
188
+ - MCP config: `~/.kiro/settings/mcp.json` or `.kiro/settings/mcp.json`. Registered as a native remote server (`url` + `headers`), never via the `mcp-remote` stdio bridge. Because the file contains the bearer token, the adapter writes and reasserts mode 0600 — see [Kiro notes](#kiro-notes).
189
+ - Skills path: `~/.kiro/skills` or `.kiro/skills`. Kiro implements the same [Agent Skills](https://agentskills.io) standard our skills ship in, so they install by copy with no conversion. Packaged installs copy rather than symlink back into the ephemeral npm cache.
190
+ - Standalone hooks: `~/.kiro/hooks/meko-{session-start,user-prompt-submit,stop}.json` or the project equivalents, covering CLI 3.x and trusted IDE workspaces.
191
+ - Managed CLI 2.x agent: `~/.kiro/agents/meko-default.json` or `.kiro/agents/meko-default.json`, with inline `agentSpawn`, `userPromptSubmit`, and `stop` hooks. The installer preserves the previous `chat.defaultAgent` before selecting it.
192
+ - Stable capture runtime: `~/.kiro/hooks/meko-hooks/hooks-handlers/` or the project equivalent. `kiro-hook-env.json` stores the endpoint and optional API key at mode 0600.
193
+ - Steering file: `~/.kiro/steering/meko.md` or `.kiro/steering/meko.md`. It follows hook capture when the session-start marker is present and falls back to agent-driven persistence only when hooks are disabled, untrusted, or a different CLI 2.x agent is selected. See [Kiro notes](#kiro-notes).
165
194
 
166
195
  ## CLI Reference
167
196
 
@@ -172,8 +201,8 @@ Usage:
172
201
 
173
202
  | Flag | Description | Default |
174
203
  |------|-------------|---------|
175
- | `--client <list>` | Target client(s): one or more of `claude-code`, `claude-desktop`, `cursor`, `codex`. Comma-separated, or `all`. `codex` covers both the OpenAI Codex CLI and the Codex Desktop App (they share `~/.codex/config.toml`). | `claude-code` |
176
- | `--url <url>` | MCP server URL (from app.mekodev.com > Datapacks > Connect) | _(interactive prompt)_ |
204
+ | `--client <list>` | Target client(s): one or more of `claude-code`, `claude-desktop`, `cursor`, `codex`, `kiro`. Comma-separated, or `all`. `codex` covers both the OpenAI Codex CLI and the Codex Desktop App (they share `~/.codex/config.toml`); `kiro` covers both the Kiro IDE and `kiro-cli` (they share `~/.kiro/settings/mcp.json`). Aliases: `claude` → `claude-code`, `kiro-cli` / `kiro-ide` → `kiro`. | `claude-code` |
205
+ | `--url <url>` | MCP server URL (from cloud.mekodata.ai > Datapacks > Connect) | Shared existing endpoint, otherwise production; conflicts prompt or require `--url` under `--yes` |
177
206
  | `--api-key <key>` | API key for Cloud Meko authentication. If a Cloud `--url` is supplied without this flag, the installer falls back to `$MEKO_API_KEY`, then to an interactive prompt on a TTY. Only fails hard when running under `--yes` or with no TTY attached. | _(interactive prompt or `$MEKO_API_KEY` env)_ |
178
207
  | `--local` | Use local Meko at `http://localhost:8000/mcp` (no API key needed) | `false` |
179
208
  | `--scope <scope>` | Config scope: `user` or `project` (`claude-desktop` uses user scope config) | `user` |
@@ -189,6 +218,13 @@ Usage:
189
218
  | `-h`, `--help` | Show help message | |
190
219
  | `-v`, `--version` | Show version | |
191
220
 
221
+ Capture health flags (durable outbox / recovery — Capture V2):
222
+
223
+ | Flag | Description | Default |
224
+ |------|-------------|---------|
225
+ | `--capture-status` | Report aggregate conversation-capture health from `~/.claude/meko-capture` (or `MEKO_WATERMARK_DIR`). Exit `0` = healthy\|catching_up, `2` = degraded_retrying, `3` = blocked_action_required. | `false` |
226
+ | `--json` | With `--capture-status`, print machine-readable JSON matching the capture-health cache shape. | `false` |
227
+
192
228
  Migrate subcommand flags (see [Migrate Existing Data](#migrate-existing-data) below for details):
193
229
 
194
230
  | Flag | Description | Default |
@@ -338,28 +374,66 @@ memory errs: 0 (failed memory_add calls; re-run with --force to
338
374
 
339
375
  ## Client Compatibility Matrix
340
376
 
341
- | Capability | Claude Code | Claude Desktop | Cursor | Codex (CLI + App) |
342
- |---|---|---|---|---|
343
- | One-command install | Yes | Yes | Yes | Yes |
344
- | MCP server registration | via `claude mcp add` | via `claude_desktop_config.json` merge using `mcp-remote` stdio bridge | via `.cursor/mcp.json` merge | via `codex mcp add` (CLI) or direct TOML write (App-only) |
345
- | Backup before config write | `.bak` on `~/.claude/settings.json` | `.bak` on `claude_desktop_config.json` | `.bak` on Cursor config | `.bak` on `~/.codex/config.toml` and `~/.codex/AGENTS.md` |
346
- | Automatic conversation capture | Yes (hooks) | **No** — see [issue #8](https://github.com/amiramm/meko-mcp-server/issues/8) | Yes (native hooks; first SessionStart may pause briefly while creating the Meko conversation) | **No** — Codex has no user-installable hooks; AGENTS.md prompts proactive memory tool calls instead |
347
- | Automatic memory persistence | Yes (hooks + skill) | Skill only (proactive `memory_add`) | Yes (hooks + skill) | Skill + AGENTS.md (proactive `memory_add`) |
348
- | Skill install | Plugin marketplace (automatic) | `.skill` bundle auto-built, user drags into app | Copy into `.cursor/skills` | Copy into `~/.agents/skills/meko-mcp-tools/` |
349
- | Uninstall | Full automatic | MCP entry removed; skill must be removed manually from app | MCP + hooks + skills cleaned up | MCP entry, skill dir, and AGENTS.md block all cleaned up |
377
+ | Capability | Claude Code | Claude Desktop | Cursor | Codex (CLI + App) | Kiro (IDE + `kiro-cli`) |
378
+ |---|---|---|---|---|---|
379
+ | One-command install | Yes | Yes | Yes | Yes | Yes |
380
+ | MCP server registration | via `claude mcp add` | via `claude_desktop_config.json` merge using `mcp-remote` stdio bridge | via `.cursor/mcp.json` merge | via `codex mcp add` (CLI) or direct TOML write (App-only) | via `~/.kiro/settings/mcp.json` merge (native remote MCP) |
381
+ | Backup before config write | `.bak` on `~/.claude/settings.json` | `.bak` on `claude_desktop_config.json` | No `.bak` — additive JSON writes preserve unrelated MCP servers, hooks, and settings | `.bak` on `~/.codex/config.toml` and `~/.codex/AGENTS.md` | No `.bak` — the write is an additive merge that preserves other `mcpServers` entries |
382
+ | Automatic conversation capture | Yes (hooks) | **No** — see [issue #8](https://github.com/amiramm/meko-mcp-server/issues/8) | Yes (native hooks; first SessionStart may pause briefly while creating the Meko conversation) | Yes (hooks) — `SessionStart` / `PreCompact` / `SessionEnd` written to `~/.codex/hooks.json`; the AGENTS.md block provides fallback instructions when hooks are unavailable | Yes — inline CLI 2.x plus standalone CLI 3.x/IDE hooks share Capture v2 |
383
+ | Automatic memory persistence | Yes (hooks + skill) | Skill only (proactive `memory_add`) | Yes (hooks + skill) | Hooks + skill; AGENTS.md fallback when hooks are unavailable | Hooks + skill; conditional steering fallback when the hook marker is absent |
384
+ | Skill install | Plugin marketplace (automatic) | `.skill` bundle auto-built, user drags into app | Copy into `.cursor/skills` | Copy into `~/.agents/skills/meko-mcp-tools/` | Copy into `~/.kiro/skills/` (native Agent Skills format) |
385
+ | Uninstall | Full automatic | MCP entry removed; skill must be removed manually from app | MCP + hooks + skills cleaned up | MCP entry, skill dir, and AGENTS.md block all cleaned up | MCP entry plus installer-owned hooks, managed agent, private env, skills, and steering; pending outbox data is preserved |
386
+ | `agent_id` used by skill | `claude_code:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `claude_desktop` | `cursor:<repo>` per project (via Cursor hook); cross-project facts go to `meko_agent` | `codex:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `kiro:<repo>` per project via hook capture; cross-project facts go to `meko_agent` |
387
+ | Transport | HTTP only | HTTP (or stdio via hand-edited config) | HTTP only | HTTP (Codex's `bearer_token_env_var` model) | HTTP only |
388
+ | Auth model | inline `Authorization: Bearer ...` header | inline header via `mcp-remote` | inline header | MCP server: env-var name reference (`MEKO_API_KEY` exported in shell or via `launchctl setenv`). Hooks: key written to `~/.codex/meko-env.sh` at mode 0600; each hook command sources the file before bash (no env block in Codex's hooks schema; see [Security](#security)). | inline `Authorization: Bearer ...` header (never `mcp-remote` — see note below) |
389
+ | Project scope | Yes (`--scope project`) | No | Yes (`--scope project`) | No (warns and degrades to user scope) | Yes (`--scope project`) |
390
+ | Deferred to a follow-up | — | `.mcpb` Desktop Extension packaging — see [issue #7](https://github.com/amiramm/meko-mcp-server/issues/7) | — | — | Tool-call/hidden-reasoning capture (not exposed by Kiro hook events) |
350
391
 
351
392
  Cursor previously had a hybrid hook mode that also wrote Claude-compatible hooks into `~/.claude/settings.json`. If you used that mode and now see duplicate `claude_code:*` Meko instructions in Cursor, remove the old Meko hook entries from `~/.claude/settings.json` unless you still use them for Claude Code.
352
- | `agent_id` used by skill | `claude_code:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `claude_desktop` | `cursor:<repo>` per project (via Cursor hook); cross-project facts go to `meko_agent` | Whatever the agent derives by following the meko-mcp-tools skill (no hook injects an agent_id; the AGENTS.md block defers to the skill) |
353
- | Transport | HTTP only | HTTP (or stdio via hand-edited config) | HTTP only | HTTP (Codex's `bearer_token_env_var` model) |
354
- | Auth model | inline `Authorization: Bearer ...` header | inline header via `mcp-remote` | inline header | MCP server: env-var name reference (`MEKO_API_KEY` exported in shell or via `launchctl setenv`). Hooks: key written to `~/.codex/meko-env.sh` at mode 0600; each hook command sources the file before bash (no env block in Codex's hooks schema; see [Security](#security)). |
355
- | Project scope | Yes (`--scope project`) | No | Yes (`--scope project`) | No (warns and degrades to user scope) |
356
- | Deferred to a follow-up | — | `.mcpb` Desktop Extension packaging — see [issue #7](https://github.com/amiramm/meko-mcp-server/issues/7) | — | Native `codex:<repo>` agent_id classification in capture.js |
393
+
394
+ ### Kiro notes
395
+
396
+ **One adapter, both surfaces.** The Kiro IDE and `kiro-cli` read the same `mcpServers` config and the same skills directories, so `--client kiro` configures both. `kiro-cli` and `kiro-ide` are accepted as aliases. `$KIRO_HOME` is honored for the global config tree, matching how Kiro resolves every global surface.
397
+
398
+ **Never use the `mcp-remote` bridge with Kiro.** Kiro speaks remote MCP natively, so the installer registers `{ url, headers }` directly.
399
+
400
+ What is measured, against `https://mcp.mekodata.ai`:
401
+
402
+ - `mcp-remote@0.1.38` reads no auth env var (its only `process.env` reference is `MCP_REMOTE_CONFIG_DIR`), so `MEKO_API_KEY` is never sent; headers come only from `--header`. It therefore connects unauthenticated and begins OAuth.
403
+ - Run directly, it fails at `registerClient` — the DCR POST — with `HTTP 403: Invalid OAuth error response … Raw body: <html>403 Forbidden</html>`. Its source builds `redirect_uri` as `http://${host}:${callbackPort}${callbackPath}`, defaulting to `localhost` and `/oauth/callback`.
404
+ - Sending mcp-remote's exact registration body to `POST /register` reproduces it, and changing **only** the redirect host fixes it: loopback → `403 text/html` from `server: awselb/2.0`; `https://example.com/...` → `201 application/json` from `server: uvicorn`. So the block is at the AWS load balancer, before the app, and keys on the redirect host — not the scheme (`http://example.com` passes) and not the `client_id` (an unregistered one returns a helpful `400 JSON`).
405
+ - Refused redirect hosts: `localhost`, `127.0.0.1`, `0.0.0.0`, RFC1918, `169.254.169.254`. Accepted: public hosts and private-use schemes. (`[::1]` and `127.1` also pass — the rule is not exhaustive.)
406
+ - **This hits the Kiro IDE too, not just `kiro-cli`.** Both start a `http://localhost:<port>/oauth/callback` server, so OAuth fails identically on both surfaces. Verified against the installed IDE: with the installer's headers its MCP log shows `[meko] Connected`; remove the headers and change nothing else and it logs `HTTP 403 ... Raw body: <html>403 Forbidden</html>`, then closes the connection. Don't assume a GUI client is safe — what matters is the callback it registers, not whether it has a window.
407
+
408
+ Confirmed on `kiro-cli` 2.18.1 itself. Its DCR registration is:
409
+
410
+ ```json
411
+ {"client_name":"kiro","redirect_uris":["http://127.0.0.1:56459"],"application_type":"native", ...}
412
+ ```
413
+
414
+ so against Cloud Meko it fails with `Dynamic registration failed: Registration failed: HTTP 403 Forbidden`. Its first `POST /mcp` also goes out with **no `User-Agent`**, which trips a second HTML-403 rule independently. With Mode 1 headers and a valid `mko_tkn_…` key it connects and lists all 23 tools — no OAuth, no 403.
415
+
416
+ Both surfaces are verified against Cloud Meko with a real key. On the **Kiro IDE** (1.0.337), the installer's config produces `[meko] Connected` in its `Kiro - MCP Logs` output. On **`kiro-cli`** (2.18.1) the agent enumerates all 23 tools. The steering file is confirmed to reach the model, not just disk: asked with tools disabled what its Meko steering requires, the agent answered that it must call `memory_add` when the user states a durable fact and that this "explicitly overrides the meko-mcp-tools skill", which assumes capture hooks are running.
417
+
418
+ One naming correction worth knowing, since it has caused confusion: **`Q DEV CLI` is not an OAuth client id.** It is the MCP `initialize` handshake's `clientInfo.name` (`"clientInfo":{"name":"Q DEV CLI","version":"1.0.0"}`); the string appears nowhere in the `kiro-cli` binary's OAuth path, and its actual DCR `client_name` is `kiro`. There is nothing named `Q DEV CLI` to allowlist. See [#277](https://github.com/yugabyte/meko-mcp-server/issues/277).
419
+
420
+ Header auth avoids the OAuth path entirely. `installer/test/clients-kiro.test.mjs` guards this.
421
+
422
+ **Two hook generations coexist.** Kiro 2.18.1 CLI 2.x reads lowercase inline hooks from the selected custom agent, while CLI 3.x and IDE 1.x read [standalone PascalCase hooks](https://kiro.dev/docs/hooks/) from `hooks/`. The installer writes both formats and routes them to one handler. It creates a default-like `meko-default` agent for CLI 2.x, records and selects it, and restores the previous `chat.defaultAgent` on uninstall only when `meko-default` is still selected. Existing files at installer-owned names are treated as user-owned collisions and left untouched.
423
+
424
+ The handler captures the exact user prompt exposed by `UserPromptSubmit`/`userPromptSubmit` and the exact final assistant response exposed by `Stop`/`stop`. Kiro does not expose tool calls or hidden reasoning through these events, so those are outside the capture boundary. Inline and standalone hooks may both deliver the same event; prompt hashes and stable turn IDs deduplicate them, including the initial prompt repeated after `agentSpawn`. If another prompt arrives before Stop, the prior turn receives the standard interrupted-response marker.
425
+
426
+ Events are fsynced to a mode-0600 local JSONL journal before delivery. The handler initializes the shared Capture v2 session on spawn/start, launches a non-blocking drain on each Stop, and starts the normal recovery timer. Create/add failures remain queued; acknowledgements advance only through the existing validated Capture v2 protocol. Kiro's `session_id` is preferred; absent that, host PID plus working directory provides correlation. Project ownership is stable as `kiro:<repo>`, and these sessions appear in the normal `--capture-status` health view.
427
+
428
+ IDE workspace hooks run only in trusted workspaces. The installer does not alter Kiro's trust decision. The steering file is therefore conditional: `MEKO_CAPTURE_SESSION_STARTED` means hooks are active and normal capture rules apply; without it, hooks may be disabled or untrusted, or CLI 2.x may be using another agent, so steering asks the agent to persist turns proactively. The file carries a `Managed by meko installer` marker and is removed only when owned by the installer.
429
+
430
+ Uninstall removes only files carrying installer ownership markers: the three standalone hook files, managed agent, private hook environment/runtime, skills, and steering. It preserves user config and filename collisions, and deliberately leaves the Capture v2 event journal and pending outbox state so recovery can finish after a reinstall.
357
431
 
358
432
  ## Cloud vs Local
359
433
 
360
434
  | | Cloud Meko | Local Meko |
361
435
  |---|-----------|-----------|
362
- | **URL** | Provided by app.mekodev.com > Datapacks > Connect | `http://localhost:8000/mcp` |
436
+ | **URL** | `https://mcp.mekodata.ai/mcp` (or the endpoint shown by cloud.mekodata.ai) | `http://localhost:8000/mcp` |
363
437
  | **Authentication** | Requires `--api-key` or `$MEKO_API_KEY` env var | None |
364
438
  | **MCP registration** | Includes `-H "Authorization: Bearer <key>"` header | No auth header |
365
439
  | **Hook env vars** | Both `MEKO_MCP_URL` and `MEKO_API_KEY` written to settings | Only `MEKO_MCP_URL` written |
@@ -384,6 +458,9 @@ The installer auto-detects cloud vs local based on the URL: any URL containing `
384
458
  - **OpenAI Codex (CLI + Desktop App)**
385
459
  - MCP-server bearer reference — `~/.codex/config.toml` stores `bearer_token_env_var = "MEKO_API_KEY"`, **not** the key itself. The runtime env (shell rc or `launchctl setenv`) supplies the value.
386
460
  - Hook commands — Codex's `~/.codex/hooks.json` schema rejects a top-level `env` block and provides no per-command env field, so the installer writes `MEKO_API_KEY` to `~/.codex/meko-env.sh` at **mode 0600** (user read/write only). Each Meko hook's `command` field sources that file before invoking bash, so the key never appears in process arguments — `ps -ef` from another user can't lift it while the hook runs. Same trust boundary as `~/.aws/credentials` or `~/.netrc` (file-system permissions on the user's home directory). To opt out: install for the local Meko URL (no key prompt), or skip Codex hook installation by deleting the Meko entries from `~/.codex/hooks.json` and removing `~/.codex/meko-env.sh` and `~/.codex/meko-hooks/` after install. The hook scripts themselves are copied to `~/.codex/meko-hooks/hooks-handlers/` (a home-dir-stable location) rather than referenced from the shipped package, so `npx`'s cache garbage-collection can't leave the hook pointing at a deleted script (which would fail with `code 127`).
461
+ - **Kiro (IDE + `kiro-cli`)**
462
+ - API key header — stored in `~/.kiro/settings/mcp.json` (or `.kiro/settings/mcp.json` for project scope) under `mcpServers.<name>.headers.Authorization`. The adapter forces the file to **mode 0600** on registration and removal rewrites.
463
+ - Hook runtime — the endpoint and optional API key are also stored in `kiro-hook-env.json` at **mode 0600** so inline and standalone hooks can authenticate without putting the key in their command strings.
387
464
 
388
465
  **How credentials are protected:**
389
466
 
@@ -396,7 +473,7 @@ The installer auto-detects cloud vs local based on the URL: any URL containing `
396
473
 
397
474
  **Backups:**
398
475
 
399
- Before modifying any config file the installer touches, it creates a `.bak` copy alongside the original (e.g. `~/.claude/settings.json.bak`, `~/.codex/config.toml.bak`, `~/.codex/AGENTS.md.bak`). The merge is additive: existing keys are preserved unless explicitly overridden.
476
+ Adapters that use backup-aware merge helpers create a `.bak` copy alongside the original (for example `~/.claude/settings.json.bak`, `~/.codex/config.toml.bak`, or `~/.codex/AGENTS.md.bak`). The support matrix above lists backup behavior per client. Cursor and Kiro use additive JSON writes but do not create `.bak` files; they preserve unrelated settings and user-owned collisions instead.
400
477
 
401
478
  ## Upgrading
402
479
 
@@ -481,13 +558,13 @@ create-meko-setup --version
481
558
 
482
559
  ### Rollback
483
560
 
484
- If an upgrade breaks something, restore the `.bak` backups the installer wrote before its changes:
561
+ For Claude Code, Claude Desktop, or Codex, restore the relevant `.bak` file written before the change. For example, to restore Claude Code settings:
485
562
 
486
563
  ```bash
487
564
  cp ~/.claude/settings.json.bak ~/.claude/settings.json
488
565
  ```
489
566
 
490
- See the Security section above for the full list of backup locations across Claude Code, Claude Desktop, and Cursor.
567
+ See the Security section above for the exact backup locations. Cursor and Kiro do not write `.bak` files; rerun or uninstall the relevant adapter to remove installer-owned entries while preserving unrelated settings and user-owned files.
491
568
 
492
569
  ## Troubleshooting
493
570
 
@@ -505,6 +582,31 @@ which claude
505
582
  claude --version
506
583
  ```
507
584
 
585
+ ### MCP server `meko` already exists in the user config
586
+
587
+ ```
588
+ [1/4] Failed to register MCP server.
589
+ MCP server meko already exists in the user config
590
+ Install for claude-code failed: MCP server registration failed.
591
+ ```
592
+
593
+ Claude Code's `claude mcp add` refuses to overwrite an existing registration, so a re-run — or a previous install that failed partway through — aborts at step 1. Remove the stale entry, then re-run the installer:
594
+
595
+ ```bash
596
+ claude mcp list # confirm the "meko" entry and which scope it is on
597
+ claude mcp remove meko --scope user # or --scope local / --scope project, matching what `list` showed
598
+ claude mcp list # confirm it is gone
599
+ npx @yugabytedb/meko-mcp@latest # re-run the installer
600
+ ```
601
+
602
+ If `claude mcp remove` errors or you want to edit the file directly, the user-scope config lives at `~/.claude.json` — open it, find the `"mcpServers"` block, and delete the `"meko": { ... }` entry. Claude Desktop and Claude Code keep **separate** configs, so a clean Desktop install does not imply a clean Code install.
603
+
604
+ Logs worth collecting before filing a bug:
605
+
606
+ - **Installer log** — `ls -lt ~/.meko*/logs 2>/dev/null; ls -lt /tmp/meko-installer* 2>/dev/null` — share the newest file.
607
+ - **Claude Code MCP log** (macOS) — `ls -lt ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-meko/ 2>/dev/null` — most recent `*.txt` shows the registration attempt and any stderr from the spawned process.
608
+ - **Current config snippet** — `grep -A 20 '"meko"' ~/.claude.json` — confirms what state Claude Code was in when the install was attempted.
609
+
508
610
  ### Connection refused
509
611
 
510
612
  ```
@@ -533,11 +635,48 @@ The MCP server is enforcing strict Streamable HTTP compliance: clients must adve
533
635
 
534
636
  ### Authentication failure (401 / 403)
535
637
 
536
- ```
638
+ Check the response shape first — it tells you which layer rejected you, and the
639
+ two causes have nothing to do with each other.
640
+
641
+ **A JSON 401 means the server saw your request and refused the credential.**
642
+
643
+ ```output
537
644
  Server returned 401. Verify your API key is correct and has not expired.
538
645
  ```
539
646
 
540
- - Confirm the API key at app.mekodev.com > Datapacks > Connect.
647
+ Work through the API-key checks below.
648
+
649
+ **An HTML 403 means a load balancer rejected the request before it reached the
650
+ server.** You'll see an unparseable error, often wrapped in a JSON parse failure
651
+ because the client expected JSON:
652
+
653
+ ```output
654
+ HTTP 403: Invalid OAuth error response: SyntaxError: Unexpected token '<',
655
+ "<html>..." is not valid JSON. Raw body: <html>403 Forbidden</html>
656
+ ```
657
+
658
+ Three known causes:
659
+
660
+ - **No `User-Agent` header.** The WAF refuses any request without one. Add
661
+ `User-Agent: meko-mcp-installer/1.0`. The installer always does; hand-written
662
+ configs and some native MCP clients don't.
663
+ - **An OAuth callback on a loopback address.** The WAF refuses any `redirect_uri`
664
+ pointing at an internal host, so dynamic client registration fails for any
665
+ client that registers such a callback, including IDEs. Use API-key auth
666
+ instead. Tracked in
667
+ [#277](https://github.com/yugabyte/meko-mcp-server/issues/277).
668
+ - **Message text that looks like a path.** Capture writes containing `../` or
669
+ absolute paths can trip a traversal rule. Tracked in
670
+ [#245](https://github.com/yugabyte/meko-mcp-server/issues/245).
671
+
672
+ **A stale key can surface as the HTML 403, not the JSON 401.** If your key is
673
+ expired, the server returns 401, the client quietly falls back to OAuth, and the
674
+ registration attempt returns the HTML 403. So verify your key before concluding
675
+ that OAuth is broken.
676
+
677
+ API-key checks:
678
+
679
+ - Confirm the API key at cloud.mekodata.ai > Datapacks > Connect.
541
680
  - If using `$MEKO_API_KEY` env var, ensure it is exported in the current shell.
542
681
  - Confirm the key environment matches the URL: PATs minted on `app.mekodev.com` only validate against `mcp.mekodev.com`; PATs minted on `cloud.mekodata.ai` only validate against `mcp.mekodata.ai`.
543
682
  - The installer normalizes API keys (trims surrounding whitespace and a single matching pair of quotes) so a paste with a trailing newline or a literal `"…"` from a `.env` file is fine — but your raw shell variable might still be contaminated. Echo it (`echo "[$MEKO_API_KEY]"`) and check the brackets bracket the key tightly with no extra characters.
@@ -596,7 +735,7 @@ After the installer writes `claude_desktop_config.json`, **quit and relaunch** C
596
735
  ```json
597
736
  "meko": {
598
737
  "command": "npx",
599
- "args": ["-y", "mcp-remote", "<url>", "--transport", "http-only", "--header", "User-Agent:meko-mcp-installer/1.0"]
738
+ "args": ["-y", "mcp-remote@0.1.38", "<url>", "--transport", "http-only", "--header", "User-Agent:meko-mcp-installer/1.0"]
600
739
  }
601
740
  ```
602
741
  If you see a `"url"` field at the top level instead, re-run the installer to rewrite it.
@@ -633,6 +772,17 @@ This reverses installer-managed changes for the selected client:
633
772
 
634
773
  Each step is safe if the component was already removed -- the uninstaller logs a warning and continues.
635
774
 
775
+ ### Claude Desktop: which artifact, and why the UI can't remove it
776
+
777
+ Claude Desktop can be connected to Meko in two different ways, and they are removed differently:
778
+
779
+ - **Config-file server** — the `mcpServers.<name>` entry this installer writes into `claude_desktop_config.json`. Claude Desktop shows it with a **"Local dev"** badge; that badge is just Desktop's label for *any* config-file server, **not** a Meko setting. It is **not** removable from the Desktop UI — remove it with the uninstall flow:
780
+ ```bash
781
+ npx @yugabytedb/meko-mcp --client claude-desktop --uninstall
782
+ ```
783
+ This removes the `mcpServers.<name>` entry (via `removeKeys(..., ['mcpServers.<name>'])`). If you installed under a non-default server name, pass `--name <name>`. Note: running bare `npx @yugabytedb/meko-mcp` re-runs the **install** flow and re-adds the entry — always include `--uninstall`. The uninstall strips only the MCP server entry; the imported Desktop **skill** must still be removed manually via **Settings > Extensions**.
784
+ - **OAuth Connector** — added by URL under **Settings > Connectors**. This is UI-managed and **is** removable directly from the Desktop UI; no CLI needed.
785
+
636
786
  Use `--verbose` for detailed output during uninstall:
637
787
 
638
788
  ```bash
@@ -661,7 +811,7 @@ node installer/bin/create-meko-setup.mjs --uninstall --verbose
661
811
 
662
812
  ### Prerequisites
663
813
 
664
- - Node.js >= 18.0.0 (required for `util.parseArgs` and `node:test`)
814
+ - Node.js >= 20.18.1 (the Claude Desktop `mcp-remote` bridge's `undici@^7` dependency requires it; `util.parseArgs` and `node:test` are also used)
665
815
  - No `npm install` needed -- zero external dependencies
666
816
 
667
817
  ### Project Structure
@@ -714,7 +864,7 @@ npm run test:integration
714
864
 
715
865
  # Cloud round-trip tests (opt-in; regression coverage for MEKO-20).
716
866
  # Requires credentials in the shell:
717
- export MEKO_TEST_CLOUD_URL=https://<your-mcp>.mekodev.com/mcp
867
+ export MEKO_TEST_CLOUD_URL=https://mcp.mekodata.ai/mcp
718
868
  export MEKO_TEST_API_KEY=<your-cloud-api-key>
719
869
  npm run test:integration:cloud
720
870
 
@@ -740,7 +890,7 @@ branch.
740
890
  ### Design Principles
741
891
 
742
892
  - **Zero external dependencies** -- Node.js built-ins only (`fs`, `path`, `readline`, `child_process`, `url`, `http`, `https`, `os`, `node:test`, `node:assert`), matching the pattern of `capture.js`.
743
- - **Non-destructive** -- Creates `.bak` backups before modifying settings.
893
+ - **Non-destructive** -- Preserves unrelated settings and user-owned files, and creates `.bak` backups where the client adapter supports them (see the support matrix).
744
894
  - **Additive merges** -- New env vars are added without overwriting existing unrelated keys.
745
895
  - **Graceful failures** -- Non-critical errors (plugin already exists) warn and continue; only missing prerequisites cause hard failures.
746
896
  - **API key safety** -- Never logged, always redacted in output.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Codex SessionEnd hook.
4
+ #
5
+ # Codex caps SessionEnd hooks at three seconds. The foreground invocation
6
+ # therefore enqueues via the shared terminal-handoff worker and exits
7
+ # immediately with `{}`. The worker drains lifecycle=closing and may retry
8
+ # until MEKO_WORKER_MAX_AGE_SECONDS, leaving the outbox pending afterward.
9
+
10
+ set -u
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
13
+ exec node "$SCRIPT_DIR/lib/terminal-handoff.js" enqueue
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Cursor native SessionStart hook. Cursor only documents context injection from
4
4
  # SessionStart, so this wrapper returns the Meko context synchronously.
5
+ # Also spawns the checkpoint/recovery daemon (same as Claude/Codex) so Cursor
6
+ # sessions get live checkpoints and participate in self-draining recovery.
5
7
 
6
8
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
9
 
@@ -39,4 +41,20 @@ load_cursor_hook_env() {
39
41
  }
40
42
 
41
43
  load_cursor_hook_env
42
- MEKO_HOOK_CLIENT=cursor node "$SCRIPT_DIR/lib/capture.js" session-start
44
+
45
+ HOOK_INPUT="$(cat)"
46
+ TRANSCRIPT_PATH="$(printf '%s' "$HOOK_INPUT" | node -e '
47
+ const d = JSON.parse(require("fs").readFileSync(0,"utf-8"));
48
+ const p = d.transcript_path || (d.hookSpecificInput||{}).transcript_path || "";
49
+ process.stdout.write(p);
50
+ ' 2>/dev/null)"
51
+
52
+ if [ -n "$TRANSCRIPT_PATH" ]; then
53
+ MEKO_LOG_DIR="${MEKO_WATERMARK_DIR:-$HOME/.claude/meko-capture}"
54
+ mkdir -p "$MEKO_LOG_DIR"
55
+ nohup node "$SCRIPT_DIR/lib/checkpoint-timer.js" "$TRANSCRIPT_PATH" \
56
+ </dev/null >/dev/null 2>>"$MEKO_LOG_DIR/timer.log" &
57
+ disown 2>/dev/null || true
58
+ fi
59
+
60
+ printf '%s' "$HOOK_INPUT" | MEKO_HOOK_CLIENT=cursor node "$SCRIPT_DIR/lib/capture.js" session-start