vector-mcp 2.1.1__tar.gz → 2.1.2__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 (84) hide show
  1. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/AGENTS.md +7 -5
  2. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/PKG-INFO +2 -2
  3. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/README.md +1 -1
  4. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/pyproject.toml +1 -1
  5. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/agent_server.py +1 -1
  6. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/mcp_server.py +1 -1
  7. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/epistemic_graph.py +62 -28
  8. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/PKG-INFO +2 -2
  9. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/.pre-commit-config.yaml +0 -0
  10. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/CHANGELOG.md +0 -0
  11. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/CLAUDE.md +0 -0
  12. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/LICENSE +0 -0
  13. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/MANIFEST.in +0 -0
  14. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/a2a.json +0 -0
  15. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/mcp_config.json +0 -0
  16. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/mkdocs.yml +0 -0
  17. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/opencode.json +0 -0
  18. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/requirements.txt +0 -0
  19. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/investigate_timeout.py +0 -0
  20. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/security_sanitizer.py +0 -0
  21. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/validate_a2a_agent.py +0 -0
  22. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/validate_agents.py +0 -0
  23. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/validate_all_dbs.py +0 -0
  24. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/scripts/verify_deps.py +0 -0
  25. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/setup.cfg +0 -0
  26. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/conftest.py +0 -0
  27. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/reproduce_chunking.py +0 -0
  28. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_action_discovery.py +0 -0
  29. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_agent_server.py +0 -0
  30. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_all_backends.py +0 -0
  31. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_auth.py +0 -0
  32. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_concept_parity.py +0 -0
  33. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_databases.py +0 -0
  34. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_init_dynamics.py +0 -0
  35. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_mcp_server.py +0 -0
  36. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_optional_dependencies.py +0 -0
  37. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_placeholder.py +0 -0
  38. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_protocol_compliance.py +0 -0
  39. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_pruning.py +0 -0
  40. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_retrievers.py +0 -0
  41. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_startup.py +0 -0
  42. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_vector_mcp.py +0 -0
  43. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/tests/test_vectordbs_mock.py +0 -0
  44. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/__init__.py +0 -0
  45. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/__main__.py +0 -0
  46. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/auth.py +0 -0
  47. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/connectors/__init__.py +0 -0
  48. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/connectors/mcp_source_presets.json +0 -0
  49. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/mcp/__init__.py +0 -0
  50. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/mcp/mcp_collection_management.py +0 -0
  51. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/mcp/mcp_search.py +0 -0
  52. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/mcp_config.json +0 -0
  53. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/ontology/__init__.py +0 -0
  54. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/ontology/vector.ttl +0 -0
  55. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/prompts/__init__.py +0 -0
  56. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/prompts/main_agent.json +0 -0
  57. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/prompts/retrieval_specialist.json +0 -0
  58. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/__init__.py +0 -0
  59. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/chromadb_retriever.py +0 -0
  60. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/couchbase_retriever.py +0 -0
  61. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/epistemic_graph_retriever.py +0 -0
  62. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/llamaindex_retriever.py +0 -0
  63. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/mongodb_retriever.py +0 -0
  64. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/postgres_retriever.py +0 -0
  65. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/qdrant_retriever.py +0 -0
  66. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/retriever/retriever.py +0 -0
  67. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/skills/__init__.py +0 -0
  68. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/skills/vector-backend-operations/SKILL.md +0 -0
  69. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/skills/vector-collection-management/SKILL.md +0 -0
  70. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/skills/vector-hybrid-search/SKILL.md +0 -0
  71. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vector_api.py +0 -0
  72. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/__init__.py +0 -0
  73. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/base.py +0 -0
  74. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/chromadb.py +0 -0
  75. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/couchbase.py +0 -0
  76. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/db_utils.py +0 -0
  77. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/mongodb.py +0 -0
  78. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/postgres.py +0 -0
  79. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp/vectordb/qdrant.py +0 -0
  80. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/SOURCES.txt +0 -0
  81. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/dependency_links.txt +0 -0
  82. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/entry_points.txt +0 -0
  83. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/requires.txt +0 -0
  84. {vector_mcp-2.1.1 → vector_mcp-2.1.2}/vector_mcp.egg-info/top_level.txt +0 -0
@@ -190,11 +190,13 @@ async def my_tool(param: str) -> str:
190
190
  - **Couchbase**: Couchbase with REST API fallback and manual cosine similarity (container required, partially functional)
191
191
 
192
192
  ### Implementation Notes
193
- - **Epistemic-Graph**: stores each chunk as an engine node (text + metadata in node
194
- properties) with its embedding in the engine's native ANN index via
195
- `SyncEpistemicGraphClient` (`.nodes.add` + `.graph.add_embedding` +
196
- `.graph.semantic_search`); a collection maps to an engine graph (`graph_name`).
197
- Embeddings are produced client-side with the shared `create_embedding_model`.
193
+ - **Epistemic-Graph**: stores each chunk as an engine node (text in the indexed
194
+ `description` property, plus metadata) with its embedding in the engine's native ANN
195
+ index via `SyncEpistemicGraphClient` (`.nodes.add` + `.graph.add_embedding`). Semantic
196
+ search is `.graph.semantic_search` (native ANN); lexical/keyword search is the engine's
197
+ one-round-trip `.graph.discover` (keyword overlap + semantic, scalable — a client-side
198
+ term scan is only a fallback for an engine too old for `discover`). A collection maps to
199
+ an engine graph (`graph_name`); embeddings come from the shared `create_embedding_model`.
198
200
  - **MongoDB**: Uses raw MongoClient instead of MongoDBAtlasVectorSearch to avoid authentication issues with local test containers. Implements manual cosine similarity calculation for semantic search.
199
201
  - **Couchbase**: Uses simple client approach with REST API fallback to bypass SDK authentication issues. Implements manual cosine similarity calculation for semantic search. Core search functionality working (10/14 tests passing), CRUD operations limited by N1QL service configuration.
200
202
  - **PostgreSQL**: Uses native PGVector with proper JSONB querying for get_documents_by_ids.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vector-mcp
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: Integrate RAG into AI Agents via MCP Server. Supports multiple Vector database technologies.
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -83,7 +83,7 @@ Dynamic: license-file
83
83
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/vector-mcp)
84
84
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/vector-mcp)
85
85
 
86
- *Version: 2.1.1*
86
+ *Version: 2.1.2*
87
87
 
88
88
  ---
89
89
 
@@ -20,7 +20,7 @@
20
20
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/vector-mcp)
21
21
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/vector-mcp)
22
22
 
23
- *Version: 2.1.1*
23
+ *Version: 2.1.2*
24
24
 
25
25
  ---
26
26
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vector-mcp"
7
- version = "2.1.1"
7
+ version = "2.1.2"
8
8
  description = "Integrate RAG into AI Agents via MCP Server. Supports multiple Vector database technologies."
9
9
  readme = "README.md"
10
10
  classifiers = [ "Development Status :: 5 - Production/Stable", "License :: Public Domain", "Environment :: Console", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3",]
@@ -4,7 +4,7 @@ import os
4
4
  import sys
5
5
  import warnings
6
6
 
7
- __version__ = "2.1.1"
7
+ __version__ = "2.1.2"
8
8
 
9
9
  logging.basicConfig(
10
10
  level=logging.INFO,
@@ -37,7 +37,7 @@ from starlette.responses import JSONResponse
37
37
  from vector_mcp.auth import get_client
38
38
  from vector_mcp.vector_api import Api
39
39
 
40
- __version__ = "2.1.1"
40
+ __version__ = "2.1.2"
41
41
 
42
42
  logger = get_logger(name="vector-mcp")
43
43
  logger.setLevel(logging.INFO)
@@ -30,9 +30,12 @@ with optional_import_block():
30
30
 
31
31
  logger = get_logger(__name__)
32
32
 
33
- # Node property key the chunk text is stored under (metadata takes the rest).
34
- _CONTENT_KEY = "content"
35
- _RESERVED_KEYS = {_CONTENT_KEY, "label", "id", "_similarity"}
33
+ # The chunk text is stored under the engine's standard ``description`` property: it is
34
+ # the field the engine keyword-indexes and that ``graph.discover`` hydrates, so lexical
35
+ # search runs engine-side (scalable) instead of an O(N) client scan. Everything not in
36
+ # the reserved set is treated as user metadata.
37
+ _TEXT_KEY = "description"
38
+ _RESERVED_KEYS = {_TEXT_KEY, "label", "id", "_similarity", "name", "type", "score"}
36
39
 
37
40
 
38
41
  @require_optional_import(["epistemic_graph", "agent_utilities"], "epistemic-graph")
@@ -107,7 +110,7 @@ class EpistemicGraphVectorDB(VectorDB):
107
110
  @staticmethod
108
111
  def _props_to_doc(node_id: str, props: dict | None) -> Document:
109
112
  props = dict(props or {})
110
- content = props.pop(_CONTENT_KEY, "") or ""
113
+ content = props.get(_TEXT_KEY, "") or ""
111
114
  meta = {k: v for k, v in props.items() if k not in _RESERVED_KEYS}
112
115
  return Document(id=node_id, content=content, metadata=meta, embedding=None)
113
116
 
@@ -173,7 +176,7 @@ class EpistemicGraphVectorDB(VectorDB):
173
176
  embedding = doc.get("embedding")
174
177
  if embedding is None:
175
178
  embedding = self._embed(text)
176
- client.nodes.add(doc_id, {_CONTENT_KEY: text, "label": "Document", **meta})
179
+ client.nodes.add(doc_id, {_TEXT_KEY: text, "label": "Document", **meta})
177
180
  client.graph.add_embedding(doc_id, [float(x) for x in embedding])
178
181
 
179
182
  def update_documents(
@@ -271,35 +274,66 @@ class EpistemicGraphVectorDB(VectorDB):
271
274
  n_results: int = 10,
272
275
  **kwargs: Any,
273
276
  ) -> QueryResults:
274
- # Term-frequency keyword match over stored node content. (The engine's ANN is
275
- # the scalable path via semantic_search; this is the term-based BM25-style
276
- # fallback, mirroring the manual scan the mongodb/couchbase backends use.)
277
+ """Keyword search over the engine's scalable index.
278
+
279
+ Routes through the engine's one-round-trip ``discover`` op it ranks nodes by
280
+ keyword overlap over the indexed text (the chunk text lives in ``description``)
281
+ AND semantic similarity, returning a hydrated top-k. Falls back to a client-side
282
+ term scan only if the engine is too old to support ``discover``.
283
+ """
277
284
  client = self._client_for(collection_name)
285
+ results: QueryResults = []
286
+ for query in queries:
287
+ terms = list(dict.fromkeys(t for t in query.lower().split() if t))
288
+ try:
289
+ q_emb = self._embed(query, is_query=True)
290
+ except Exception:
291
+ q_emb = [] # discover degrades to a bounded keyword-only scan
292
+ try:
293
+ hits = client.graph.discover(terms, q_emb, n_results) or []
294
+ except Exception as e:
295
+ logger.info(f"discover unavailable, using client scan: {e}")
296
+ results.append(self._lexical_scan(client, terms, n_results))
297
+ continue
298
+ query_result: list[tuple[Document, float]] = []
299
+ for item in hits[:n_results]:
300
+ if isinstance(item, dict):
301
+ node_id = str(item.get("id", ""))
302
+ score = float(item.get("score", 0.0) or 0.0)
303
+ # discover hydrates text in-band; fetch full props for metadata.
304
+ try:
305
+ props = client.nodes.properties(node_id) or item
306
+ except Exception:
307
+ props = item
308
+ else:
309
+ node_id, score, props = str(item), 0.0, None
310
+ if not node_id:
311
+ continue
312
+ query_result.append((self._props_to_doc(node_id, props), score))
313
+ results.append(query_result)
314
+ return results
315
+
316
+ def _lexical_scan(
317
+ self, client: Any, terms: list[str], n_results: int
318
+ ) -> list[tuple[Document, float]]:
319
+ """Fallback term-frequency scan (only when the engine lacks ``discover``)."""
278
320
  try:
279
321
  listing = client.nodes.list() or []
280
322
  except Exception as e:
281
- logger.info(f"lexical search (list nodes): {e}")
282
- listing = []
283
- corpus: list[tuple[str, dict]] = []
323
+ logger.info(f"lexical scan (list nodes): {e}")
324
+ return []
325
+ scored: list[tuple[Document, float]] = []
284
326
  for entry in listing:
285
327
  node_id = str(entry[0]) if isinstance(entry, list | tuple) else str(entry)
286
328
  try:
287
329
  props = client.nodes.properties(node_id) or {}
288
330
  except Exception:
289
- props = {}
290
- corpus.append((node_id, props))
291
-
292
- results: QueryResults = []
293
- for query in queries:
294
- terms = [t for t in query.lower().split() if t]
295
- scored: list[tuple[Document, float]] = []
296
- for node_id, props in corpus:
297
- content = str(props.get(_CONTENT_KEY, "") or "").lower()
298
- if not content:
299
- continue
300
- freq = sum(content.count(t) for t in terms)
301
- if freq > 0:
302
- scored.append((self._props_to_doc(node_id, props), float(freq)))
303
- scored.sort(key=lambda x: x[1], reverse=True)
304
- results.append(scored[:n_results])
305
- return results
331
+ continue
332
+ content = str(props.get(_TEXT_KEY, "") or "").lower()
333
+ if not content:
334
+ continue
335
+ freq = sum(content.count(t) for t in terms)
336
+ if freq > 0:
337
+ scored.append((self._props_to_doc(node_id, props), float(freq)))
338
+ scored.sort(key=lambda x: x[1], reverse=True)
339
+ return scored[:n_results]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vector-mcp
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: Integrate RAG into AI Agents via MCP Server. Supports multiple Vector database technologies.
5
5
  Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
6
  License: MIT
@@ -83,7 +83,7 @@ Dynamic: license-file
83
83
  ![PyPI - Wheel](https://img.shields.io/pypi/wheel/vector-mcp)
84
84
  ![PyPI - Implementation](https://img.shields.io/pypi/implementation/vector-mcp)
85
85
 
86
- *Version: 2.1.1*
86
+ *Version: 2.1.2*
87
87
 
88
88
  ---
89
89
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes