mcp-vector-search 0.4.11__py3-none-any.whl → 0.4.13__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.
- mcp_vector_search/__init__.py +2 -2
- mcp_vector_search/cli/commands/init.py +5 -6
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/didyoumean.py +374 -75
- mcp_vector_search/cli/main.py +117 -5
- mcp_vector_search/cli/suggestions.py +325 -0
- mcp_vector_search/core/database.py +213 -6
- mcp_vector_search/core/exceptions.py +6 -0
- mcp_vector_search/core/search.py +24 -2
- mcp_vector_search/mcp/server.py +38 -14
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/RECORD +15 -13
- mcp_vector_search-0.4.13.dist-info/entry_points.txt +2 -0
- mcp_vector_search-0.4.11.dist-info/entry_points.txt +0 -2
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.4.11.dist-info → mcp_vector_search-0.4.13.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/__init__.py
CHANGED
|
@@ -22,7 +22,6 @@ from ..output import (
|
|
|
22
22
|
init_app = typer.Typer(help="Initialize project for semantic search")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
@init_app.command()
|
|
26
25
|
def main(
|
|
27
26
|
ctx: typer.Context,
|
|
28
27
|
config_file: Path | None = typer.Option(
|
|
@@ -92,10 +91,10 @@ def main(
|
|
|
92
91
|
Perfect for getting started quickly in any project!
|
|
93
92
|
|
|
94
93
|
Examples:
|
|
95
|
-
mcp-vector-search init
|
|
96
|
-
mcp-vector-search init
|
|
97
|
-
mcp-vector-search init
|
|
98
|
-
mcp-vector-search init
|
|
94
|
+
mcp-vector-search init # Full setup with smart defaults
|
|
95
|
+
mcp-vector-search init --no-mcp # Setup without MCP integration
|
|
96
|
+
mcp-vector-search init --extensions .py,.js,.ts,.txt # Custom file types
|
|
97
|
+
mcp-vector-search init --force # Re-initialize existing project
|
|
99
98
|
"""
|
|
100
99
|
try:
|
|
101
100
|
# Get project root from context or auto-detect
|
|
@@ -168,7 +167,7 @@ def main(
|
|
|
168
167
|
if project_manager.is_initialized() and not force:
|
|
169
168
|
print_success("Project is already initialized and ready to use!")
|
|
170
169
|
print_info("Your project has vector search capabilities enabled.")
|
|
171
|
-
print_info("Use --force to re-initialize or run 'mcp-vector-search status
|
|
170
|
+
print_info("Use --force to re-initialize or run 'mcp-vector-search status' to see current configuration")
|
|
172
171
|
return # Exit gracefully without raising an exception
|
|
173
172
|
|
|
174
173
|
# Parse file extensions
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"""Reset and recovery commands for MCP Vector Search."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.panel import Panel
|
|
11
|
+
from rich.prompt import Confirm
|
|
12
|
+
|
|
13
|
+
from ...core.exceptions import DatabaseError, IndexCorruptionError
|
|
14
|
+
from ...core.project import ProjectManager
|
|
15
|
+
from ..output import print_error, print_success, print_warning
|
|
16
|
+
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
# Create Typer app for reset commands
|
|
20
|
+
reset_app = typer.Typer(
|
|
21
|
+
name="reset",
|
|
22
|
+
help="Reset and recovery operations",
|
|
23
|
+
rich_markup_mode="rich",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@reset_app.command("index")
|
|
28
|
+
def reset_index(
|
|
29
|
+
project_root: Path = typer.Option(
|
|
30
|
+
None,
|
|
31
|
+
"--project-root",
|
|
32
|
+
"-p",
|
|
33
|
+
help="Project root directory",
|
|
34
|
+
),
|
|
35
|
+
force: bool = typer.Option(
|
|
36
|
+
False,
|
|
37
|
+
"--force",
|
|
38
|
+
"-f",
|
|
39
|
+
help="Skip confirmation prompt",
|
|
40
|
+
),
|
|
41
|
+
backup: bool = typer.Option(
|
|
42
|
+
True,
|
|
43
|
+
"--backup/--no-backup",
|
|
44
|
+
help="Create backup before resetting",
|
|
45
|
+
),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Reset the vector search index (clear corrupted data).
|
|
48
|
+
|
|
49
|
+
This command will:
|
|
50
|
+
- Create a backup of the current index (unless --no-backup)
|
|
51
|
+
- Clear the entire vector database
|
|
52
|
+
- Preserve your configuration settings
|
|
53
|
+
|
|
54
|
+
After reset, run 'mcp-vector-search index' to rebuild.
|
|
55
|
+
"""
|
|
56
|
+
root = project_root or Path.cwd()
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
# Check if project is initialized
|
|
60
|
+
project_manager = ProjectManager(root)
|
|
61
|
+
if not project_manager.is_initialized():
|
|
62
|
+
print_error("Project not initialized. Run 'mcp-vector-search init' first.")
|
|
63
|
+
raise typer.Exit(1)
|
|
64
|
+
|
|
65
|
+
# Get confirmation unless forced
|
|
66
|
+
if not force:
|
|
67
|
+
console.print(
|
|
68
|
+
Panel(
|
|
69
|
+
"[yellow]⚠️ Warning: This will clear the entire search index![/yellow]\n\n"
|
|
70
|
+
"The following will happen:\n"
|
|
71
|
+
"• All indexed code chunks will be deleted\n"
|
|
72
|
+
"• The vector database will be reset\n"
|
|
73
|
+
"• Configuration settings will be preserved\n"
|
|
74
|
+
f"• {'A backup will be created' if backup else 'No backup will be created'}\n\n"
|
|
75
|
+
"You will need to run 'mcp-vector-search index' afterward to rebuild.",
|
|
76
|
+
title="[red]Index Reset Confirmation[/red]",
|
|
77
|
+
border_style="red",
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not Confirm.ask("\nDo you want to proceed?", default=False):
|
|
82
|
+
console.print("[yellow]Reset cancelled[/yellow]")
|
|
83
|
+
raise typer.Exit(0)
|
|
84
|
+
|
|
85
|
+
# Get the database directory
|
|
86
|
+
config = project_manager.load_config()
|
|
87
|
+
db_path = root / ".mcp_vector_search" / "db"
|
|
88
|
+
|
|
89
|
+
if not db_path.exists():
|
|
90
|
+
print_warning("No index found. Nothing to reset.")
|
|
91
|
+
raise typer.Exit(0)
|
|
92
|
+
|
|
93
|
+
# Create backup if requested
|
|
94
|
+
if backup:
|
|
95
|
+
backup_dir = root / ".mcp_vector_search" / "backups"
|
|
96
|
+
backup_dir.mkdir(exist_ok=True)
|
|
97
|
+
|
|
98
|
+
import time
|
|
99
|
+
timestamp = int(time.time())
|
|
100
|
+
backup_path = backup_dir / f"db_backup_{timestamp}"
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
shutil.copytree(db_path, backup_path)
|
|
104
|
+
print_success(f"Created backup at: {backup_path.relative_to(root)}")
|
|
105
|
+
except Exception as e:
|
|
106
|
+
print_warning(f"Could not create backup: {e}")
|
|
107
|
+
if not force:
|
|
108
|
+
if not Confirm.ask("Continue without backup?", default=False):
|
|
109
|
+
console.print("[yellow]Reset cancelled[/yellow]")
|
|
110
|
+
raise typer.Exit(0)
|
|
111
|
+
|
|
112
|
+
# Clear the index
|
|
113
|
+
console.print("[cyan]Clearing index...[/cyan]")
|
|
114
|
+
try:
|
|
115
|
+
shutil.rmtree(db_path)
|
|
116
|
+
db_path.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
print_success("Index cleared successfully!")
|
|
118
|
+
except Exception as e:
|
|
119
|
+
print_error(f"Failed to clear index: {e}")
|
|
120
|
+
raise typer.Exit(1)
|
|
121
|
+
|
|
122
|
+
# Show next steps
|
|
123
|
+
console.print(
|
|
124
|
+
Panel(
|
|
125
|
+
"[green]✅ Index reset complete![/green]\n\n"
|
|
126
|
+
"Next steps:\n"
|
|
127
|
+
"1. Run [cyan]mcp-vector-search index[/cyan] to rebuild the search index\n"
|
|
128
|
+
"2. Or run [cyan]mcp-vector-search watch[/cyan] to start incremental indexing",
|
|
129
|
+
title="[green]Reset Complete[/green]",
|
|
130
|
+
border_style="green",
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
except (DatabaseError, IndexCorruptionError) as e:
|
|
135
|
+
print_error(f"Reset failed: {e}")
|
|
136
|
+
raise typer.Exit(1)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"Unexpected error during reset: {e}")
|
|
139
|
+
print_error(f"Unexpected error: {e}")
|
|
140
|
+
raise typer.Exit(1)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@reset_app.command("all")
|
|
144
|
+
def reset_all(
|
|
145
|
+
project_root: Path = typer.Option(
|
|
146
|
+
None,
|
|
147
|
+
"--project-root",
|
|
148
|
+
"-p",
|
|
149
|
+
help="Project root directory",
|
|
150
|
+
),
|
|
151
|
+
force: bool = typer.Option(
|
|
152
|
+
False,
|
|
153
|
+
"--force",
|
|
154
|
+
"-f",
|
|
155
|
+
help="Skip confirmation prompt",
|
|
156
|
+
),
|
|
157
|
+
) -> None:
|
|
158
|
+
"""Reset everything (index and configuration).
|
|
159
|
+
|
|
160
|
+
This will completely remove all MCP Vector Search data,
|
|
161
|
+
requiring re-initialization with 'mcp-vector-search init'.
|
|
162
|
+
"""
|
|
163
|
+
root = project_root or Path.cwd()
|
|
164
|
+
|
|
165
|
+
# Get confirmation unless forced
|
|
166
|
+
if not force:
|
|
167
|
+
console.print(
|
|
168
|
+
Panel(
|
|
169
|
+
"[red]⚠️ DANGER: This will remove ALL MCP Vector Search data![/red]\n\n"
|
|
170
|
+
"The following will be deleted:\n"
|
|
171
|
+
"• All indexed code chunks\n"
|
|
172
|
+
"• The vector database\n"
|
|
173
|
+
"• All configuration settings\n"
|
|
174
|
+
"• All project metadata\n\n"
|
|
175
|
+
"You will need to run 'mcp-vector-search init' to start over.",
|
|
176
|
+
title="[red]Complete Reset Confirmation[/red]",
|
|
177
|
+
border_style="red",
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if not Confirm.ask("\nAre you absolutely sure?", default=False):
|
|
182
|
+
console.print("[yellow]Reset cancelled[/yellow]")
|
|
183
|
+
raise typer.Exit(0)
|
|
184
|
+
|
|
185
|
+
# Double confirmation for destructive action
|
|
186
|
+
if not Confirm.ask("Type 'yes' to confirm complete reset", default=False):
|
|
187
|
+
console.print("[yellow]Reset cancelled[/yellow]")
|
|
188
|
+
raise typer.Exit(0)
|
|
189
|
+
|
|
190
|
+
# Remove entire .mcp_vector_search directory
|
|
191
|
+
mcp_dir = root / ".mcp_vector_search"
|
|
192
|
+
|
|
193
|
+
if not mcp_dir.exists():
|
|
194
|
+
print_warning("No MCP Vector Search data found. Nothing to reset.")
|
|
195
|
+
raise typer.Exit(0)
|
|
196
|
+
|
|
197
|
+
console.print("[cyan]Removing all MCP Vector Search data...[/cyan]")
|
|
198
|
+
try:
|
|
199
|
+
shutil.rmtree(mcp_dir)
|
|
200
|
+
print_success("All data removed successfully!")
|
|
201
|
+
|
|
202
|
+
console.print(
|
|
203
|
+
Panel(
|
|
204
|
+
"[green]✅ Complete reset done![/green]\n\n"
|
|
205
|
+
"To start using MCP Vector Search again:\n"
|
|
206
|
+
"1. Run [cyan]mcp-vector-search init[/cyan] to initialize the project\n"
|
|
207
|
+
"2. Run [cyan]mcp-vector-search index[/cyan] to index your codebase",
|
|
208
|
+
title="[green]Reset Complete[/green]",
|
|
209
|
+
border_style="green",
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
print_error(f"Failed to remove data: {e}")
|
|
214
|
+
raise typer.Exit(1)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@reset_app.command("health")
|
|
218
|
+
async def check_health(
|
|
219
|
+
project_root: Path = typer.Option(
|
|
220
|
+
None,
|
|
221
|
+
"--project-root",
|
|
222
|
+
"-p",
|
|
223
|
+
help="Project root directory",
|
|
224
|
+
),
|
|
225
|
+
fix: bool = typer.Option(
|
|
226
|
+
False,
|
|
227
|
+
"--fix",
|
|
228
|
+
help="Attempt to fix issues if found",
|
|
229
|
+
),
|
|
230
|
+
) -> None:
|
|
231
|
+
"""Check the health of the search index.
|
|
232
|
+
|
|
233
|
+
This command will:
|
|
234
|
+
- Verify database connectivity
|
|
235
|
+
- Check for index corruption
|
|
236
|
+
- Validate collection integrity
|
|
237
|
+
- Optionally attempt repairs with --fix
|
|
238
|
+
"""
|
|
239
|
+
root = project_root or Path.cwd()
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
# Check if project is initialized
|
|
243
|
+
project_manager = ProjectManager(root)
|
|
244
|
+
if not project_manager.is_initialized():
|
|
245
|
+
print_error("Project not initialized. Run 'mcp-vector-search init' first.")
|
|
246
|
+
raise typer.Exit(1)
|
|
247
|
+
|
|
248
|
+
console.print("[cyan]Performing health check...[/cyan]\n")
|
|
249
|
+
|
|
250
|
+
# Initialize database
|
|
251
|
+
from ...core.database import ChromaVectorDatabase
|
|
252
|
+
from ...core.embeddings import create_embedding_function
|
|
253
|
+
from ...config.defaults import get_default_cache_path
|
|
254
|
+
|
|
255
|
+
config = project_manager.load_config()
|
|
256
|
+
db_path = root / ".mcp_vector_search" / "db"
|
|
257
|
+
|
|
258
|
+
# Setup embedding function and cache
|
|
259
|
+
cache_dir = (
|
|
260
|
+
get_default_cache_path(root) if config.cache_embeddings else None
|
|
261
|
+
)
|
|
262
|
+
embedding_function, _ = create_embedding_function(
|
|
263
|
+
model_name=config.embedding_model,
|
|
264
|
+
cache_dir=cache_dir,
|
|
265
|
+
cache_size=config.max_cache_size,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Create database instance
|
|
269
|
+
db = ChromaVectorDatabase(
|
|
270
|
+
persist_directory=db_path,
|
|
271
|
+
embedding_function=embedding_function,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Initialize and check health
|
|
275
|
+
try:
|
|
276
|
+
await db.initialize()
|
|
277
|
+
is_healthy = await db.health_check()
|
|
278
|
+
|
|
279
|
+
if is_healthy:
|
|
280
|
+
# Get stats for additional info
|
|
281
|
+
stats = await db.get_stats()
|
|
282
|
+
|
|
283
|
+
console.print(
|
|
284
|
+
Panel(
|
|
285
|
+
f"[green]✅ Index is healthy![/green]\n\n"
|
|
286
|
+
f"Statistics:\n"
|
|
287
|
+
f"• Total chunks: {stats.total_chunks:,}\n"
|
|
288
|
+
f"• Total files: {stats.total_files:,}\n"
|
|
289
|
+
f"• Languages: {', '.join(stats.languages.keys()) if stats.languages else 'None'}\n"
|
|
290
|
+
f"• Index size: {stats.index_size_mb:.2f} MB",
|
|
291
|
+
title="[green]Health Check Passed[/green]",
|
|
292
|
+
border_style="green",
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
else:
|
|
296
|
+
console.print(
|
|
297
|
+
Panel(
|
|
298
|
+
"[red]❌ Index health check failed![/red]\n\n"
|
|
299
|
+
"Detected issues:\n"
|
|
300
|
+
"• Index may be corrupted\n"
|
|
301
|
+
"• Database operations failing\n\n"
|
|
302
|
+
f"{'Run with --fix to attempt automatic repair' if not fix else 'Attempting to fix...'}",
|
|
303
|
+
title="[red]Health Check Failed[/red]",
|
|
304
|
+
border_style="red",
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if fix:
|
|
309
|
+
console.print("\n[cyan]Attempting to repair index...[/cyan]")
|
|
310
|
+
# The health check already attempts recovery
|
|
311
|
+
# Try to reinitialize
|
|
312
|
+
await db.close()
|
|
313
|
+
await db.initialize()
|
|
314
|
+
|
|
315
|
+
# Check again
|
|
316
|
+
is_healthy = await db.health_check()
|
|
317
|
+
if is_healthy:
|
|
318
|
+
print_success("Index repaired successfully!")
|
|
319
|
+
else:
|
|
320
|
+
print_error(
|
|
321
|
+
"Automatic repair failed. "
|
|
322
|
+
"Please run 'mcp-vector-search reset index' followed by 'mcp-vector-search index'"
|
|
323
|
+
)
|
|
324
|
+
raise typer.Exit(1)
|
|
325
|
+
else:
|
|
326
|
+
print_warning(
|
|
327
|
+
"Run 'mcp-vector-search reset health --fix' to attempt automatic repair,\n"
|
|
328
|
+
"or 'mcp-vector-search reset index' to clear and rebuild."
|
|
329
|
+
)
|
|
330
|
+
raise typer.Exit(1)
|
|
331
|
+
|
|
332
|
+
except IndexCorruptionError as e:
|
|
333
|
+
console.print(
|
|
334
|
+
Panel(
|
|
335
|
+
f"[red]❌ Index corruption detected![/red]\n\n"
|
|
336
|
+
f"Error: {e}\n\n"
|
|
337
|
+
"Recommended actions:\n"
|
|
338
|
+
"1. Run [cyan]mcp-vector-search reset index[/cyan] to clear the corrupted index\n"
|
|
339
|
+
"2. Run [cyan]mcp-vector-search index[/cyan] to rebuild",
|
|
340
|
+
title="[red]Corruption Detected[/red]",
|
|
341
|
+
border_style="red",
|
|
342
|
+
)
|
|
343
|
+
)
|
|
344
|
+
raise typer.Exit(1)
|
|
345
|
+
|
|
346
|
+
finally:
|
|
347
|
+
await db.close()
|
|
348
|
+
|
|
349
|
+
except Exception as e:
|
|
350
|
+
logger.error(f"Health check error: {e}")
|
|
351
|
+
print_error(f"Health check failed: {e}")
|
|
352
|
+
raise typer.Exit(1)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# Main reset command that shows subcommands
|
|
356
|
+
@reset_app.callback(invoke_without_command=True)
|
|
357
|
+
def reset_main(ctx: typer.Context) -> None:
|
|
358
|
+
"""Reset and recovery operations for MCP Vector Search."""
|
|
359
|
+
if ctx.invoked_subcommand is None:
|
|
360
|
+
console.print(
|
|
361
|
+
Panel(
|
|
362
|
+
"Available reset commands:\n\n"
|
|
363
|
+
"[cyan]mcp-vector-search reset index[/cyan]\n"
|
|
364
|
+
" Reset the search index (preserves config)\n\n"
|
|
365
|
+
"[cyan]mcp-vector-search reset health[/cyan]\n"
|
|
366
|
+
" Check index health and optionally repair\n\n"
|
|
367
|
+
"[cyan]mcp-vector-search reset all[/cyan]\n"
|
|
368
|
+
" Complete reset (removes everything)\n",
|
|
369
|
+
title="Reset Commands",
|
|
370
|
+
border_style="cyan",
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# Export for backwards compatibility
|
|
376
|
+
main = reset_main
|
|
377
|
+
|
|
378
|
+
# Make health check synchronous for CLI
|
|
379
|
+
def health_main(
|
|
380
|
+
project_root: Path = typer.Option(
|
|
381
|
+
None,
|
|
382
|
+
"--project-root",
|
|
383
|
+
"-p",
|
|
384
|
+
help="Project root directory",
|
|
385
|
+
),
|
|
386
|
+
fix: bool = typer.Option(
|
|
387
|
+
False,
|
|
388
|
+
"--fix",
|
|
389
|
+
help="Attempt to fix issues if found",
|
|
390
|
+
),
|
|
391
|
+
) -> None:
|
|
392
|
+
"""Check the health of the search index (sync wrapper)."""
|
|
393
|
+
asyncio.run(check_health(project_root, fix))
|