mcp-vector-search 0.4.12__py3-none-any.whl → 0.4.14__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.

Potentially problematic release.


This version of mcp-vector-search might be problematic. Click here for more details.

@@ -1,5 +1,6 @@
1
1
  """Database abstraction and ChromaDB implementation for MCP Vector Search."""
2
2
 
3
+ import shutil
3
4
  from abc import ABC, abstractmethod
4
5
  from pathlib import Path
5
6
  from typing import Any, Protocol, runtime_checkable
@@ -12,6 +13,7 @@ from .exceptions import (
12
13
  DatabaseInitializationError,
13
14
  DatabaseNotInitializedError,
14
15
  DocumentAdditionError,
16
+ IndexCorruptionError,
15
17
  SearchError,
16
18
  )
17
19
  from .models import CodeChunk, IndexStats, SearchResult
@@ -95,6 +97,15 @@ class VectorDatabase(ABC):
95
97
  """Reset the database (delete all data)."""
96
98
  ...
97
99
 
100
+ @abstractmethod
101
+ async def health_check(self) -> bool:
102
+ """Check database health and integrity.
103
+
104
+ Returns:
105
+ True if database is healthy, False otherwise
106
+ """
107
+ ...
108
+
98
109
  async def __aenter__(self) -> "VectorDatabase":
99
110
  """Async context manager entry."""
100
111
  await self.initialize()
@@ -128,12 +139,15 @@ class ChromaVectorDatabase(VectorDatabase):
128
139
  self._collection = None
129
140
 
130
141
  async def initialize(self) -> None:
131
- """Initialize ChromaDB client and collection."""
142
+ """Initialize ChromaDB client and collection with corruption recovery."""
132
143
  try:
133
144
  import chromadb
134
145
 
135
146
  # Ensure directory exists
136
147
  self.persist_directory.mkdir(parents=True, exist_ok=True)
148
+
149
+ # Check for corruption before initializing
150
+ await self._detect_and_recover_corruption()
137
151
 
138
152
  # Create client with new API
139
153
  self._client = chromadb.PersistentClient(
@@ -156,10 +170,22 @@ class ChromaVectorDatabase(VectorDatabase):
156
170
  logger.debug(f"ChromaDB initialized at {self.persist_directory}")
157
171
 
158
172
  except Exception as e:
159
- logger.error(f"Failed to initialize ChromaDB: {e}")
160
- raise DatabaseInitializationError(
161
- f"ChromaDB initialization failed: {e}"
162
- ) from e
173
+ # Check if this is a corruption error
174
+ error_msg = str(e).lower()
175
+ if any(indicator in error_msg for indicator in [
176
+ "pickle", "unpickling", "eof", "ran out of input",
177
+ "hnsw", "index", "deserialize", "corrupt"
178
+ ]):
179
+ logger.warning(f"Detected index corruption: {e}")
180
+ # Try to recover
181
+ await self._recover_from_corruption()
182
+ # Retry initialization
183
+ await self.initialize()
184
+ else:
185
+ logger.error(f"Failed to initialize ChromaDB: {e}")
186
+ raise DatabaseInitializationError(
187
+ f"ChromaDB initialization failed: {e}"
188
+ ) from e
163
189
 
164
190
  async def remove_file_chunks(self, file_path: str) -> int:
165
191
  """Remove all chunks for a specific file.
@@ -438,6 +464,114 @@ class ChromaVectorDatabase(VectorDatabase):
438
464
 
439
465
  return where
440
466
 
467
+ async def _detect_and_recover_corruption(self) -> None:
468
+ """Detect and recover from index corruption proactively."""
469
+ # Check for common corruption indicators in ChromaDB files
470
+ chroma_db_path = self.persist_directory / "chroma.sqlite3"
471
+
472
+ # If database doesn't exist yet, nothing to check
473
+ if not chroma_db_path.exists():
474
+ return
475
+
476
+ # Check for HNSW index files that might be corrupted
477
+ collection_path = self.persist_directory / "chroma-collections.parquet"
478
+ index_path = self.persist_directory / "index"
479
+
480
+ if index_path.exists():
481
+ # Look for pickle files in the index
482
+ pickle_files = list(index_path.glob("**/*.pkl"))
483
+ pickle_files.extend(list(index_path.glob("**/*.pickle")))
484
+
485
+ for pickle_file in pickle_files:
486
+ try:
487
+ # Try to read the pickle file to detect corruption
488
+ import pickle
489
+ with open(pickle_file, 'rb') as f:
490
+ pickle.load(f)
491
+ except (EOFError, pickle.UnpicklingError, Exception) as e:
492
+ logger.warning(f"Corrupted index file detected: {pickle_file} - {e}")
493
+ await self._recover_from_corruption()
494
+ return
495
+
496
+ async def _recover_from_corruption(self) -> None:
497
+ """Recover from index corruption by rebuilding the index."""
498
+ logger.info("Attempting to recover from index corruption...")
499
+
500
+ # Create backup directory
501
+ backup_dir = self.persist_directory.parent / f"{self.persist_directory.name}_backup"
502
+ backup_dir.mkdir(exist_ok=True)
503
+
504
+ # Backup current state (in case we need it)
505
+ import time
506
+ timestamp = int(time.time())
507
+ backup_path = backup_dir / f"backup_{timestamp}"
508
+
509
+ if self.persist_directory.exists():
510
+ try:
511
+ shutil.copytree(self.persist_directory, backup_path)
512
+ logger.info(f"Created backup at {backup_path}")
513
+ except Exception as e:
514
+ logger.warning(f"Could not create backup: {e}")
515
+
516
+ # Clear the corrupted index
517
+ if self.persist_directory.exists():
518
+ try:
519
+ shutil.rmtree(self.persist_directory)
520
+ logger.info(f"Cleared corrupted index at {self.persist_directory}")
521
+ except Exception as e:
522
+ logger.error(f"Failed to clear corrupted index: {e}")
523
+ raise IndexCorruptionError(
524
+ f"Could not clear corrupted index: {e}"
525
+ ) from e
526
+
527
+ # Recreate the directory
528
+ self.persist_directory.mkdir(parents=True, exist_ok=True)
529
+ logger.info("Index directory recreated. Please re-index your codebase.")
530
+
531
+ async def health_check(self) -> bool:
532
+ """Check database health and integrity.
533
+
534
+ Returns:
535
+ True if database is healthy, False otherwise
536
+ """
537
+ try:
538
+ # First check if client is initialized
539
+ if not self._client or not self._collection:
540
+ logger.warning("Database not initialized")
541
+ return False
542
+
543
+ # Try a simple operation to test the connection
544
+ try:
545
+ # Attempt to get count - this will fail if index is corrupted
546
+ count = self._collection.count()
547
+ logger.debug(f"Health check passed: {count} chunks in database")
548
+
549
+ # Try a minimal query to ensure search works
550
+ self._collection.query(
551
+ query_texts=["test"],
552
+ n_results=1,
553
+ include=["metadatas"]
554
+ )
555
+
556
+ return True
557
+
558
+ except Exception as e:
559
+ error_msg = str(e).lower()
560
+ if any(indicator in error_msg for indicator in [
561
+ "pickle", "unpickling", "eof", "ran out of input",
562
+ "hnsw", "index", "deserialize", "corrupt"
563
+ ]):
564
+ logger.error(f"Index corruption detected during health check: {e}")
565
+ return False
566
+ else:
567
+ # Some other error
568
+ logger.warning(f"Health check failed: {e}")
569
+ return False
570
+
571
+ except Exception as e:
572
+ logger.error(f"Health check error: {e}")
573
+ return False
574
+
441
575
 
442
576
  class PooledChromaVectorDatabase(VectorDatabase):
443
577
  """ChromaDB implementation with connection pooling for improved performance."""
@@ -729,7 +863,80 @@ class PooledChromaVectorDatabase(VectorDatabase):
729
863
 
730
864
  async def health_check(self) -> bool:
731
865
  """Perform a health check on the database and connection pool."""
732
- return await self._pool.health_check()
866
+ try:
867
+ # Check pool health
868
+ pool_healthy = await self._pool.health_check()
869
+ if not pool_healthy:
870
+ return False
871
+
872
+ # Try a simple query to verify database integrity
873
+ try:
874
+ async with self._pool.get_connection() as conn:
875
+ # Test basic operations
876
+ conn.collection.count()
877
+ conn.collection.query(
878
+ query_texts=["test"],
879
+ n_results=1,
880
+ include=["metadatas"]
881
+ )
882
+ return True
883
+ except Exception as e:
884
+ error_msg = str(e).lower()
885
+ if any(indicator in error_msg for indicator in [
886
+ "pickle", "unpickling", "eof", "ran out of input",
887
+ "hnsw", "index", "deserialize", "corrupt"
888
+ ]):
889
+ logger.error(f"Index corruption detected: {e}")
890
+ # Attempt recovery
891
+ await self._recover_from_corruption()
892
+ return False
893
+ else:
894
+ logger.warning(f"Health check failed: {e}")
895
+ return False
896
+ except Exception as e:
897
+ logger.error(f"Health check error: {e}")
898
+ return False
899
+
900
+ async def _recover_from_corruption(self) -> None:
901
+ """Recover from index corruption by rebuilding the index."""
902
+ logger.info("Attempting to recover from index corruption...")
903
+
904
+ # Close the pool first
905
+ await self._pool.close()
906
+
907
+ # Create backup directory
908
+ backup_dir = self.persist_directory.parent / f"{self.persist_directory.name}_backup"
909
+ backup_dir.mkdir(exist_ok=True)
910
+
911
+ # Backup current state
912
+ import time
913
+ timestamp = int(time.time())
914
+ backup_path = backup_dir / f"backup_{timestamp}"
915
+
916
+ if self.persist_directory.exists():
917
+ try:
918
+ shutil.copytree(self.persist_directory, backup_path)
919
+ logger.info(f"Created backup at {backup_path}")
920
+ except Exception as e:
921
+ logger.warning(f"Could not create backup: {e}")
922
+
923
+ # Clear the corrupted index
924
+ if self.persist_directory.exists():
925
+ try:
926
+ shutil.rmtree(self.persist_directory)
927
+ logger.info(f"Cleared corrupted index at {self.persist_directory}")
928
+ except Exception as e:
929
+ logger.error(f"Failed to clear corrupted index: {e}")
930
+ raise IndexCorruptionError(
931
+ f"Could not clear corrupted index: {e}"
932
+ ) from e
933
+
934
+ # Recreate the directory
935
+ self.persist_directory.mkdir(parents=True, exist_ok=True)
936
+
937
+ # Reinitialize the pool
938
+ await self._pool.initialize()
939
+ logger.info("Index recovered. Please re-index your codebase.")
733
940
 
734
941
  async def __aenter__(self):
735
942
  """Async context manager entry."""
@@ -47,6 +47,12 @@ class SearchError(DatabaseError):
47
47
  pass
48
48
 
49
49
 
50
+ class IndexCorruptionError(DatabaseError):
51
+ """Index corruption detected."""
52
+
53
+ pass
54
+
55
+
50
56
  class ParsingError(MCPVectorSearchError):
51
57
  """Code parsing errors."""
52
58
 
@@ -66,6 +66,16 @@ class SemanticSearchEngine:
66
66
  if not query.strip():
67
67
  return []
68
68
 
69
+ # Health check before search
70
+ try:
71
+ if hasattr(self.database, 'health_check'):
72
+ is_healthy = await self.database.health_check()
73
+ if not is_healthy:
74
+ logger.warning("Database health check failed - attempting recovery")
75
+ # Health check already attempts recovery, so we can proceed
76
+ except Exception as e:
77
+ logger.warning(f"Health check failed: {e}")
78
+
69
79
  # Auto-reindex check before search
70
80
  if self.search_triggered_indexer:
71
81
  try:
@@ -106,8 +116,20 @@ class SemanticSearchEngine:
106
116
  return ranked_results
107
117
 
108
118
  except Exception as e:
109
- logger.error(f"Search failed for query '{query}': {e}")
110
- raise SearchError(f"Search failed: {e}") from e
119
+ error_msg = str(e).lower()
120
+ # Check for corruption indicators
121
+ if any(indicator in error_msg for indicator in [
122
+ "pickle", "unpickling", "eof", "ran out of input",
123
+ "hnsw", "index", "deserialize", "corrupt"
124
+ ]):
125
+ logger.error(f"Index corruption detected during search: {e}")
126
+ logger.info("The index appears to be corrupted. Please run 'mcp-vector-search reset' to clear the index and then 'mcp-vector-search index' to rebuild it.")
127
+ raise SearchError(
128
+ "Index corruption detected. Please run 'mcp-vector-search reset' followed by 'mcp-vector-search index' to rebuild."
129
+ ) from e
130
+ else:
131
+ logger.error(f"Search failed for query '{query}': {e}")
132
+ raise SearchError(f"Search failed: {e}") from e
111
133
 
112
134
  async def search_similar(
113
135
  self,
@@ -499,7 +499,6 @@ class MCPVectorSearchServer:
499
499
 
500
500
  try:
501
501
  from pathlib import Path
502
- from ..cli.commands.search import run_similar_search
503
502
 
504
503
  # Convert to Path object
505
504
  file_path_obj = Path(file_path)
@@ -532,11 +531,24 @@ class MCPVectorSearchServer:
532
531
  )]
533
532
  )
534
533
 
535
- result_text = f"Found {len(results)} similar code snippets for {file_path}:\n\n"
534
+ response_lines = [f"Found {len(results)} similar code snippets for {file_path}\n"]
535
+
536
536
  for i, result in enumerate(results, 1):
537
- result_text += f"{i}. {result.file_path}:{result.line_number}\n"
538
- result_text += f" Similarity: {result.similarity:.3f}\n"
539
- result_text += f" {result.content[:100]}...\n\n"
537
+ response_lines.append(f"## Result {i} (Score: {result.similarity_score:.3f})")
538
+ response_lines.append(f"**File:** {result.file_path}")
539
+ if result.function_name:
540
+ response_lines.append(f"**Function:** {result.function_name}")
541
+ if result.class_name:
542
+ response_lines.append(f"**Class:** {result.class_name}")
543
+ response_lines.append(f"**Lines:** {result.start_line}-{result.end_line}")
544
+ response_lines.append("**Code:**")
545
+ response_lines.append("```" + (result.language or ""))
546
+ # Show more of the content for similar search
547
+ content_preview = result.content[:500] if len(result.content) > 500 else result.content
548
+ response_lines.append(content_preview + ("..." if len(result.content) > 500 else ""))
549
+ response_lines.append("```\n")
550
+
551
+ result_text = "\n".join(response_lines)
540
552
 
541
553
  return CallToolResult(
542
554
  content=[TextContent(
@@ -586,15 +598,27 @@ class MCPVectorSearchServer:
586
598
  )]
587
599
  )
588
600
 
589
- result_text = f"Found {len(results)} contextually relevant code snippets"
601
+ response_lines = [f"Found {len(results)} contextually relevant code snippets"]
590
602
  if focus_areas:
591
- result_text += f" (focus: {', '.join(focus_areas)})"
592
- result_text += f" for: {description}\n\n"
593
-
603
+ response_lines[0] += f" (focus: {', '.join(focus_areas)})"
604
+ response_lines[0] += f" for: {description}\n"
605
+
594
606
  for i, result in enumerate(results, 1):
595
- result_text += f"{i}. {result.file_path}:{result.line_number}\n"
596
- result_text += f" Similarity: {result.similarity:.3f}\n"
597
- result_text += f" {result.content[:100]}...\n\n"
607
+ response_lines.append(f"## Result {i} (Score: {result.similarity_score:.3f})")
608
+ response_lines.append(f"**File:** {result.file_path}")
609
+ if result.function_name:
610
+ response_lines.append(f"**Function:** {result.function_name}")
611
+ if result.class_name:
612
+ response_lines.append(f"**Class:** {result.class_name}")
613
+ response_lines.append(f"**Lines:** {result.start_line}-{result.end_line}")
614
+ response_lines.append("**Code:**")
615
+ response_lines.append("```" + (result.language or ""))
616
+ # Show more of the content for context search
617
+ content_preview = result.content[:500] if len(result.content) > 500 else result.content
618
+ response_lines.append(content_preview + ("..." if len(result.content) > 500 else ""))
619
+ response_lines.append("```\n")
620
+
621
+ result_text = "\n".join(response_lines)
598
622
 
599
623
  return CallToolResult(
600
624
  content=[TextContent(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-vector-search
3
- Version: 0.4.12
3
+ Version: 0.4.14
4
4
  Summary: CLI-first semantic code search with MCP integration
5
5
  Project-URL: Homepage, https://github.com/bobmatnyc/mcp-vector-search
6
6
  Project-URL: Documentation, https://mcp-vector-search.readthedocs.io
@@ -1,12 +1,13 @@
1
- mcp_vector_search/__init__.py,sha256=nFyxm4tNaoAt44JrlTIxd09tNWtdvFhQr-svXkpKxTo,300
1
+ mcp_vector_search/__init__.py,sha256=ir_M_lclJGDDVJ6Gf_IYKqrhZLJU1I7Tq1zE7pTA7dM,300
2
2
  mcp_vector_search/py.typed,sha256=lCKeV9Qcn9sGtbRsgg-LJO2ZwWRuknnnlmomq3bJFH0,43
3
3
  mcp_vector_search/cli/__init__.py,sha256=TNB7CaOASz8u3yHWLbNmo8-GtHF0qwUjVKWAuNphKgo,40
4
- mcp_vector_search/cli/didyoumean.py,sha256=F4b9jTJfeAkg5XLDx93sgiNS-o7NTmnDVEwDrNcg64w,6438
4
+ mcp_vector_search/cli/didyoumean.py,sha256=eq2uhP3E3qrPHmk2BrbFq8i8nT896uq24_IB8dzMHIk,16092
5
5
  mcp_vector_search/cli/export.py,sha256=iluxuRT2KELdKlQeDAlVkteiel4GGrng153UAw9H0as,10804
6
6
  mcp_vector_search/cli/history.py,sha256=osQVNiTIdGSRZQiJEjC_AYMmHxaqv7RSKSeuO325Ip0,9115
7
7
  mcp_vector_search/cli/interactive.py,sha256=T7P4dAdvbglznzQYgiePv5YNyOx9FeE57Y3OKYnnbYE,12744
8
- mcp_vector_search/cli/main.py,sha256=q_714AV8q7Euf5fTgk5Zs82ELrZ44mRbFqMOmZklZcw,9030
8
+ mcp_vector_search/cli/main.py,sha256=I5WXHyB654YV0j2HODSv8Cy_zm_xfr91pFCSTb_0hLQ,15342
9
9
  mcp_vector_search/cli/output.py,sha256=TGtWHrsfFg2tFf05aplZI2pDkoSnlKf_if78qXSRDtE,8077
10
+ mcp_vector_search/cli/suggestions.py,sha256=J7GB4r4PBqGY5QO20ZjfLLls1y1QYdvq0VxE-U3Cz70,12717
10
11
  mcp_vector_search/cli/commands/__init__.py,sha256=vQls-YKZ54YEwmf7g1dL0T2SS9D4pdQljXzsUChG_V4,42
11
12
  mcp_vector_search/cli/commands/auto_index.py,sha256=imVVbxWRlA128NPdK9BetNNl3ELrsdq-hqcsLqyAmoM,12712
12
13
  mcp_vector_search/cli/commands/config.py,sha256=EHLqToCXrZs3gjIAg7pV8Bq8yVslUXWC4AnTcZQgSPQ,11337
@@ -14,6 +15,7 @@ mcp_vector_search/cli/commands/index.py,sha256=LsFCfqfXWd5s11wE_21mpsTitmsKsdGUh
14
15
  mcp_vector_search/cli/commands/init.py,sha256=vKg4JlWaPipa9Nca-ruLs8ZZ5tXbczDQrPjHzp9zN1A,24816
15
16
  mcp_vector_search/cli/commands/install.py,sha256=sE5mjv2pCDp2tvMj4UqfKLHpSt8Yedcb_CirWLoedDw,10375
16
17
  mcp_vector_search/cli/commands/mcp.py,sha256=gpt9hfSmfpcr4rdis2DsenhNnGW5a0B8Xmb3RVEEtuY,17822
18
+ mcp_vector_search/cli/commands/reset.py,sha256=MwAbpqWYoXBHGzks0HDQclwN0qvUUZyPafOYrDOHQSo,14066
17
19
  mcp_vector_search/cli/commands/search.py,sha256=UmMtRs15ZO5Bzc_DKWgBRoGwZgm9XXn6Lppsl1o-1I0,16785
18
20
  mcp_vector_search/cli/commands/status.py,sha256=CqD3W4wI70o6c2XJiq0c7W0maQshWrsYQkeMyI6S13U,16600
19
21
  mcp_vector_search/cli/commands/watch.py,sha256=2pyWRoo4fIppFnyQ4sW4IBLHmpb_IwnTjRnzHkVBPcQ,8927
@@ -23,20 +25,20 @@ mcp_vector_search/config/settings.py,sha256=v1bc2K2yTwDzQKiy_BQhTWCP7FinSWX99vQG
23
25
  mcp_vector_search/core/__init__.py,sha256=bWKtKmmaFs7gG5XPCbrx77UYIVeO1FF8wIJxpj1dLNw,48
24
26
  mcp_vector_search/core/auto_indexer.py,sha256=0S4lZXaUgqEytMSA2FxQsh5hN7V1mbSLYVzEf_dslYQ,10307
25
27
  mcp_vector_search/core/connection_pool.py,sha256=Yo-gUQQbHawtuvh6OcJiAlbbvWQGQBd31QZOvs498fg,11224
26
- mcp_vector_search/core/database.py,sha256=afYg_AcLY6gcNV6yJ79UUa9zk5OULHcS-s8t3O5LY_Q,26691
28
+ mcp_vector_search/core/database.py,sha256=fo1hp0gs4BXquVuYm3O932f1dRF9N3NAg7HdiXzvDAQ,35178
27
29
  mcp_vector_search/core/embeddings.py,sha256=wSMUNxZcuGPMxxQ1AbKqA1a3-0c6AiOqmuuI7OqTyaQ,10578
28
- mcp_vector_search/core/exceptions.py,sha256=9cW1E2MdWnx9o9gaFBk5XaOwIbWeKGheM_jG7cCZJ3k,1505
30
+ mcp_vector_search/core/exceptions.py,sha256=3bCjT8wmrLz_0e_Tayr90049zNTKYFWZa19kl0saKz8,1597
29
31
  mcp_vector_search/core/factory.py,sha256=GnsCBcRndBaUBWSXwtt8QKInAo-rGGBTSOKznUFETwA,10016
30
32
  mcp_vector_search/core/git_hooks.py,sha256=xOfPpzgKoNTwM-vbhAihUucgudBQk45bCAVR5zJOFlQ,10878
31
33
  mcp_vector_search/core/indexer.py,sha256=NroJxIoAQg1Egv_hZK76co13pbJrBxZ-IN6ZWDFu9W0,15645
32
34
  mcp_vector_search/core/models.py,sha256=fnZxvUkd9Afxmdwtw2BJX7uik6rQTwuWBTTqTeqDi0A,6697
33
35
  mcp_vector_search/core/project.py,sha256=RNeLBZZw6SO5mXqCwYfhStTGuVgeMq1US5UftG0SBYk,10069
34
36
  mcp_vector_search/core/scheduler.py,sha256=PBSlu-ieDYCXOMGYY7QKv9UReFEDPHNmwnUv_xb4vxg,11761
35
- mcp_vector_search/core/search.py,sha256=qViLXKQuxJEHejtuQDiZOF-sd0IY59xsztxI6hRjDzg,28350
37
+ mcp_vector_search/core/search.py,sha256=5xBl73xxQC0NGAHO0EyvKq39ZNVeW4MVpCrjl_U8UhA,29570
36
38
  mcp_vector_search/core/watcher.py,sha256=-DFRCnuUfcqcTrkZPQqfJSvxKAxnpt-axgEj1V-B0O4,10862
37
39
  mcp_vector_search/mcp/__init__.py,sha256=gfKR0QV7Jqvj5y0LMBe9gSghd5_rPsvm_rml0ryQtoY,158
38
40
  mcp_vector_search/mcp/__main__.py,sha256=vhAUa4S8hoXqfJt4w0yX5z2h5GoPAar8iFqgIW-WdbY,575
39
- mcp_vector_search/mcp/server.py,sha256=mzlM2RGAoSV-bj6CWOGA86VTBv6weUQPlhVETKwSj80,27020
41
+ mcp_vector_search/mcp/server.py,sha256=ZzLvqHnkIvWNkhqIMPXGpafgS38tS8XtmEmq_i7doHo,28547
40
42
  mcp_vector_search/parsers/__init__.py,sha256=nk4clWDWQURMxzC1ev8O_vGlfraHlXqizTDXgFqIP5U,46
41
43
  mcp_vector_search/parsers/base.py,sha256=-zBY9T0modfegowaNyf5_upkS3ImR4TgrRwoSLuAiDw,5421
42
44
  mcp_vector_search/parsers/javascript.py,sha256=P7fT_tXCzUuXATTkTx_DyD4EuG0_KjIDlay09MhkKTE,9824
@@ -47,8 +49,8 @@ mcp_vector_search/utils/__init__.py,sha256=Eq6lY-oPMfCt-GpPUbg9QbmTHuQVmTaVDBMU2
47
49
  mcp_vector_search/utils/gitignore.py,sha256=U1-1FERSYnDbxkH8JGG_azLxLasqkAh1urRUbZskmRU,8208
48
50
  mcp_vector_search/utils/timing.py,sha256=THC7mfbTYnUpnnDcblgQacYMzbEkfFoIShx6plmhCgg,11285
49
51
  mcp_vector_search/utils/version.py,sha256=d7fS-CLemxb8UzZ9j18zH0Y0Ud097ljKKYYOPulnGPE,1138
50
- mcp_vector_search-0.4.12.dist-info/METADATA,sha256=opAJJIZHYh57dju7UAooK4ijFMZ5PjkQ0TvjEdlJ68Y,15890
51
- mcp_vector_search-0.4.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
52
- mcp_vector_search-0.4.12.dist-info/entry_points.txt,sha256=dw8_HpBvwhauz6bkMbs3QM6dbstV1mPGo9DcNpVM-bE,69
53
- mcp_vector_search-0.4.12.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
54
- mcp_vector_search-0.4.12.dist-info/RECORD,,
52
+ mcp_vector_search-0.4.14.dist-info/METADATA,sha256=EbalUrvvEgqQn5hGu1sD0WyDnL3EFQmZB2meZzmNRdA,15890
53
+ mcp_vector_search-0.4.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
54
+ mcp_vector_search-0.4.14.dist-info/entry_points.txt,sha256=y3Ygtc_JiBchNEIL-tPABo7EbzBExGAxwGdkkeP5D2I,86
55
+ mcp_vector_search-0.4.14.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
56
+ mcp_vector_search-0.4.14.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mcp-vector-search = mcp_vector_search.cli.main:cli_with_suggestions
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- mcp-vector-search = mcp_vector_search.cli.main:app