knowledge-rag 4.6.0__tar.gz → 4.7.0__tar.gz

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 (22) hide show
  1. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/.gitignore +1 -0
  2. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/PKG-INFO +24 -2
  3. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/README.md +23 -1
  4. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/__init__.py +1 -1
  5. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/server.py +23 -2
  6. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/pyproject.toml +1 -1
  7. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/LICENSE +0 -0
  8. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/config.example.yaml +0 -0
  9. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/config.py +0 -0
  10. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/guarded.py +0 -0
  11. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/ingestion.py +0 -0
  12. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/instance_lock.py +0 -0
  13. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/metrics.py +0 -0
  14. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/preflight.py +0 -0
  15. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/ratelimit.py +0 -0
  16. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/mcp_server/security.py +0 -0
  17. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/npm/README.md +0 -0
  18. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/presets/cybersecurity.yaml +0 -0
  19. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/presets/developer.yaml +0 -0
  20. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/presets/general.yaml +0 -0
  21. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/presets/research.yaml +0 -0
  22. {knowledge_rag-4.6.0 → knowledge_rag-4.7.0}/requirements.txt +0 -0
@@ -71,3 +71,4 @@ dist/
71
71
  # Path(config.data_dir) reproduces. Preventive: use spec=Config or
72
72
  # types.SimpleNamespace when mocking config in tests.
73
73
  MagicMock/
74
+ .benchmarks/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: knowledge-rag
3
- Version: 4.6.0
3
+ Version: 4.7.0
4
4
  Summary: Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 13 MCP Tools + 20 Format Parsers. Zero external servers.
5
5
  Project-URL: Homepage, https://github.com/lyonzin/knowledge-rag
6
6
  Project-URL: Repository, https://github.com/lyonzin/knowledge-rag
@@ -97,7 +97,21 @@ pip install knowledge-rag → restart Claude Code → search_knowledge("your que
97
97
 
98
98
  ---
99
99
 
100
- ## What's New in v4.2.0
100
+ ## What's New in v4.6.0
101
+
102
+ ### MCP spec 2026-07-28 via Anthropic Tier 1 SDK (v4.6.0)
103
+
104
+ Adopts the [**MCP spec 2026-07-28**](https://blog.modelcontextprotocol.io/posts/2026-07-28/) — stateless request/response core, per-request `_meta.io.modelcontextprotocol/protocolVersion` + `clientCapabilities`, `serverInfo` on every response, retirement of the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header. Delivered by moving directly to the **Anthropic Tier 1 Python SDK** (`mcp>=2.0.0,<3.0.0`, published 2026-07-28).
105
+
106
+ **What changed under the hood**:
107
+ - `mcp>=1.6.0,<2.0.0` → **`mcp>=2.0.0,<3.0.0`**
108
+ - `from mcp.server.fastmcp import FastMCP` → `from mcp.server import MCPServer`
109
+ - `FastMCP(name, host=, port=)` → `MCPServer(name, version="4.6.0")` — `host` / `port` moved to `mcp.run(transport=..., host=..., port=...)` on non-stdio transports (per v2 API)
110
+ - Server now advertises `version` in `serverInfo`, matching the 2026-07-28 spec recommendation
111
+
112
+ **Zero user-facing changes** — `@mcp.tool()` / `@mcp.resource()` / `@mcp.prompt()` decorator ergonomics are unchanged. All 13 MCP tool signatures frozen. **stdio users see zero behaviour change**. Existing clients (Claude Code, Claude Desktop, Cursor, Windsurf, VS Code Copilot, Cline, Gemini CLI, Zed) negotiate the spec version per request and continue to work.
113
+
114
+ **Why the Tier 1 SDK and not the third-party `fastmcp` package**: an early experiment with jlowin's [`fastmcp`](https://gofastmcp.com) tripped the Pillar 5 perf gate — `test_bench_orchestrator_idle_rss` +21.9% and `test_bench_query_cache_5000_entries` +17.1% RSS from the ~20 transitive deps its `[client,server]` extras pull in. Cutting the extras broke `@mcp.tool()` at runtime. Anthropic's `mcp 2.x` is the direct upstream reference — no third-party intermediary, no dependency bloat. Full details in the [v4.6.0 changelog entry](#v460-2026-07-30--mcp-spec-2026-07-28-via-anthropic-tier-1-sdk-mcp-2x) and closed PR #134.
101
115
 
102
116
  ### Search Performance & Output Quality (v4.2.0)
103
117
 
@@ -1448,6 +1462,14 @@ Common issues:
1448
1462
 
1449
1463
  ### Unreleased
1450
1464
 
1465
+ ### v4.7.0 (2026-07-31) — BM25 Fragment Query Support
1466
+
1467
+ - **FIX (retrieval)**: BM25 tokenizer now emits **sub-tokens** for hyphenated alphanumeric-code composites, so fragment queries no longer silently return `NO_RESULTS`. Before v4.7.0, `MDR-AD002` was indexed as a single token `mdr-ad002`; queries like `AD002`, `MDR`, `CS005` returned zero even when the composite lived in the corpus. This is not a bug specific to MDR — it hit every hyphenated code taxonomy in typical infosec / doc corpora (`MDR-*`, `CVE-*`, `ADR-*`, `MS17-*`, `MDR-Custom001-xxxx`). The tokenizer now emits both the composite token AND its sub-parts of length ≥ 2 (`mdr-ad002` → `["mdr-ad002", "mdr", "ad002"]`). IDF preserves ranking — composite matches still rank above fragment matches because the composite is rarer. **Heuristic (perf-safety)**: sub-token expansion is triggered ONLY when the composite contains at least one digit — so `pass-the-hash`, `state-of-the-art`, and other natural-language hyphenated phrases stay as single tokens (expanding them would flood the inverted index with stop-word-like sub-parts and hurt concurrent-query throughput). (#140)
1468
+ - **NEW (tests)**: `tests/test_bm25_tokenizer_fragment.py` — 25 tests across 4 classes covering unit tokenizer behavior, end-to-end fragment matching, multi-doc disambiguation, and the 5 query patterns explicitly reported (`MDR-AD019`, `MDR-Custom001-xxxx`, `MDR`, `AD019`, `CS005`). Includes retrocompat sentinel + IDF ranking invariant. Baseline: 314 → 339.
1469
+ - **UPGRADE NOTE**: run `reindex_documents(force=True)` once after upgrade to rebuild the BM25 inverted index with the new sub-token emission. ChromaDB vectors are untouched. Expect a **~30–50% increase in BM25 index memory** (measured +32.5% on synthetic corpus) — negligible for typical corpora, worth reviewing for deployments with >100K docs.
1470
+ - **KNOWN LIMITATION**: alphanumeric-glued tokens without separators (`HARDLAB11`, `6a635623e114b8...`) still require exact match — no sub-token expansion possible without character n-grams (5-10× index overhead). Tracked as follow-up.
1471
+ - **VERSION**: 4.6.0 → **4.7.0** (MINOR — tokenization behavior change + reindex requirement, though no API/config break).
1472
+
1451
1473
  ### v4.6.0 (2026-07-30) — MCP spec 2026-07-28 via Anthropic Tier 1 SDK (mcp 2.x)
1452
1474
 
1453
1475
  - **NEW (protocol)**: adopt the [MCP spec `2026-07-28`](https://blog.modelcontextprotocol.io/posts/2026-07-28/) — stateless request/response core, per-request `_meta.io.modelcontextprotocol/protocolVersion` + `clientCapabilities`, `serverInfo` on responses, retirement of the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header. The MCP client Claude Code (and every Tier 1 client) negotiates the spec version per request, so this release stays backwards-compatible for clients speaking earlier spec revisions.
@@ -49,7 +49,21 @@ pip install knowledge-rag → restart Claude Code → search_knowledge("your que
49
49
 
50
50
  ---
51
51
 
52
- ## What's New in v4.2.0
52
+ ## What's New in v4.6.0
53
+
54
+ ### MCP spec 2026-07-28 via Anthropic Tier 1 SDK (v4.6.0)
55
+
56
+ Adopts the [**MCP spec 2026-07-28**](https://blog.modelcontextprotocol.io/posts/2026-07-28/) — stateless request/response core, per-request `_meta.io.modelcontextprotocol/protocolVersion` + `clientCapabilities`, `serverInfo` on every response, retirement of the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header. Delivered by moving directly to the **Anthropic Tier 1 Python SDK** (`mcp>=2.0.0,<3.0.0`, published 2026-07-28).
57
+
58
+ **What changed under the hood**:
59
+ - `mcp>=1.6.0,<2.0.0` → **`mcp>=2.0.0,<3.0.0`**
60
+ - `from mcp.server.fastmcp import FastMCP` → `from mcp.server import MCPServer`
61
+ - `FastMCP(name, host=, port=)` → `MCPServer(name, version="4.6.0")` — `host` / `port` moved to `mcp.run(transport=..., host=..., port=...)` on non-stdio transports (per v2 API)
62
+ - Server now advertises `version` in `serverInfo`, matching the 2026-07-28 spec recommendation
63
+
64
+ **Zero user-facing changes** — `@mcp.tool()` / `@mcp.resource()` / `@mcp.prompt()` decorator ergonomics are unchanged. All 13 MCP tool signatures frozen. **stdio users see zero behaviour change**. Existing clients (Claude Code, Claude Desktop, Cursor, Windsurf, VS Code Copilot, Cline, Gemini CLI, Zed) negotiate the spec version per request and continue to work.
65
+
66
+ **Why the Tier 1 SDK and not the third-party `fastmcp` package**: an early experiment with jlowin's [`fastmcp`](https://gofastmcp.com) tripped the Pillar 5 perf gate — `test_bench_orchestrator_idle_rss` +21.9% and `test_bench_query_cache_5000_entries` +17.1% RSS from the ~20 transitive deps its `[client,server]` extras pull in. Cutting the extras broke `@mcp.tool()` at runtime. Anthropic's `mcp 2.x` is the direct upstream reference — no third-party intermediary, no dependency bloat. Full details in the [v4.6.0 changelog entry](#v460-2026-07-30--mcp-spec-2026-07-28-via-anthropic-tier-1-sdk-mcp-2x) and closed PR #134.
53
67
 
54
68
  ### Search Performance & Output Quality (v4.2.0)
55
69
 
@@ -1400,6 +1414,14 @@ Common issues:
1400
1414
 
1401
1415
  ### Unreleased
1402
1416
 
1417
+ ### v4.7.0 (2026-07-31) — BM25 Fragment Query Support
1418
+
1419
+ - **FIX (retrieval)**: BM25 tokenizer now emits **sub-tokens** for hyphenated alphanumeric-code composites, so fragment queries no longer silently return `NO_RESULTS`. Before v4.7.0, `MDR-AD002` was indexed as a single token `mdr-ad002`; queries like `AD002`, `MDR`, `CS005` returned zero even when the composite lived in the corpus. This is not a bug specific to MDR — it hit every hyphenated code taxonomy in typical infosec / doc corpora (`MDR-*`, `CVE-*`, `ADR-*`, `MS17-*`, `MDR-Custom001-xxxx`). The tokenizer now emits both the composite token AND its sub-parts of length ≥ 2 (`mdr-ad002` → `["mdr-ad002", "mdr", "ad002"]`). IDF preserves ranking — composite matches still rank above fragment matches because the composite is rarer. **Heuristic (perf-safety)**: sub-token expansion is triggered ONLY when the composite contains at least one digit — so `pass-the-hash`, `state-of-the-art`, and other natural-language hyphenated phrases stay as single tokens (expanding them would flood the inverted index with stop-word-like sub-parts and hurt concurrent-query throughput). (#140)
1420
+ - **NEW (tests)**: `tests/test_bm25_tokenizer_fragment.py` — 25 tests across 4 classes covering unit tokenizer behavior, end-to-end fragment matching, multi-doc disambiguation, and the 5 query patterns explicitly reported (`MDR-AD019`, `MDR-Custom001-xxxx`, `MDR`, `AD019`, `CS005`). Includes retrocompat sentinel + IDF ranking invariant. Baseline: 314 → 339.
1421
+ - **UPGRADE NOTE**: run `reindex_documents(force=True)` once after upgrade to rebuild the BM25 inverted index with the new sub-token emission. ChromaDB vectors are untouched. Expect a **~30–50% increase in BM25 index memory** (measured +32.5% on synthetic corpus) — negligible for typical corpora, worth reviewing for deployments with >100K docs.
1422
+ - **KNOWN LIMITATION**: alphanumeric-glued tokens without separators (`HARDLAB11`, `6a635623e114b8...`) still require exact match — no sub-token expansion possible without character n-grams (5-10× index overhead). Tracked as follow-up.
1423
+ - **VERSION**: 4.6.0 → **4.7.0** (MINOR — tokenization behavior change + reindex requirement, though no API/config break).
1424
+
1403
1425
  ### v4.6.0 (2026-07-30) — MCP spec 2026-07-28 via Anthropic Tier 1 SDK (mcp 2.x)
1404
1426
 
1405
1427
  - **NEW (protocol)**: adopt the [MCP spec `2026-07-28`](https://blog.modelcontextprotocol.io/posts/2026-07-28/) — stateless request/response core, per-request `_meta.io.modelcontextprotocol/protocolVersion` + `clientCapabilities`, `serverInfo` on responses, retirement of the `initialize`/`initialized` handshake and the `Mcp-Session-Id` header. The MCP client Claude Code (and every Tier 1 client) negotiates the spec version per request, so this release stays backwards-compatible for clients speaking earlier spec revisions.
@@ -8,7 +8,7 @@ import sys # noqa: I001
8
8
  _original_stdout = sys.stdout
9
9
  sys.stdout = sys.stderr
10
10
 
11
- __version__ = "4.6.0"
11
+ __version__ = "4.7.0"
12
12
  __author__ = "Ailton Rocha (Lyon.)"
13
13
 
14
14
  from .config import Config # noqa: E402
@@ -696,9 +696,30 @@ class BM25Index:
696
696
  self._index_built: bool = False
697
697
 
698
698
  def _tokenize(self, text: str) -> List[str]:
699
- """Simple tokenization: lowercase, split on non-alphanumeric, keep hyphens"""
699
+ """Tokenize: lowercase, split on non-alphanumeric, emit composite + sub-tokens.
700
+
701
+ For alphanumeric-code composites (containing at least one digit — e.g.
702
+ "mdr-ad002", "cve-2024-1234", "ms17-010"), emit both the composite token
703
+ AND its sub-parts of length >= 2. This enables fragment queries ("AD002",
704
+ "CVE", "010") to match while IDF preserves exact-match ranking (composite
705
+ is rarer).
706
+
707
+ Natural-language hyphenated words (e.g. "pass-the-hash", "state-of-the-art")
708
+ are kept as single tokens — expanding them would flood the inverted index
709
+ with high-frequency stop-word-like sub-parts and hurt query throughput
710
+ without helping recall for typical use cases.
711
+ """
700
712
  text_lower = text.lower()
701
- tokens = re.findall(r"[a-z0-9][-a-z0-9]*[a-z0-9]|[a-z0-9]", text_lower)
713
+ composite_tokens = re.findall(r"[a-z0-9][-a-z0-9]*[a-z0-9]|[a-z0-9]", text_lower)
714
+ tokens: List[str] = []
715
+ for tok in composite_tokens:
716
+ tokens.append(tok)
717
+ # Only expand codes (composites containing at least one digit).
718
+ # Skips natural-language phrases like "pass-the-hash".
719
+ if "-" in tok and any(c.isdigit() for c in tok):
720
+ for part in tok.split("-"):
721
+ if len(part) >= 2:
722
+ tokens.append(part)
702
723
  return tokens
703
724
 
704
725
  def expand_query(self, query: str) -> str:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "knowledge-rag"
7
- version = "4.6.0"
7
+ version = "4.7.0"
8
8
  description = "Local RAG System for Claude Code — Hybrid search + Cross-encoder Reranking + 13 MCP Tools + 20 Format Parsers. Zero external servers."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes