compendium-mcp 0.2.0 → 0.6.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.
- package/README.md +41 -34
- package/npm/lib/platform.js +54 -2
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -101,9 +101,9 @@ Single MCP tool: **`compendium`**. Choose the operation with `action`:
|
|
|
101
101
|
|
|
102
102
|
| `action` | Purpose | Main fields |
|
|
103
103
|
|----------|---------|-------------|
|
|
104
|
-
| `filter` | Strip ANSI, boilerplate, whitespace; densify JSON; keep/drop regexes | `text`, `filter` |
|
|
105
|
-
| `compress` | Dense representation of text/code/logs | `text`, `compress` |
|
|
106
|
-
| `compress_output` | Domain-aware stdout/stderr scrub (git, cargo, npm, docker, …) | `text`, `output` |
|
|
104
|
+
| `filter` | Strip ANSI, boilerplate, whitespace; densify JSON; keep/drop regexes | `text`, `filter` — not for cargo/npm dumps (`compress_output`) |
|
|
105
|
+
| `compress` | Dense representation of text/code/logs | `text`, `compress` — soft inputs under ~1000 chars bypass unless `force` |
|
|
106
|
+
| `compress_output` | Domain-aware stdout/stderr scrub (git, cargo, npm, docker, …) | `text`, `output` — prefer when CLI domain is known |
|
|
107
107
|
| `summarize` | Hierarchical summary (conversation / file tree / outline) | `text`, `summarize` |
|
|
108
108
|
| `summarize_smart` | Local-SLM dense summary (heuristic fallback if unset/fails) | `text`, `smart?`, `summarize?` |
|
|
109
109
|
| `filter_relevant` | Query-aware keep of relevant lines (local SLM + heuristic fallback) | `text`, `query`, `smart?` |
|
|
@@ -111,20 +111,20 @@ Single MCP tool: **`compendium`**. Choose the operation with `action`:
|
|
|
111
111
|
| `chunk` | Split into `cmp://` chunks (session-cached) | `text`, `chunk` |
|
|
112
112
|
| `resolve` | Fetch chunk content by id | `id` (+ optional `map` / `text`) |
|
|
113
113
|
| `count_tokens` | Measure tokens | `text` |
|
|
114
|
-
| `stats` | Session savings + latency/bypass/backend telemetry | `reset?` |
|
|
114
|
+
| `stats` | Session savings + latency/bypass/backend telemetry | `reset?` — see playbook `stats-debug` |
|
|
115
115
|
| `cache_store` | Park bulky payload outside the prompt | `text`, `cache` |
|
|
116
116
|
| `cache_get` | Retrieve by key | `key` |
|
|
117
117
|
| `cache_invalidate` | Drop one key or clear cache | `key?` |
|
|
118
|
-
| `sanitize` | Redact secrets + neutralize IPI phrases | `text`, `sanitize?` |
|
|
119
|
-
| `rerank` | BM25 (+ optional loopback embeddings) rank candidates / chunks | `query`, `items` or `text` or chunk `map`, `rerank?` |
|
|
118
|
+
| `sanitize` | Redact secrets + neutralize IPI phrases | `text`, `sanitize?` — or `sanitize_input` |
|
|
119
|
+
| `rerank` | BM25 (+ optional loopback embeddings + opt-in SLM cross-encoder) rank candidates / chunks | `query`, `items` or `text` or chunk `map`, `rerank?` |
|
|
120
120
|
| `brief` | Scan a workspace; pack a structured starter briefing + cache key | `query`, `brief?` (`root`, caps), optional `text` hint |
|
|
121
|
-
| `catalog` | Short action (+ playbook) ads; prefer before guessing | _(none)_ |
|
|
121
|
+
| `catalog` | Short action (+ playbook) ads; prefer before guessing | _(none)_ — call first when unsure |
|
|
122
122
|
| `help` | Usage notes for one action (default **compressed**; `force: true` → full) | `id`, `force?` |
|
|
123
123
|
| `playbooks` | List playbook ads | _(none)_ |
|
|
124
124
|
| `playbook` | Load one playbook body | `id` |
|
|
125
125
|
| `pack` | Zip text/files into a bounded archive | `text` or `items`, `pack?` |
|
|
126
126
|
| `unpack` | Unpack zip with size caps into chunks (never runs scripts) | `text` or `key`, `pack?` |
|
|
127
|
-
| `llm_status` | Probe configured local LLM (models; `force` = chat ping) | `force?` |
|
|
127
|
+
| `llm_status` | Probe configured local LLM (models; `force` = chat ping) | `force?` — when smart/hybrid unexpectedly heuristic |
|
|
128
128
|
|
|
129
129
|
### Progressive disclosure (skills)
|
|
130
130
|
|
|
@@ -162,22 +162,24 @@ Response envelope: `{ "ok": true, "action": "filter", "result_json": "{...}" }`.
|
|
|
162
162
|
assets/ # brand mark (SVG/PNG); baked into MCP icons via data URI
|
|
163
163
|
docs/ # architecture notes
|
|
164
164
|
examples/ # sample MCP tool-call JSON payloads
|
|
165
|
+
testdata/ # eval fixtures (noisy logs, cargo fail, …)
|
|
165
166
|
src/
|
|
166
167
|
main.rs # CLI: stdio | http
|
|
167
168
|
lib.rs
|
|
168
169
|
brand.rs # SEP-973 icons for serverInfo + tool
|
|
169
170
|
config.rs # COMPENDIUM_* env config
|
|
170
|
-
server
|
|
171
|
+
server/ # MCP tool + resources + action handlers (rmcp)
|
|
171
172
|
http.rs # Streamable HTTP/SSE (feature = "http")
|
|
172
173
|
pipeline/
|
|
174
|
+
brief/ # workspace brief (walk / window / pack / synthesize)
|
|
173
175
|
tokens.rs # heuristic or tiktoken BPE (feature = "real-tokens")
|
|
174
176
|
filter.rs
|
|
175
177
|
compress.rs
|
|
176
178
|
summarize.rs
|
|
177
179
|
smart.rs # summarize_smart + filter_relevant
|
|
178
|
-
local_llm.rs # OpenAI-compatible local SLM client
|
|
180
|
+
local_llm.rs # OpenAI-compatible local SLM client (+ embed cache)
|
|
179
181
|
chunk.rs # chunk + resolve
|
|
180
|
-
cache.rs # session key/value cache (+ optional disk)
|
|
182
|
+
cache.rs # session key/value cache (+ optional disk / embed vectors)
|
|
181
183
|
catalog.rs # action ads + help (progressive disclosure)
|
|
182
184
|
playbook.rs # bundled / dir playbooks
|
|
183
185
|
pack.rs # zip pack/unpack with size caps
|
|
@@ -188,6 +190,7 @@ playbooks/ # embedded skill-md playbooks
|
|
|
188
190
|
tests/
|
|
189
191
|
integration.rs
|
|
190
192
|
e2e_smoke.rs # spawns binary, MCP handshake, tools + resources
|
|
193
|
+
eval_regression.rs # B1 heuristic quality + latency smoke
|
|
191
194
|
CHANGELOG.md
|
|
192
195
|
REPORT.md # design essay + Shipped/Next/Deferred roadmap
|
|
193
196
|
```
|
|
@@ -232,6 +235,12 @@ Same `command` / `args` / `env` as Cursor, in Claude’s MCP config file.
|
|
|
232
235
|
|
|
233
236
|
### Local Cargo binary (developers)
|
|
234
237
|
|
|
238
|
+
After code changes, rebuild and **reload MCP** so the live tool schema matches source (avoid stale `npx`/Release binaries during development):
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
cargo build --release --features real-tokens,http
|
|
242
|
+
```
|
|
243
|
+
|
|
235
244
|
```json
|
|
236
245
|
{
|
|
237
246
|
"mcpServers": {
|
|
@@ -269,6 +278,8 @@ Point an MCP streamable-HTTP client at that URL (e.g. `StreamableHttpClientTrans
|
|
|
269
278
|
| `COMPENDIUM_LOCAL_LLM_MODEL` | `Qwen3-4B-GGUF` | Model id on that server (Ollama: e.g. `qwen:latest`) |
|
|
270
279
|
| `COMPENDIUM_LOCAL_EMBED_MODEL` | _(same as chat)_ | Embeddings model for hybrid `rerank` / `brief` (e.g. `nomic-embed-text`) |
|
|
271
280
|
| `COMPENDIUM_HYBRID_ALPHA` | `0.55` | BM25 weight in hybrid score (0–1); remainder is embedding cosine |
|
|
281
|
+
| `COMPENDIUM_RERANK_CROSS_ENCODER` | _(off)_ | When `1`/`true`, `rerank` SLM-rescores top-N after BM25/hybrid |
|
|
282
|
+
| `COMPENDIUM_CROSS_ENCODER_TOP_N` | `16` | Candidates passed to cross-encoder (clamped 4–64) |
|
|
272
283
|
| `COMPENDIUM_AUDIT_PATH` | _(unset)_ | Append-only JSONL audit log (action metadata only; no payloads) |
|
|
273
284
|
| `COMPENDIUM_LOCAL_LLM_API_KEY` | _(unset)_ | Optional bearer token for locked loopback servers |
|
|
274
285
|
| `COMPENDIUM_LOCAL_LLM_TIMEOUT_SECS` | `120` | HTTP timeout (first model load can be slow) |
|
|
@@ -279,23 +290,23 @@ Point an MCP streamable-HTTP client at that URL (e.g. `StreamableHttpClientTrans
|
|
|
279
290
|
| `COMPENDIUM_ARCHIVE_MAX_UNCOMPRESSED` | `4194304` | Max total uncompressed bytes for pack/unpack |
|
|
280
291
|
| `COMPENDIUM_ARCHIVE_MAX_FILES` | `50` | Max files per archive |
|
|
281
292
|
| `COMPENDIUM_SKILL_TTL_MS` | `300000` | Soft TTL (ms) on skill `resources/read` responses |
|
|
282
|
-
| `COMPENDIUM_CACHE_DIR` | _(unset)_ | Persist session cache (chunks/cache keys) across restarts; default size cap 64 MiB |
|
|
293
|
+
| `COMPENDIUM_CACHE_DIR` | _(unset)_ | Persist session cache (chunks/cache keys) across restarts; default size cap 64 MiB. Multiple MCP processes may share one dir — **no** cross-process lock; TTL/eviction are best-effort. Prefer a dedicated dir per user/host. |
|
|
283
294
|
| `COMPENDIUM_CACHE_MAX_BYTES` | _(unset / 64MiB with dir)_ | Soft cap on total cached payload bytes |
|
|
284
295
|
| `RUST_LOG` | `compendium=info` | Logs on **stderr** only |
|
|
285
296
|
|
|
286
297
|
## Example tool calls
|
|
287
298
|
|
|
299
|
+
All calls use the single tool **`compendium`** with an `action` field.
|
|
300
|
+
|
|
288
301
|
**Filter noisy terminal output**
|
|
289
302
|
|
|
290
303
|
```json
|
|
291
304
|
{
|
|
292
|
-
"
|
|
293
|
-
"
|
|
294
|
-
|
|
295
|
-
"
|
|
296
|
-
|
|
297
|
-
"keep_patterns": ["ERROR|WARN"]
|
|
298
|
-
}
|
|
305
|
+
"action": "filter",
|
|
306
|
+
"text": "\u001b[31mERROR\u001b[0m boom\n\n\nINFO ok",
|
|
307
|
+
"filter": {
|
|
308
|
+
"strip_ansi": true,
|
|
309
|
+
"keep_patterns": ["ERROR|WARN"]
|
|
299
310
|
}
|
|
300
311
|
}
|
|
301
312
|
```
|
|
@@ -304,13 +315,11 @@ Point an MCP streamable-HTTP client at that URL (e.g. `StreamableHttpClientTrans
|
|
|
304
315
|
|
|
305
316
|
```json
|
|
306
317
|
{
|
|
307
|
-
"
|
|
308
|
-
"
|
|
309
|
-
|
|
310
|
-
"
|
|
311
|
-
|
|
312
|
-
"max_tokens": 512
|
|
313
|
-
}
|
|
318
|
+
"action": "compress",
|
|
319
|
+
"text": "...",
|
|
320
|
+
"compress": {
|
|
321
|
+
"content_type": "log",
|
|
322
|
+
"max_tokens": 512
|
|
314
323
|
}
|
|
315
324
|
}
|
|
316
325
|
```
|
|
@@ -319,14 +328,12 @@ Point an MCP streamable-HTTP client at that URL (e.g. `StreamableHttpClientTrans
|
|
|
319
328
|
|
|
320
329
|
```json
|
|
321
330
|
{
|
|
322
|
-
"
|
|
323
|
-
"
|
|
324
|
-
|
|
325
|
-
"
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
"overlap_tokens": 40
|
|
329
|
-
}
|
|
331
|
+
"action": "chunk",
|
|
332
|
+
"text": "... huge file ...",
|
|
333
|
+
"chunk": {
|
|
334
|
+
"source": "file:///path/to/doc.md",
|
|
335
|
+
"chunk_tokens": 400,
|
|
336
|
+
"overlap_tokens": 40
|
|
330
337
|
}
|
|
331
338
|
}
|
|
332
339
|
```
|
package/npm/lib/platform.js
CHANGED
|
@@ -7,10 +7,13 @@
|
|
|
7
7
|
* 1. Prefer optionalDependency platform packages (esbuild-style) — offline, fast.
|
|
8
8
|
* 2. Fall back to downloading the matching GitHub Release asset into a local cache.
|
|
9
9
|
* 3. Dev override: COMPENDIUM_BINARY or ./target/release/compendium.
|
|
10
|
+
* 4. Force key: COMPENDIUM_PLATFORM (e.g. linux-x64-musl).
|
|
10
11
|
*/
|
|
11
12
|
|
|
13
|
+
const fs = require('fs');
|
|
12
14
|
const os = require('os');
|
|
13
15
|
const path = require('path');
|
|
16
|
+
const { execSync } = require('child_process');
|
|
14
17
|
|
|
15
18
|
/** @typedef {{ pkg: string, asset: string, rustTarget: string }} PlatformSpec */
|
|
16
19
|
|
|
@@ -31,6 +34,11 @@ const PLATFORMS = {
|
|
|
31
34
|
asset: 'compendium-linux-x64',
|
|
32
35
|
rustTarget: 'x86_64-unknown-linux-gnu',
|
|
33
36
|
},
|
|
37
|
+
'linux-x64-musl': {
|
|
38
|
+
pkg: 'compendium-mcp-linux-x64-musl',
|
|
39
|
+
asset: 'compendium-linux-x64-musl',
|
|
40
|
+
rustTarget: 'x86_64-unknown-linux-musl',
|
|
41
|
+
},
|
|
34
42
|
'linux-arm64': {
|
|
35
43
|
pkg: 'compendium-mcp-linux-arm64',
|
|
36
44
|
asset: 'compendium-linux-arm64',
|
|
@@ -41,6 +49,11 @@ const PLATFORMS = {
|
|
|
41
49
|
asset: 'compendium-win32-x64.exe',
|
|
42
50
|
rustTarget: 'x86_64-pc-windows-msvc',
|
|
43
51
|
},
|
|
52
|
+
'win32-arm64': {
|
|
53
|
+
pkg: 'compendium-mcp-win32-arm64',
|
|
54
|
+
asset: 'compendium-win32-arm64.exe',
|
|
55
|
+
rustTarget: 'aarch64-pc-windows-msvc',
|
|
56
|
+
},
|
|
44
57
|
};
|
|
45
58
|
|
|
46
59
|
function packageVersion() {
|
|
@@ -56,15 +69,51 @@ function githubRepo() {
|
|
|
56
69
|
);
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
/** Best-effort musl detection (Alpine / static libc). Default is glibc. */
|
|
73
|
+
function isLinuxMusl() {
|
|
74
|
+
if (process.platform !== 'linux') return false;
|
|
75
|
+
try {
|
|
76
|
+
if (typeof process.report?.getReport === 'function') {
|
|
77
|
+
const report = process.report.getReport();
|
|
78
|
+
if (report?.header?.glibcVersionRuntime) return false;
|
|
79
|
+
}
|
|
80
|
+
} catch (_) {
|
|
81
|
+
/* ignore */
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
if (fs.existsSync('/etc/alpine-release')) return true;
|
|
85
|
+
} catch (_) {
|
|
86
|
+
/* ignore */
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const out = execSync('ldd --version 2>&1 || true', {
|
|
90
|
+
encoding: 'utf8',
|
|
91
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
92
|
+
});
|
|
93
|
+
if (/musl/i.test(out)) return true;
|
|
94
|
+
} catch (_) {
|
|
95
|
+
/* ignore */
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
59
100
|
/**
|
|
60
101
|
* Normalize Node's process.platform + process.arch into our key.
|
|
102
|
+
* Override with COMPENDIUM_PLATFORM when needed (e.g. linux-x64-musl).
|
|
61
103
|
* @returns {string}
|
|
62
104
|
*/
|
|
63
105
|
function platformKey() {
|
|
106
|
+
const forced = (process.env.COMPENDIUM_PLATFORM || '').trim();
|
|
107
|
+
if (forced) return forced;
|
|
108
|
+
|
|
64
109
|
const platform = process.platform;
|
|
65
110
|
let arch = process.arch;
|
|
66
111
|
// Rosetta / rare aliases
|
|
67
112
|
if (arch === 'ia32') arch = 'x64';
|
|
113
|
+
|
|
114
|
+
if (platform === 'linux' && arch === 'x64' && isLinuxMusl()) {
|
|
115
|
+
return 'linux-x64-musl';
|
|
116
|
+
}
|
|
68
117
|
return `${platform}-${arch}`;
|
|
69
118
|
}
|
|
70
119
|
|
|
@@ -78,7 +127,7 @@ function currentPlatform() {
|
|
|
78
127
|
const supported = Object.keys(PLATFORMS).join(', ');
|
|
79
128
|
throw new Error(
|
|
80
129
|
`Unsupported platform "${key}". Supported: ${supported}.\n` +
|
|
81
|
-
`Set COMPENDIUM_BINARY to a local build, or open an issue for this target.`
|
|
130
|
+
`Set COMPENDIUM_BINARY to a local build, COMPENDIUM_PLATFORM to a known key, or open an issue for this target.`
|
|
82
131
|
);
|
|
83
132
|
}
|
|
84
133
|
return spec;
|
|
@@ -89,7 +138,9 @@ function currentPlatform() {
|
|
|
89
138
|
* @param {PlatformSpec} [spec]
|
|
90
139
|
*/
|
|
91
140
|
function binaryName(spec = currentPlatform()) {
|
|
92
|
-
return process.platform === 'win32'
|
|
141
|
+
return process.platform === 'win32' || spec.asset.endsWith('.exe')
|
|
142
|
+
? 'compendium.exe'
|
|
143
|
+
: 'compendium';
|
|
93
144
|
}
|
|
94
145
|
|
|
95
146
|
/**
|
|
@@ -112,4 +163,5 @@ module.exports = {
|
|
|
112
163
|
currentPlatform,
|
|
113
164
|
binaryName,
|
|
114
165
|
cacheDir,
|
|
166
|
+
isLinuxMusl,
|
|
115
167
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compendium-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "MCP server that compresses, summarizes, and filters context to minimize LLM token usage",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,11 +38,13 @@
|
|
|
38
38
|
"prepare": "node npm/scripts/link-bins.js"
|
|
39
39
|
},
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"compendium-mcp-darwin-arm64": "0.
|
|
42
|
-
"compendium-mcp-darwin-x64": "0.
|
|
43
|
-
"compendium-mcp-linux-x64": "0.
|
|
44
|
-
"compendium-mcp-linux-
|
|
45
|
-
"compendium-mcp-
|
|
41
|
+
"compendium-mcp-darwin-arm64": "0.6.0",
|
|
42
|
+
"compendium-mcp-darwin-x64": "0.6.0",
|
|
43
|
+
"compendium-mcp-linux-x64": "0.6.0",
|
|
44
|
+
"compendium-mcp-linux-x64-musl": "0.6.0",
|
|
45
|
+
"compendium-mcp-linux-arm64": "0.6.0",
|
|
46
|
+
"compendium-mcp-win32-x64": "0.6.0",
|
|
47
|
+
"compendium-mcp-win32-arm64": "0.6.0"
|
|
46
48
|
},
|
|
47
49
|
"preferUnplugged": true
|
|
48
50
|
}
|