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

Potentially problematic release.


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

Files changed (29) hide show
  1. mcp_vector_search/__init__.py +2 -2
  2. mcp_vector_search/cli/commands/index.py +73 -31
  3. mcp_vector_search/cli/commands/init.py +189 -113
  4. mcp_vector_search/cli/commands/install.py +525 -113
  5. mcp_vector_search/cli/commands/mcp.py +201 -151
  6. mcp_vector_search/cli/commands/reset.py +41 -41
  7. mcp_vector_search/cli/commands/search.py +73 -14
  8. mcp_vector_search/cli/commands/status.py +51 -17
  9. mcp_vector_search/cli/didyoumean.py +254 -246
  10. mcp_vector_search/cli/main.py +114 -43
  11. mcp_vector_search/cli/output.py +152 -0
  12. mcp_vector_search/cli/suggestions.py +246 -197
  13. mcp_vector_search/core/database.py +81 -49
  14. mcp_vector_search/core/indexer.py +10 -4
  15. mcp_vector_search/core/search.py +17 -6
  16. mcp_vector_search/mcp/__main__.py +1 -1
  17. mcp_vector_search/mcp/server.py +211 -203
  18. mcp_vector_search/parsers/__init__.py +6 -0
  19. mcp_vector_search/parsers/dart.py +605 -0
  20. mcp_vector_search/parsers/php.py +694 -0
  21. mcp_vector_search/parsers/registry.py +16 -1
  22. mcp_vector_search/parsers/ruby.py +678 -0
  23. mcp_vector_search/parsers/text.py +31 -25
  24. mcp_vector_search/utils/gitignore.py +72 -71
  25. {mcp_vector_search-0.4.14.dist-info → mcp_vector_search-0.5.0.dist-info}/METADATA +59 -2
  26. {mcp_vector_search-0.4.14.dist-info → mcp_vector_search-0.5.0.dist-info}/RECORD +29 -26
  27. {mcp_vector_search-0.4.14.dist-info → mcp_vector_search-0.5.0.dist-info}/WHEEL +0 -0
  28. {mcp_vector_search-0.4.14.dist-info → mcp_vector_search-0.5.0.dist-info}/entry_points.txt +0 -0
  29. {mcp_vector_search-0.4.14.dist-info → mcp_vector_search-0.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  """MCP Vector Search - CLI-first semantic code search with MCP integration."""
2
2
 
3
- __version__ = "0.4.14"
4
- __build__ = "16"
3
+ __version__ = "0.5.0"
4
+ __build__ = "18"
5
5
  __author__ = "Robert Matsuoka"
6
6
  __email__ = "bobmatnyc@gmail.com"
7
7
 
@@ -17,7 +17,9 @@ from ..output import (
17
17
  print_error,
18
18
  print_index_stats,
19
19
  print_info,
20
+ print_next_steps,
20
21
  print_success,
22
+ print_tip,
21
23
  )
22
24
 
23
25
  # Create index subcommand app
@@ -32,23 +34,27 @@ def main(
32
34
  "--watch",
33
35
  "-w",
34
36
  help="Watch for file changes and update index incrementally",
37
+ rich_help_panel="⚙️ Advanced Options",
35
38
  ),
36
39
  incremental: bool = typer.Option(
37
40
  True,
38
41
  "--incremental/--full",
39
42
  help="Use incremental indexing (skip unchanged files)",
43
+ rich_help_panel="📊 Indexing Options",
40
44
  ),
41
45
  extensions: str | None = typer.Option(
42
46
  None,
43
47
  "--extensions",
44
48
  "-e",
45
49
  help="Override file extensions to index (comma-separated)",
50
+ rich_help_panel="📁 Configuration",
46
51
  ),
47
52
  force: bool = typer.Option(
48
53
  False,
49
54
  "--force",
50
55
  "-f",
51
56
  help="Force reindexing of all files",
57
+ rich_help_panel="📊 Indexing Options",
52
58
  ),
53
59
  batch_size: int = typer.Option(
54
60
  32,
@@ -57,17 +63,37 @@ def main(
57
63
  help="Batch size for embedding generation",
58
64
  min=1,
59
65
  max=128,
66
+ rich_help_panel="⚡ Performance",
60
67
  ),
61
68
  ) -> None:
62
- """Index your codebase for semantic search.
69
+ """📑 Index your codebase for semantic search.
63
70
 
64
- This command parses your code files using Tree-sitter, generates embeddings
65
- using the configured model, and stores them in ChromaDB for fast semantic search.
71
+ Parses code files, generates semantic embeddings, and stores them in ChromaDB.
72
+ Supports incremental indexing to skip unchanged files for faster updates.
66
73
 
67
- Examples:
68
- mcp-vector-search index
69
- mcp-vector-search index --force --extensions .py,.js
70
- mcp-vector-search index --watch
74
+ [bold cyan]Basic Examples:[/bold cyan]
75
+
76
+ [green]Index entire project:[/green]
77
+ $ mcp-vector-search index
78
+
79
+ [green]Force full reindex:[/green]
80
+ $ mcp-vector-search index --force
81
+
82
+ [green]Custom file extensions:[/green]
83
+ $ mcp-vector-search index --extensions .py,.js,.ts,.md
84
+
85
+ [bold cyan]Advanced Usage:[/bold cyan]
86
+
87
+ [green]Watch mode (experimental):[/green]
88
+ $ mcp-vector-search index --watch
89
+
90
+ [green]Full reindex (no incremental):[/green]
91
+ $ mcp-vector-search index --full
92
+
93
+ [green]Optimize for large projects:[/green]
94
+ $ mcp-vector-search index --batch-size 64
95
+
96
+ [dim]💡 Tip: Use incremental indexing (default) for faster updates on subsequent runs.[/dim]
71
97
  """
72
98
  try:
73
99
  project_root = ctx.obj.get("project_root") or Path.cwd()
@@ -190,6 +216,21 @@ async def _run_batch_indexing(
190
216
  stats = await indexer.get_indexing_stats()
191
217
  print_index_stats(stats)
192
218
 
219
+ # Add next-step hints
220
+ if indexed_count > 0:
221
+ steps = [
222
+ "[cyan]mcp-vector-search search 'your query'[/cyan] - Try semantic search",
223
+ "[cyan]mcp-vector-search status[/cyan] - View detailed statistics",
224
+ ]
225
+ print_next_steps(steps, title="Ready to Search")
226
+ else:
227
+ print_info("\n[bold]No files were indexed. Possible reasons:[/bold]")
228
+ print_info(" • No matching files found for configured extensions")
229
+ print_info(" • All files already indexed (use --force to reindex)")
230
+ print_tip(
231
+ "Check configured extensions with [cyan]mcp-vector-search status[/cyan]"
232
+ )
233
+
193
234
 
194
235
  async def _run_watch_mode(indexer: SemanticIndexer, show_progress: bool) -> None:
195
236
  """Run indexing in watch mode."""
@@ -228,12 +269,12 @@ def reindex_file(
228
269
  ),
229
270
  ) -> None:
230
271
  """Reindex files in the project.
231
-
272
+
232
273
  Can reindex a specific file or the entire project:
233
274
  - Without arguments: reindexes entire project (with confirmation)
234
275
  - With file path: reindexes specific file
235
276
  - With --all flag: explicitly reindexes entire project
236
-
277
+
237
278
  Examples:
238
279
  mcp-vector-search index reindex # Reindex entire project
239
280
  mcp-vector-search index reindex --all # Explicitly reindex entire project
@@ -247,7 +288,7 @@ def reindex_file(
247
288
  if file_path is not None and all:
248
289
  print_error("Cannot specify both a file path and --all flag")
249
290
  raise typer.Exit(1)
250
-
291
+
251
292
  if file_path is not None:
252
293
  # Reindex specific file
253
294
  asyncio.run(_reindex_single_file(project_root, file_path))
@@ -255,14 +296,13 @@ def reindex_file(
255
296
  # Reindex entire project
256
297
  if not force and not all:
257
298
  from ..output import confirm_action
258
-
299
+
259
300
  if not confirm_action(
260
- "This will reindex the entire project. Continue?",
261
- default=False
301
+ "This will reindex the entire project. Continue?", default=False
262
302
  ):
263
303
  print_info("Reindex operation cancelled")
264
304
  raise typer.Exit(0)
265
-
305
+
266
306
  # Use the full project reindexing
267
307
  asyncio.run(_reindex_entire_project(project_root))
268
308
 
@@ -278,21 +318,21 @@ def reindex_file(
278
318
  async def _reindex_entire_project(project_root: Path) -> None:
279
319
  """Reindex the entire project."""
280
320
  print_info("Starting full project reindex...")
281
-
321
+
282
322
  # Load project configuration
283
323
  project_manager = ProjectManager(project_root)
284
-
324
+
285
325
  if not project_manager.is_initialized():
286
326
  raise ProjectNotFoundError(
287
327
  f"Project not initialized at {project_root}. Run 'mcp-vector-search init' first."
288
328
  )
289
-
329
+
290
330
  config = project_manager.load_config()
291
-
331
+
292
332
  print_info(f"Project: {project_root}")
293
333
  print_info(f"File extensions: {', '.join(config.file_extensions)}")
294
334
  print_info(f"Embedding model: {config.embedding_model}")
295
-
335
+
296
336
  # Setup embedding function and cache
297
337
  cache_dir = (
298
338
  get_default_cache_path(project_root) if config.cache_embeddings else None
@@ -302,44 +342,44 @@ async def _reindex_entire_project(project_root: Path) -> None:
302
342
  cache_dir=cache_dir,
303
343
  cache_size=config.max_cache_size,
304
344
  )
305
-
345
+
306
346
  # Setup database
307
347
  database = ChromaVectorDatabase(
308
348
  persist_directory=config.index_path,
309
349
  embedding_function=embedding_function,
310
350
  )
311
-
351
+
312
352
  # Setup indexer
313
353
  indexer = SemanticIndexer(
314
354
  database=database,
315
355
  project_root=project_root,
316
356
  file_extensions=config.file_extensions,
317
357
  )
318
-
358
+
319
359
  try:
320
360
  async with database:
321
361
  # First, clean the existing index
322
362
  print_info("Clearing existing index...")
323
363
  await database.reset()
324
-
364
+
325
365
  # Then reindex everything with progress
326
366
  with create_progress() as progress:
327
367
  task = progress.add_task("Reindexing files...", total=None)
328
-
368
+
329
369
  # Force reindex all files
330
370
  indexed_count = await indexer.index_project(
331
371
  force_reindex=True, # Force reindexing
332
372
  show_progress=False, # We handle progress here
333
373
  )
334
-
374
+
335
375
  progress.update(task, completed=indexed_count, total=indexed_count)
336
-
376
+
337
377
  print_success(f"Successfully reindexed {indexed_count} files")
338
-
378
+
339
379
  # Show statistics
340
380
  stats = await indexer.get_indexing_stats()
341
381
  print_index_stats(stats)
342
-
382
+
343
383
  except Exception as e:
344
384
  logger.error(f"Full reindex error: {e}")
345
385
  raise
@@ -354,12 +394,12 @@ async def _reindex_single_file(project_root: Path, file_path: Path) -> None:
354
394
  # Make file path absolute if it's not already
355
395
  if not file_path.is_absolute():
356
396
  file_path = file_path.resolve()
357
-
397
+
358
398
  # Check if file exists
359
399
  if not file_path.exists():
360
400
  print_error(f"File not found: {file_path}")
361
401
  return
362
-
402
+
363
403
  # Check if file is within project root
364
404
  try:
365
405
  file_path.relative_to(project_root)
@@ -395,7 +435,9 @@ async def _reindex_single_file(project_root: Path, file_path: Path) -> None:
395
435
  print_error(f"Failed to reindex: {file_path}")
396
436
  # Check if file extension is in the list of indexable extensions
397
437
  if file_path.suffix not in config.file_extensions:
398
- print_info(f"Note: {file_path.suffix} is not in the configured file extensions: {', '.join(config.file_extensions)}")
438
+ print_info(
439
+ f"Note: {file_path.suffix} is not in the configured file extensions: {', '.join(config.file_extensions)}"
440
+ )
399
441
 
400
442
 
401
443
  @index_app.command("clean")