@yugabytedb/meko-mcp
v1.0.8
Published
Single-line installer for Meko MCP Server across Claude and Cursor clients
Readme
Meko Setup Installer
A zero-dependency Node.js CLI that configures Meko MCP Server for Claude Code, Claude Desktop, and Cursor in one command. It registers MCP server settings, configures hook/runtime environment where supported, installs skills support, and validates the setup.
Reduces manual setup to a single command.
Prerequisites
- Node.js 18 or newer on your PATH. Get it from nodejs.org or via a version manager (
nvm,fnm,asdf).npx, which comes bundled with Node, is how you invoke the installer.
Quick Start
The installer is path-agnostic — the three forms below are equivalent. Pick the one that matches how you obtained the code:
| Source | Command |
|---|---|
| npm (no repo clone needed) | npx @yugabytedb/meko-mcp [options] |
| Repo clone, from repo root | node installer/bin/create-meko-setup.mjs [options] |
| Repo clone, from installer/ | node bin/create-meko-setup.mjs [options] |
Claude Desktop install (issue #7) still requires a repo clone — the .skill packaging script isn't bundled. All other clients work from the npm tarball without a checkout.
Interactive (recommended for first-time users):
npx @yugabytedb/meko-mcpThe installer walks you through connection type, URL, API key, and skills installation with guided prompts.
Local one-liner (docker-compose stack already running):
npx @yugabytedb/meko-mcp --local --yesCursor project install (local):
npx @yugabytedb/meko-mcp --client cursor --local --scope project --yesClaude Desktop install (local, from a repo clone):
Claude Desktop supports two install paths — pick one per machine:
Option A — Desktop Extension (.mcpb), one-click. Download meko-<version>.mcpb from the GitHub Releases page and drag it onto Claude Desktop > Settings > Extensions > Install from file. You'll be prompted for your Meko MCP URL and API key in the Settings UI, and that's it. Best for non-technical users. See mcpb/README.md for what's in the bundle. Prerequisite: Node 18+ on PATH (the bundle launches npx mcp-remote under the hood).
Option B — create-meko-setup installer. Use this when you want a scripted / repeatable install, or when you need the .skill bundle built at the same time:
node installer/bin/create-meko-setup.mjs --client claude-desktop --local --yesBuilds a .skill bundle at skills/meko-mcp-tools-desktop.skill. Drag it onto Claude Desktop (or import via Settings > Extensions) once and restart the app. The installer also merges mcpServers.meko into claude_desktop_config.json. If it detects that Meko was previously installed via the .mcpb path (Option A), it flags the entry and prompts before overwriting so you don't end up with two conflicting configs.
Install on multiple clients at once:
# Target two clients in one run:
npx @yugabytedb/meko-mcp --client claude-code,claude-desktop --local --yes
# Target every supported client (claude-code, claude-desktop, cursor):
npx @yugabytedb/meko-mcp --client all --local --yesEach client is installed sequentially. A failure on one does not abort the others — the command exits with status 2 on partial success, 1 on total failure.
CI / non-interactive (Cloud Meko):
npx @yugabytedb/meko-mcp \
--url https://your-mcp.mekodev.com/mcp \
--api-key "$MEKO_API_KEY" \
--yesWhat It Does
The installer performs up to 5 steps (some are skippable via flags):
| Step | Action | Command / File Modified |
|------|--------|------------------------|
| 1 | Register MCP server | claude mcp add meko <url> --transport http --scope user (with -H "Authorization: Bearer <key>" for cloud) |
| 2 | Set hook environment vars | Writes MEKO_MCP_URL and MEKO_API_KEY into ~/.claude/settings.json under the env key |
| 3 | Register plugin marketplace | claude plugin marketplace add yugabyte/meko-mcp-server --scope user |
| 4 | Install skills plugin | claude plugin install meko-agent-skills --scope user |
| 5 | Validate setup | Config check via claude mcp list, MCP initialize handshake, tools/list verification |
Files modified (depends on --client):
- Claude Code
~/.claude/settings.json-- env vars (MEKO_MCP_URL,MEKO_API_KEY) that lifecycle hooks read at runtime.- Claude Code internal config (
~/.claude.json) -- MCP registration and plugin state (managed byclaudeCLI).
- Claude Desktop
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json - Windows:
%USERPROFILE%/AppData/Roaming/Claude/claude_desktop_config.json
- macOS:
- Cursor
- MCP config:
~/.cursor/mcp.jsonor.cursor/mcp.json - Hooks config:
~/.cursor/hooks.jsonor.cursor/hooks.json(native mode) - Skills path:
~/.cursor/skillsor.cursor/skills
- MCP config:
CLI Reference
Usage:
create-meko-setup [options]| Flag | Description | Default |
|------|-------------|---------|
| --client <list> | Target client(s): one or more of claude-code, claude-desktop, cursor. Comma-separated, or all | claude-code |
| --url <url> | MCP server URL (from app.mekodev.com > Datapacks > Connect) | (interactive prompt) |
| --api-key <key> | API key for Cloud Meko authentication | (interactive prompt or $MEKO_API_KEY env) |
| --local | Use local Meko at http://localhost:8000/mcp (no API key needed) | false |
| --scope <scope> | Config scope: user or project (claude-desktop uses user scope config) | user |
| --name <name> | MCP server name in config | meko |
| --cursor-hook-mode <mode> | Cursor hook strategy: native, claude-compat, hybrid | hybrid |
| --skip-skills | Skip plugin marketplace and skills installation (steps 3-4) | false |
| --skip-validation | Skip post-install validation (step 5) | false |
| --dry-run | Show what would be done without making changes | false |
| --uninstall | Remove Meko MCP server, skills, env vars, and marketplace entry | false |
| --verbose | Show detailed output (API keys are always redacted) | false |
| --yes | Accept all defaults, run non-interactively | false |
| -h, --help | Show help message | |
| -v, --version | Show version | |
Migrate subcommand flags (see Migrate Existing Data below for details):
| Flag | Description | Default |
|------|-------------|---------|
| --migrate | Start a detached migration of existing Claude Code + Cursor conversations and CLAUDE.md memories into Meko. | false |
| --with-migrate | With --yes, kick off --migrate at the end of a successful install without prompting. CI-friendly. | false |
| --migrate-status | Print the status of the latest (or --run-id-specified) migration run. | false |
| --migrate-stop | Stop the running migration (SIGTERM, then SIGKILL after 2s). | false |
| --no-extract | Skip memory_add(messages=...) (the Mem0 extractor call). Replay via conversation_create + conversation_add_message only; standalone memory_add(text=...) for CLAUDE.md / memory files still runs. | false |
| --rate <n> | Max concurrent MCP calls during migration. | 4 |
| --force | Ignore a live lockfile or re-ingest already-processed items. | false |
| --run-id <id> | Target a specific run-id for --migrate-status. | (latest run) |
Migrate Existing Data
After installing Meko, --migrate seeds your new datapack with the conversations and memories already on your machine so the first session isn't an empty slate.
What the migrator reads
| Source | Location | Becomes |
|---|---|---|
| Claude Code transcripts | ~/.claude/projects/<slug>/<uuid>.jsonl | One Meko conversation (one Langfuse trace) per session; one paired user↔assistant turn per message pair. |
| Cursor transcripts | ~/.cursor/projects/<name>/agent-transcripts/<uuid>/*.jsonl | Same — one conversation per session, one paired turn per user↔assistant round. |
| User-scope CLAUDE.md | ~/.claude/CLAUDE.md | One memory per top-level # section (agent = claude-code:user). |
| Project-scope CLAUDE.md | <projectCwd>/.claude/CLAUDE.md | One memory per top-level # section (agent = claude-code:<slug>). |
| Indexed project memories | ~/.claude/projects/<slug>/memory/*.md | One memory per file; YAML frontmatter (name, description, type) is preserved in metadata. |
Project cwd is derived by reading the cwd field from a real session file in each slug directory — never by reverse-slugging the directory name, which loses . and - in component names.
What the migrator writes (MCP calls)
Per migrated Claude Code / Cursor session:
conversation_create— once per session. Capturescwd,gitBranch,startedAt, and source agent (claude-codeorcursor) in metadata. Returns theconversation_idused for subsequent calls.conversation_add_message— once per paired user↔assistant turn. Carriesinput,output, andreasoning(thinking blocks + tool-use/tool-result summaries), plus a deterministicseedfor server-side dedup. Fire-and-forget; Meko batches to Langfuse.memory_add(messages=[{role,content},...])— once per paired turn. This invokes Meko's server-side Mem0 extractor (the same pipeline the demo chatbot uses atchatbot.py:177-178) so the migrator seeds structured memories, not just raw transcripts. Skipped entirely under--no-extract.
Per CLAUDE.md / memory directory discovered:
conversation_create— one umbrella "memory-migration" conversation per agent (reused for all MD items under that agent, to satisfy Meko'smemory_addrequirement that memories be associated with a conversation).memory_add(text=...)— once per CLAUDE.md section ormemory/*.mdfile. Uses thetext=form (notmessages=) because the file is already curated memory; no LLM extraction needed.
So a real run exercises both the Langfuse observability surface (1 + 2) and the Mem0 memory surface (3 + 5). --dry-run prints the exact breakdown before you commit:
Dry run:
Claude Code sessions: 94
Cursor sessions: 10
Paired user↔asst turns: 887
Memory items (MD): 14
Planned MCP calls:
conversation_create: 105 ← one per session + one umbrella per memory agent
conversation_add_message: 887 ← one per paired turn (Langfuse)
memory_add (messages=): 887 ← one per paired turn (Mem0 extractor)
memory_add (text=): 14 ← one per CLAUDE.md section / memory file
total: 1893Why the migrator drives memory extraction
The Meko MCP server does not currently auto-extract memories on conversation_add_message (that call only writes to Langfuse). See yugabyte/meko#120 — auto-extraction on the live write path was deferred because of LLM cost, but batch extraction for previously-existing conversations was explicitly endorsed. Until #120 lands, the migrator closes that gap itself by calling memory_add(messages=...) once per paired turn.
--no-extract skips step 3 above, turning migration into conversation-only replay. Use it when you're re-running for any reason other than seeding memories, when extraction cost is a concern, or if / when #120 lands (the migrator will be updated to default to --no-extract then).
Scope
--scope user(default) — every Claude Code and Cursor project on the machine, plus~/.claude/CLAUDE.md, plus every per-project.claude/CLAUDE.mdand indexedmemory/*.mddirectory.--scope project— only sessions whosecwdequalsprocess.cwd(), plus that one project's.claude/CLAUDE.mdand memory directory.
Running
# Plan-only (no HTTP, no fork). Works without --url / --api-key — prints
# session counts, paired-turn counts, and per-tool planned-call totals so
# you can estimate LLM extraction cost before firing a real run.
create-meko-setup --migrate --dry-run --scope user
# Start a real migration; returns immediately with a run-id.
create-meko-setup --migrate --scope user --url https://... --api-key "$MEKO_API_KEY"
# Install + migrate in one command (CI-friendly).
create-meko-setup --url https://... --api-key "$MEKO_API_KEY" --yes --with-migrate
# Watch progress (or pass --run-id <id>).
create-meko-setup --migrate-status
# Stop a long-running migration (SIGTERM, then SIGKILL after 2s).
create-meko-setup --migrate-stop
# Conversation replay only; do not invoke the Mem0 extractor.
create-meko-setup --migrate --scope user --no-extractReading --migrate-status output
run-id: 20260429-000912-74dbe6
status: running (pending → running → done | failed | stopped)
scope: user
started: 2026-04-29T00:09:12.673Z
finished: (in progress)
current: claude-code:-Users-.../meko-test / a2f6a1d6-... (<adapter>:<source-session> / <message-id>)
sessions: 76 / 111 (processed / discovered)
messages: 674
memory pairs: 674 (memory_add from Mem0 extractor)
memory (MD): 0 (memory_add from CLAUDE.md / memory files)
warnings: 0 (non-fatal; run continues)
memory errs: 0 (failed memory_add calls; re-run with --force to retry)| Field | Meaning |
|---|---|
| run-id | Unique ID; also the directory name under ~/.meko/migrate/<run-id>/. |
| status | Terminal states are done, failed, stopped. A running row that hasn't advanced in >30 s may indicate the daemon died — check ~/.meko/migrate/<run-id>/stdout.log. |
| scope | Matches the --scope flag used at start (user or project). |
| started / finished | UTC timestamps. finished shows (in progress) until a terminal state is reached. |
| current | Which source item is being replayed — <adapter>:<source-session> (adapter = claude-code / cursor / memory-md). Becomes stale on done/failed/stopped. |
| sessions | Conversation sessions processed / discovered across all adapters. Climbs during the run. |
| messages | Total messages replayed so far via conversation_add_message. |
| memory pairs | memory_add calls made via the Mem0 extractor path (messages-style input). Usually close to messages when the extractor is enabled. |
| memory (MD) | memory_add calls from CLAUDE.md / memory-file sources (plain-text input). |
| warnings | Non-fatal issues (skipped item, partial parse). Run keeps going. |
| memory errs | memory_add calls that failed. Non-zero means the memory extractor couldn't reach the server or rejected the payload — check the per-run log. Re-run with --force to retry only the failed items. |
Behavior around install
- Interactive install (no
--yes): after a successful install, the installer dry-runs the enumerator, prints how much local data would be migrated, and asksY/n. Declining prints a reminder to run--migratelater. --yeswithout--with-migrate: install succeeds silently and prints a one-line tip pointing atcreate-meko-setup --migrate. No migration is started.--yes --with-migrate: install succeeds, then the detached migration is started automatically. Progress via--migrate-status.
Idempotency, resume, and state
- Per-run logs:
~/.meko/migrate/<run-id>/log.ndjson(one JSON object per line).tail -f | jq .is a reasonable debug loop. - Per-run progress snapshot:
~/.meko/migrate/<run-id>/progress.json(what--migrate-statusreads). - Durable state:
~/.meko/migrate/state.jsontracks per-session checkpoints (conversationId,messagesSent,lastUuid,status) and per-memory content hashes. A re-run skips sessions markeddoneand memories whose body hash is unchanged. A partial session resumes fromlastUuid + 1. - Server-side dedup:
conversation_add_messagegets a deterministicseed = sha256(agentId + ":" + sessionUuid + ":" + messageUuid)so partial-run overlap doesn't create duplicate messages. --forcewipes resume state and re-issues every MCP call (useful for testing or after a server-side wipe).
What does NOT get migrated (v1)
- Slash-command skills, hooks, and
.claude/settings.json— those remain in Claude Code's own config; Meko has no equivalent tool. - Knowledge-base documents — would need an S3 upload path and
knowledgebase_trigger_index_creationwiring. - Transcripts from other coding agents (Aider, Continue.dev, Windsurf, Codex CLI). Claude Code + Cursor only.
user_idis left null on every call (the server fills it from the API key). Multi-user routing is a follow-up.
Client Compatibility Matrix
| Capability | Claude Code | Claude Desktop | Cursor |
|---|---|---|---|
| One-command install | Yes | Yes | Yes |
| MCP server registration | via claude mcp add | via claude_desktop_config.json merge using mcp-remote stdio bridge | via .cursor/mcp.json merge |
| Backup before config write | .bak on ~/.claude/settings.json | .bak on claude_desktop_config.json | .bak on Cursor config |
| Automatic conversation capture | Yes (hooks) | No — see issue #8 | Yes (hybrid hook mode) |
| Automatic memory persistence | Yes (hooks + skill) | Skill only (proactive memory_add) | Yes (hooks + skill) |
| Skill install | Plugin marketplace (automatic) | .skill bundle auto-built, user drags into app | Copy into .cursor/skills |
| Uninstall | Full automatic | MCP entry removed; skill must be removed manually from app | MCP + hooks + skills cleaned up |
| agent_id used by skill | claude_code | claude_desktop | claude_code |
| Transport | HTTP only | HTTP (or stdio via hand-edited config) | HTTP only |
| Deferred to a follow-up | — | .mcpb Desktop Extension packaging — see issue #7 | — |
Cloud vs Local
| | Cloud Meko | Local Meko |
|---|-----------|-----------|
| URL | Provided by app.mekodev.com > Datapacks > Connect | http://localhost:8000/mcp |
| Authentication | Requires --api-key or $MEKO_API_KEY env var | None |
| MCP registration | Includes -H "Authorization: Bearer <key>" header | No auth header |
| Hook env vars | Both MEKO_MCP_URL and MEKO_API_KEY written to settings | Only MEKO_MCP_URL written |
| Infrastructure | Hosted, no local setup needed | Requires docker compose up -d running the Meko stack |
| Use case | Production, team collaboration | Development, testing |
| Flag | --url <url> --api-key <key> | --local |
The installer auto-detects cloud vs local based on the URL: any URL containing localhost or 127.0.0.1 is treated as local (no API key required). All other URLs are cloud and require authentication.
Security
Where credentials are stored:
- API key header -- stored in
~/.claude.json(MCP server config, managed byclaude mcp add). Readable only by the current user. MEKO_API_KEYenv var -- written to~/.claude/settings.jsonso lifecycle hooks can authenticate with the MCP server. This file has standard user-only filesystem permissions.
How credentials are protected:
- The
--verboseflag never prints the actual API key. It always appears as<set>or<not set>. --dry-runmode redacts the key in displayed commands (shown as<set>).- The API key is never logged to stdout or stderr during normal operation.
- Interactive mode uses masked input (echoes
*characters) when prompting for the API key. - The
MEKO_API_KEYenv var fallback means the key does not need to appear in shell history -- set it in your shell profile or CI secrets.
Backups:
Before modifying ~/.claude/settings.json, the installer creates a .bak copy at ~/.claude/settings.json.bak. The merge is additive: existing keys are preserved unless explicitly overridden.
Troubleshooting
Claude Code CLI not found
Claude Code CLI not found.
Install it first: https://docs.anthropic.com/en/docs/claude-code/getting-startedThe claude binary is not installed or not on your PATH. After installing, verify:
which claude
claude --versionConnection refused
Connection refused. Is the MCP server running?
For local Meko, ensure `docker compose up -d` has started the stack.For local setups, confirm the stack is running and the MCP endpoint is accessible:
curl -s http://localhost:8000/mcp -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'Authentication failure (401 / 403)
Server returned 401. Verify your API key is correct and has not expired.- Confirm the API key at app.mekodev.com > Datapacks > Connect.
- If using
$MEKO_API_KEYenv var, ensure it is exported in the current shell. - Re-run the installer interactively to re-enter the key.
Plugin marketplace already registered
This is non-fatal. The installer logs a warning and continues. If you need to force a re-registration, uninstall first (--uninstall) then install again.
Skills plugin already installed
Same as above -- non-fatal. The existing plugin is kept. Use --uninstall followed by a fresh install if you need to update.
Invalid JSON in settings.json
Invalid JSON in ~/.claude/settings.json: ...
Fix the file manually or delete it and re-run the installer.The settings file has been corrupted or hand-edited incorrectly. Restore from the .bak backup:
cp ~/.claude/settings.json.bak ~/.claude/settings.jsonMissing core tools
Missing core tools: memory_search, conversation_create. Found 0 tool(s) total.The MCP server responded but does not expose the expected tools (memory_search, conversation_create, db_summarize_database). This usually means a server version mismatch. Update the MCP server or check which datapack is connected.
DNS lookup failed
DNS lookup failed for host. Check the URL is correct.Verify the MCP URL is spelled correctly and your network can resolve it.
Request timed out
Request timed out after 10s. Is the server running and reachable?The server did not respond within 10 seconds. Check network connectivity, firewall rules, or server health.
Claude Desktop doesn't see the new MCP server
After the installer writes claude_desktop_config.json, quit and relaunch Claude Desktop — it only reads the config on startup. If Desktop shows "Some MCP servers could not be loaded" or the server still doesn't appear:
- Check the
mekoentry is the stdio shape. Claude Desktop rejects the HTTP{ "url": ... }shape with a silent warning. The installer writes the stdio form that wraps the URL with themcp-remotebridge:
If you see a"meko": { "command": "npx", "args": ["-y", "mcp-remote", "<url>", "--transport", "http-only"] }"url"field at the top level instead, re-run the installer to rewrite it. - Validate the config is well-formed JSON:
python3 -m json.tool ~/Library/Application\ Support/Claude/claude_desktop_config.json - Verify
npxis on PATH (the bridge is launched vianpx -y mcp-remote):which npx - Check the Desktop logs at
~/Library/Logs/Claude/mcp.log(macOS) or%APPDATA%\Claude\logs\(Windows) for load errors. - Restore the
.bakbackup if needed:cp ~/Library/Application\ Support/Claude/claude_desktop_config.json.bak ~/Library/Application\ Support/Claude/claude_desktop_config.json
Claude Desktop skill bundle didn't build
The installer runs skills/scripts/package-desktop-skill.sh via bash. If packaging fails:
- Run the script directly to see the error:
bash skills/scripts/package-desktop-skill.sh - Verify
zipis on your PATH (which zip) - The output file
skills/meko-mcp-tools-desktop.skillis gitignored — safe to regenerate
Claude Desktop capture doesn't happen automatically
Expected: Claude Desktop has no SessionStart / PreCompact / SessionEnd hook API, so automatic transcript capture is not yet implemented. The skill tells the agent to proactively call memory_add and conversation_create, but this relies on agent behavior. See issue #8 for the planned automatic-capture work.
Uninstalling
Remove Meko configuration for the selected client:
node installer/bin/create-meko-setup.mjs --client cursor --scope project --uninstallThis reverses installer-managed changes for the selected client:
- Removes MCP registration/config entries
- Removes installer-managed hook/runtime config
- Removes installer-managed skills wiring where applicable
Each step is safe if the component was already removed -- the uninstaller logs a warning and continues.
Use --verbose for detailed output during uninstall:
node installer/bin/create-meko-setup.mjs --uninstall --verboseManual Test Plan
| # | Scenario | Steps | Expected Result |
|---|----------|-------|-----------------|
| M1 | Fresh local install | node installer/bin/create-meko-setup.mjs --local --yes with docker stack running | All 5 steps pass, validation shows 3 green checks |
| M2 | Fresh cloud install | Run interactively, provide Cloud Meko URL + API key | MCP registered with Authorization: Bearer header, env vars set, validation passes |
| M3 | Existing config | Run installer when meko MCP is already registered | Prompts to overwrite; answering No keeps existing config |
| M4 | No claude CLI | Run on a machine without claude in PATH | Exits with error message and install link |
| M5 | Server unreachable | Install with --skip-validation, then re-run without it | Install succeeds; validation warns about connectivity |
| M6 | Uninstall | Run --uninstall after a successful install | MCP removed, env vars removed, plugin removed, marketplace entry removed |
| M7 | Dry run | --local --dry-run --verbose | Shows all planned commands with redacted keys, no files changed on disk |
| M8 | Cloud hooks capture | After cloud install, start a new Claude Code session | SessionStart hook creates conversation via cloud MCP (check watermark in ~/.claude/meko-capture/) |
| M9 | API key redaction | Run with --verbose using a cloud URL and API key | API key appears only as <set>, never as the actual value |
| M10 | Idempotent re-install | Run installer twice with --local --yes | Second run detects existing config, overwrites cleanly, all checks pass |
| M11 | Invoke from repo root | cd <repo> && node installer/bin/create-meko-setup.mjs --client cursor --local --scope user --dry-run --yes | Dry-run succeeds; no path-resolution errors |
| M12 | Invoke from installer/ | cd <repo>/installer && node bin/create-meko-setup.mjs --client cursor --local --scope user --dry-run --yes | Dry-run succeeds (note: --scope project gives different .cursor/... paths because project scope uses cwd — pick a fixed cwd or --scope user to compare byte-for-byte) |
| M13 | Clone-free via npm pack | cd installer && npm pack → npm install -g ./yugabytedb-meko-mcp-*.tgz → from a directory with no repo clone, run create-meko-setup --client cursor --local --scope project --dry-run | Succeeds; asset paths resolve under the globally-installed node_modules/@yugabytedb/meko-mcp/assets/... |
Development
Prerequisites
- Node.js >= 18.0.0 (required for
util.parseArgsandnode:test) - No
npm installneeded -- zero external dependencies
Project Structure
installer/
package.json # @yugabytedb/meko-mcp
bin/
create-meko-setup.mjs # CLI entry point (arg parsing, orchestration)
lib/
installer.mjs # Shared multi-client orchestration
clients/ # Per-client adapters (claude-code/desktop/cursor)
claude-code.mjs # Backward-compatible Claude wrapper
config.mjs # Safe JSON read/merge/write + path helpers
detect.mjs # Claude CLI and existing config detection
logger.mjs # ANSI-colored console output (respects NO_COLOR)
prompt.mjs # Interactive readline prompts (choice, text, secret, yes/no)
validate.mjs # Post-install validation (config, connectivity, tools)
test/
config.test.mjs # Unit tests for JSON merge/read/write
clients.test.mjs # Unit tests for cursor adapter behavior
validate.test.mjs # Unit tests for validation logic
installer.test.mjs # Integration tests for full install flow
fixtures/ # Mock settings files for testsRunning Tests
cd installer
# All tests
node --test test/
# Unit tests only
npm run test:unit
# Integration tests (opt-in; can mutate local config)
npm run test:integration
# Cloud round-trip tests (opt-in; regression coverage for MEKO-20).
# Requires credentials in the shell:
export MEKO_TEST_CLOUD_URL=https://<your-mcp>.mekodev.com/mcp
export MEKO_TEST_API_KEY=<your-cloud-api-key>
npm run test:integration:cloudThe cloud round-trip tests point the installer at a throw-away $HOME via
spawnSync, so the developer's real ~/.claude/settings.json is never
modified. They skip cleanly when either env var is unset.
Design Principles
- Zero external dependencies -- Node.js built-ins only (
fs,path,readline,child_process,url,http,https,os,node:test,node:assert), matching the pattern ofcapture.js. - Non-destructive -- Creates
.bakbackups before modifying settings. - Additive merges -- New env vars are added without overwriting existing unrelated keys.
- Graceful failures -- Non-critical errors (plugin already exists) warn and continue; only missing prerequisites cause hard failures.
- API key safety -- Never logged, always redacted in output.
- NO_COLOR support -- Respects the
NO_COLORenv var to suppress ANSI color codes.
