@oomkapwn/enquire-mcp 3.5.3 → 3.5.5
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/CHANGELOG.md +54 -0
- package/SECURITY.md +17 -3
- package/assets/social-preview.png +0 -0
- package/dist/index.js +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [3.5.5] — 2026-05-10
|
|
6
|
+
|
|
7
|
+
**Patch — fixes from external review #2.** Two issues: test flakiness on cold I/O + a documentation drift between SECURITY.md and the v2.14.0 stateful-HTTP code path. No behavior changes.
|
|
8
|
+
|
|
9
|
+
### Fixed — `tests/doctor.test.ts` cold-import flake
|
|
10
|
+
|
|
11
|
+
The first test in `runDoctor (v2.11.0)` calls `runDoctor()`, which probes optional deps via `await import(...)` — including `@huggingface/transformers` (~100 MB + ONNX runtime). On a slow disk / cold module cache, the first import in a fresh Vitest process can take 5-30 seconds, tripping the default 5 s test timeout. Subsequent tests in the same describe block reuse Node's module cache and finish in <100 ms each — the flake only ever hits the first test.
|
|
12
|
+
|
|
13
|
+
Fix: per-test `30_000 ms` timeout on the offending case, with a comment explaining why. Lighter than mocking the import (which would hide real "transformers actually loads" regressions), heavier than wishing-it-away.
|
|
14
|
+
|
|
15
|
+
### Fixed — SECURITY.md: stateful-HTTP posture (v2.14.0+) now documented
|
|
16
|
+
|
|
17
|
+
Pre-v3.5.5 `SECURITY.md` said:
|
|
18
|
+
|
|
19
|
+
> v2.6.0 ships **stateless** mode only [...] Stateful sessions with `Mcp-Session-Id` + persistent SSE streams are tracked for v2.7+ if there's demand.
|
|
20
|
+
|
|
21
|
+
That document hadn't been updated since v2.6 — but v2.14.0 (2026-05-09) shipped the stateful path with `Mcp-Session-Id` + persistent SSE via `GET /mcp` + `DELETE /mcp` termination + idle eviction + max-sessions cap. The security posture was real in code but missing from SECURITY.md, leaving consumers without the threat model for a path they could already enable via `--stateful`.
|
|
22
|
+
|
|
23
|
+
Fix: rewrote the `### Stateful sessions` section to cover the actual v2.14 surface:
|
|
24
|
+
- Off by default (`--stateful` is opt-in)
|
|
25
|
+
- Session ID = 128-bit random hex, allocated at `initialize`
|
|
26
|
+
- Max concurrent sessions cap via `--max-sessions <n>` (default 100); overflow → 503 + Retry-After
|
|
27
|
+
- Idle eviction via `--session-idle-timeout-ms <n>` (default 30 min)
|
|
28
|
+
- Explicit termination via `DELETE /mcp` (idempotent — 404 on unknown ID)
|
|
29
|
+
- Persistent SSE via `GET /mcp` with the same auth + rate-limit predicates
|
|
30
|
+
- Privacy filter parity with stateless
|
|
31
|
+
- Graceful shutdown drains the session map
|
|
32
|
+
- Out-of-scope: session takeover on bearer-token leak, cross-session shared-state leakage (single-tenant tool by design)
|
|
33
|
+
|
|
34
|
+
### Tests
|
|
35
|
+
|
|
36
|
+
664 unit tests pass (unchanged count). The flake is now ABSENT on slow-I/O machines — the test gets up to 30 s headroom for the cold transformers.js import.
|
|
37
|
+
|
|
38
|
+
### Migration
|
|
39
|
+
|
|
40
|
+
**No-op for default users.** Pure test stability + docs sync.
|
|
41
|
+
|
|
42
|
+
## [3.5.4] — 2026-05-10
|
|
43
|
+
|
|
44
|
+
**Patch — quick wins from external review.** Two single-line config tightenings, no behavior changes.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **Biome:** `noUnusedVariables` and `noUnusedImports` upgraded from `warn` → `error`. Lint already passes with the stricter level (no dead code currently in tree); the upgrade is purely defensive to prevent future drift past CI. Catches unused imports / variables before they accumulate.
|
|
49
|
+
- **`package.json`:** added `$schema: "https://json.schemastore.org/package.json"`. Enables IDE validation + autocomplete on the manifest. No effect on npm publish or runtime.
|
|
50
|
+
|
|
51
|
+
### Tests
|
|
52
|
+
|
|
53
|
+
664 unit tests pass (unchanged). Lint still clean under stricter rules.
|
|
54
|
+
|
|
55
|
+
### Migration
|
|
56
|
+
|
|
57
|
+
**No-op.** Pure config tightening.
|
|
58
|
+
|
|
5
59
|
## [3.5.3] — 2026-05-09
|
|
6
60
|
|
|
7
61
|
**Patch — CHANGELOG cleanup.** No code or config changes. Removes references to internal operational notes from the v3.5.1 / v3.5.2 entries that are not relevant to consumers of the package. Repository-level admin items are tracked privately, not in the public CHANGELOG.
|
package/SECURITY.md
CHANGED
|
@@ -190,9 +190,23 @@ The `serve-http` subcommand (added v2.6.0) exposes the same MCP server over [Str
|
|
|
190
190
|
- **Multi-tenant cross-token attacks.** This is a single-tenant tool. A small team should run **one process per user** (e.g. systemd template unit) and not share tokens. We don't do tenant isolation in-process beyond the per-token rate-limit.
|
|
191
191
|
- **OAuth.** No OAuth flow, no token minting, no refresh logic. Static long-lived bearer is by design — generated with `enquire-mcp gen-token`, rotated manually. OAuth is tracked for v2.7+ if a user explicitly needs it.
|
|
192
192
|
|
|
193
|
-
### Stateful sessions
|
|
194
|
-
|
|
195
|
-
v2.6.0
|
|
193
|
+
### Stateful sessions (v2.14.0+)
|
|
194
|
+
|
|
195
|
+
v2.6.0 initially shipped **stateless** mode only (fresh `McpServer` per request over the SHARED vault + FTS5 + embedding handles). v2.14.0 added an **opt-in stateful** mode via `--stateful` for clients that need persistent state across requests (notably ChatGPT custom GPT actions). Stateful posture:
|
|
196
|
+
|
|
197
|
+
- **Off by default.** `--stateful` is explicit opt-in; stateless remains the default for minimum attack surface. Short-running tools (search, read, frontmatter ops) work fine stateless and don't need the persistence-aware shutdown complexity.
|
|
198
|
+
- **Session ID generation.** `Mcp-Session-Id` is `randomBytes(16).toString("hex")` — 128 bits, allocated at `initialize` time, returned in response header. Clients must echo it on subsequent requests; unknown IDs return 404 (no info leak about whether the ID was ever valid).
|
|
199
|
+
- **Per-token + per-session rate limit.** The bearer-token rate limit still applies. Sessions are anchored to a bearer token; one token holding multiple sessions is allowed, but each session is bound to the token that initialized it.
|
|
200
|
+
- **Max concurrent sessions cap.** `--max-sessions <n>` (default **100**). New sessions beyond the cap return **503 + `Retry-After`**. Prevents memory exhaustion via session-spam.
|
|
201
|
+
- **Idle eviction.** `--session-idle-timeout-ms <n>` (default **1,800,000 ms = 30 min**). A periodic sweep terminates transports idle longer than the timeout. Memory bounded.
|
|
202
|
+
- **Explicit termination.** `DELETE /mcp` with a valid `Mcp-Session-Id` tears down the transport immediately. Idempotent — repeat DELETE on a no-longer-existing ID returns 404, not 500.
|
|
203
|
+
- **GET /mcp for persistent SSE.** A `GET /mcp` with a valid `Mcp-Session-Id` opens a server-sent-events stream for server-initiated notifications. Same auth + rate-limit predicates as POST. Stream closes on DELETE or idle eviction.
|
|
204
|
+
- **Privacy filter parity.** `--exclude-glob` / `--read-paths` apply identically to stateful and stateless paths. There is no codepath where a stateful session bypasses the privacy filter.
|
|
205
|
+
- **Graceful shutdown.** SIGINT / SIGTERM / `beforeExit` trigger session-map drain — all transports are closed before the process exits. No leaked SSE streams.
|
|
206
|
+
|
|
207
|
+
Out of scope (stateful mode specifically):
|
|
208
|
+
- **Session takeover** if a bearer token leaks. The session-id is in a response header, not a secret — possession of the bearer token is sufficient to initialize new sessions OR (if the attacker captured a previous `Mcp-Session-Id`) re-attach to an existing one. Treat the bearer token as the trust boundary; don't share it.
|
|
209
|
+
- **Cross-session leakage.** Each session has its own `McpServer` instance but shares the vault + FTS5 + embedding handles. A misbehaving tool that mutates shared state could affect other sessions. Write tools (`--enable-write`) are still atomic per-file; read tools don't mutate. We don't run per-session sandboxing — single-tenant tool, see "Multi-tenant cross-token attacks" above.
|
|
196
210
|
|
|
197
211
|
### Observability
|
|
198
212
|
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { chunkContent, defaultIndexFile, FtsIndex } from "./fts5.js";
|
|
|
12
12
|
import { appendToNote, archiveNote, chatThreadAppend, chatThreadRead, contextPack, createNote, dataviewQuery, embeddingsSearch, findPath, findSimilar, frontmatterGet, frontmatterSearch, frontmatterSet, getBacklinks, getNoteNeighbors, getOpenQuestions, getOutboundLinks, getRecentEdits, getUnresolvedWikilinks, getVaultStats, lintWiki, listCanvases, listNotes, listPdfs, listTags, ocrPdf, openInUi, paperAudit, readCanvas, readNote, readPdf, renameNote, replaceInNotes, resolveWikilink, searchHybrid, searchText, semanticSearch, validateNoteProposal } from "./tools.js";
|
|
13
13
|
import { Vault } from "./vault.js";
|
|
14
14
|
import { VaultWatcher } from "./watcher.js";
|
|
15
|
-
const VERSION = "3.5.
|
|
15
|
+
const VERSION = "3.5.5";
|
|
16
16
|
/** Default location for the persistent embedding index, alongside .fts5.db. */
|
|
17
17
|
function embedDbPath(vaultRoot) {
|
|
18
18
|
// Match the FTS5 location convention by stripping the .fts5.db extension
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
2
3
|
"name": "@oomkapwn/enquire-mcp",
|
|
3
|
-
"version": "3.5.
|
|
4
|
+
"version": "3.5.5",
|
|
4
5
|
"description": "The most advanced MCP server for Obsidian vaults. Hybrid retrieval (BM25 + TF-IDF + multilingual ML embeddings, RRF-fused) with BGE cross-encoder reranking, HNSW vector index, int8 quantization, late-chunking, HyDE-augmented retrieval, sub-question decomposition, PDFs (with OCR), Bases (.base query execution, standalone — no Obsidian needed), GraphRAG-light (Louvain wikilink community detection), wikilinks, backlinks, Dataview, frontmatter, canvas. 44 tools, 19 MCP prompts, 5 cross-encoder reranker models, 664 tests, SLSA-3, semver-bound. Works with Claude Code, Claude Desktop, Cursor, ChatGPT custom GPT, Codex, and any MCP client.",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"bin": {
|