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.
@@ -23,7 +23,10 @@ def search_content(
23
23
  ) -> ToolResponse:
24
24
  """Perform full-text search across table content using natural language queries."""
25
25
  from .. import server
26
- return cast(ToolResponse, get_database(server.DB_PATH).search_content(query, tables, limit))
26
+
27
+ return cast(
28
+ ToolResponse, get_database(server.DB_PATH).search_content(query, tables, limit)
29
+ )
27
30
 
28
31
 
29
32
  @catch_errors
@@ -33,7 +36,11 @@ def explore_tables(
33
36
  ) -> ToolResponse:
34
37
  """Explore and discover table structures and content for better searchability."""
35
38
  from .. import server
36
- return cast(ToolResponse, get_database(server.DB_PATH).explore_tables(pattern, include_row_counts))
39
+
40
+ return cast(
41
+ ToolResponse,
42
+ get_database(server.DB_PATH).explore_tables(pattern, include_row_counts),
43
+ )
37
44
 
38
45
 
39
46
  @catch_errors
@@ -45,9 +52,13 @@ def add_embeddings(
45
52
  ) -> ToolResponse:
46
53
  """Generate and store vector embeddings for semantic search on table content."""
47
54
  from .. import server
48
- return cast(ToolResponse, get_database(server.DB_PATH).generate_embeddings(
49
- table_name, text_columns, embedding_column, model_name
50
- ))
55
+
56
+ return cast(
57
+ ToolResponse,
58
+ get_database(server.DB_PATH).generate_embeddings(
59
+ table_name, text_columns, embedding_column, model_name
60
+ ),
61
+ )
51
62
 
52
63
 
53
64
  @catch_errors
@@ -60,9 +71,13 @@ def semantic_search(
60
71
  ) -> ToolResponse:
61
72
  """Find content using natural language semantic similarity rather than exact keyword matching."""
62
73
  from .. import server
63
- return cast(ToolResponse, get_database(server.DB_PATH).semantic_search(
64
- query, tables, "embedding", None, similarity_threshold, limit, model_name
65
- ))
74
+
75
+ return cast(
76
+ ToolResponse,
77
+ get_database(server.DB_PATH).semantic_search(
78
+ query, tables, "embedding", None, similarity_threshold, limit, model_name
79
+ ),
80
+ )
66
81
 
67
82
 
68
83
  @catch_errors
@@ -75,9 +90,13 @@ def find_related(
75
90
  ) -> ToolResponse:
76
91
  """Find content related to a specific row by semantic similarity."""
77
92
  from .. import server
78
- return cast(ToolResponse, get_database(server.DB_PATH).find_related_content(
79
- table_name, row_id, "embedding", similarity_threshold, limit, model_name
80
- ))
93
+
94
+ return cast(
95
+ ToolResponse,
96
+ get_database(server.DB_PATH).find_related_content(
97
+ table_name, row_id, "embedding", similarity_threshold, limit, model_name
98
+ ),
99
+ )
81
100
 
82
101
 
83
102
  @catch_errors
@@ -91,9 +110,20 @@ def smart_search(
91
110
  ) -> ToolResponse:
92
111
  """Intelligent hybrid search combining semantic understanding with keyword matching."""
93
112
  from .. import server
94
- return cast(ToolResponse, get_database(server.DB_PATH).hybrid_search(
95
- query, tables, None, "embedding", semantic_weight, text_weight, limit, model_name
96
- ))
113
+
114
+ return cast(
115
+ ToolResponse,
116
+ get_database(server.DB_PATH).hybrid_search(
117
+ query,
118
+ tables,
119
+ None,
120
+ "embedding",
121
+ semantic_weight,
122
+ text_weight,
123
+ limit,
124
+ model_name,
125
+ ),
126
+ )
97
127
 
98
128
 
99
129
  @catch_errors
@@ -103,7 +133,11 @@ def embedding_stats(
103
133
  ) -> ToolResponse:
104
134
  """Get statistics about semantic search readiness for a table."""
105
135
  from .. import server
106
- return cast(ToolResponse, get_database(server.DB_PATH).get_embedding_stats(table_name, embedding_column))
136
+
137
+ return cast(
138
+ ToolResponse,
139
+ get_database(server.DB_PATH).get_embedding_stats(table_name, embedding_column),
140
+ )
107
141
 
108
142
 
109
143
  @catch_errors
@@ -153,9 +187,10 @@ def auto_semantic_search(
153
187
  """
154
188
  try:
155
189
  from .. import server
190
+
156
191
  db = get_database(server.DB_PATH)
157
192
  auto_embedded_tables: List[str] = []
158
-
193
+
159
194
  # Get tables to search
160
195
  search_tables: List[str]
161
196
  if tables:
@@ -169,59 +204,79 @@ def auto_semantic_search(
169
204
  search_tables = all_tables
170
205
  else:
171
206
  search_tables = []
172
-
207
+
173
208
  # Auto-embed text columns in tables that don't have embeddings
174
209
  for table_name in search_tables:
175
210
  try:
176
211
  # Check if table has embeddings
177
212
  stats_result = db.get_embedding_stats(table_name, "embedding")
178
213
  coverage_percent = stats_result.get("coverage_percent", 0)
179
- if stats_result.get("success") and isinstance(coverage_percent, (int, float)) and coverage_percent > 0:
214
+ if (
215
+ stats_result.get("success")
216
+ and isinstance(coverage_percent, (int, float))
217
+ and coverage_percent > 0
218
+ ):
180
219
  continue # Table already has embeddings
181
-
220
+
182
221
  # Get table schema to find text columns
183
222
  schema_result = db.describe_table(table_name)
184
223
  if not schema_result.get("success"):
185
224
  continue
186
-
225
+
187
226
  # Find text columns
188
227
  text_columns = []
189
228
  columns = schema_result.get("columns", [])
190
229
  if isinstance(columns, list):
191
230
  for col in columns:
192
- if isinstance(col, dict) and "TEXT" in col.get("type", "").upper():
231
+ if (
232
+ isinstance(col, dict)
233
+ and "TEXT" in col.get("type", "").upper()
234
+ ):
193
235
  text_columns.append(col["name"])
194
-
236
+
195
237
  # Auto-embed text columns
196
238
  if text_columns:
197
- embed_result = db.generate_embeddings(table_name, text_columns, "embedding", model_name)
239
+ embed_result = db.generate_embeddings(
240
+ table_name, text_columns, "embedding", model_name
241
+ )
198
242
  if embed_result.get("success"):
199
243
  auto_embedded_tables.append(table_name)
200
-
244
+
201
245
  except Exception:
202
246
  # If auto-embedding fails, continue without it
203
247
  continue
204
-
248
+
205
249
  # Perform semantic search
206
250
  search_result = db.semantic_search(
207
- query, search_tables, "embedding", None, similarity_threshold, limit, model_name
251
+ query,
252
+ search_tables,
253
+ "embedding",
254
+ None,
255
+ similarity_threshold,
256
+ limit,
257
+ model_name,
208
258
  )
209
-
259
+
210
260
  # Add auto-embedding info to result
211
261
  if isinstance(search_result, dict):
212
262
  search_result["auto_embedded_tables"] = auto_embedded_tables
213
263
  if auto_embedded_tables:
214
- search_result["auto_embedding_note"] = f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
215
-
264
+ search_result["auto_embedding_note"] = (
265
+ f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
266
+ )
267
+
216
268
  return cast(ToolResponse, search_result)
217
-
269
+
218
270
  except Exception as e:
219
- return cast(ToolResponse, {
220
- "success": False,
221
- "error": f"Auto semantic search failed: {str(e)}",
222
- "category": "SEMANTIC_SEARCH_ERROR",
223
- "details": {"query": query, "tables": tables}
224
- })
271
+ return cast(
272
+ ToolResponse,
273
+ {
274
+ "success": False,
275
+ "error": f"Auto semantic search failed: {str(e)}",
276
+ "category": "SEMANTIC_SEARCH_ERROR",
277
+ "details": {"query": query, "tables": tables},
278
+ },
279
+ )
225
280
 
226
281
 
227
282
  @catch_errors
@@ -269,9 +324,10 @@ def auto_smart_search(
269
324
  """
270
325
  try:
271
326
  from .. import server
327
+
272
328
  db = get_database(server.DB_PATH)
273
329
  auto_embedded_tables: List[str] = []
274
-
330
+
275
331
  # Get tables to search
276
332
  search_tables: List[str]
277
333
  if tables:
@@ -285,49 +341,69 @@ def auto_smart_search(
285
341
  search_tables = all_tables
286
342
  else:
287
343
  search_tables = []
288
-
344
+
289
345
  # Auto-embed text columns in tables that don't have embeddings
290
346
  for table_name in search_tables:
291
347
  try:
292
348
  # Check if table has embeddings
293
349
  stats_result = db.get_embedding_stats(table_name, "embedding")
294
350
  coverage_percent = stats_result.get("coverage_percent", 0)
295
- if stats_result.get("success") and isinstance(coverage_percent, (int, float)) and coverage_percent > 0:
351
+ if (
352
+ stats_result.get("success")
353
+ and isinstance(coverage_percent, (int, float))
354
+ and coverage_percent > 0
355
+ ):
296
356
  continue # Table already has embeddings
297
-
357
+
298
358
  # Get table schema to find text columns
299
359
  schema_result = db.describe_table(table_name)
300
360
  if not schema_result.get("success"):
301
361
  continue
302
-
362
+
303
363
  # Find text columns
304
364
  text_columns = []
305
365
  columns = schema_result.get("columns", [])
306
366
  if isinstance(columns, list):
307
367
  for col in columns:
308
- if isinstance(col, dict) and "TEXT" in col.get("type", "").upper():
368
+ if (
369
+ isinstance(col, dict)
370
+ and "TEXT" in col.get("type", "").upper()
371
+ ):
309
372
  text_columns.append(col["name"])
310
-
373
+
311
374
  # Auto-embed text columns
312
375
  if text_columns:
313
- embed_result = db.generate_embeddings(table_name, text_columns, "embedding", model_name)
376
+ embed_result = db.generate_embeddings(
377
+ table_name, text_columns, "embedding", model_name
378
+ )
314
379
  if embed_result.get("success"):
315
380
  auto_embedded_tables.append(table_name)
316
-
381
+
317
382
  except Exception:
318
383
  # If auto-embedding fails, continue without it
319
384
  continue
320
-
385
+
321
386
  # Now perform hybrid search using the same pattern as smart_search
322
387
  try:
323
388
  hybrid_result = get_database(server.DB_PATH).hybrid_search(
324
- query, search_tables, None, "embedding", semantic_weight, text_weight, limit, model_name
389
+ query,
390
+ search_tables,
391
+ None,
392
+ "embedding",
393
+ semantic_weight,
394
+ text_weight,
395
+ limit,
396
+ model_name,
325
397
  )
326
398
  except Exception as search_error:
327
399
  # If hybrid search fails, fall back to regular content search
328
- logging.warning(f"Hybrid search failed, falling back to content search: {search_error}")
400
+ logging.warning(
401
+ f"Hybrid search failed, falling back to content search: {search_error}"
402
+ )
329
403
  try:
330
- fallback_result = get_database(server.DB_PATH).search_content(query, search_tables, limit)
404
+ fallback_result = get_database(server.DB_PATH).search_content(
405
+ query, search_tables, limit
406
+ )
331
407
  if fallback_result.get("success"):
332
408
  # Create a new dictionary to avoid type issues
333
409
  enhanced_fallback = dict(fallback_result)
@@ -336,21 +412,27 @@ def auto_smart_search(
336
412
  enhanced_fallback["fallback_reason"] = str(search_error)
337
413
  return cast(ToolResponse, enhanced_fallback)
338
414
  except Exception as fallback_error:
339
- return cast(ToolResponse, {
415
+ return cast(
416
+ ToolResponse,
417
+ {
418
+ "success": False,
419
+ "error": f"Both hybrid and fallback search failed. Hybrid: {search_error}, Fallback: {fallback_error}",
420
+ "category": "HYBRID_SEARCH_ERROR",
421
+ "details": {"query": query, "tables": tables},
422
+ },
423
+ )
424
+
425
+ # If we get here, both searches failed
426
+ return cast(
427
+ ToolResponse,
428
+ {
340
429
  "success": False,
341
- "error": f"Both hybrid and fallback search failed. Hybrid: {search_error}, Fallback: {fallback_error}",
430
+ "error": f"Hybrid search failed: {search_error}",
342
431
  "category": "HYBRID_SEARCH_ERROR",
343
- "details": {"query": query, "tables": tables}
344
- })
345
-
346
- # If we get here, both searches failed
347
- return cast(ToolResponse, {
348
- "success": False,
349
- "error": f"Hybrid search failed: {search_error}",
350
- "category": "HYBRID_SEARCH_ERROR",
351
- "details": {"query": query, "tables": tables}
352
- })
353
-
432
+ "details": {"query": query, "tables": tables},
433
+ },
434
+ )
435
+
354
436
  # Add auto-embedding info to result
355
437
  if isinstance(hybrid_result, dict) and hybrid_result.get("success"):
356
438
  # Convert to mutable dict to add extra fields
@@ -358,23 +440,28 @@ def auto_smart_search(
358
440
  final_result["search_type"] = "auto_hybrid"
359
441
  final_result["auto_embedded_tables"] = auto_embedded_tables
360
442
  if auto_embedded_tables:
361
- final_result["auto_embedding_note"] = f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
443
+ final_result["auto_embedding_note"] = (
444
+ f"Automatically generated embeddings for {len(auto_embedded_tables)} table(s)"
445
+ )
362
446
  return cast(ToolResponse, final_result)
363
447
  else:
364
448
  return cast(ToolResponse, hybrid_result)
365
-
449
+
366
450
  except Exception as e:
367
451
  # Add detailed error information for debugging
368
452
  error_details = {
369
- "query": query,
453
+ "query": query,
370
454
  "tables": tables,
371
455
  "error_type": type(e).__name__,
372
456
  "error_str": str(e),
373
- "traceback": traceback.format_exc()
457
+ "traceback": traceback.format_exc(),
374
458
  }
375
- return cast(ToolResponse, {
376
- "success": False,
377
- "error": f"Auto smart search failed: {str(e)}",
378
- "category": "HYBRID_SEARCH_ERROR",
379
- "details": error_details
380
- })
459
+ return cast(
460
+ ToolResponse,
461
+ {
462
+ "success": False,
463
+ "error": f"Auto smart search failed: {str(e)}",
464
+ "category": "HYBRID_SEARCH_ERROR",
465
+ "details": error_details,
466
+ },
467
+ )
@@ -42,7 +42,12 @@ class MemoryBankError(Exception):
42
42
 
43
43
  def to_dict(self) -> Dict[str, Any]:
44
44
  """Convert error to a dict format suitable for FastMCP responses."""
45
- return {"success": False, "error": self.message, "category": self.category.name, "details": self.details or {}}
45
+ return {
46
+ "success": False,
47
+ "error": self.message,
48
+ "category": self.category.name,
49
+ "details": self.details or {},
50
+ }
46
51
 
47
52
 
48
53
  class ValidationError(MemoryBankError):