@jmtrin/kevin-mcp 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +246 -242
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,242 +1,246 @@
1
- <div align="center">
2
-
3
- # ⚡ Kevin MCP — Bridge
4
-
5
- ```
6
- ╔══════════════════════════════════════════════╗
7
- ║ @jmtrin/kevin-mcp 2.0.0 ║
8
- ║ MCP Bridge for Kevin ║
9
- ║ stdio · zero network · WAL ║
10
- ╚══════════════════════════════════════════════╝
11
- ```
12
-
13
- ### Same SQLite, every harness — Kevin via Model Context Protocol
14
-
15
- **Kevin MCP exposes the local `kevin.db` to Claude Code, Codex, Cursor, Windsurf, Gemini CLI and Opencode through one stdio server.**
16
-
17
- ![version](https://img.shields.io/badge/version-2.0.0-blue)
18
- ![node](https://img.shields.io/badge/node-%E2%89%A522.5-green)
19
- ![mcp](https://img.shields.io/badge/MCP-1.30.0-purple)
20
- ![transport](https://img.shields.io/badge/transport-stdio-black)
21
- ![license](https://img.shields.io/badge/license-MIT-lightgrey)
22
-
23
- </div>
24
-
25
- > **No new database. No HTTP. One WAL file, two processes.**
26
-
27
- > **Commonwealth (2.0.0):** same bridge, same WAL, now with `kevin_sources` provenance and sharded OKF v3 support (`014`) — reader walks `knowledge/` shards, writer gated by `okf_write_version`.
28
-
29
- ---
30
-
31
- ## 📖 Contents
32
-
33
- - [Why a Bridge](#-why-a-bridge)
34
- - [Quick start](#-quick-start)
35
- - [Tools (11)](#-tools-11)
36
- - [Reads vs writes — gates](#-reads-vs-writes--gates)
37
- - [Identity & repo scope](#-identity--repo-scope)
38
- - [Provenance](#-provenance)
39
- - [Harnesses](#-harnesses)
40
- - [Architecture](#-architecture)
41
- - [Configuration](#%EF%B8%8F-configuration)
42
- - [Latency budgets](#-latency-budgets)
43
- - [Development](#-development)
44
- - [License](#-license)
45
-
46
- ---
47
-
48
- ## 🤔 Why a Bridge
49
-
50
- OpenCode plugin memory is excellent inside OpenCode. The bridge makes that same ranked recall available to **any MCP host** without a second sync, a server, or a cloud hop.
51
-
52
- | Before | After |
53
- |---|---|
54
- | `kevin.db` only reachable from plugin | `kevin.db` shared via WAL + `busy_timeout=5000` |
55
- | one host | 6 harnesses (Claude Code / Codex / Cursor / Windsurf / Gemini CLI / Opencode) |
56
-
57
- ---
58
-
59
- ## 🚀 Quick start
60
-
61
- ```bash
62
- npx -y @jmtrin/kevin-mcp # ro by default, stderr ready line
63
- npx -y @jmtrin/kevin-mcp --repo 2114ad162af50a25 # pinned repo_id
64
- npx -y @jmtrin/kevin-mcp --help
65
- ```
66
-
67
- ### Claude Code (`~/.claude.json`)
68
-
69
- ```json
70
- {
71
- "mcpServers": {
72
- "kevin-mcp": { "command": "npx", "args": ["-y", "@jmtrin/kevin-mcp"] }
73
- }
74
- }
75
- ```
76
-
77
- ### Codex / Cursor / Windsurf / Gemini CLI
78
-
79
- See `docs/harnesses/{codex,cursor,windsurf,gemini-cli,opencode}.md` for exact JSON/TOML snippets, verification (`npx @jmtrin/kevin-mcp --version`), troubleshooting and uninstall.
80
-
81
- ### How to verify inside a host
82
-
83
- ```
84
- what does Kevin remember about <topic>?
85
- → recall returns results + provenance {repo_id, identity_source, channel:"mcp"}
86
- ```
87
-
88
- ---
89
-
90
- ## 🧰 Tools (11)
91
-
92
- <details open>
93
- <summary><b>Always-on reads (7) + ping</b></summary>
94
-
95
- | Tool | What it does | Ledger |
96
- |---|---|---|
97
- | `ping` | Liveness probe | — |
98
- | `query` | Slim search | — |
99
- | `get` | Fetch one memory | — |
100
- | `recall` | Ranked recall (BM25 × origin × recency → token budget) | `channel='mcp'` injection row, tokens `ceil(chars/4)` |
101
- | `why` | Failure→fix trace via `kevinWhy` | — |
102
- | `status` | `{repo_id, resolved_repo_id, requested_repo_id, gates, counters{requests,reads,writes_accepted/refused}, perf}` | — |
103
- | `trace` | Dry-run injection preview, zero side effects | — |
104
- | `feedback` | Rate a memory `useful/wrong/outdated/ignore` | — |
105
-
106
- Every read returns `provenance: {repo_id, identity_source, channel:"mcp"}` plus confidence/evidence when the underlying row carries them.
107
-
108
- </details>
109
-
110
- <details>
111
- <summary><b>Gated writes (3) — disabled by default</b></summary>
112
-
113
- | Tool | Gate | On refuse |
114
- |---|---|---|
115
- | `save` | `mcp_write_enabled==='1'` | `{error:"disabled", hint:"set mcp_write_enabled=1"}` + `mcp_writes_refused++` |
116
- | `approve` | `mcp_write_enabled==='1'` **and** `mcp_approve_enabled==='1'` | same (`disabled`) |
117
- | `share` | double-gate as `approve` (and existing `share_requires_approval` chain) | `disabled` → `missing_approval_chain` → `executed` |
118
-
119
- On success `mcp_writes_accepted++`. All writes are repo-scoped and funnel through core's single write path.
120
-
121
- </details>
122
-
123
- ---
124
-
125
- ## 🔐 Identity & repo scope
126
-
127
- Repository identity resolves **once** at server init, in order:
128
-
129
- `--repo <id>` (`KEVIN_REPO`) → `kevin_settings.mcp_repo_override` (`setting:mcp_repo_override`) → `RepoIdentity.resolve` (declared → remote hash → path).
130
-
131
- Every tool carries an optional `repo_id` arg; mismatch returns:
132
-
133
- ```json
134
- { "error": "repo_mismatch", "expected": "<server repo_id>", "got": "<caller repo_id>" }
135
- ```
136
-
137
- Declared ids must be 16-char lowercase hex (`/^[0-9a-f]{16}$/`).
138
-
139
- ---
140
-
141
- ## 🧾 Provenance
142
-
143
- ```json
144
- {
145
- "provenance": {
146
- "repo_id": "2114ad162af50a25",
147
- "identity_source": "setting:mcp_repo_override",
148
- "channel": "mcp"
149
- }
150
- }
151
- ```
152
-
153
- When the memory row has confidence/evidence, those fields surface as `confidence`, `evidence_count`, `last_verified_at`.
154
-
155
- ---
156
-
157
- ## 🔌 Harnesses
158
-
159
- | Harness | Recipe | Tested-on |
160
- |---|---|---|
161
- | Claude Code | `docs/harnesses/claude-code.md` | claude-code v1.0.0 |
162
- | Codex | `docs/harnesses/codex.md` | codex v0.5.0 |
163
- | Cursor | `docs/harnesses/cursor.md` | cursor v1.2.0 |
164
- | Windsurf | `docs/harnesses/windsurf.md` | windsurf v1.0 |
165
- | Gemini CLI | `docs/harnesses/gemini-cli.md` | gemini-cli v0.4.0 |
166
- | Opencode | `docs/harnesses/opencode.md` | opencode v1.18.0 |
167
-
168
- Each recipe is a tested JSON/TOML block (parsed by `tests/unit/docs_config_lint.test.ts`), verification command, troubleshooting and uninstall note. Demo: `docs/demo-cross-harness.md` (10-min `▶` script: opencode `save` → Claude Code `recall`).
169
-
170
- ---
171
-
172
- ## ⚙️ Architecture
173
-
174
- ```
175
- plugin (opencode) ─┐
176
- ├─► kevin.db (WAL, busy_timeout=5000) ◄─ kevin-mcp (stdio, SDK 1.30.0)
177
- MCP host (any) ────┘ │ ▲ │
178
- │ └─ kevin_audit mcp block ─┘
179
- └── perf_samples (mcp.read/write)
180
- ```
181
-
182
- - **Zero network** — forbidden list enforced: `node:http/https/net/dgram, fetch, XMLHttpRequest, SSETransport, HttpTransport, child_process/spawn`; only `node:fs/path/os/sqlite`.
183
- - **Logs on stderr only** — `stderr ready repo=... mode=ro|rw db=...`; stdout is MCP JSON only.
184
- - **Lifecycle** — `resolveEnv → Store(busy_timeout) → Migrate(014) → Metrics+Perf → registry`; SIGINT/SIGTERM flush metrics + perf (every 100 req or signal).
185
-
186
- Package layout:
187
-
188
- ```
189
- src/server.ts lifecycle, registry, ready line, signals
190
- src/identity.ts resolution + mismatch guard
191
- src/tools/read.ts 7 reads + ping + provenance helper
192
- src/tools/write.ts 3 gated writes
193
- src/provenance.ts block builder
194
- src/perf-mcp.ts mcp.read/write budgets wrapper
195
- ```
196
-
197
- ---
198
-
199
- ## ⚙️ Configuration
200
-
201
- Text settings via `kevin_config` (compare `=== "1"`):
202
-
203
- | Key | Default | Purpose |
204
- |---|---|---|
205
- | `mcp_write_enabled` | `'0'` | Gate for MCP `save` |
206
- | `mcp_approve_enabled` | `'0'` | Double-gate for MCP `approve`/`share` |
207
- | `mcp_repo_override` | `''` | Override RepoIdentity (hex-16) |
208
-
209
- Plus the 40 core/plugin keys (`C-04` since `2.0.0` → golden 43 settings: `+sources_enabled`, `+source_*×3`, `+okf_write_version`, `-import_host_memory`). `kevin_audit` block `mcp` appears only on schema `013`+; pre-013 omitted (`partial:true`). Channel split counters in `kevin_metrics` + `kevin_injections.channel`.
210
-
211
- ---
212
-
213
- ## ⏱️ Latency budgets
214
-
215
- | Scope | p95 | max |
216
- |---|---|---|
217
- | `mcp.read` | 25 ms | 100 ms |
218
- | `mcp.write` | 50 ms | 250 ms |
219
-
220
- Measured on reference laptop: recall p50 ≈ 0.2ms. Persists to `perf_samples` every 100 requests or SIGINT; `bench:check` enforces.
221
-
222
- ---
223
-
224
- ## 🛠️ Development
225
-
226
- ```bash
227
- npm install -w @jmtrin/kevin-mcp
228
- npm run build -w @jmtrin/kevin-mcp
229
- npm run typecheck -w @jmtrin/kevin-mcp
230
- npx vitest run packages/mcp/tests/purity_scan.test.ts
231
- npm pack --dry-run -w @jmtrin/kevin-mcp
232
- # boot smoke (no stdout, stderr ready):
233
- node packages/mcp/dist/server.js --help
234
- ```
235
-
236
- Monorepo publish order: `core → tui → plugin → mcp` (exact `2.0.0` pin), see `docs/DISTRIBUTION.md`.
237
-
238
- ---
239
-
240
- ## 📄 License
241
-
242
- MIT — see `LICENSE`. Kevin is built by [jmtrin](https://github.com/jmtrin); bug reports and PRs welcome at the [issue tracker](https://github.com/jmtrin/opencode-kevin/issues).
1
+ <div align="center">
2
+
3
+ # ⚡ Kevin MCP — Bridge
4
+
5
+ ```
6
+ ╔══════════════════════════════════════════════╗
7
+ ║ @jmtrin/kevin-mcp 2.2.1 ║
8
+ ║ MCP Bridge for Kevin ║
9
+ ║ stdio · zero network · WAL ║
10
+ ╚══════════════════════════════════════════════╝
11
+ ```
12
+
13
+ ### Same SQLite, every harness — Kevin via Model Context Protocol
14
+
15
+ **Kevin MCP exposes the local `kevin.db` to Claude Code, Codex, Cursor, Windsurf, Gemini CLI and Opencode through one stdio server.**
16
+
17
+ ![version](https://img.shields.io/badge/version-2.2.1-blue)
18
+ ![node](https://img.shields.io/badge/node-%E2%89%A522.5-green)
19
+ ![mcp](https://img.shields.io/badge/MCP-1.30.0-purple)
20
+ ![transport](https://img.shields.io/badge/transport-stdio-black)
21
+ ![license](https://img.shields.io/badge/license-MIT-lightgrey)
22
+
23
+ </div>
24
+
25
+ > **No new database. No HTTP. One WAL file, two processes.**
26
+
27
+ > **Commonwealth (2.0.0):** same bridge, same WAL, now with `kevin_sources` provenance and sharded OKF v3 support (`014`) — reader walks `knowledge/` shards, writer gated by `okf_write_version`.
28
+ >
29
+ > **Relay (2.1.0):** `mcp_write_enabled` / `mcp_approve_enabled` / `mcp_repo_override` settings + 5 `mcp_*` metrics (`013`); gated writes unchanged.
30
+ >
31
+ > **Harbor (2.2.0):** the MCP trio is now seeded by migration `016`, so fresh `kevin_config list` shows all 44 keys — gates and defaults unchanged (`'0'`/`'0'`/`''`).
32
+
33
+ ---
34
+
35
+ ## 📖 Contents
36
+
37
+ - [Why a Bridge](#-why-a-bridge)
38
+ - [Quick start](#-quick-start)
39
+ - [Tools (11)](#-tools-11)
40
+ - [Reads vs writes — gates](#-reads-vs-writes--gates)
41
+ - [Identity & repo scope](#-identity--repo-scope)
42
+ - [Provenance](#-provenance)
43
+ - [Harnesses](#-harnesses)
44
+ - [Architecture](#-architecture)
45
+ - [Configuration](#%EF%B8%8F-configuration)
46
+ - [Latency budgets](#-latency-budgets)
47
+ - [Development](#-development)
48
+ - [License](#-license)
49
+
50
+ ---
51
+
52
+ ## 🤔 Why a Bridge
53
+
54
+ OpenCode plugin memory is excellent inside OpenCode. The bridge makes that same ranked recall available to **any MCP host** without a second sync, a server, or a cloud hop.
55
+
56
+ | Before | After |
57
+ |---|---|
58
+ | `kevin.db` only reachable from plugin | `kevin.db` shared via WAL + `busy_timeout=5000` |
59
+ | one host | 6 harnesses (Claude Code / Codex / Cursor / Windsurf / Gemini CLI / Opencode) |
60
+
61
+ ---
62
+
63
+ ## 🚀 Quick start
64
+
65
+ ```bash
66
+ npx -y @jmtrin/kevin-mcp # ro by default, stderr ready line
67
+ npx -y @jmtrin/kevin-mcp --repo 2114ad162af50a25 # pinned repo_id
68
+ npx -y @jmtrin/kevin-mcp --help
69
+ ```
70
+
71
+ ### Claude Code (`~/.claude.json`)
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "kevin-mcp": { "command": "npx", "args": ["-y", "@jmtrin/kevin-mcp"] }
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Codex / Cursor / Windsurf / Gemini CLI
82
+
83
+ See `docs/harnesses/{codex,cursor,windsurf,gemini-cli,opencode}.md` for exact JSON/TOML snippets, verification (`npx @jmtrin/kevin-mcp --version`), troubleshooting and uninstall.
84
+
85
+ ### How to verify inside a host
86
+
87
+ ```
88
+ what does Kevin remember about <topic>?
89
+ → recall returns results + provenance {repo_id, identity_source, channel:"mcp"}
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 🧰 Tools (11)
95
+
96
+ <details open>
97
+ <summary><b>Always-on reads (7) + ping</b></summary>
98
+
99
+ | Tool | What it does | Ledger |
100
+ |---|---|---|
101
+ | `ping` | Liveness probe | — |
102
+ | `query` | Slim search | — |
103
+ | `get` | Fetch one memory | — |
104
+ | `recall` | Ranked recall (BM25 × origin × recency → token budget) | `channel='mcp'` injection row, tokens `ceil(chars/4)` |
105
+ | `why` | Failure→fix trace via `kevinWhy` | — |
106
+ | `status` | `{repo_id, resolved_repo_id, requested_repo_id, gates, counters{requests,reads,writes_accepted/refused}, perf}` | — |
107
+ | `trace` | Dry-run injection preview, zero side effects | — |
108
+ | `feedback` | Rate a memory `useful/wrong/outdated/ignore` | — |
109
+
110
+ Every read returns `provenance: {repo_id, identity_source, channel:"mcp"}` plus confidence/evidence when the underlying row carries them.
111
+
112
+ </details>
113
+
114
+ <details>
115
+ <summary><b>Gated writes (3) — disabled by default</b></summary>
116
+
117
+ | Tool | Gate | On refuse |
118
+ |---|---|---|
119
+ | `save` | `mcp_write_enabled==='1'` | `{error:"disabled", hint:"set mcp_write_enabled=1"}` + `mcp_writes_refused++` |
120
+ | `approve` | `mcp_write_enabled==='1'` **and** `mcp_approve_enabled==='1'` | same (`disabled`) |
121
+ | `share` | double-gate as `approve` (and existing `share_requires_approval` chain) | `disabled` → `missing_approval_chain` → `executed` |
122
+
123
+ On success `mcp_writes_accepted++`. All writes are repo-scoped and funnel through core's single write path.
124
+
125
+ </details>
126
+
127
+ ---
128
+
129
+ ## 🔐 Identity & repo scope
130
+
131
+ Repository identity resolves **once** at server init, in order:
132
+
133
+ `--repo <id>` (`KEVIN_REPO`) → `kevin_settings.mcp_repo_override` (`setting:mcp_repo_override`) → `RepoIdentity.resolve` (declared → remote hash → path).
134
+
135
+ Every tool carries an optional `repo_id` arg; mismatch returns:
136
+
137
+ ```json
138
+ { "error": "repo_mismatch", "expected": "<server repo_id>", "got": "<caller repo_id>" }
139
+ ```
140
+
141
+ Declared ids must be 16-char lowercase hex (`/^[0-9a-f]{16}$/`).
142
+
143
+ ---
144
+
145
+ ## 🧾 Provenance
146
+
147
+ ```json
148
+ {
149
+ "provenance": {
150
+ "repo_id": "2114ad162af50a25",
151
+ "identity_source": "setting:mcp_repo_override",
152
+ "channel": "mcp"
153
+ }
154
+ }
155
+ ```
156
+
157
+ When the memory row has confidence/evidence, those fields surface as `confidence`, `evidence_count`, `last_verified_at`.
158
+
159
+ ---
160
+
161
+ ## 🔌 Harnesses
162
+
163
+ | Harness | Recipe | Tested-on |
164
+ |---|---|---|
165
+ | Claude Code | `docs/harnesses/claude-code.md` | claude-code v1.0.0 |
166
+ | Codex | `docs/harnesses/codex.md` | codex v0.5.0 |
167
+ | Cursor | `docs/harnesses/cursor.md` | cursor v1.2.0 |
168
+ | Windsurf | `docs/harnesses/windsurf.md` | windsurf v1.0 |
169
+ | Gemini CLI | `docs/harnesses/gemini-cli.md` | gemini-cli v0.4.0 |
170
+ | Opencode | `docs/harnesses/opencode.md` | opencode v1.18.0 |
171
+
172
+ Each recipe is a tested JSON/TOML block (parsed by `tests/unit/docs_config_lint.test.ts`), verification command, troubleshooting and uninstall note. Demo: `docs/demo-cross-harness.md` (10-min `▶` script: opencode `save` → Claude Code `recall`).
173
+
174
+ ---
175
+
176
+ ## ⚙️ Architecture
177
+
178
+ ```
179
+ plugin (opencode) ─┐
180
+ ├─► kevin.db (WAL, busy_timeout=5000) ◄─ kevin-mcp (stdio, SDK 1.30.0)
181
+ MCP host (any) ────┘ │ ▲ │
182
+ │ └─ kevin_audit mcp block ─┘
183
+ └── perf_samples (mcp.read/write)
184
+ ```
185
+
186
+ - **Zero network** — forbidden list enforced: `node:http/https/net/dgram, fetch, XMLHttpRequest, SSETransport, HttpTransport, child_process/spawn`; only `node:fs/path/os/sqlite`.
187
+ - **Logs on stderr only** — `stderr ready repo=... mode=ro|rw db=...`; stdout is MCP JSON only.
188
+ - **Lifecycle** — `resolveEnv → Store(busy_timeout) → Migrate(014) → Metrics+Perf → registry`; SIGINT/SIGTERM flush metrics + perf (every 100 req or signal).
189
+
190
+ Package layout:
191
+
192
+ ```
193
+ src/server.ts lifecycle, registry, ready line, signals
194
+ src/identity.ts resolution + mismatch guard
195
+ src/tools/read.ts 7 reads + ping + provenance helper
196
+ src/tools/write.ts 3 gated writes
197
+ src/provenance.ts block builder
198
+ src/perf-mcp.ts mcp.read/write budgets wrapper
199
+ ```
200
+
201
+ ---
202
+
203
+ ## ⚙️ Configuration
204
+
205
+ Text settings via `kevin_config` (compare `=== "1"`):
206
+
207
+ | Key | Default | Purpose |
208
+ |---|---|---|
209
+ | `mcp_write_enabled` | `'0'` | Gate for MCP `save` |
210
+ | `mcp_approve_enabled` | `'0'` | Double-gate for MCP `approve`/`share` |
211
+ | `mcp_repo_override` | `''` | Override RepoIdentity (hex-16) |
212
+
213
+ Plus the 40 core/plugin keys (`C-04` since `2.0.0` → golden 43 settings: `+sources_enabled`, `+source_*×3`, `+okf_write_version`, `-import_host_memory`). `kevin_audit` block `mcp` appears only on schema `013`+; pre-013 omitted (`partial:true`). Channel split counters in `kevin_metrics` + `kevin_injections.channel`.
214
+
215
+ ---
216
+
217
+ ## ⏱️ Latency budgets
218
+
219
+ | Scope | p95 | max |
220
+ |---|---|---|
221
+ | `mcp.read` | 25 ms | 100 ms |
222
+ | `mcp.write` | 50 ms | 250 ms |
223
+
224
+ Measured on reference laptop: recall p50 ≈ 0.2ms. Persists to `perf_samples` every 100 requests or SIGINT; `bench:check` enforces.
225
+
226
+ ---
227
+
228
+ ## 🛠️ Development
229
+
230
+ ```bash
231
+ npm install -w @jmtrin/kevin-mcp
232
+ npm run build -w @jmtrin/kevin-mcp
233
+ npm run typecheck -w @jmtrin/kevin-mcp
234
+ npx vitest run packages/mcp/tests/purity_scan.test.ts
235
+ npm pack --dry-run -w @jmtrin/kevin-mcp
236
+ # boot smoke (no stdout, stderr ready):
237
+ node packages/mcp/dist/server.js --help
238
+ ```
239
+
240
+ Monorepo publish order: `core → tui → plugin → mcp` (exact `2.2.1` pin), see `docs/DISTRIBUTION.md`.
241
+
242
+ ---
243
+
244
+ ## 📄 License
245
+
246
+ MIT — see `LICENSE`. Kevin is built by [jmtrin](https://github.com/jmtrin); bug reports and PRs welcome at the [issue tracker](https://github.com/jmtrin/opencode-kevin/issues).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmtrin/kevin-mcp",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "Kevin MCP — stdio bridge for any MCP harness (Bridge)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "prepublishOnly": "npm run build"
22
22
  },
23
23
  "dependencies": {
24
- "@jmtrin/kevin-core": "2.1.0",
24
+ "@jmtrin/kevin-core": "2.2.1",
25
25
  "@modelcontextprotocol/sdk": "1.30.0",
26
26
  "zod": "^3.25.0"
27
27
  },