mcp-vector-search 0.7.5__py3-none-any.whl → 0.7.6__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/demo.py +2 -4
- mcp_vector_search/cli/commands/index.py +130 -30
- mcp_vector_search/cli/commands/mcp.py +83 -56
- mcp_vector_search/cli/commands/status.py +23 -9
- mcp_vector_search/cli/main.py +0 -2
- mcp_vector_search/core/database.py +117 -54
- mcp_vector_search/core/indexer.py +191 -15
- mcp_vector_search/core/project.py +6 -3
- mcp_vector_search/utils/gitignore.py +31 -23
- {mcp_vector_search-0.7.5.dist-info → mcp_vector_search-0.7.6.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.7.5.dist-info → mcp_vector_search-0.7.6.dist-info}/RECORD +15 -15
- {mcp_vector_search-0.7.5.dist-info → mcp_vector_search-0.7.6.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.7.5.dist-info → mcp_vector_search-0.7.6.dist-info}/entry_points.txt +0 -0
- {mcp_vector_search-0.7.5.dist-info → mcp_vector_search-0.7.6.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ import typer
|
|
|
9
9
|
from loguru import logger
|
|
10
10
|
from rich.console import Console
|
|
11
11
|
|
|
12
|
-
from ..output import print_error, print_info, print_success
|
|
12
|
+
from ..output import print_error, print_info, print_success
|
|
13
13
|
|
|
14
14
|
console = Console()
|
|
15
15
|
|
|
@@ -321,9 +321,7 @@ class UserAPI:
|
|
|
321
321
|
console.print(" ✅ Automatic code indexing")
|
|
322
322
|
if not quick:
|
|
323
323
|
console.print(" ✅ Semantic code search in action")
|
|
324
|
-
console.print(
|
|
325
|
-
" ✅ Finding code by meaning (not just keywords)\n"
|
|
326
|
-
)
|
|
324
|
+
console.print(" ✅ Finding code by meaning (not just keywords)\n")
|
|
327
325
|
|
|
328
326
|
console.print("[bold cyan]Next steps to use in your project:[/bold cyan]")
|
|
329
327
|
console.print(" 1. [green]cd /your/project[/green]")
|
|
@@ -13,7 +13,6 @@ from ...core.exceptions import ProjectNotFoundError
|
|
|
13
13
|
from ...core.indexer import SemanticIndexer
|
|
14
14
|
from ...core.project import ProjectManager
|
|
15
15
|
from ..output import (
|
|
16
|
-
create_progress,
|
|
17
16
|
print_error,
|
|
18
17
|
print_index_stats,
|
|
19
18
|
print_info,
|
|
@@ -201,17 +200,138 @@ async def _run_batch_indexing(
|
|
|
201
200
|
) -> None:
|
|
202
201
|
"""Run batch indexing of all files."""
|
|
203
202
|
if show_progress:
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
# Import enhanced progress utilities
|
|
204
|
+
from rich.layout import Layout
|
|
205
|
+
from rich.live import Live
|
|
206
|
+
from rich.panel import Panel
|
|
207
|
+
from rich.progress import (
|
|
208
|
+
BarColumn,
|
|
209
|
+
Progress,
|
|
210
|
+
SpinnerColumn,
|
|
211
|
+
TextColumn,
|
|
212
|
+
TimeRemainingColumn,
|
|
213
|
+
)
|
|
214
|
+
from rich.table import Table
|
|
215
|
+
|
|
216
|
+
from ..output import console
|
|
217
|
+
|
|
218
|
+
# Pre-scan to get total file count
|
|
219
|
+
console.print("[dim]Scanning for indexable files...[/dim]")
|
|
220
|
+
indexable_files, files_to_index = await indexer.get_files_to_index(
|
|
221
|
+
force_reindex=force_reindex
|
|
222
|
+
)
|
|
223
|
+
total_files = len(files_to_index)
|
|
206
224
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
if total_files == 0:
|
|
226
|
+
console.print("[yellow]No files need indexing[/yellow]")
|
|
227
|
+
indexed_count = 0
|
|
228
|
+
else:
|
|
229
|
+
console.print(f"[dim]Found {total_files} files to index[/dim]\n")
|
|
230
|
+
|
|
231
|
+
# Track recently indexed files for display
|
|
232
|
+
recent_files = []
|
|
233
|
+
current_file_name = ""
|
|
234
|
+
indexed_count = 0
|
|
235
|
+
failed_count = 0
|
|
236
|
+
|
|
237
|
+
# Create layout for two-panel display
|
|
238
|
+
layout = Layout()
|
|
239
|
+
layout.split_column(
|
|
240
|
+
Layout(name="progress", size=4),
|
|
241
|
+
Layout(name="samples", size=7),
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Create progress bar
|
|
245
|
+
progress = Progress(
|
|
246
|
+
SpinnerColumn(),
|
|
247
|
+
TextColumn("[progress.description]{task.description}"),
|
|
248
|
+
BarColumn(bar_width=40),
|
|
249
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
250
|
+
TextColumn("({task.completed}/{task.total} files)"),
|
|
251
|
+
TimeRemainingColumn(),
|
|
252
|
+
console=console,
|
|
211
253
|
)
|
|
212
254
|
|
|
213
|
-
progress.
|
|
255
|
+
task = progress.add_task("Indexing files...", total=total_files)
|
|
256
|
+
|
|
257
|
+
# Create live display with both panels
|
|
258
|
+
with Live(layout, console=console, refresh_per_second=4):
|
|
259
|
+
# Index files with progress updates
|
|
260
|
+
async for (
|
|
261
|
+
file_path,
|
|
262
|
+
chunks_added,
|
|
263
|
+
success,
|
|
264
|
+
) in indexer.index_files_with_progress(files_to_index, force_reindex):
|
|
265
|
+
# Update counts
|
|
266
|
+
if success:
|
|
267
|
+
indexed_count += 1
|
|
268
|
+
else:
|
|
269
|
+
failed_count += 1
|
|
270
|
+
|
|
271
|
+
# Update progress
|
|
272
|
+
progress.update(task, advance=1)
|
|
273
|
+
|
|
274
|
+
# Update current file name for display
|
|
275
|
+
current_file_name = file_path.name
|
|
276
|
+
|
|
277
|
+
# Keep last 5 files for sampling display
|
|
278
|
+
try:
|
|
279
|
+
relative_path = str(file_path.relative_to(indexer.project_root))
|
|
280
|
+
except ValueError:
|
|
281
|
+
relative_path = str(file_path)
|
|
282
|
+
|
|
283
|
+
recent_files.append((relative_path, chunks_added, success))
|
|
284
|
+
if len(recent_files) > 5:
|
|
285
|
+
recent_files.pop(0)
|
|
286
|
+
|
|
287
|
+
# Update display layouts
|
|
288
|
+
layout["progress"].update(
|
|
289
|
+
Panel(
|
|
290
|
+
progress,
|
|
291
|
+
title="[bold]Indexing Progress[/bold]",
|
|
292
|
+
border_style="blue",
|
|
293
|
+
)
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Build samples panel content
|
|
297
|
+
samples_table = Table.grid(expand=True)
|
|
298
|
+
samples_table.add_column(style="dim")
|
|
299
|
+
|
|
300
|
+
if current_file_name:
|
|
301
|
+
samples_table.add_row(
|
|
302
|
+
f"[bold cyan]Currently processing:[/bold cyan] {current_file_name}"
|
|
303
|
+
)
|
|
304
|
+
samples_table.add_row("")
|
|
305
|
+
|
|
306
|
+
samples_table.add_row("[dim]Recently indexed:[/dim]")
|
|
307
|
+
for rel_path, chunk_count, file_success in recent_files[-5:]:
|
|
308
|
+
icon = "✓" if file_success else "✗"
|
|
309
|
+
style = "green" if file_success else "red"
|
|
310
|
+
chunk_info = (
|
|
311
|
+
f"({chunk_count} chunks)"
|
|
312
|
+
if chunk_count > 0
|
|
313
|
+
else "(no chunks)"
|
|
314
|
+
)
|
|
315
|
+
samples_table.add_row(
|
|
316
|
+
f" [{style}]{icon}[/{style}] [cyan]{rel_path}[/cyan] [dim]{chunk_info}[/dim]"
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
layout["samples"].update(
|
|
320
|
+
Panel(
|
|
321
|
+
samples_table,
|
|
322
|
+
title="[bold]File Processing[/bold]",
|
|
323
|
+
border_style="dim",
|
|
324
|
+
)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Final progress summary
|
|
328
|
+
console.print()
|
|
329
|
+
if failed_count > 0:
|
|
330
|
+
console.print(
|
|
331
|
+
f"[yellow]⚠ {failed_count} files failed to index[/yellow]"
|
|
332
|
+
)
|
|
214
333
|
else:
|
|
334
|
+
# Non-progress mode (fallback to original behavior)
|
|
215
335
|
indexed_count = await indexer.index_project(
|
|
216
336
|
force_reindex=force_reindex,
|
|
217
337
|
show_progress=show_progress,
|
|
@@ -374,28 +494,8 @@ async def _reindex_entire_project(project_root: Path) -> None:
|
|
|
374
494
|
print_info("Clearing existing index...")
|
|
375
495
|
await database.reset()
|
|
376
496
|
|
|
377
|
-
# Then reindex everything with progress
|
|
378
|
-
|
|
379
|
-
task = progress.add_task("Reindexing files...", total=None)
|
|
380
|
-
|
|
381
|
-
# Force reindex all files
|
|
382
|
-
indexed_count = await indexer.index_project(
|
|
383
|
-
force_reindex=True, # Force reindexing
|
|
384
|
-
show_progress=False, # We handle progress here
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
progress.update(task, completed=indexed_count, total=indexed_count)
|
|
388
|
-
|
|
389
|
-
# Show statistics
|
|
390
|
-
stats = await indexer.get_indexing_stats()
|
|
391
|
-
|
|
392
|
-
# Display success message with chunk count for clarity
|
|
393
|
-
total_chunks = stats.get("total_chunks", 0)
|
|
394
|
-
print_success(
|
|
395
|
-
f"Processed {indexed_count} files ({total_chunks} searchable chunks created)"
|
|
396
|
-
)
|
|
397
|
-
|
|
398
|
-
print_index_stats(stats)
|
|
497
|
+
# Then reindex everything with enhanced progress display
|
|
498
|
+
await _run_batch_indexing(indexer, force_reindex=True, show_progress=True)
|
|
399
499
|
|
|
400
500
|
except Exception as e:
|
|
401
501
|
logger.error(f"Full reindex error: {e}")
|
|
@@ -7,7 +7,7 @@ import subprocess
|
|
|
7
7
|
import sys
|
|
8
8
|
import tomllib
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import Any
|
|
11
11
|
|
|
12
12
|
import typer
|
|
13
13
|
from rich.console import Console
|
|
@@ -49,26 +49,26 @@ SUPPORTED_TOOLS = {
|
|
|
49
49
|
"name": "Auggie",
|
|
50
50
|
"config_path": "~/.augment/settings.json",
|
|
51
51
|
"format": "json",
|
|
52
|
-
"description": "Augment Code AI assistant"
|
|
52
|
+
"description": "Augment Code AI assistant",
|
|
53
53
|
},
|
|
54
54
|
"claude-code": {
|
|
55
55
|
"name": "Claude Code",
|
|
56
56
|
"config_path": ".mcp.json",
|
|
57
57
|
"format": "json",
|
|
58
|
-
"description": "Claude Code (project-scoped)"
|
|
58
|
+
"description": "Claude Code (project-scoped)",
|
|
59
59
|
},
|
|
60
60
|
"codex": {
|
|
61
61
|
"name": "Codex",
|
|
62
62
|
"config_path": "~/.codex/config.toml",
|
|
63
63
|
"format": "toml",
|
|
64
|
-
"description": "OpenAI Codex CLI"
|
|
64
|
+
"description": "OpenAI Codex CLI",
|
|
65
65
|
},
|
|
66
66
|
"gemini": {
|
|
67
67
|
"name": "Gemini",
|
|
68
68
|
"config_path": "~/.gemini/mcp.json",
|
|
69
69
|
"format": "json",
|
|
70
|
-
"description": "Google Gemini CLI"
|
|
71
|
-
}
|
|
70
|
+
"description": "Google Gemini CLI",
|
|
71
|
+
},
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
|
|
@@ -124,15 +124,18 @@ def get_mcp_server_command(
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
def get_mcp_server_config_for_tool(
|
|
127
|
-
project_root: Path,
|
|
128
|
-
|
|
127
|
+
project_root: Path,
|
|
128
|
+
tool_name: str,
|
|
129
|
+
server_name: str,
|
|
130
|
+
enable_file_watching: bool = True,
|
|
131
|
+
) -> dict[str, Any]:
|
|
129
132
|
"""Generate MCP server configuration for a specific tool."""
|
|
130
133
|
base_config = {
|
|
131
134
|
"command": "uv",
|
|
132
135
|
"args": ["run", "mcp-vector-search", "mcp"],
|
|
133
136
|
"env": {
|
|
134
137
|
"MCP_ENABLE_FILE_WATCHING": "true" if enable_file_watching else "false"
|
|
135
|
-
}
|
|
138
|
+
},
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
if tool_name == "auggie":
|
|
@@ -140,29 +143,20 @@ def get_mcp_server_config_for_tool(
|
|
|
140
143
|
return base_config
|
|
141
144
|
elif tool_name == "claude-code":
|
|
142
145
|
# Claude Code requires type: stdio and no cwd
|
|
143
|
-
return {
|
|
144
|
-
"type": "stdio",
|
|
145
|
-
**base_config
|
|
146
|
-
}
|
|
146
|
+
return {"type": "stdio", **base_config}
|
|
147
147
|
elif tool_name == "codex":
|
|
148
148
|
# Codex uses TOML format with different structure
|
|
149
149
|
return {
|
|
150
150
|
"command": base_config["command"],
|
|
151
151
|
"args": base_config["args"],
|
|
152
|
-
"env": base_config["env"]
|
|
152
|
+
"env": base_config["env"],
|
|
153
153
|
}
|
|
154
154
|
elif tool_name == "gemini":
|
|
155
155
|
# Gemini uses standard format with cwd
|
|
156
|
-
return {
|
|
157
|
-
**base_config,
|
|
158
|
-
"cwd": str(project_root.absolute())
|
|
159
|
-
}
|
|
156
|
+
return {**base_config, "cwd": str(project_root.absolute())}
|
|
160
157
|
else:
|
|
161
158
|
# Default configuration
|
|
162
|
-
return {
|
|
163
|
-
**base_config,
|
|
164
|
-
"cwd": str(project_root.absolute())
|
|
165
|
-
}
|
|
159
|
+
return {**base_config, "cwd": str(project_root.absolute())}
|
|
166
160
|
|
|
167
161
|
|
|
168
162
|
def create_project_claude_config(
|
|
@@ -215,7 +209,7 @@ def configure_tool_mcp(
|
|
|
215
209
|
project_root: Path,
|
|
216
210
|
server_name: str = "mcp-vector-search",
|
|
217
211
|
enable_file_watching: bool = True,
|
|
218
|
-
force: bool = False
|
|
212
|
+
force: bool = False,
|
|
219
213
|
) -> bool:
|
|
220
214
|
"""Configure MCP integration for a specific AI tool."""
|
|
221
215
|
if tool_name not in SUPPORTED_TOOLS:
|
|
@@ -236,13 +230,21 @@ def configure_tool_mcp(
|
|
|
236
230
|
|
|
237
231
|
try:
|
|
238
232
|
if tool_name == "auggie":
|
|
239
|
-
return configure_auggie_mcp(
|
|
233
|
+
return configure_auggie_mcp(
|
|
234
|
+
config_path, project_root, server_name, enable_file_watching, force
|
|
235
|
+
)
|
|
240
236
|
elif tool_name == "claude-code":
|
|
241
|
-
return configure_claude_code_mcp(
|
|
237
|
+
return configure_claude_code_mcp(
|
|
238
|
+
config_path, project_root, server_name, enable_file_watching, force
|
|
239
|
+
)
|
|
242
240
|
elif tool_name == "codex":
|
|
243
|
-
return configure_codex_mcp(
|
|
241
|
+
return configure_codex_mcp(
|
|
242
|
+
config_path, project_root, server_name, enable_file_watching, force
|
|
243
|
+
)
|
|
244
244
|
elif tool_name == "gemini":
|
|
245
|
-
return configure_gemini_mcp(
|
|
245
|
+
return configure_gemini_mcp(
|
|
246
|
+
config_path, project_root, server_name, enable_file_watching, force
|
|
247
|
+
)
|
|
246
248
|
else:
|
|
247
249
|
print_error(f"Configuration for {tool_name} not implemented yet")
|
|
248
250
|
return False
|
|
@@ -256,7 +258,7 @@ def configure_auggie_mcp(
|
|
|
256
258
|
project_root: Path,
|
|
257
259
|
server_name: str,
|
|
258
260
|
enable_file_watching: bool,
|
|
259
|
-
force: bool
|
|
261
|
+
force: bool,
|
|
260
262
|
) -> bool:
|
|
261
263
|
"""Configure Auggie MCP integration."""
|
|
262
264
|
# Create backup if file exists
|
|
@@ -268,7 +270,9 @@ def configure_auggie_mcp(
|
|
|
268
270
|
with open(config_path) as f:
|
|
269
271
|
config = json.load(f)
|
|
270
272
|
if config.get("mcpServers", {}).get(server_name):
|
|
271
|
-
print_warning(
|
|
273
|
+
print_warning(
|
|
274
|
+
f"MCP server '{server_name}' already exists in Auggie config"
|
|
275
|
+
)
|
|
272
276
|
print_info("Use --force to overwrite")
|
|
273
277
|
return False
|
|
274
278
|
shutil.copy2(config_path, backup_path)
|
|
@@ -283,7 +287,9 @@ def configure_auggie_mcp(
|
|
|
283
287
|
config["mcpServers"] = {}
|
|
284
288
|
|
|
285
289
|
# Get server configuration
|
|
286
|
-
server_config = get_mcp_server_config_for_tool(
|
|
290
|
+
server_config = get_mcp_server_config_for_tool(
|
|
291
|
+
project_root, "auggie", server_name, enable_file_watching
|
|
292
|
+
)
|
|
287
293
|
config["mcpServers"][server_name] = server_config
|
|
288
294
|
|
|
289
295
|
# Write updated config
|
|
@@ -299,7 +305,7 @@ def configure_claude_code_mcp(
|
|
|
299
305
|
project_root: Path,
|
|
300
306
|
server_name: str,
|
|
301
307
|
enable_file_watching: bool,
|
|
302
|
-
force: bool
|
|
308
|
+
force: bool,
|
|
303
309
|
) -> bool:
|
|
304
310
|
"""Configure Claude Code MCP integration."""
|
|
305
311
|
# Use existing function for Claude Code
|
|
@@ -307,7 +313,9 @@ def configure_claude_code_mcp(
|
|
|
307
313
|
with open(config_path) as f:
|
|
308
314
|
config = json.load(f)
|
|
309
315
|
if config.get("mcpServers", {}).get(server_name):
|
|
310
|
-
print_warning(
|
|
316
|
+
print_warning(
|
|
317
|
+
f"MCP server '{server_name}' already exists in Claude Code config"
|
|
318
|
+
)
|
|
311
319
|
print_info("Use --force to overwrite")
|
|
312
320
|
return False
|
|
313
321
|
|
|
@@ -321,7 +329,7 @@ def configure_codex_mcp(
|
|
|
321
329
|
project_root: Path,
|
|
322
330
|
server_name: str,
|
|
323
331
|
enable_file_watching: bool,
|
|
324
|
-
force: bool
|
|
332
|
+
force: bool,
|
|
325
333
|
) -> bool:
|
|
326
334
|
"""Configure Codex MCP integration."""
|
|
327
335
|
# Create backup if file exists
|
|
@@ -334,7 +342,9 @@ def configure_codex_mcp(
|
|
|
334
342
|
with open(config_path, "rb") as f:
|
|
335
343
|
config = tomllib.load(f)
|
|
336
344
|
if config.get("mcp_servers", {}).get(server_name):
|
|
337
|
-
print_warning(
|
|
345
|
+
print_warning(
|
|
346
|
+
f"MCP server '{server_name}' already exists in Codex config"
|
|
347
|
+
)
|
|
338
348
|
print_info("Use --force to overwrite")
|
|
339
349
|
return False
|
|
340
350
|
except Exception as e:
|
|
@@ -342,19 +352,21 @@ def configure_codex_mcp(
|
|
|
342
352
|
|
|
343
353
|
shutil.copy2(config_path, backup_path)
|
|
344
354
|
# Read as text to preserve existing content
|
|
345
|
-
with open(config_path
|
|
355
|
+
with open(config_path) as f:
|
|
346
356
|
config_text = f.read()
|
|
347
357
|
else:
|
|
348
358
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
349
359
|
config_text = ""
|
|
350
360
|
|
|
351
361
|
# Get server configuration
|
|
352
|
-
server_config = get_mcp_server_config_for_tool(
|
|
362
|
+
server_config = get_mcp_server_config_for_tool(
|
|
363
|
+
project_root, "codex", server_name, enable_file_watching
|
|
364
|
+
)
|
|
353
365
|
|
|
354
366
|
# Generate TOML section for the server
|
|
355
367
|
toml_section = f"\n[mcp_servers.{server_name}]\n"
|
|
356
368
|
toml_section += f'command = "{server_config["command"]}"\n'
|
|
357
|
-
toml_section += f
|
|
369
|
+
toml_section += f"args = {server_config['args']}\n"
|
|
358
370
|
|
|
359
371
|
if server_config.get("env"):
|
|
360
372
|
toml_section += f"\n[mcp_servers.{server_name}.env]\n"
|
|
@@ -364,7 +376,7 @@ def configure_codex_mcp(
|
|
|
364
376
|
# Append or replace the section
|
|
365
377
|
if f"[mcp_servers.{server_name}]" in config_text:
|
|
366
378
|
# Replace existing section (simple approach)
|
|
367
|
-
lines = config_text.split(
|
|
379
|
+
lines = config_text.split("\n")
|
|
368
380
|
new_lines = []
|
|
369
381
|
skip_section = False
|
|
370
382
|
|
|
@@ -378,7 +390,7 @@ def configure_codex_mcp(
|
|
|
378
390
|
elif not skip_section:
|
|
379
391
|
new_lines.append(line)
|
|
380
392
|
|
|
381
|
-
config_text =
|
|
393
|
+
config_text = "\n".join(new_lines) + toml_section
|
|
382
394
|
else:
|
|
383
395
|
config_text += toml_section
|
|
384
396
|
|
|
@@ -395,7 +407,7 @@ def configure_gemini_mcp(
|
|
|
395
407
|
project_root: Path,
|
|
396
408
|
server_name: str,
|
|
397
409
|
enable_file_watching: bool,
|
|
398
|
-
force: bool
|
|
410
|
+
force: bool,
|
|
399
411
|
) -> bool:
|
|
400
412
|
"""Configure Gemini MCP integration."""
|
|
401
413
|
# Create backup if file exists
|
|
@@ -407,7 +419,9 @@ def configure_gemini_mcp(
|
|
|
407
419
|
with open(config_path) as f:
|
|
408
420
|
config = json.load(f)
|
|
409
421
|
if config.get("mcpServers", {}).get(server_name):
|
|
410
|
-
print_warning(
|
|
422
|
+
print_warning(
|
|
423
|
+
f"MCP server '{server_name}' already exists in Gemini config"
|
|
424
|
+
)
|
|
411
425
|
print_info("Use --force to overwrite")
|
|
412
426
|
return False
|
|
413
427
|
shutil.copy2(config_path, backup_path)
|
|
@@ -422,7 +436,9 @@ def configure_gemini_mcp(
|
|
|
422
436
|
config["mcpServers"] = {}
|
|
423
437
|
|
|
424
438
|
# Get server configuration
|
|
425
|
-
server_config = get_mcp_server_config_for_tool(
|
|
439
|
+
server_config = get_mcp_server_config_for_tool(
|
|
440
|
+
project_root, "gemini", server_name, enable_file_watching
|
|
441
|
+
)
|
|
426
442
|
config["mcpServers"][server_name] = server_config
|
|
427
443
|
|
|
428
444
|
# Write updated config
|
|
@@ -481,7 +497,9 @@ def configure_auggie(
|
|
|
481
497
|
raise typer.Exit(1)
|
|
482
498
|
|
|
483
499
|
enable_file_watching = not no_watch
|
|
484
|
-
success = configure_tool_mcp(
|
|
500
|
+
success = configure_tool_mcp(
|
|
501
|
+
"auggie", project_root, server_name, enable_file_watching, force
|
|
502
|
+
)
|
|
485
503
|
|
|
486
504
|
if success:
|
|
487
505
|
print_info("Auggie will automatically detect the server when restarted")
|
|
@@ -540,10 +558,14 @@ def configure_claude_code(
|
|
|
540
558
|
raise typer.Exit(1)
|
|
541
559
|
|
|
542
560
|
enable_file_watching = not no_watch
|
|
543
|
-
success = configure_tool_mcp(
|
|
561
|
+
success = configure_tool_mcp(
|
|
562
|
+
"claude-code", project_root, server_name, enable_file_watching, force
|
|
563
|
+
)
|
|
544
564
|
|
|
545
565
|
if success:
|
|
546
|
-
print_info(
|
|
566
|
+
print_info(
|
|
567
|
+
"Claude Code will automatically detect the server when you open this project"
|
|
568
|
+
)
|
|
547
569
|
else:
|
|
548
570
|
raise typer.Exit(1)
|
|
549
571
|
|
|
@@ -599,7 +621,9 @@ def configure_codex(
|
|
|
599
621
|
raise typer.Exit(1)
|
|
600
622
|
|
|
601
623
|
enable_file_watching = not no_watch
|
|
602
|
-
success = configure_tool_mcp(
|
|
624
|
+
success = configure_tool_mcp(
|
|
625
|
+
"codex", project_root, server_name, enable_file_watching, force
|
|
626
|
+
)
|
|
603
627
|
|
|
604
628
|
if success:
|
|
605
629
|
print_info("Codex will automatically detect the server when restarted")
|
|
@@ -658,7 +682,9 @@ def configure_gemini(
|
|
|
658
682
|
raise typer.Exit(1)
|
|
659
683
|
|
|
660
684
|
enable_file_watching = not no_watch
|
|
661
|
-
success = configure_tool_mcp(
|
|
685
|
+
success = configure_tool_mcp(
|
|
686
|
+
"gemini", project_root, server_name, enable_file_watching, force
|
|
687
|
+
)
|
|
662
688
|
|
|
663
689
|
if success:
|
|
664
690
|
print_info("Gemini will automatically detect the server when restarted")
|
|
@@ -730,10 +756,14 @@ def install_mcp_integration(
|
|
|
730
756
|
raise typer.Exit(1)
|
|
731
757
|
|
|
732
758
|
enable_file_watching = not no_watch
|
|
733
|
-
success = configure_tool_mcp(
|
|
759
|
+
success = configure_tool_mcp(
|
|
760
|
+
"claude-code", project_root, server_name, enable_file_watching, force
|
|
761
|
+
)
|
|
734
762
|
|
|
735
763
|
if success:
|
|
736
|
-
print_info(
|
|
764
|
+
print_info(
|
|
765
|
+
"Claude Code will automatically detect the server when you open this project"
|
|
766
|
+
)
|
|
737
767
|
|
|
738
768
|
# Test the server (using project_root for the server command)
|
|
739
769
|
print_info("Testing server startup...")
|
|
@@ -870,15 +900,12 @@ def list_tools() -> None:
|
|
|
870
900
|
except Exception:
|
|
871
901
|
status = "❓ Unknown"
|
|
872
902
|
|
|
873
|
-
table.add_row(
|
|
874
|
-
tool_id,
|
|
875
|
-
tool_info["name"],
|
|
876
|
-
str(config_path),
|
|
877
|
-
status
|
|
878
|
-
)
|
|
903
|
+
table.add_row(tool_id, tool_info["name"], str(config_path), status)
|
|
879
904
|
|
|
880
905
|
console.print(table)
|
|
881
|
-
console.print(
|
|
906
|
+
console.print(
|
|
907
|
+
"\n[dim]💡 Use 'mcp-vector-search mcp <tool>' to configure a specific tool[/dim]"
|
|
908
|
+
)
|
|
882
909
|
|
|
883
910
|
|
|
884
911
|
@mcp_app.command("tools")
|
|
@@ -102,15 +102,28 @@ def main(
|
|
|
102
102
|
if project_root is None:
|
|
103
103
|
project_root = Path.cwd()
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
async def run_status_with_timeout():
|
|
106
|
+
"""Run status command with timeout protection."""
|
|
107
|
+
try:
|
|
108
|
+
await asyncio.wait_for(
|
|
109
|
+
show_status(
|
|
110
|
+
project_root=project_root,
|
|
111
|
+
verbose=verbose,
|
|
112
|
+
health_check=health_check,
|
|
113
|
+
mcp=mcp,
|
|
114
|
+
json_output=json_output,
|
|
115
|
+
),
|
|
116
|
+
timeout=30.0, # 30 second timeout
|
|
117
|
+
)
|
|
118
|
+
except TimeoutError:
|
|
119
|
+
logger.error("Status check timed out after 30 seconds")
|
|
120
|
+
print_error(
|
|
121
|
+
"Status check timed out after 30 seconds. "
|
|
122
|
+
"Try running with --verbose for more details."
|
|
123
|
+
)
|
|
124
|
+
raise typer.Exit(1)
|
|
125
|
+
|
|
126
|
+
asyncio.run(run_status_with_timeout())
|
|
114
127
|
|
|
115
128
|
except Exception as e:
|
|
116
129
|
logger.error(f"Status check failed: {e}")
|
|
@@ -162,6 +175,7 @@ async def show_status(
|
|
|
162
175
|
file_extensions=config.file_extensions,
|
|
163
176
|
)
|
|
164
177
|
|
|
178
|
+
# Get indexing stats (runs async file scanning in thread pool)
|
|
165
179
|
async with database:
|
|
166
180
|
index_stats = await indexer.get_indexing_stats()
|
|
167
181
|
db_stats = await database.get_stats()
|