mcp-sqlite-memory-bank 1.5.1__py3-none-any.whl → 1.6.2__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.
@@ -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("sentence-transformers not available. Install with: pip install sentence-transformers")
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:
@@ -124,7 +126,9 @@ class SemanticSearchEngine:
124
126
 
125
127
  try:
126
128
  embeddings = self.model.encode(
127
- valid_texts, convert_to_tensor=False, show_progress_bar=len(valid_texts) > 10
129
+ valid_texts,
130
+ convert_to_tensor=False,
131
+ show_progress_bar=len(valid_texts) > 10,
128
132
  )
129
133
  return [emb.tolist() for emb in embeddings]
130
134
  except Exception as e:
@@ -193,7 +197,12 @@ class SemanticSearchEngine:
193
197
  return []
194
198
 
195
199
  # Use efficient torch/sentence-transformers if available
196
- if TORCH_AVAILABLE and torch is not None and SENTENCE_TRANSFORMERS_AVAILABLE and util is not None:
200
+ if (
201
+ TORCH_AVAILABLE
202
+ and torch is not None
203
+ and SENTENCE_TRANSFORMERS_AVAILABLE
204
+ and util is not None
205
+ ):
197
206
  try:
198
207
  # Convert to tensors
199
208
  query_tensor = torch.tensor(query_embedding).unsqueeze(0)
@@ -291,6 +300,10 @@ class SemanticSearchEngine:
291
300
  original_idx = valid_indices[candidate_idx]
292
301
  row = content_data[original_idx].copy()
293
302
 
303
+ # Remove embedding data to avoid polluting LLM responses
304
+ if embedding_column in row:
305
+ del row[embedding_column]
306
+
294
307
  # Add similarity score
295
308
  row["similarity_score"] = round(similarity_score, 3)
296
309
 
@@ -344,10 +357,9 @@ class SemanticSearchEngine:
344
357
  semantic_weight /= total_weight
345
358
  text_weight /= total_weight
346
359
 
347
- # Get semantic search results
348
- semantic_results = self.semantic_search(
349
- query, content_data, embedding_column, similarity_threshold=0.3, top_k=top_k * 2 # Get more for reranking
350
- )
360
+ # Use the provided content_data as semantic results (already filtered by database)
361
+ # The content_data passed here should already be the semantic search results
362
+ semantic_results = content_data.copy() if content_data else []
351
363
 
352
364
  # Add text matching scores
353
365
  query_lower = query.lower()
@@ -373,7 +385,7 @@ class SemanticSearchEngine:
373
385
 
374
386
  return semantic_results[:top_k]
375
387
 
376
- def clear_cache(self):
388
+ def clear_cache(self) -> None:
377
389
  """Clear the embedding cache."""
378
390
  self._embedding_cache.clear()
379
391
  logging.info("Semantic search cache cleared")
@@ -392,13 +404,13 @@ def get_semantic_engine(model_name: str = "all-MiniLM-L6-v2") -> SemanticSearchE
392
404
  if not SENTENCE_TRANSFORMERS_AVAILABLE:
393
405
  raise ValueError("Sentence transformers not available for semantic search")
394
406
  _semantic_engine = SemanticSearchEngine(model_name)
395
-
407
+
396
408
  # Verify the engine is properly initialized
397
- if not hasattr(_semantic_engine, 'hybrid_search'):
409
+ if not hasattr(_semantic_engine, "hybrid_search"):
398
410
  raise ValueError("Semantic engine missing hybrid_search method")
399
-
411
+
400
412
  return _semantic_engine
401
-
413
+
402
414
  except Exception as e:
403
415
  raise DatabaseError(f"Failed to initialize semantic engine: {e}")
404
416
 
@@ -43,14 +43,25 @@ Each tool is designed for explicit, discoverable use by LLMs and agents:
43
43
  Author: Robert Meisner
44
44
  """
45
45
 
46
+ from .tools.discovery import (
47
+ intelligent_discovery as intelligent_discovery_impl,
48
+ discovery_templates as discovery_templates_impl,
49
+ discover_relationships as discover_relationships_impl,
50
+ )
51
+ from .tools.search import (
52
+ search_content as search_content_impl,
53
+ explore_tables as explore_tables_impl,
54
+ add_embeddings as add_embeddings_impl,
55
+ auto_semantic_search as auto_semantic_search_impl,
56
+ auto_smart_search as auto_smart_search_impl,
57
+ embedding_stats as embedding_stats_impl,
58
+ )
46
59
  import os
47
- import re
48
60
  import logging
49
61
  from typing import Dict, Optional, List, cast, Any
50
62
  from fastmcp import FastMCP
51
63
 
52
64
  from .database import get_database
53
- from .semantic import is_semantic_search_available
54
65
  from .types import (
55
66
  ToolResponse,
56
67
  CreateTableResponse,
@@ -265,6 +276,40 @@ def create_row(table_name: str, data: Dict[str, Any]) -> ToolResponse:
265
276
  return cast(CreateRowResponse, get_database(DB_PATH).insert_row(table_name, data))
266
277
 
267
278
 
279
+ @mcp.tool
280
+ @catch_errors
281
+ def upsert_memory(table_name: str, data: Dict[str, Any], match_columns: List[str]) -> ToolResponse:
282
+ """
283
+ 🔄 **SMART MEMORY UPSERT** - Prevent duplicates and maintain data consistency!
284
+
285
+ Update existing records or create new ones based on matching columns.
286
+ This is the preferred method for memory management as it prevents duplicates.
287
+
288
+ Args:
289
+ table_name (str): Table to upsert into
290
+ data (Dict[str, Any]): Data to upsert (column-value pairs)
291
+ match_columns (List[str]): Columns to use for finding existing records
292
+
293
+ Returns:
294
+ ToolResponse: On success: {"success": True, "action": "updated"|"created", "id": rowid}
295
+ On error: {"success": False, "error": str, "category": str, "details": dict}
296
+
297
+ Examples:
298
+ >>> upsert_memory('technical_decisions',
299
+ ... {'decision_name': 'API Design', 'chosen_approach': 'REST'},
300
+ ... ['decision_name'])
301
+ {"success": True, "action": "updated", "id": 15, "rows_affected": 1}
302
+
303
+ FastMCP Tool Info:
304
+ - **PREVENTS DUPLICATES**: Automatically updates existing records instead of creating duplicates
305
+ - **SMART MATCHING**: Uses specified columns to find existing records
306
+ - **EFFICIENT MEMORY MANAGEMENT**: Ideal for agent memory patterns
307
+ - **CLEAR FEEDBACK**: Returns whether record was created or updated
308
+ - **PERFECT FOR AGENTS**: Handles the common "update or create" pattern automatically
309
+ """
310
+ return basic.upsert_memory(table_name, data, match_columns)
311
+
312
+
268
313
  @mcp.tool
269
314
  @catch_errors
270
315
  def read_rows(table_name: str, where: Optional[Dict[str, Any]] = None) -> ToolResponse:
@@ -293,7 +338,9 @@ def read_rows(table_name: str, where: Optional[Dict[str, Any]] = None) -> ToolRe
293
338
 
294
339
  @mcp.tool
295
340
  @catch_errors
296
- def update_rows(table_name: str, data: Dict[str, Any], where: Optional[Dict[str, Any]] = None) -> ToolResponse:
341
+ def update_rows(
342
+ table_name: str, data: Dict[str, Any], where: Optional[Dict[str, Any]] = None
343
+ ) -> ToolResponse:
297
344
  """
298
345
  Update rows in any table in the SQLite Memory Bank for Copilot/AI agents, matching the WHERE clause.
299
346
 
@@ -349,7 +396,10 @@ def delete_rows(table_name: str, where: Optional[Dict[str, Any]] = None) -> Tool
349
396
  @mcp.tool
350
397
  @catch_errors
351
398
  def run_select_query(
352
- table_name: str, columns: Optional[List[str]] = None, where: Optional[Dict[str, Any]] = None, limit: int = 100
399
+ table_name: str,
400
+ columns: Optional[List[str]] = None,
401
+ where: Optional[Dict[str, Any]] = None,
402
+ limit: int = 100,
353
403
  ) -> ToolResponse:
354
404
  """
355
405
  Run a safe SELECT query on a table in the SQLite memory bank.
@@ -374,7 +424,10 @@ def run_select_query(
374
424
  - Only SELECT queries are allowed (no arbitrary SQL)
375
425
  - Default limit of 100 rows prevents memory issues
376
426
  """
377
- return cast(SelectQueryResponse, get_database(DB_PATH).select_query(table_name, columns, where, limit))
427
+ return cast(
428
+ SelectQueryResponse,
429
+ get_database(DB_PATH).select_query(table_name, columns, where, limit),
430
+ )
378
431
 
379
432
 
380
433
  @mcp.tool
@@ -400,24 +453,12 @@ def list_all_columns() -> ToolResponse:
400
453
 
401
454
 
402
455
  # Import the implementation functions from tools modules
403
- from .tools.search import (
404
- search_content as search_content_impl,
405
- explore_tables as explore_tables_impl,
406
- add_embeddings as add_embeddings_impl,
407
- auto_semantic_search as auto_semantic_search_impl,
408
- auto_smart_search as auto_smart_search_impl,
409
- embedding_stats as embedding_stats_impl,
410
- )
411
456
 
412
- # Import the implementation functions from discovery module
413
- from .tools.discovery import (
414
- intelligent_discovery as intelligent_discovery_impl,
415
- discovery_templates as discovery_templates_impl,
416
- discover_relationships as discover_relationships_impl,
417
- )
457
+ # Import the implementation functions from discovery module
418
458
 
419
459
  # --- MCP Tool Definitions (Required in main server.py for FastMCP) ---
420
460
 
461
+
421
462
  @mcp.tool
422
463
  @catch_errors
423
464
  def search_content(
@@ -455,7 +496,7 @@ def search_content(
455
496
 
456
497
 
457
498
  @mcp.tool
458
- @catch_errors
499
+ @catch_errors
459
500
  def explore_tables(
460
501
  pattern: Optional[str] = None,
461
502
  include_row_counts: bool = True,
@@ -656,7 +697,7 @@ def embedding_stats(
656
697
 
657
698
  FastMCP Tool Info:
658
699
  - Shows how much content is ready for semantic search
659
- - Helps identify tables that need embedding generation
700
+ - Helps identify tables that need embedding generation
660
701
  - Provides embedding dimension info for debugging
661
702
  - Useful for monitoring semantic search capabilities
662
703
  """
@@ -808,6 +849,7 @@ def find_related(
808
849
 
809
850
  # --- Advanced Discovery Tools for SQLite Memory Bank ---
810
851
 
852
+
811
853
  @mcp.tool
812
854
  @catch_errors
813
855
  def intelligent_discovery(
@@ -825,14 +867,14 @@ def intelligent_discovery(
825
867
  Args:
826
868
  discovery_goal (str): What you want to achieve
827
869
  - "understand_content": Learn what data is available and how it's organized
828
- - "find_patterns": Discover themes, relationships, and content patterns
870
+ - "find_patterns": Discover themes, relationships, and content patterns
829
871
  - "explore_structure": Understand database schema and organization
830
872
  - "assess_quality": Evaluate content quality and completeness
831
873
  - "prepare_search": Get ready for effective content searching
832
874
  focus_area (Optional[str]): Specific table or topic to focus on (default: all)
833
875
  depth (str): How thorough the discovery should be
834
876
  - "quick": Fast overview with key insights
835
- - "moderate": Balanced analysis with actionable recommendations
877
+ - "moderate": Balanced analysis with actionable recommendations
836
878
  - "comprehensive": Deep dive with detailed analysis
837
879
  agent_id (Optional[str]): Agent identifier for learning discovery patterns
838
880
 
@@ -861,8 +903,7 @@ def intelligent_discovery(
861
903
  @mcp.tool
862
904
  @catch_errors
863
905
  def discovery_templates(
864
- template_type: str = "first_time_exploration",
865
- customize_for: Optional[str] = None
906
+ template_type: str = "first_time_exploration", customize_for: Optional[str] = None
866
907
  ) -> ToolResponse:
867
908
  """
868
909
  📋 **DISCOVERY TEMPLATES** - Pre-built exploration workflows for common scenarios!
@@ -895,7 +936,7 @@ def discovery_templates(
895
936
  }}
896
937
 
897
938
  FastMCP Tool Info:
898
- - **PROVEN WORKFLOWS**: Battle-tested discovery sequences
939
+ - **PROVEN WORKFLOWS**: Battle-tested discovery sequences
899
940
  - **STEP-BY-STEP GUIDANCE**: Exact tools and parameters to use
900
941
  - **CUSTOMIZABLE**: Adapt templates to your specific needs
901
942
  - **LEARNING-OPTIMIZED**: Based on successful discovery patterns
@@ -907,8 +948,12 @@ def discovery_templates(
907
948
  @catch_errors
908
949
  def discover_relationships(
909
950
  table_name: Optional[str] = None,
910
- relationship_types: List[str] = ["foreign_keys", "semantic_similarity", "temporal_patterns"],
911
- similarity_threshold: float = 0.6
951
+ relationship_types: List[str] = [
952
+ "foreign_keys",
953
+ "semantic_similarity",
954
+ "temporal_patterns",
955
+ ],
956
+ similarity_threshold: float = 0.6,
912
957
  ) -> ToolResponse:
913
958
  """
914
959
  🔗 **RELATIONSHIP DISCOVERY** - Find hidden connections in your data!
@@ -983,12 +1028,13 @@ __all__ = [
983
1028
  "app",
984
1029
  "mcp",
985
1030
  "create_table",
986
- "drop_table",
1031
+ "drop_table",
987
1032
  "rename_table",
988
1033
  "list_tables",
989
1034
  "describe_table",
990
1035
  "list_all_columns",
991
1036
  "create_row",
1037
+ "upsert_memory",
992
1038
  "read_rows",
993
1039
  "update_rows",
994
1040
  "delete_rows",
@@ -1008,7 +1054,10 @@ __all__ = [
1008
1054
  def mcp_server():
1009
1055
  """Entry point for MCP stdio server (for uvx and package installations)."""
1010
1056
  # Configure logging for MCP server
1011
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
1057
+ logging.basicConfig(
1058
+ level=logging.INFO,
1059
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
1060
+ )
1012
1061
 
1013
1062
  # Log startup information
1014
1063
  logging.info(f"Starting SQLite Memory Bank MCP server with database at {DB_PATH}")
@@ -1040,12 +1089,20 @@ def main():
1040
1089
  print(f"Database path: {DB_PATH}")
1041
1090
  print("Available at: http://localhost:8000/docs")
1042
1091
 
1043
- uvicorn.run("mcp_sqlite_memory_bank.server:app", host=args.host, port=args.port, reload=args.reload)
1092
+ uvicorn.run(
1093
+ "mcp_sqlite_memory_bank.server:app",
1094
+ host=args.host,
1095
+ port=args.port,
1096
+ reload=args.reload,
1097
+ )
1044
1098
 
1045
1099
 
1046
1100
  if __name__ == "__main__":
1047
1101
  # Configure logging
1048
- logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
1102
+ logging.basicConfig(
1103
+ level=logging.INFO,
1104
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
1105
+ )
1049
1106
 
1050
1107
  # Log startup information
1051
1108
  logging.info(f"Starting SQLite Memory Bank with database at {DB_PATH}")
@@ -1085,3 +1142,88 @@ _get_content_health_score_impl = analytics.get_content_health_score
1085
1142
  _intelligent_discovery_impl = intelligent_discovery_impl
1086
1143
  _discovery_templates_impl = discovery_templates_impl
1087
1144
  _discover_relationships_impl = discover_relationships_impl
1145
+
1146
+
1147
+ @mcp.tool
1148
+ @catch_errors
1149
+ def batch_create_memories(
1150
+ table_name: str,
1151
+ data_list: List[Dict[str, Any]],
1152
+ match_columns: Optional[List[str]] = None,
1153
+ use_upsert: bool = True,
1154
+ ) -> ToolResponse:
1155
+ """
1156
+ 🚀 **BATCH MEMORY CREATION** - Efficiently add multiple memories at once!
1157
+
1158
+ Create multiple memory records in a single operation with optional duplicate prevention.
1159
+ Much faster than creating records one by one.
1160
+
1161
+ Args:
1162
+ table_name (str): Table to insert records into
1163
+ data_list (List[Dict[str, Any]]): List of memory records to create
1164
+ match_columns (Optional[List[str]]): Columns to use for duplicate detection (if use_upsert=True)
1165
+ use_upsert (bool): Whether to use upsert logic to prevent duplicates (default: True)
1166
+
1167
+ Returns:
1168
+ ToolResponse: On success: {"success": True, "created": int, "updated": int, "failed": int}
1169
+ On error: {"success": False, "error": str, "category": str, "details": dict}
1170
+
1171
+ Examples:
1172
+ >>> batch_create_memories('technical_decisions', [
1173
+ ... {'decision_name': 'API Design', 'chosen_approach': 'REST'},
1174
+ ... {'decision_name': 'Database Choice', 'chosen_approach': 'SQLite'},
1175
+ ... {'decision_name': 'Frontend Framework', 'chosen_approach': 'React'}
1176
+ ... ], match_columns=['decision_name'])
1177
+ {"success": True, "created": 2, "updated": 1, "failed": 0, "total_processed": 3}
1178
+
1179
+ FastMCP Tool Info:
1180
+ - **EFFICIENT**: Process multiple records in one operation
1181
+ - **SMART DEDUPLICATION**: Optional upsert logic prevents duplicates
1182
+ - **DETAILED FEEDBACK**: Returns counts for created, updated, and failed records
1183
+ - **PARTIAL SUCCESS**: Continues processing even if some records fail
1184
+ - **PERFECT FOR BULK IMPORTS**: Ideal for importing knowledge bases or datasets
1185
+ """
1186
+ return basic.batch_create_memories(table_name, data_list, match_columns, use_upsert)
1187
+
1188
+
1189
+ @mcp.tool
1190
+ @catch_errors
1191
+ def batch_delete_memories(
1192
+ table_name: str, where_conditions: List[Dict[str, Any]], match_all: bool = False
1193
+ ) -> ToolResponse:
1194
+ """
1195
+ 🗑️ **BATCH MEMORY DELETION** - Efficiently delete multiple memories at once!
1196
+
1197
+ Delete multiple memory records in a single operation with flexible matching conditions.
1198
+ Much faster than deleting records one by one.
1199
+
1200
+ Args:
1201
+ table_name (str): Table to delete records from
1202
+ where_conditions (List[Dict[str, Any]]): List of WHERE conditions for deletion
1203
+ match_all (bool): If True, delete records matching ALL conditions; if False, delete records matching ANY condition (default: False)
1204
+
1205
+ Returns:
1206
+ ToolResponse: On success: {"success": True, "deleted": int, "failed": int}
1207
+ On error: {"success": False, "error": str, "category": str, "details": dict}
1208
+
1209
+ Examples:
1210
+ >>> batch_delete_memories('technical_decisions', [
1211
+ ... {'decision_name': 'Old Decision 1'},
1212
+ ... {'decision_name': 'Old Decision 2'},
1213
+ ... {'id': 42}
1214
+ ... ])
1215
+ {"success": True, "deleted": 3, "failed": 0, "total_conditions": 3}
1216
+
1217
+ >>> batch_delete_memories('notes', [
1218
+ ... {'category': 'temp', 'created_date': '2024-01-01'}
1219
+ ... ], match_all=True)
1220
+ {"success": True, "deleted": 15, "failed": 0} # Deletes notes that are BOTH temp AND from that date
1221
+
1222
+ FastMCP Tool Info:
1223
+ - **EFFICIENT**: Process multiple deletions in one operation
1224
+ - **FLEXIBLE MATCHING**: Support both OR logic (any condition) and AND logic (all conditions)
1225
+ - **DETAILED FEEDBACK**: Returns counts and per-condition results
1226
+ - **PARTIAL SUCCESS**: Continues processing even if some deletions fail
1227
+ - **SAFE**: Uses parameterized queries to prevent SQL injection
1228
+ """
1229
+ return basic.batch_delete_memories(table_name, where_conditions, match_all)
@@ -3,7 +3,7 @@ Tools module for SQLite Memory Bank MCP server.
3
3
 
4
4
  This module organizes the various MCP tools into logical categories:
5
5
  - analytics: Content analysis and health assessment tools
6
- - search: Intelligent search and discovery tools
6
+ - search: Intelligent search and discovery tools
7
7
  - discovery: Advanced exploration and relationship discovery tools
8
8
  - basic: Core CRUD operations and table management
9
9
  """
@@ -45,35 +45,32 @@ from .basic import (
45
45
 
46
46
  __all__ = [
47
47
  # Analytics tools
48
- 'analyze_memory_patterns',
49
- 'get_content_health_score',
50
-
48
+ "analyze_memory_patterns",
49
+ "get_content_health_score",
51
50
  # Search tools
52
- 'search_content',
53
- 'explore_tables',
54
- 'add_embeddings',
55
- 'semantic_search',
56
- 'find_related',
57
- 'smart_search',
58
- 'embedding_stats',
59
- 'auto_semantic_search',
60
- 'auto_smart_search',
61
-
51
+ "search_content",
52
+ "explore_tables",
53
+ "add_embeddings",
54
+ "semantic_search",
55
+ "find_related",
56
+ "smart_search",
57
+ "embedding_stats",
58
+ "auto_semantic_search",
59
+ "auto_smart_search",
62
60
  # Discovery tools
63
- 'intelligent_discovery',
64
- 'discovery_templates',
65
- 'discover_relationships',
66
-
61
+ "intelligent_discovery",
62
+ "discovery_templates",
63
+ "discover_relationships",
67
64
  # Basic tools
68
- 'create_table',
69
- 'list_tables',
70
- 'describe_table',
71
- 'drop_table',
72
- 'rename_table',
73
- 'create_row',
74
- 'read_rows',
75
- 'update_rows',
76
- 'delete_rows',
77
- 'run_select_query',
78
- 'list_all_columns',
65
+ "create_table",
66
+ "list_tables",
67
+ "describe_table",
68
+ "drop_table",
69
+ "rename_table",
70
+ "create_row",
71
+ "read_rows",
72
+ "update_rows",
73
+ "delete_rows",
74
+ "run_select_query",
75
+ "list_all_columns",
79
76
  ]