mcp-sqlite-memory-bank 1.5.0__py3-none-any.whl → 1.6.0__py3-none-any.whl
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.
- mcp_sqlite_memory_bank/__init__.py +2 -2
- mcp_sqlite_memory_bank/__main__.py +68 -0
- mcp_sqlite_memory_bank/database.py +234 -68
- mcp_sqlite_memory_bank/prompts.py +76 -52
- mcp_sqlite_memory_bank/resources.py +250 -150
- mcp_sqlite_memory_bank/semantic.py +50 -17
- mcp_sqlite_memory_bank/server.py +351 -23
- mcp_sqlite_memory_bank/tools/__init__.py +33 -25
- mcp_sqlite_memory_bank/tools/analytics.py +225 -139
- mcp_sqlite_memory_bank/tools/basic.py +417 -7
- mcp_sqlite_memory_bank/tools/discovery.py +1428 -0
- mcp_sqlite_memory_bank/tools/search.py +159 -72
- mcp_sqlite_memory_bank/types.py +6 -1
- mcp_sqlite_memory_bank/utils.py +165 -107
- {mcp_sqlite_memory_bank-1.5.0.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/METADATA +54 -6
- mcp_sqlite_memory_bank-1.6.0.dist-info/RECORD +21 -0
- mcp_sqlite_memory_bank-1.5.0.dist-info/RECORD +0 -19
- {mcp_sqlite_memory_bank-1.5.0.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/WHEEL +0 -0
- {mcp_sqlite_memory_bank-1.5.0.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/entry_points.txt +0 -0
- {mcp_sqlite_memory_bank-1.5.0.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_sqlite_memory_bank-1.5.0.dist-info → mcp_sqlite_memory_bank-1.6.0.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,9 @@ except ImportError:
|
|
21
21
|
SENTENCE_TRANSFORMERS_AVAILABLE = False
|
22
22
|
SentenceTransformer = None # type: ignore
|
23
23
|
util = None # type: ignore
|
24
|
-
logging.warning(
|
24
|
+
logging.warning(
|
25
|
+
"sentence-transformers not available. Install with: pip install sentence-transformers"
|
26
|
+
)
|
25
27
|
|
26
28
|
try:
|
27
29
|
import torch
|
@@ -58,7 +60,7 @@ class SemanticSearchEngine:
|
|
58
60
|
)
|
59
61
|
|
60
62
|
@property
|
61
|
-
def model(self):
|
63
|
+
def model(self) -> Any:
|
62
64
|
"""Lazy load the sentence transformer model."""
|
63
65
|
if self._model is None:
|
64
66
|
if not SENTENCE_TRANSFORMERS_AVAILABLE or SentenceTransformer is None:
|
@@ -67,7 +69,9 @@ class SemanticSearchEngine:
|
|
67
69
|
self._model = SentenceTransformer(self.model_name)
|
68
70
|
logging.info(f"Loaded semantic search model: {self.model_name}")
|
69
71
|
except Exception as e:
|
70
|
-
raise DatabaseError(
|
72
|
+
raise DatabaseError(
|
73
|
+
f"Failed to load semantic search model {self.model_name}: {e}"
|
74
|
+
)
|
71
75
|
return self._model
|
72
76
|
|
73
77
|
def get_embedding_dimensions(self) -> Optional[int]:
|
@@ -124,13 +128,17 @@ class SemanticSearchEngine:
|
|
124
128
|
|
125
129
|
try:
|
126
130
|
embeddings = self.model.encode(
|
127
|
-
valid_texts,
|
131
|
+
valid_texts,
|
132
|
+
convert_to_tensor=False,
|
133
|
+
show_progress_bar=len(valid_texts) > 10,
|
128
134
|
)
|
129
135
|
return [emb.tolist() for emb in embeddings]
|
130
136
|
except Exception as e:
|
131
137
|
raise DatabaseError(f"Failed to generate batch embeddings: {e}")
|
132
138
|
|
133
|
-
def calculate_similarity(
|
139
|
+
def calculate_similarity(
|
140
|
+
self, embedding1: List[float], embedding2: List[float]
|
141
|
+
) -> float:
|
134
142
|
"""
|
135
143
|
Calculate cosine similarity between two embeddings.
|
136
144
|
|
@@ -193,7 +201,12 @@ class SemanticSearchEngine:
|
|
193
201
|
return []
|
194
202
|
|
195
203
|
# Use efficient torch/sentence-transformers if available
|
196
|
-
if
|
204
|
+
if (
|
205
|
+
TORCH_AVAILABLE
|
206
|
+
and torch is not None
|
207
|
+
and SENTENCE_TRANSFORMERS_AVAILABLE
|
208
|
+
and util is not None
|
209
|
+
):
|
197
210
|
try:
|
198
211
|
# Convert to tensors
|
199
212
|
query_tensor = torch.tensor(query_embedding).unsqueeze(0)
|
@@ -213,7 +226,9 @@ class SemanticSearchEngine:
|
|
213
226
|
results.sort(key=lambda x: x[1], reverse=True)
|
214
227
|
return results[:top_k]
|
215
228
|
except Exception as e:
|
216
|
-
logging.warning(
|
229
|
+
logging.warning(
|
230
|
+
f"Torch similarity search failed, using numpy fallback: {e}"
|
231
|
+
)
|
217
232
|
|
218
233
|
# Fallback to numpy implementation
|
219
234
|
results = []
|
@@ -291,6 +306,10 @@ class SemanticSearchEngine:
|
|
291
306
|
original_idx = valid_indices[candidate_idx]
|
292
307
|
row = content_data[original_idx].copy()
|
293
308
|
|
309
|
+
# Remove embedding data to avoid polluting LLM responses
|
310
|
+
if embedding_column in row:
|
311
|
+
del row[embedding_column]
|
312
|
+
|
294
313
|
# Add similarity score
|
295
314
|
row["similarity_score"] = round(similarity_score, 3)
|
296
315
|
|
@@ -298,7 +317,11 @@ class SemanticSearchEngine:
|
|
298
317
|
if content_columns:
|
299
318
|
matched_content = []
|
300
319
|
for col in content_columns:
|
301
|
-
if
|
320
|
+
if (
|
321
|
+
col in row
|
322
|
+
and row[col]
|
323
|
+
and query.lower() in str(row[col]).lower()
|
324
|
+
):
|
302
325
|
matched_content.append(f"{col}: {row[col]}")
|
303
326
|
if matched_content:
|
304
327
|
row["matched_content"] = matched_content
|
@@ -346,7 +369,11 @@ class SemanticSearchEngine:
|
|
346
369
|
|
347
370
|
# Get semantic search results
|
348
371
|
semantic_results = self.semantic_search(
|
349
|
-
query,
|
372
|
+
query,
|
373
|
+
content_data,
|
374
|
+
embedding_column,
|
375
|
+
similarity_threshold=0.3,
|
376
|
+
top_k=top_k * 2, # Get more for reranking
|
350
377
|
)
|
351
378
|
|
352
379
|
# Add text matching scores
|
@@ -360,11 +387,15 @@ class SemanticSearchEngine:
|
|
360
387
|
content = str(result[col]).lower()
|
361
388
|
if query_lower in content:
|
362
389
|
# Simple frequency-based text scoring
|
363
|
-
text_score += content.count(query_lower) / len(
|
390
|
+
text_score += content.count(query_lower) / len(
|
391
|
+
content.split()
|
392
|
+
)
|
364
393
|
|
365
394
|
# Combine scores
|
366
395
|
semantic_score = result.get("similarity_score", 0.0)
|
367
|
-
combined_score = (semantic_score * semantic_weight) + (
|
396
|
+
combined_score = (semantic_score * semantic_weight) + (
|
397
|
+
text_score * text_weight
|
398
|
+
)
|
368
399
|
result["combined_score"] = round(combined_score, 3)
|
369
400
|
result["text_score"] = round(text_score, 3)
|
370
401
|
|
@@ -373,7 +404,7 @@ class SemanticSearchEngine:
|
|
373
404
|
|
374
405
|
return semantic_results[:top_k]
|
375
406
|
|
376
|
-
def clear_cache(self):
|
407
|
+
def clear_cache(self) -> None:
|
377
408
|
"""Clear the embedding cache."""
|
378
409
|
self._embedding_cache.clear()
|
379
410
|
logging.info("Semantic search cache cleared")
|
@@ -390,15 +421,17 @@ def get_semantic_engine(model_name: str = "all-MiniLM-L6-v2") -> SemanticSearchE
|
|
390
421
|
try:
|
391
422
|
if _semantic_engine is None or _semantic_engine.model_name != model_name:
|
392
423
|
if not SENTENCE_TRANSFORMERS_AVAILABLE:
|
393
|
-
raise ValueError(
|
424
|
+
raise ValueError(
|
425
|
+
"Sentence transformers not available for semantic search"
|
426
|
+
)
|
394
427
|
_semantic_engine = SemanticSearchEngine(model_name)
|
395
|
-
|
428
|
+
|
396
429
|
# Verify the engine is properly initialized
|
397
|
-
if not hasattr(_semantic_engine,
|
430
|
+
if not hasattr(_semantic_engine, "hybrid_search"):
|
398
431
|
raise ValueError("Semantic engine missing hybrid_search method")
|
399
|
-
|
432
|
+
|
400
433
|
return _semantic_engine
|
401
|
-
|
434
|
+
|
402
435
|
except Exception as e:
|
403
436
|
raise DatabaseError(f"Failed to initialize semantic engine: {e}")
|
404
437
|
|