mcp-sqlite-memory-bank 1.4.2__tar.gz → 1.4.3__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 (24) hide show
  1. {mcp_sqlite_memory_bank-1.4.2/src/mcp_sqlite_memory_bank.egg-info → mcp_sqlite_memory_bank-1.4.3}/PKG-INFO +1 -1
  2. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/pyproject.toml +1 -1
  3. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/database.py +18 -2
  4. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/server.py +100 -17
  5. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/types.py +3 -1
  6. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3/src/mcp_sqlite_memory_bank.egg-info}/PKG-INFO +1 -1
  7. mcp_sqlite_memory_bank-1.4.3/tests/test_api.py +984 -0
  8. mcp_sqlite_memory_bank-1.4.2/tests/test_api.py +0 -434
  9. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/LICENSE +0 -0
  10. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/MANIFEST.in +0 -0
  11. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/README.md +0 -0
  12. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/setup.cfg +0 -0
  13. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/__init__.py +0 -0
  14. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/prompts.py +0 -0
  15. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/py.typed +0 -0
  16. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/resources.py +0 -0
  17. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/semantic.py +0 -0
  18. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank/utils.py +0 -0
  19. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank.egg-info/SOURCES.txt +0 -0
  20. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank.egg-info/dependency_links.txt +0 -0
  21. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank.egg-info/entry_points.txt +0 -0
  22. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank.egg-info/requires.txt +0 -0
  23. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/src/mcp_sqlite_memory_bank.egg-info/top_level.txt +0 -0
  24. {mcp_sqlite_memory_bank-1.4.2 → mcp_sqlite_memory_bank-1.4.3}/tests/test_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp_sqlite_memory_bank
3
- Version: 1.4.2
3
+ Version: 1.4.3
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcp_sqlite_memory_bank"
7
- version = "1.4.2"
7
+ version = "1.4.3"
8
8
  description = "A dynamic, agent/LLM-friendly SQLite memory bank for MCP servers with semantic search capabilities."
9
9
  authors = [
10
10
  { name="Robert Meisner", email="robert@catchit.pl" }
@@ -27,7 +27,6 @@ from .types import (
27
27
  SemanticSearchResponse,
28
28
  RelatedContentResponse,
29
29
  HybridSearchResponse,
30
- EmbeddingStatsResponse,
31
30
  )
32
31
  from .semantic import get_semantic_engine, is_semantic_search_available
33
32
 
@@ -932,11 +931,28 @@ class SQLiteMemoryDatabase:
932
931
  raise e
933
932
  raise DatabaseError(f"Hybrid search failed: {str(e)}")
934
933
 
935
- def get_embedding_stats(self, table_name: str, embedding_column: str = "embedding") -> EmbeddingStatsResponse:
934
+ def get_embedding_stats(self, table_name: str, embedding_column: str = "embedding") -> ToolResponse:
936
935
  """Get statistics about embeddings in a table."""
937
936
  try:
938
937
  table = self._ensure_table_exists(table_name)
939
938
 
939
+ # Check if embedding column exists
940
+ if embedding_column not in [col.name for col in table.columns]:
941
+ # Return 0% coverage when column doesn't exist (for compatibility with tests)
942
+ total_count = 0
943
+ with self.get_connection() as conn:
944
+ total_count = conn.execute(select(text("COUNT(*)")).select_from(table)).scalar() or 0
945
+
946
+ return {
947
+ "success": True,
948
+ "table_name": table_name,
949
+ "total_rows": total_count,
950
+ "embedded_rows": 0,
951
+ "coverage_percent": 0.0,
952
+ "embedding_dimensions": None,
953
+ "embedding_column": embedding_column,
954
+ }
955
+
940
956
  with self.get_connection() as conn:
941
957
  # Count total rows
942
958
  total_count = conn.execute(select(text("COUNT(*)")).select_from(table)).scalar() or 0
@@ -715,23 +715,29 @@ def auto_semantic_search(
715
715
  """
716
716
  try:
717
717
  db = get_database(DB_PATH)
718
- auto_embedded_tables = []
718
+ auto_embedded_tables: List[str] = []
719
719
 
720
720
  # Get tables to search
721
+ search_tables: List[str]
721
722
  if tables:
722
723
  search_tables = tables
723
724
  else:
724
725
  tables_result = db.list_tables()
725
726
  if not tables_result.get("success"):
726
727
  return cast(ToolResponse, tables_result)
727
- search_tables = tables_result.get("tables", [])
728
+ all_tables = tables_result.get("tables", [])
729
+ if isinstance(all_tables, list):
730
+ search_tables = all_tables
731
+ else:
732
+ search_tables = []
728
733
 
729
734
  # Auto-embed text columns in tables that don't have embeddings
730
735
  for table_name in search_tables:
731
736
  try:
732
737
  # Check if table has embeddings
733
738
  stats_result = db.get_embedding_stats(table_name, "embedding")
734
- if stats_result.get("success") and stats_result.get("coverage_percent", 0) > 0:
739
+ coverage_percent = stats_result.get("coverage_percent", 0)
740
+ if stats_result.get("success") and isinstance(coverage_percent, (int, float)) and coverage_percent > 0:
735
741
  continue # Table already has embeddings
736
742
 
737
743
  # Get table schema to find text columns
@@ -741,9 +747,11 @@ def auto_semantic_search(
741
747
 
742
748
  # Find text columns
743
749
  text_columns = []
744
- for col in schema_result.get("columns", []):
745
- if "TEXT" in col.get("type", "").upper():
746
- text_columns.append(col["name"])
750
+ columns = schema_result.get("columns", [])
751
+ if isinstance(columns, list):
752
+ for col in columns:
753
+ if isinstance(col, dict) and "TEXT" in col.get("type", "").upper():
754
+ text_columns.append(col["name"])
747
755
 
748
756
  # Auto-embed text columns
749
757
  if text_columns:
@@ -822,12 +830,54 @@ def auto_smart_search(
822
830
  - Perfect for agents - ultimate search tool that just works!
823
831
  """
824
832
  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 = []
833
+ db = get_database(DB_PATH)
834
+ auto_embedded_tables: List[str] = []
828
835
 
829
- if auto_semantic_result.get("success"):
830
- auto_embedded_tables = auto_semantic_result.get("auto_embedded_tables", [])
836
+ # Get tables to search
837
+ search_tables: List[str]
838
+ if tables:
839
+ search_tables = tables
840
+ else:
841
+ tables_result = db.list_tables()
842
+ if not tables_result.get("success"):
843
+ return cast(ToolResponse, tables_result)
844
+ all_tables = tables_result.get("tables", [])
845
+ if isinstance(all_tables, list):
846
+ search_tables = all_tables
847
+ else:
848
+ search_tables = []
849
+
850
+ # Auto-embed text columns in tables that don't have embeddings
851
+ for table_name in search_tables:
852
+ try:
853
+ # Check if table has embeddings
854
+ stats_result = db.get_embedding_stats(table_name, "embedding")
855
+ coverage_percent = stats_result.get("coverage_percent", 0)
856
+ if stats_result.get("success") and isinstance(coverage_percent, (int, float)) and coverage_percent > 0:
857
+ continue # Table already has embeddings
858
+
859
+ # Get table schema to find text columns
860
+ schema_result = db.describe_table(table_name)
861
+ if not schema_result.get("success"):
862
+ continue
863
+
864
+ # Find text columns
865
+ text_columns = []
866
+ columns = schema_result.get("columns", [])
867
+ if isinstance(columns, list):
868
+ for col in columns:
869
+ if isinstance(col, dict) and "TEXT" in col.get("type", "").upper():
870
+ text_columns.append(col["name"])
871
+
872
+ # Auto-embed text columns
873
+ if text_columns:
874
+ embed_result = db.generate_embeddings(table_name, text_columns, "embedding", model_name)
875
+ if embed_result.get("success"):
876
+ auto_embedded_tables.append(table_name)
877
+
878
+ except Exception:
879
+ # If auto-embedding fails, continue without it
880
+ continue
831
881
 
832
882
  # Now perform hybrid search
833
883
  db = get_database(DB_PATH)
@@ -836,13 +886,16 @@ def auto_smart_search(
836
886
  )
837
887
 
838
888
  # 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
889
+ if isinstance(hybrid_result, dict) and hybrid_result.get("success"):
890
+ # Convert to mutable dict to add extra fields
891
+ final_result = dict(hybrid_result)
892
+ final_result["search_type"] = "auto_hybrid"
893
+ final_result["auto_embedded_tables"] = auto_embedded_tables
842
894
  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)
895
+ final_result["auto_embedding_note"] = f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
896
+ return cast(ToolResponse, final_result)
897
+ else:
898
+ return cast(ToolResponse, hybrid_result)
846
899
 
847
900
  except Exception as e:
848
901
  return cast(ToolResponse, {
@@ -853,6 +906,36 @@ def auto_smart_search(
853
906
  })
854
907
 
855
908
 
909
+ @mcp.tool
910
+ @catch_errors
911
+ def embedding_stats(table_name: str, embedding_column: str = "embedding") -> ToolResponse:
912
+ """
913
+ Get statistics about semantic search readiness for a table.
914
+
915
+ Check which content has embeddings and can be searched semantically.
916
+
917
+ Args:
918
+ table_name (str): Table to analyze
919
+ embedding_column (str): Embedding column to check (default: "embedding")
920
+
921
+ Returns:
922
+ ToolResponse: On success: {"success": True, "coverage_percent": float, "total_rows": int}
923
+ On error: {"success": False, "error": str, "category": str, "details": dict}
924
+
925
+ Examples:
926
+ >>> embedding_stats("technical_decisions")
927
+ {"success": True, "total_rows": 25, "embedded_rows": 25, "coverage_percent": 100.0,
928
+ "embedding_dimensions": 384}
929
+
930
+ FastMCP Tool Info:
931
+ - Shows how much content is ready for semantic search
932
+ - Helps identify tables that need embedding generation
933
+ - Provides embedding dimension info for debugging
934
+ - Useful for monitoring semantic search capabilities
935
+ """
936
+ return cast(ToolResponse, get_database(DB_PATH).get_embedding_stats(table_name, embedding_column))
937
+
938
+
856
939
  # --- Enhanced Tool Discovery and Categorization ---
857
940
 
858
941
 
@@ -180,7 +180,7 @@ class ExploreTablesResponse(SuccessResponse):
180
180
 
181
181
 
182
182
  # Semantic Search Response Types
183
- class SemanticSearchResponse(TypedDict):
183
+ class SemanticSearchResponse(TypedDict, total=False):
184
184
  """Response type for semantic search operations."""
185
185
 
186
186
  success: bool
@@ -190,6 +190,8 @@ class SemanticSearchResponse(TypedDict):
190
190
  total_results: int
191
191
  model: str
192
192
  similarity_threshold: float
193
+ auto_embedded_tables: List[str] # Tables that had embeddings auto-generated
194
+ auto_embedding_note: str # Message about auto-embedding
193
195
 
194
196
 
195
197
  class RelatedContentResponse(TypedDict, total=False):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp_sqlite_memory_bank
3
- Version: 1.4.2
3
+ Version: 1.4.3
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