mcp-sqlite-memory-bank 1.4.1__py3-none-any.whl → 1.4.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.
@@ -429,7 +429,12 @@ class SQLiteMemoryDatabase:
429
429
  )
430
430
 
431
431
  # Sort by relevance and limit results
432
- results.sort(key=lambda x: x["relevance"], reverse=True)
432
+ def get_relevance(x: Dict[str, Any]) -> float:
433
+ rel = x.get("relevance", 0)
434
+ if isinstance(rel, (int, float)):
435
+ return float(rel)
436
+ return 0.0
437
+ results.sort(key=get_relevance, reverse=True)
433
438
  results = results[:limit]
434
439
 
435
440
  return {
@@ -453,7 +458,7 @@ class SQLiteMemoryDatabase:
453
458
  if pattern:
454
459
  table_names = [name for name in table_names if pattern.replace("%", "") in name]
455
460
 
456
- exploration = {"tables": [], "total_tables": len(table_names), "total_rows": 0}
461
+ exploration: Dict[str, Any] = {"tables": [], "total_tables": len(table_names), "total_rows": 0}
457
462
 
458
463
  with self.get_connection() as conn:
459
464
  for table_name in table_names:
@@ -461,7 +466,7 @@ class SQLiteMemoryDatabase:
461
466
 
462
467
  # Build column info and identify text columns
463
468
  columns = []
464
- text_columns = []
469
+ text_columns: List[str] = []
465
470
 
466
471
  for col in table.columns:
467
472
  col_data = {
@@ -476,7 +481,7 @@ class SQLiteMemoryDatabase:
476
481
  if "TEXT" in str(col.type).upper() or "VARCHAR" in str(col.type).upper():
477
482
  text_columns.append(col.name)
478
483
 
479
- table_info = {"name": table_name, "columns": columns, "text_columns": text_columns}
484
+ table_info: Dict[str, Any] = {"name": table_name, "columns": columns, "text_columns": text_columns}
480
485
 
481
486
  # Add row count if requested
482
487
  if include_row_counts:
@@ -493,11 +498,11 @@ class SQLiteMemoryDatabase:
493
498
 
494
499
  # Add content preview for text columns
495
500
  if text_columns:
496
- content_preview = {}
501
+ content_preview: Dict[str, List[Any]] = {}
497
502
  for col_name in text_columns[:3]: # Limit to first 3 text columns
498
503
  col = table.c[col_name]
499
504
  preview_result = conn.execute(select(col).distinct().where(col.isnot(None)).limit(5))
500
- unique_values = [row[0] for row in preview_result.fetchall() if row[0]]
505
+ unique_values: List[Any] = [row[0] for row in preview_result.fetchall() if row[0]]
501
506
  if unique_values:
502
507
  content_preview[col_name] = unique_values
503
508
 
@@ -1001,6 +1006,9 @@ def get_database(db_path: Optional[str] = None) -> SQLiteMemoryDatabase:
1001
1006
  global _db_instance
1002
1007
 
1003
1008
  actual_path = db_path or os.environ.get("DB_PATH", "./test.db")
1009
+ if actual_path is None:
1010
+ actual_path = "./test.db"
1011
+
1004
1012
  if _db_instance is None or (db_path and db_path != _db_instance.db_path):
1005
1013
  # Close previous instance if it exists
1006
1014
  if _db_instance is not None:
@@ -11,7 +11,7 @@ stored memory content into LLM conversations.
11
11
  Author: Robert Meisner
12
12
  """
13
13
 
14
- from typing import Optional
14
+ from typing import Optional, Dict, List, Any, cast
15
15
  from fastmcp import FastMCP
16
16
  from .database import get_database
17
17
  import json
@@ -35,7 +35,7 @@ class MemoryBankPrompts:
35
35
 
36
36
  if table_name:
37
37
  # Analyze specific table
38
- result = db.read_rows(table_name, {})
38
+ result = cast(Dict[str, Any], db.read_rows(table_name, {}))
39
39
  if not result.get("success"):
40
40
  return f"Error: Could not access table '{table_name}'. Please check if it exists."
41
41
 
@@ -55,7 +55,7 @@ Please provide:
55
55
  Focus on actionable insights that could help improve how this information is stored and retrieved."""
56
56
  else:
57
57
  # Analyze all tables
58
- tables_result = db.list_tables()
58
+ tables_result = cast(Dict[str, Any], db.list_tables())
59
59
  if not tables_result.get("success"):
60
60
  return "Error: Could not access memory bank tables."
61
61
 
@@ -63,10 +63,11 @@ Focus on actionable insights that could help improve how this information is sto
63
63
  overview = {"tables": len(tables), "total_content": []}
64
64
 
65
65
  for table in tables[:5]: # Limit to first 5 tables
66
- rows_result = db.read_rows(table, {})
66
+ rows_result = cast(Dict[str, Any], db.read_rows(table, {}))
67
67
  if rows_result.get("success"):
68
68
  rows = rows_result.get("rows", [])
69
- overview["total_content"].append({
69
+ total_content = cast(List[Any], overview["total_content"])
70
+ total_content.append({
70
71
  "table": table,
71
72
  "rows": len(rows),
72
73
  "sample": rows[:2] if rows else []
@@ -93,7 +94,7 @@ Focus on high-level strategic insights about the memory bank's utility and organ
93
94
  db = get_database(self.db_path)
94
95
 
95
96
  # Perform search
96
- result = db.search_content(query, None, max_results or 10)
97
+ result = cast(Dict[str, Any], db.search_content(query, None, max_results or 10))
97
98
  if not result.get("success"):
98
99
  return f"Error: Could not search for '{query}'. {result.get('error', 'Unknown error')}"
99
100
 
@@ -130,7 +131,7 @@ Use this information to provide a thorough, well-organized response that synthes
130
131
  db = get_database(self.db_path)
131
132
 
132
133
  # Try to find technical_decisions table
133
- tables_result = db.list_tables()
134
+ tables_result = cast(Dict[str, Any], db.list_tables())
134
135
  if not tables_result.get("success"):
135
136
  return "Error: Could not access memory bank."
136
137
 
@@ -162,7 +163,8 @@ The table should include fields like: decision_name, chosen_approach, rationale,
162
163
 
163
164
  # Format decisions for analysis
164
165
  formatted_decisions = []
165
- for i, decision in enumerate(decisions, 1):
166
+ decisions_list = cast(List[Dict[str, Any]], decisions)
167
+ for i, decision in enumerate(decisions_list, 1):
166
168
  formatted_decisions.append(f"{i}. Decision: {decision.get('decision_name', 'Unknown')}")
167
169
  formatted_decisions.append(f" Approach: {decision.get('chosen_approach', 'Not specified')}")
168
170
  formatted_decisions.append(f" Rationale: {decision.get('rationale', 'Not provided')}")
@@ -215,19 +217,21 @@ Focus on actionable insights that can improve technical decision-making processe
215
217
  }
216
218
 
217
219
  if context_type == "brief":
220
+ tables_list = cast(List[str], tables)
218
221
  prompt = f"""Memory Bank Context (Brief):
219
- Available tables: {', '.join(tables)}
220
- Total tables: {len(tables)}
222
+ Available tables: {', '.join(tables_list)}
223
+ Total tables: {len(tables_list)}
221
224
 
222
225
  This memory bank contains structured information that can be searched and analyzed. Use the available tools to access specific content as needed."""
223
226
  else:
224
227
  # Get sample content from a few tables
225
228
  sample_content = {}
226
- for table in tables[:3]: # Sample from first 3 tables
229
+ tables_list = cast(List[str], tables)
230
+ for table in tables_list[:3]: # Sample from first 3 tables
227
231
  try:
228
- result = db.read_rows(table, {})
232
+ result = cast(Dict[str, Any], db.read_rows(table, {}))
229
233
  if result.get("success"):
230
- rows = result.get("rows", [])
234
+ rows = cast(List[Any], result.get("rows", []))
231
235
  sample_content[table] = {
232
236
  "row_count": len(rows),
233
237
  "sample_row": rows[0] if rows else None
@@ -11,6 +11,7 @@ the standardized MCP protocol.
11
11
  Author: Robert Meisner
12
12
  """
13
13
 
14
+ from typing import Dict, Any, cast
14
15
  from fastmcp import FastMCP
15
16
  from .database import get_database
16
17
  import json
@@ -31,7 +32,7 @@ class MemoryBankResources:
31
32
  async def get_tables_list() -> str:
32
33
  """Provide a list of all available tables as an MCP resource."""
33
34
  db = get_database(self.db_path)
34
- result = db.list_tables()
35
+ result = cast(Dict[str, Any], db.list_tables())
35
36
 
36
37
  if not result.get("success"):
37
38
  return json.dumps({"error": "Failed to fetch tables", "details": result})
@@ -50,7 +51,7 @@ class MemoryBankResources:
50
51
  async def get_table_schema(table_name: str) -> str:
51
52
  """Provide table schema information as an MCP resource."""
52
53
  db = get_database(self.db_path)
53
- result = db.describe_table(table_name)
54
+ result = cast(Dict[str, Any], db.describe_table(table_name))
54
55
 
55
56
  if not result.get("success"):
56
57
  return json.dumps({"error": f"Failed to fetch schema for table '{table_name}'", "details": result})
@@ -70,7 +71,7 @@ class MemoryBankResources:
70
71
  async def get_table_data(table_name: str) -> str:
71
72
  """Provide table data as an MCP resource."""
72
73
  db = get_database(self.db_path)
73
- result = db.read_rows(table_name, {})
74
+ result = cast(Dict[str, Any], db.read_rows(table_name, {}))
74
75
 
75
76
  if not result.get("success"):
76
77
  return json.dumps({"error": f"Failed to fetch data for table '{table_name}'", "details": result})
@@ -91,7 +92,7 @@ class MemoryBankResources:
91
92
  async def search_memory_content(query: str) -> str:
92
93
  """Provide search results as an MCP resource."""
93
94
  db = get_database(self.db_path)
94
- result = db.search_content(query, None, 50) # Search all tables, limit to 50 results
95
+ result = cast(Dict[str, Any], db.search_content(query, None, 50)) # Search all tables, limit to 50 results
95
96
 
96
97
  if not result.get("success"):
97
98
  return json.dumps({"error": f"Failed to search for '{query}'", "details": result})
@@ -114,7 +115,7 @@ class MemoryBankResources:
114
115
  db = get_database(self.db_path)
115
116
 
116
117
  # Get table list
117
- tables_result = db.list_tables()
118
+ tables_result = cast(Dict[str, Any], db.list_tables())
118
119
  if not tables_result.get("success"):
119
120
  return json.dumps({"error": "Failed to fetch memory overview", "details": tables_result})
120
121
 
@@ -125,7 +126,7 @@ class MemoryBankResources:
125
126
  # Get row counts for each table
126
127
  for table in tables:
127
128
  try:
128
- rows_result = db.read_rows(table, {})
129
+ rows_result = cast(Dict[str, Any], db.read_rows(table, {}))
129
130
  if rows_result.get("success"):
130
131
  row_count = len(rows_result.get("rows", []))
131
132
  table_stats[table] = {
@@ -144,13 +145,24 @@ class MemoryBankResources:
144
145
  "status": f"error: {str(e)}"
145
146
  }
146
147
 
148
+ # Find largest table
149
+ largest_table = None
150
+ if table_stats:
151
+ max_rows = 0
152
+ for table_name, stats in table_stats.items():
153
+ row_count_obj = stats.get("row_count", 0)
154
+ row_count = int(row_count_obj) if isinstance(row_count_obj, (int, str)) else 0
155
+ if row_count > max_rows:
156
+ max_rows = row_count
157
+ largest_table = table_name
158
+
147
159
  resource_content = {
148
160
  "resource_type": "memory_overview",
149
161
  "description": "Overview of memory bank contents and usage",
150
162
  "summary": {
151
163
  "total_tables": len(tables),
152
164
  "total_rows": total_rows,
153
- "largest_table": max(table_stats.items(), key=lambda x: x[1]["row_count"])[0] if table_stats else None
165
+ "largest_table": largest_table
154
166
  },
155
167
  "table_statistics": table_stats,
156
168
  "last_updated": "dynamic"
@@ -19,8 +19,8 @@ try:
19
19
  SENTENCE_TRANSFORMERS_AVAILABLE = True
20
20
  except ImportError:
21
21
  SENTENCE_TRANSFORMERS_AVAILABLE = False
22
- SentenceTransformer = None
23
- util = None
22
+ SentenceTransformer = None # type: ignore
23
+ util = None # type: ignore
24
24
  logging.warning("sentence-transformers not available. Install with: pip install sentence-transformers")
25
25
 
26
26
  try:
@@ -29,7 +29,7 @@ try:
29
29
  TORCH_AVAILABLE = True
30
30
  except ImportError:
31
31
  TORCH_AVAILABLE = False
32
- torch = None
32
+ torch = None # type: ignore
33
33
  logging.warning("torch not available. Install with: pip install torch")
34
34
 
35
35
  from .types import ValidationError, DatabaseError
@@ -50,7 +50,7 @@ class SemanticSearchEngine:
50
50
  """Initialize the semantic search engine."""
51
51
  self.model_name = model_name
52
52
  self._model = None
53
- self._embedding_cache = {}
53
+ self._embedding_cache: Dict[str, Any] = {}
54
54
 
55
55
  if not SENTENCE_TRANSFORMERS_AVAILABLE:
56
56
  raise ValueError(
@@ -470,7 +470,12 @@ def add_embeddings(
470
470
  table_name: str, text_columns: List[str], embedding_column: str = "embedding", model_name: str = "all-MiniLM-L6-v2"
471
471
  ) -> ToolResponse:
472
472
  """
473
+ ⚠️ **ADVANCED TOOL** - Most agents should use auto_smart_search() instead!
474
+
473
475
  Generate and store vector embeddings for semantic search on table content.
476
+
477
+ **RECOMMENDATION**: Use auto_smart_search() or auto_semantic_search() for automatic setup.
478
+ This tool is for advanced users who need manual control over embedding generation.
474
479
 
475
480
  This tool enables intelligent knowledge discovery by creating vector representations
476
481
  of text content that can be searched semantically rather than just by exact keywords.
@@ -511,7 +516,12 @@ def semantic_search(
511
516
  model_name: str = "all-MiniLM-L6-v2",
512
517
  ) -> ToolResponse:
513
518
  """
519
+ ⚠️ **ADVANCED TOOL** - Most agents should use auto_smart_search() instead!
520
+
514
521
  Find content using natural language semantic similarity rather than exact keyword matching.
522
+
523
+ **RECOMMENDATION**: Use auto_smart_search() for automatic setup and hybrid search capabilities.
524
+ This tool requires manual embedding setup via add_embeddings() first.
515
525
 
516
526
  This enables intelligent knowledge discovery - find related concepts even when
517
527
  they use different terminology or phrasing.
@@ -610,7 +620,12 @@ def smart_search(
610
620
  model_name: str = "all-MiniLM-L6-v2",
611
621
  ) -> ToolResponse:
612
622
  """
623
+ ⚠️ **ADVANCED TOOL** - Most agents should use auto_smart_search() instead!
624
+
613
625
  Intelligent hybrid search combining semantic understanding with keyword matching.
626
+
627
+ **RECOMMENDATION**: Use auto_smart_search() for the same functionality with automatic setup.
628
+ This tool requires manual embedding setup via add_embeddings() first.
614
629
 
615
630
  Provides the best of both worlds - semantic similarity for concept discovery
616
631
  plus exact text matching for precise searches.
@@ -639,7 +654,7 @@ def smart_search(
639
654
  - Provides separate scores for transparency
640
655
  - Falls back gracefully if semantic search unavailable
641
656
  - Optimal for both exploratory and precise searches
642
- - Recommended for general-purpose knowledge discovery
657
+ - Perfect for agents - ultimate search tool that just works!
643
658
  """
644
659
  return cast(
645
660
  ToolResponse,
@@ -649,34 +664,193 @@ def smart_search(
649
664
  )
650
665
 
651
666
 
667
+ # --- Auto-Embedding Semantic Search Tools ---
668
+
669
+
652
670
  @mcp.tool
653
671
  @catch_errors
654
- def embedding_stats(table_name: str, embedding_column: str = "embedding") -> ToolResponse:
672
+ def auto_semantic_search(
673
+ query: str,
674
+ tables: Optional[List[str]] = None,
675
+ similarity_threshold: float = 0.5,
676
+ limit: int = 10,
677
+ model_name: str = "all-MiniLM-L6-v2",
678
+ ) -> ToolResponse:
655
679
  """
656
- Get statistics about semantic search readiness for a table.
680
+ 🚀 **ZERO-SETUP SEMANTIC SEARCH** - Just search, embeddings are handled automatically!
657
681
 
658
- Check which content has embeddings and can be searched semantically.
682
+ Find content using natural language semantic similarity. If embeddings don't exist,
683
+ they will be automatically generated for text columns. This is the easiest way to
684
+ do semantic search - no manual setup required!
659
685
 
660
686
  Args:
661
- table_name (str): Table to analyze
662
- embedding_column (str): Embedding column to check (default: "embedding")
687
+ query (str): Natural language search query
688
+ tables (Optional[List[str]]): Specific tables to search (default: all tables)
689
+ similarity_threshold (float): Minimum similarity score (0.0-1.0, default: 0.5)
690
+ limit (int): Maximum number of results to return (default: 10)
691
+ model_name (str): Model to use for embeddings (default: "all-MiniLM-L6-v2")
663
692
 
664
693
  Returns:
665
- ToolResponse: On success: {"success": True, "coverage_percent": float, "total_rows": int}
694
+ ToolResponse: On success: {"success": True, "results": List[...], "auto_embedded_tables": List[str]}
666
695
  On error: {"success": False, "error": str, "category": str, "details": dict}
667
696
 
668
697
  Examples:
669
- >>> embedding_stats("technical_decisions")
670
- {"success": True, "total_rows": 25, "embedded_rows": 25, "coverage_percent": 100.0,
671
- "embedding_dimensions": 384}
698
+ >>> auto_semantic_search("API design patterns")
699
+ {"success": True, "results": [
700
+ {"table_name": "technical_decisions", "similarity_score": 0.87, "decision_name": "REST API Structure", ...}
701
+ ], "auto_embedded_tables": ["technical_decisions"]}
702
+
703
+ >>> auto_semantic_search("machine learning concepts")
704
+ # Finds content about "ML", "AI", "neural networks", etc.
705
+ # Automatically creates embeddings if they don't exist!
672
706
 
673
707
  FastMCP Tool Info:
674
- - Shows how much content is ready for semantic search
675
- - Helps identify tables that need embedding generation
676
- - Provides embedding dimension info for debugging
677
- - Useful for monitoring semantic search capabilities
708
+ - **COMPLETELY AUTOMATIC**: No manual embedding setup required
709
+ - Auto-detects text columns and creates embeddings as needed
710
+ - Works across multiple tables simultaneously
711
+ - Finds conceptually similar content regardless of exact wording
712
+ - Returns relevance scores for ranking results
713
+ - Supports fuzzy matching and concept discovery
714
+ - Perfect for agents - just search and it works!
678
715
  """
679
- return cast(ToolResponse, get_database(DB_PATH).get_embedding_stats(table_name, embedding_column))
716
+ try:
717
+ db = get_database(DB_PATH)
718
+ auto_embedded_tables = []
719
+
720
+ # Get tables to search
721
+ if tables:
722
+ search_tables = tables
723
+ else:
724
+ tables_result = db.list_tables()
725
+ if not tables_result.get("success"):
726
+ return cast(ToolResponse, tables_result)
727
+ search_tables = tables_result.get("tables", [])
728
+
729
+ # Auto-embed text columns in tables that don't have embeddings
730
+ for table_name in search_tables:
731
+ try:
732
+ # Check if table has embeddings
733
+ stats_result = db.get_embedding_stats(table_name, "embedding")
734
+ if stats_result.get("success") and stats_result.get("coverage_percent", 0) > 0:
735
+ continue # Table already has embeddings
736
+
737
+ # Get table schema to find text columns
738
+ schema_result = db.describe_table(table_name)
739
+ if not schema_result.get("success"):
740
+ continue
741
+
742
+ # Find text columns
743
+ text_columns = []
744
+ for col in schema_result.get("columns", []):
745
+ if "TEXT" in col.get("type", "").upper():
746
+ text_columns.append(col["name"])
747
+
748
+ # Auto-embed text columns
749
+ if text_columns:
750
+ embed_result = db.generate_embeddings(table_name, text_columns, "embedding", model_name)
751
+ if embed_result.get("success"):
752
+ auto_embedded_tables.append(table_name)
753
+
754
+ except Exception:
755
+ # If auto-embedding fails, continue without it
756
+ continue
757
+
758
+ # Perform semantic search
759
+ search_result = db.semantic_search(
760
+ query, search_tables, "embedding", None, similarity_threshold, limit, model_name
761
+ )
762
+
763
+ # Add auto-embedding info to result
764
+ if isinstance(search_result, dict):
765
+ search_result["auto_embedded_tables"] = auto_embedded_tables
766
+ if auto_embedded_tables:
767
+ search_result["auto_embedding_note"] = f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
768
+
769
+ return cast(ToolResponse, search_result)
770
+
771
+ except Exception as e:
772
+ return cast(ToolResponse, {
773
+ "success": False,
774
+ "error": f"Auto semantic search failed: {str(e)}",
775
+ "category": "SEMANTIC_SEARCH_ERROR",
776
+ "details": {"query": query, "tables": tables}
777
+ })
778
+
779
+
780
+ @mcp.tool
781
+ @catch_errors
782
+ def auto_smart_search(
783
+ query: str,
784
+ tables: Optional[List[str]] = None,
785
+ semantic_weight: float = 0.7,
786
+ text_weight: float = 0.3,
787
+ limit: int = 10,
788
+ model_name: str = "all-MiniLM-L6-v2",
789
+ ) -> ToolResponse:
790
+ """
791
+ 🚀 **ZERO-SETUP HYBRID SEARCH** - Best of both worlds with automatic embedding!
792
+
793
+ Intelligent hybrid search combining semantic understanding with keyword matching.
794
+ Automatically generates embeddings for text columns when needed. This is the
795
+ ultimate search tool - no manual setup required!
796
+
797
+ Args:
798
+ query (str): Search query (natural language or keywords)
799
+ tables (Optional[List[str]]): Tables to search (default: all)
800
+ semantic_weight (float): Weight for semantic similarity (0.0-1.0, default: 0.7)
801
+ text_weight (float): Weight for keyword matching (0.0-1.0, default: 0.3)
802
+ limit (int): Maximum results (default: 10)
803
+ model_name (str): Semantic model to use (default: "all-MiniLM-L6-v2")
804
+
805
+ Returns:
806
+ ToolResponse: On success: {"success": True, "results": List[...], "search_type": "auto_hybrid"}
807
+ On error: {"success": False, "error": str, "category": str, "details": dict}
808
+
809
+ Examples:
810
+ >>> auto_smart_search("user authentication security")
811
+ {"success": True, "results": [
812
+ {"combined_score": 0.89, "semantic_score": 0.92, "text_score": 0.82, ...}
813
+ ], "search_type": "auto_hybrid", "auto_embedded_tables": ["user_data"]}
814
+
815
+ FastMCP Tool Info:
816
+ - **COMPLETELY AUTOMATIC**: No manual embedding setup required
817
+ - Automatically balances semantic and keyword search
818
+ - Auto-detects text columns and creates embeddings as needed
819
+ - Provides separate scores for transparency
820
+ - Falls back gracefully if semantic search unavailable
821
+ - Optimal for both exploratory and precise searches
822
+ - Perfect for agents - ultimate search tool that just works!
823
+ """
824
+ try:
825
+ # First try auto semantic search to ensure embeddings exist
826
+ auto_semantic_result = auto_semantic_search(query, tables, 0.3, limit, model_name)
827
+ auto_embedded_tables = []
828
+
829
+ if auto_semantic_result.get("success"):
830
+ auto_embedded_tables = auto_semantic_result.get("auto_embedded_tables", [])
831
+
832
+ # Now perform hybrid search
833
+ db = get_database(DB_PATH)
834
+ hybrid_result = db.hybrid_search(
835
+ query, tables, None, "embedding", semantic_weight, text_weight, limit, model_name
836
+ )
837
+
838
+ # Add auto-embedding info to result
839
+ if isinstance(hybrid_result, dict):
840
+ hybrid_result["search_type"] = "auto_hybrid"
841
+ hybrid_result["auto_embedded_tables"] = auto_embedded_tables
842
+ if auto_embedded_tables:
843
+ hybrid_result["auto_embedding_note"] = f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
844
+
845
+ return cast(ToolResponse, hybrid_result)
846
+
847
+ except Exception as e:
848
+ return cast(ToolResponse, {
849
+ "success": False,
850
+ "error": f"Auto smart search failed: {str(e)}",
851
+ "category": "HYBRID_SEARCH_ERROR",
852
+ "details": {"query": query, "tables": tables}
853
+ })
680
854
 
681
855
 
682
856
  # --- Enhanced Tool Discovery and Categorization ---
@@ -792,9 +966,6 @@ def get_tools_by_category(category: str) -> ToolResponse:
792
966
  })
793
967
 
794
968
 
795
- # ...existing code...
796
-
797
-
798
969
  # Export the FastMCP app for use in other modules and server runners
799
970
  app = mcp
800
971
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp_sqlite_memory_bank
3
- Version: 1.4.1
3
+ Version: 1.4.2
4
4
  Summary: A dynamic, agent/LLM-friendly SQLite memory bank for MCP servers with semantic search capabilities.
5
5
  Author-email: Robert Meisner <robert@catchit.pl>
6
6
  License-Expression: MIT
@@ -0,0 +1,15 @@
1
+ mcp_sqlite_memory_bank/__init__.py,sha256=6Y9_iSiQIWOPJYMcMkbrqmaWiM-ymRHdNR6W-8jHj-k,2403
2
+ mcp_sqlite_memory_bank/database.py,sha256=dQdl3QPqBBf_AQwMXHjRZ8rdget0UKQ2vz0V-Ik1o7g,42231
3
+ mcp_sqlite_memory_bank/prompts.py,sha256=nLY6rf08wU5TeSLoSxjTlwcU_OIiJeOIkJYDQM_PFpo,11762
4
+ mcp_sqlite_memory_bank/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ mcp_sqlite_memory_bank/resources.py,sha256=A55G44MIQdNiYlOa9fJqGVC7OL_Cx7sbE8oCF4JlnX8,7464
6
+ mcp_sqlite_memory_bank/semantic.py,sha256=wvabBqlThNN76feyEa8BNRachBZYxkZQaPPIweHgxV8,14855
7
+ mcp_sqlite_memory_bank/server.py,sha256=x4cHGEheG6XY54ErHjtRaPPsDjbQUdvmWZPgipKk7rU,48096
8
+ mcp_sqlite_memory_bank/types.py,sha256=2rNhd6dbvEFsey9QGHQ0VPGSB3U0RaXw8fKVfiBuUJw,6535
9
+ mcp_sqlite_memory_bank/utils.py,sha256=wHbR0cUlV-AWBk8ToI5ZgCrfrMp380ofyEc_GLB0l4g,6185
10
+ mcp_sqlite_memory_bank-1.4.2.dist-info/licenses/LICENSE,sha256=KPr7eFgCJqQIjeSAcwRafbjcgm-10zkrJ7MFoTOGJQg,1092
11
+ mcp_sqlite_memory_bank-1.4.2.dist-info/METADATA,sha256=D52NnWZDvyA9lVqgM-YZaev8X3lfAeQdo2udl3GHj_k,33094
12
+ mcp_sqlite_memory_bank-1.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
+ mcp_sqlite_memory_bank-1.4.2.dist-info/entry_points.txt,sha256=S9yGWiCe8f_rgcGCgbwEAX2FfJ9jXWxcc4K4Jenbcn8,150
14
+ mcp_sqlite_memory_bank-1.4.2.dist-info/top_level.txt,sha256=xQ8MTGECpWMR-9DV4H8mMqaSoZqE-C8EvpOg9E2U1wM,23
15
+ mcp_sqlite_memory_bank-1.4.2.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- mcp_sqlite_memory_bank/__init__.py,sha256=6Y9_iSiQIWOPJYMcMkbrqmaWiM-ymRHdNR6W-8jHj-k,2403
2
- mcp_sqlite_memory_bank/database.py,sha256=kBHiibDV2ucm9alaDrNB-txm7v-hGt-uTNHIFKuFlKI,41873
3
- mcp_sqlite_memory_bank/prompts.py,sha256=AYTpyxRh_YacQQ4SfFJIXGLLyxWaAVmEnkZ9-fgZv1c,11320
4
- mcp_sqlite_memory_bank/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- mcp_sqlite_memory_bank/resources.py,sha256=g1IId2yCDQuv0zC5oEzBGhEZrDgi6z3wKpJZujXsr0Y,6869
6
- mcp_sqlite_memory_bank/semantic.py,sha256=XVfM1C95TdZDtXOrwrGxR5JZnmeeO4O45gxniPWa6go,14791
7
- mcp_sqlite_memory_bank/server.py,sha256=2isYtWyGFIVE1kOE_HWJR0R610YHHWCduKb6srC5ajM,40222
8
- mcp_sqlite_memory_bank/types.py,sha256=2rNhd6dbvEFsey9QGHQ0VPGSB3U0RaXw8fKVfiBuUJw,6535
9
- mcp_sqlite_memory_bank/utils.py,sha256=wHbR0cUlV-AWBk8ToI5ZgCrfrMp380ofyEc_GLB0l4g,6185
10
- mcp_sqlite_memory_bank-1.4.1.dist-info/licenses/LICENSE,sha256=KPr7eFgCJqQIjeSAcwRafbjcgm-10zkrJ7MFoTOGJQg,1092
11
- mcp_sqlite_memory_bank-1.4.1.dist-info/METADATA,sha256=DJa6MX4cN5wxlX-sr0W8MaGuZgeASXkl-XsX7Z9kw7w,33094
12
- mcp_sqlite_memory_bank-1.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- mcp_sqlite_memory_bank-1.4.1.dist-info/entry_points.txt,sha256=S9yGWiCe8f_rgcGCgbwEAX2FfJ9jXWxcc4K4Jenbcn8,150
14
- mcp_sqlite_memory_bank-1.4.1.dist-info/top_level.txt,sha256=xQ8MTGECpWMR-9DV4H8mMqaSoZqE-C8EvpOg9E2U1wM,23
15
- mcp_sqlite_memory_bank-1.4.1.dist-info/RECORD,,