mcp-vector-search 0.12.0__py3-none-any.whl → 0.12.1__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,22 +1,40 @@
1
- """Install command for MCP Vector Search CLI."""
1
+ """Install and integration commands for MCP Vector Search CLI.
2
+
3
+ This module provides installation commands for:
4
+ 1. Project initialization (main command)
5
+ 2. Platform-specific MCP integrations (subcommands)
6
+
7
+ Examples:
8
+ # Install in current project
9
+ $ mcp-vector-search install
10
+
11
+ # Install Claude Code integration
12
+ $ mcp-vector-search install claude-code
13
+
14
+ # Install all available integrations
15
+ $ mcp-vector-search install --all
16
+ """
2
17
 
3
18
  import asyncio
4
19
  import json
5
20
  import shutil
6
- import subprocess
7
- import sys
8
21
  from pathlib import Path
22
+ from typing import Any
9
23
 
10
24
  import typer
11
25
  from loguru import logger
12
26
  from rich.console import Console
13
27
  from rich.panel import Panel
14
- from rich.progress import Progress, SpinnerColumn, TextColumn
28
+ from rich.table import Table
15
29
 
30
+ from ...config.defaults import DEFAULT_EMBEDDING_MODELS, DEFAULT_FILE_EXTENSIONS
31
+ from ...core.exceptions import ProjectInitializationError
16
32
  from ...core.project import ProjectManager
33
+ from ..didyoumean import create_enhanced_typer
17
34
  from ..output import (
18
35
  print_error,
19
36
  print_info,
37
+ print_next_steps,
20
38
  print_success,
21
39
  print_warning,
22
40
  )
@@ -24,115 +42,200 @@ from ..output import (
24
42
  # Create console for rich output
25
43
  console = Console()
26
44
 
27
- # Create install subcommand app
28
- install_app = typer.Typer(help="Install mcp-vector-search in projects")
29
-
45
+ # Create install app with subcommands
46
+ install_app = create_enhanced_typer(
47
+ help="""📦 Install mcp-vector-search and MCP integrations
48
+
49
+ [bold cyan]Usage Patterns:[/bold cyan]
50
+
51
+ [green]1. Project Installation (Primary)[/green]
52
+ Install mcp-vector-search in the current project:
53
+ [code]$ mcp-vector-search install[/code]
54
+
55
+ [green]2. MCP Platform Integration[/green]
56
+ Add MCP integration for specific platforms:
57
+ [code]$ mcp-vector-search install claude-code[/code]
58
+ [code]$ mcp-vector-search install cursor[/code]
59
+ [code]$ mcp-vector-search install windsurf[/code]
60
+
61
+ [green]3. Complete Setup[/green]
62
+ Install project + all MCP integrations:
63
+ [code]$ mcp-vector-search install --with-mcp[/code]
64
+
65
+ [bold cyan]Supported Platforms:[/bold cyan]
66
+ • [green]claude-code[/green] - Claude Code (project-scoped .mcp.json)
67
+ • [green]claude-desktop[/green] - Claude Desktop (~/.claude/config.json)
68
+ • [green]cursor[/green] - Cursor IDE (~/.cursor/mcp.json)
69
+ • [green]windsurf[/green] - Windsurf IDE (~/.codeium/windsurf/mcp_config.json)
70
+ • [green]vscode[/green] - VS Code (~/.vscode/mcp.json)
71
+
72
+ [dim]💡 Use 'mcp-vector-search uninstall <platform>' to remove integrations[/dim]
73
+ """,
74
+ invoke_without_command=True,
75
+ no_args_is_help=False,
76
+ )
30
77
 
31
- # ============================================================================
32
- # MCP Multi-Tool Integration Helpers
33
- # ============================================================================
34
78
 
79
+ # ==============================================================================
80
+ # Platform Configuration
81
+ # ==============================================================================
82
+
83
+ SUPPORTED_PLATFORMS = {
84
+ "claude-code": {
85
+ "name": "Claude Code",
86
+ "config_path": ".mcp.json", # Project-scoped
87
+ "description": "Claude Code with project-scoped configuration",
88
+ "scope": "project",
89
+ },
90
+ "claude-desktop": {
91
+ "name": "Claude Desktop",
92
+ "config_path": "~/Library/Application Support/Claude/claude_desktop_config.json",
93
+ "description": "Claude Desktop application",
94
+ "scope": "global",
95
+ },
96
+ "cursor": {
97
+ "name": "Cursor",
98
+ "config_path": "~/.cursor/mcp.json",
99
+ "description": "Cursor IDE",
100
+ "scope": "global",
101
+ },
102
+ "windsurf": {
103
+ "name": "Windsurf",
104
+ "config_path": "~/.codeium/windsurf/mcp_config.json",
105
+ "description": "Windsurf IDE",
106
+ "scope": "global",
107
+ },
108
+ "vscode": {
109
+ "name": "VS Code",
110
+ "config_path": "~/.vscode/mcp.json",
111
+ "description": "Visual Studio Code",
112
+ "scope": "global",
113
+ },
114
+ }
115
+
116
+
117
+ def get_platform_config_path(platform: str, project_root: Path) -> Path:
118
+ """Get the configuration file path for a platform.
35
119
 
36
- def detect_ai_tools() -> dict[str, Path]:
37
- """Detect installed AI coding tools by checking config file existence.
120
+ Args:
121
+ platform: Platform name (e.g., "claude-code", "cursor")
122
+ project_root: Project root directory (for project-scoped configs)
38
123
 
39
124
  Returns:
40
- Dictionary mapping tool names to their config file paths.
41
- For Claude Code, returns a placeholder path since it uses project-scoped .mcp.json
125
+ Path to the configuration file
42
126
  """
43
- home = Path.home()
44
-
45
- config_locations = {
46
- "claude-desktop": home
47
- / "Library"
48
- / "Application Support"
49
- / "Claude"
50
- / "claude_desktop_config.json",
51
- "cursor": home / ".cursor" / "mcp.json",
52
- "windsurf": home / ".codeium" / "windsurf" / "mcp_config.json",
53
- "vscode": home / ".vscode" / "mcp.json",
54
- }
127
+ if platform not in SUPPORTED_PLATFORMS:
128
+ raise ValueError(f"Unsupported platform: {platform}")
55
129
 
56
- # Return only tools with existing config files
57
- detected_tools = {}
58
- for tool_name, config_path in config_locations.items():
59
- if config_path.exists():
60
- detected_tools[tool_name] = config_path
130
+ config_info = SUPPORTED_PLATFORMS[platform]
131
+ config_path_str = config_info["config_path"]
61
132
 
62
- # Always include Claude Code as an option (it uses project-scoped .mcp.json)
63
- detected_tools["claude-code"] = Path(
64
- ".mcp.json"
65
- ) # Placeholder - will be project-scoped
66
-
67
- return detected_tools
133
+ # Resolve project-scoped vs global paths
134
+ if config_info["scope"] == "project":
135
+ return project_root / config_path_str
136
+ else:
137
+ return Path(config_path_str).expanduser()
68
138
 
69
139
 
70
140
  def get_mcp_server_config(
71
- project_root: Path, enable_watch: bool = True, tool_name: str = ""
72
- ) -> dict:
73
- """Generate MCP server configuration dict.
141
+ project_root: Path,
142
+ platform: str,
143
+ enable_watch: bool = True,
144
+ ) -> dict[str, Any]:
145
+ """Generate MCP server configuration for a platform.
74
146
 
75
147
  Args:
76
- project_root: Path to the project root directory
77
- enable_watch: Whether to enable file watching (default: True)
78
- tool_name: Name of the tool (for tool-specific config adjustments)
148
+ project_root: Project root directory
149
+ platform: Platform name
150
+ enable_watch: Whether to enable file watching
79
151
 
80
152
  Returns:
81
- Dictionary containing MCP server configuration.
153
+ Dictionary containing MCP server configuration
82
154
  """
83
- # Base configuration
84
- config = {
155
+ # Base configuration using uv for compatibility
156
+ config: dict[str, Any] = {
85
157
  "command": "uv",
86
158
  "args": ["run", "mcp-vector-search", "mcp"],
87
- "env": {"MCP_ENABLE_FILE_WATCHING": "true" if enable_watch else "false"},
159
+ "env": {
160
+ "MCP_ENABLE_FILE_WATCHING": "true" if enable_watch else "false",
161
+ },
88
162
  }
89
163
 
90
- # Add "type": "stdio" for Claude Code and other tools that require it
91
- if tool_name in ("claude-code", "cursor", "windsurf", "vscode"):
164
+ # Platform-specific adjustments
165
+ if platform in ("claude-code", "cursor", "windsurf", "vscode"):
166
+ # These platforms require "type": "stdio"
92
167
  config["type"] = "stdio"
93
168
 
94
- # Add cwd only for tools that support it (not Claude Code)
95
- if tool_name not in ("claude-code",):
169
+ # Only add cwd for global-scope platforms (not project-scoped)
170
+ if SUPPORTED_PLATFORMS[platform]["scope"] == "global":
96
171
  config["cwd"] = str(project_root.absolute())
97
172
 
98
173
  return config
99
174
 
100
175
 
101
- def configure_mcp_for_tool(
102
- tool_name: str,
103
- config_path: Path,
176
+ def detect_installed_platforms() -> dict[str, Path]:
177
+ """Detect which MCP platforms are installed on the system.
178
+
179
+ Returns:
180
+ Dictionary mapping platform names to their config paths
181
+ """
182
+ detected = {}
183
+
184
+ for platform, info in SUPPORTED_PLATFORMS.items():
185
+ # For project-scoped platforms, always include them
186
+ if info["scope"] == "project":
187
+ detected[platform] = Path(info["config_path"])
188
+ continue
189
+
190
+ # For global platforms, check if config directory exists
191
+ config_path = Path(info["config_path"]).expanduser()
192
+ if config_path.parent.exists():
193
+ detected[platform] = config_path
194
+
195
+ return detected
196
+
197
+
198
+ def configure_platform(
199
+ platform: str,
104
200
  project_root: Path,
105
201
  server_name: str = "mcp-vector-search",
106
202
  enable_watch: bool = True,
203
+ force: bool = False,
107
204
  ) -> bool:
108
- """Add MCP server configuration to a tool's config file.
205
+ """Configure MCP integration for a specific platform.
109
206
 
110
207
  Args:
111
- tool_name: Name of the AI tool (e.g., "claude-code", "cursor")
112
- config_path: Path to the tool's configuration file
113
- project_root: Path to the project root directory
208
+ platform: Platform name (e.g., "claude-code", "cursor")
209
+ project_root: Project root directory
114
210
  server_name: Name for the MCP server entry
115
211
  enable_watch: Whether to enable file watching
212
+ force: Whether to overwrite existing configuration
116
213
 
117
214
  Returns:
118
- True if configuration was successful, False otherwise.
215
+ True if configuration was successful, False otherwise
119
216
  """
120
217
  try:
121
- # For Claude Code, we create .mcp.json in project root instead of ~/.claude.json
122
- if tool_name == "claude-code":
123
- # Override config_path to project-scoped .mcp.json
124
- config_path = project_root / ".mcp.json"
218
+ config_path = get_platform_config_path(platform, project_root)
125
219
 
126
- # Create backup of existing config
127
- backup_path = config_path.with_suffix(config_path.suffix + ".backup")
128
-
129
- # Load existing config or create new one
220
+ # Create backup if file exists
130
221
  if config_path.exists():
222
+ backup_path = config_path.with_suffix(config_path.suffix + ".backup")
131
223
  shutil.copy2(config_path, backup_path)
224
+
225
+ # Load existing config
132
226
  with open(config_path) as f:
133
227
  config = json.load(f)
228
+
229
+ # Check if server already exists
230
+ if "mcpServers" in config and server_name in config["mcpServers"]:
231
+ if not force:
232
+ print_warning(
233
+ f" ⚠️ Server '{server_name}' already exists in {platform} config"
234
+ )
235
+ print_info(" Use --force to overwrite")
236
+ return False
134
237
  else:
135
- # Create parent directory if it doesn't exist
238
+ # Create new config
136
239
  config_path.parent.mkdir(parents=True, exist_ok=True)
137
240
  config = {}
138
241
 
@@ -140,556 +243,432 @@ def configure_mcp_for_tool(
140
243
  if "mcpServers" not in config:
141
244
  config["mcpServers"] = {}
142
245
 
143
- # Get the MCP server configuration with tool-specific settings
144
- server_config = get_mcp_server_config(project_root, enable_watch, tool_name)
145
-
146
246
  # Add server configuration
247
+ server_config = get_mcp_server_config(project_root, platform, enable_watch)
147
248
  config["mcpServers"][server_name] = server_config
148
249
 
149
- # Write the updated config
250
+ # Write configuration
150
251
  with open(config_path, "w") as f:
151
252
  json.dump(config, f, indent=2)
152
253
 
153
- print_success(f" ✅ Configured {tool_name} at {config_path}")
254
+ platform_name = SUPPORTED_PLATFORMS[platform]["name"]
255
+ print_success(f" ✅ Configured {platform_name}")
256
+ print_info(f" Config: {config_path}")
257
+
154
258
  return True
155
259
 
156
260
  except Exception as e:
157
- print_error(f"Failed to configure {tool_name}: {e}")
158
- # Restore backup if it exists
159
- if backup_path.exists():
160
- shutil.copy2(backup_path, config_path)
261
+ logger.error(f"Failed to configure {platform}: {e}")
262
+ print_error(f" ❌ Failed to configure {platform}: {e}")
161
263
  return False
162
264
 
163
265
 
164
- def setup_mcp_integration(
165
- project_root: Path,
166
- mcp_tool: str | None = None,
167
- enable_watch: bool = True,
168
- interactive: bool = True,
169
- ) -> dict[str, bool]:
170
- """Setup MCP integration for one or more AI tools.
171
-
172
- Args:
173
- project_root: Path to the project root directory
174
- mcp_tool: Specific tool to configure (None for interactive selection)
175
- enable_watch: Whether to enable file watching
176
- interactive: Whether to prompt user for tool selection
177
-
178
- Returns:
179
- Dictionary mapping tool names to success status.
180
- """
181
- detected_tools = detect_ai_tools()
182
-
183
- if not detected_tools:
184
- print_warning("No AI coding tools detected on this system.")
185
- print_info(
186
- "Supported tools: Claude Code, Claude Desktop, Cursor, Windsurf, VS Code"
187
- )
188
- print_info("Install one of these tools and try again.")
189
- return {}
190
-
191
- # Determine which tools to configure
192
- tools_to_configure = {}
193
-
194
- if mcp_tool:
195
- # Specific tool requested
196
- if mcp_tool in detected_tools:
197
- tools_to_configure[mcp_tool] = detected_tools[mcp_tool]
198
- else:
199
- print_error(f"Tool '{mcp_tool}' not found or not installed.")
200
- print_info(f"Detected tools: {', '.join(detected_tools.keys())}")
201
- return {}
202
- elif interactive and len(detected_tools) > 1:
203
- # Multiple tools detected, prompt user
204
- console.print("\n[bold blue]🔍 Detected AI coding tools:[/bold blue]")
205
- for i, tool_name in enumerate(detected_tools.keys(), 1):
206
- console.print(f" {i}. {tool_name}")
207
-
208
- console.print("\n[bold]Configure MCP integration for:[/bold]")
209
- console.print(" [1] All detected tools")
210
- console.print(" [2] Choose specific tool(s)")
211
- console.print(" [3] Skip MCP setup")
212
-
213
- choice = typer.prompt("\nSelect option", type=int, default=1)
214
-
215
- if choice == 1:
216
- # Configure all tools
217
- tools_to_configure = detected_tools
218
- elif choice == 2:
219
- # Let user choose specific tools
220
- console.print(
221
- "\n[bold]Select tools to configure (comma-separated numbers):[/bold]"
222
- )
223
- tool_list = list(detected_tools.keys())
224
- for i, tool_name in enumerate(tool_list, 1):
225
- console.print(f" {i}. {tool_name}")
226
-
227
- selections = typer.prompt("Tool numbers").strip()
228
- for num_str in selections.split(","):
229
- try:
230
- idx = int(num_str.strip()) - 1
231
- if 0 <= idx < len(tool_list):
232
- tool_name = tool_list[idx]
233
- tools_to_configure[tool_name] = detected_tools[tool_name]
234
- except ValueError:
235
- print_warning(f"Invalid selection: {num_str}")
236
- else:
237
- # Skip MCP setup
238
- print_info("Skipping MCP setup")
239
- return {}
240
- else:
241
- # Single tool or non-interactive mode - configure all
242
- tools_to_configure = detected_tools
243
-
244
- # Configure selected tools
245
- results = {}
246
-
247
- if tools_to_configure:
248
- console.print("\n[bold blue]🔗 Configuring MCP integration...[/bold blue]")
249
-
250
- for tool_name, config_path in tools_to_configure.items():
251
- results[tool_name] = configure_mcp_for_tool(
252
- tool_name=tool_name,
253
- config_path=config_path,
254
- project_root=project_root,
255
- server_name="mcp-vector-search",
256
- enable_watch=enable_watch,
257
- )
258
-
259
- return results
260
-
261
-
262
- def print_next_steps(
263
- project_root: Path,
264
- indexed: bool,
265
- mcp_results: dict[str, bool],
266
- ) -> None:
267
- """Print helpful next steps after installation.
268
-
269
- Args:
270
- project_root: Path to the project root
271
- indexed: Whether the codebase was indexed
272
- mcp_results: Results of MCP integration (tool_name -> success)
273
- """
274
- console.print("\n[bold green]🎉 Installation Complete![/bold green]")
275
-
276
- # Show what was completed
277
- console.print("\n[bold blue]✨ Setup Summary:[/bold blue]")
278
- console.print(" ✅ Vector database initialized")
279
- if indexed:
280
- console.print(" ✅ Codebase indexed and searchable")
281
- else:
282
- console.print(" ⏭️ Indexing skipped (use --no-index flag)")
283
-
284
- if mcp_results:
285
- successful_tools = [tool for tool, success in mcp_results.items() if success]
286
- if successful_tools:
287
- console.print(
288
- f" ✅ MCP integration configured for: {', '.join(successful_tools)}"
289
- )
290
-
291
- # Next steps
292
- console.print("\n[bold green]🚀 Ready to use:[/bold green]")
293
- console.print(
294
- " • Search your code: [code]mcp-vector-search search 'your query'[/code]"
295
- )
296
- console.print(" • Check status: [code]mcp-vector-search status[/code]")
297
-
298
- if mcp_results:
299
- console.print("\n[bold blue]🤖 Using MCP Integration:[/bold blue]")
300
- if "claude-code" in mcp_results and mcp_results["claude-code"]:
301
- console.print(" • Open Claude Code in this project directory")
302
- console.print(" • Use: 'Search my code for authentication functions'")
303
- if "cursor" in mcp_results and mcp_results["cursor"]:
304
- console.print(" • Open Cursor in this project directory")
305
- console.print(" • MCP tools should be available automatically")
306
- if "claude-desktop" in mcp_results and mcp_results["claude-desktop"]:
307
- console.print(" • Restart Claude Desktop")
308
- console.print(" • The mcp-vector-search server will be available")
309
-
310
- console.print(
311
- "\n[dim]💡 Tip: Run 'mcp-vector-search --help' for more commands[/dim]"
312
- )
313
-
314
-
315
- # ============================================================================
316
- # Main Install Command
317
- # ============================================================================
266
+ # ==============================================================================
267
+ # Main Install Command (Project Installation)
268
+ # ==============================================================================
318
269
 
319
270
 
271
+ @install_app.callback()
320
272
  def main(
321
273
  ctx: typer.Context,
322
- project_path: Path = typer.Argument(
323
- ...,
324
- help="Project directory to initialize and index",
325
- ),
326
274
  extensions: str | None = typer.Option(
327
275
  None,
328
276
  "--extensions",
329
277
  "-e",
330
- help="Comma-separated file extensions (e.g., .py,.js,.ts,.dart)",
331
- ),
332
- no_index: bool = typer.Option(
333
- False,
334
- "--no-index",
335
- help="Skip initial indexing",
336
- ),
337
- no_mcp: bool = typer.Option(
338
- False,
339
- "--no-mcp",
340
- help="Skip MCP integration setup",
341
- ),
342
- mcp_tool: str | None = typer.Option(
343
- None,
344
- "--mcp-tool",
345
- help="Specific AI tool for MCP integration (claude-code, cursor, etc.)",
346
- ),
347
- no_watch: bool = typer.Option(
348
- False,
349
- "--no-watch",
350
- help="Disable file watching for MCP integration",
278
+ help="Comma-separated file extensions (e.g., .py,.js,.ts)",
279
+ rich_help_panel="📁 Configuration",
351
280
  ),
352
281
  embedding_model: str = typer.Option(
353
- "sentence-transformers/all-MiniLM-L6-v2",
282
+ DEFAULT_EMBEDDING_MODELS["code"],
354
283
  "--embedding-model",
355
284
  "-m",
356
- help="Embedding model to use for semantic search",
285
+ help="Embedding model for semantic search",
286
+ rich_help_panel="🧠 Model Settings",
357
287
  ),
358
288
  similarity_threshold: float = typer.Option(
359
289
  0.5,
360
290
  "--similarity-threshold",
361
291
  "-s",
362
- help="Similarity threshold for search results (0.0 to 1.0)",
292
+ help="Similarity threshold (0.0-1.0)",
363
293
  min=0.0,
364
294
  max=1.0,
295
+ rich_help_panel="🧠 Model Settings",
296
+ ),
297
+ auto_index: bool = typer.Option(
298
+ True,
299
+ "--auto-index/--no-auto-index",
300
+ help="Automatically index after initialization",
301
+ rich_help_panel="🚀 Workflow",
302
+ ),
303
+ with_mcp: bool = typer.Option(
304
+ False,
305
+ "--with-mcp",
306
+ help="Install all available MCP integrations",
307
+ rich_help_panel="🚀 Workflow",
365
308
  ),
366
309
  force: bool = typer.Option(
367
310
  False,
368
311
  "--force",
369
312
  "-f",
370
- help="Force re-installation if project is already initialized",
313
+ help="Force re-initialization",
314
+ rich_help_panel="⚙️ Advanced",
371
315
  ),
372
316
  ) -> None:
373
- """Install mcp-vector-search with complete setup including MCP integration.
317
+ """📦 Install mcp-vector-search in the current project.
374
318
 
375
- This command provides a comprehensive one-step installation that:
319
+ This command initializes mcp-vector-search with:
320
+ ✅ Vector database setup
321
+ ✅ Configuration file creation
322
+ ✅ Automatic code indexing
323
+ ✅ Ready-to-use semantic search
376
324
 
377
- Initializes mcp-vector-search in the project directory
378
- ✅ Auto-detects programming languages and file types
379
- ✅ Indexes the codebase for semantic search
380
- ✅ Configures MCP integration for multiple AI tools
381
- ✅ Sets up file watching for automatic updates
325
+ [bold cyan]Examples:[/bold cyan]
382
326
 
383
- Perfect for getting started quickly with semantic code search!
327
+ [green]Basic installation:[/green]
328
+ $ mcp-vector-search install
384
329
 
385
- Examples:
386
- mcp-vector-search install . # Install in current directory
387
- mcp-vector-search install ~/my-project # Install in specific directory
388
- mcp-vector-search install . --no-mcp # Skip MCP integration
389
- mcp-vector-search install . --mcp-tool claude-code # Configure specific tool
390
- mcp-vector-search install . --extensions .py,.js,.ts # Custom file types
391
- mcp-vector-search install . --force # Force re-initialization
330
+ [green]Custom file types:[/green]
331
+ $ mcp-vector-search install --extensions .py,.js,.ts
332
+
333
+ [green]Install with MCP integrations:[/green]
334
+ $ mcp-vector-search install --with-mcp
335
+
336
+ [green]Skip auto-indexing:[/green]
337
+ $ mcp-vector-search install --no-auto-index
338
+
339
+ [dim]💡 After installation, use 'mcp-vector-search search' to search your code[/dim]
392
340
  """
341
+ # Only run main logic if no subcommand was invoked
342
+ if ctx.invoked_subcommand is not None:
343
+ return
344
+
393
345
  try:
394
- # Resolve project path
395
- project_root = project_path.resolve()
346
+ project_root = ctx.obj.get("project_root") or Path.cwd()
396
347
 
397
- # Show installation header
398
348
  console.print(
399
349
  Panel.fit(
400
- f"[bold blue]🚀 MCP Vector Search - Complete Installation[/bold blue]\n\n"
401
- f"📁 Project: [cyan]{project_root}[/cyan]\n"
402
- f"🔧 Setting up with full initialization and MCP integration",
403
- border_style="blue",
350
+ f"[bold cyan]Installing mcp-vector-search[/bold cyan]\n"
351
+ f"📁 Project: {project_root}",
352
+ border_style="cyan",
404
353
  )
405
354
  )
406
355
 
407
- # Check if project directory exists
408
- if not project_root.exists():
409
- print_error(f"Project directory does not exist: {project_root}")
410
- raise typer.Exit(1)
411
-
412
356
  # Check if already initialized
413
357
  project_manager = ProjectManager(project_root)
414
358
  if project_manager.is_initialized() and not force:
415
- print_success("✅ Project is already initialized!")
416
- print_info("Vector search capabilities are enabled.")
417
- print_info("Use --force to re-initialize if needed.")
418
-
419
- # Show MCP configuration option
420
- if not no_mcp:
421
- console.print("\n[bold blue]💡 MCP Integration:[/bold blue]")
422
- console.print(
423
- " Run install again with --force to reconfigure MCP integration"
424
- )
425
-
426
- return
359
+ print_success("✅ Project already initialized!")
360
+ print_info(" Use --force to re-initialize")
361
+ raise typer.Exit(0)
427
362
 
428
363
  # Parse file extensions
429
364
  file_extensions = None
430
365
  if extensions:
431
- file_extensions = [ext.strip() for ext in extensions.split(",")]
432
- # Ensure extensions start with dot
433
366
  file_extensions = [
434
- ext if ext.startswith(".") else f".{ext}" for ext in file_extensions
367
+ ext.strip() if ext.startswith(".") else f".{ext.strip()}"
368
+ for ext in extensions.split(",")
435
369
  ]
370
+ else:
371
+ file_extensions = DEFAULT_FILE_EXTENSIONS
372
+
373
+ # Show configuration
374
+ console.print("\n[bold blue]Configuration:[/bold blue]")
375
+ console.print(f" 📄 Extensions: {', '.join(file_extensions)}")
376
+ console.print(f" 🧠 Model: {embedding_model}")
377
+ console.print(f" 🎯 Threshold: {similarity_threshold}")
378
+ console.print(f" 🔍 Auto-index: {'✅' if auto_index else '❌'}")
379
+ console.print(f" 🔗 With MCP: {'✅' if with_mcp else '❌'}")
380
+
381
+ # Initialize project
382
+ console.print("\n[bold]Initializing project...[/bold]")
383
+ project_manager.initialize(
384
+ file_extensions=file_extensions,
385
+ embedding_model=embedding_model,
386
+ similarity_threshold=similarity_threshold,
387
+ force=force,
388
+ )
389
+ print_success("✅ Project initialized")
390
+
391
+ # Auto-index if requested
392
+ if auto_index:
393
+ console.print("\n[bold]🔍 Indexing codebase...[/bold]")
394
+ from .index import run_indexing
395
+
396
+ try:
397
+ asyncio.run(
398
+ run_indexing(
399
+ project_root=project_root,
400
+ force_reindex=False,
401
+ show_progress=True,
402
+ )
403
+ )
404
+ print_success("✅ Indexing completed")
405
+ except Exception as e:
406
+ print_error(f"❌ Indexing failed: {e}")
407
+ print_info(" Run 'mcp-vector-search index' to index later")
408
+
409
+ # Install MCP integrations if requested
410
+ if with_mcp:
411
+ console.print("\n[bold blue]🔗 Installing MCP integrations...[/bold blue]")
412
+ detected = detect_installed_platforms()
413
+
414
+ if detected:
415
+ for platform in detected:
416
+ configure_platform(platform, project_root, enable_watch=True)
417
+ else:
418
+ print_warning("No MCP platforms detected")
419
+ print_info("Install platforms manually using:")
420
+ print_info(" mcp-vector-search install <platform>")
436
421
 
437
- # ========================================================================
438
- # STEP 1: Initialize Project
439
- # ========================================================================
440
- with Progress(
441
- SpinnerColumn(),
442
- TextColumn("[progress.description]{task.description}"),
443
- console=console,
444
- ) as progress:
445
- task = progress.add_task("📁 Initializing project...", total=None)
446
-
447
- # Initialize the project
448
- project_manager.initialize(
449
- file_extensions=file_extensions,
450
- embedding_model=embedding_model,
451
- similarity_threshold=similarity_threshold,
452
- force=force,
453
- )
422
+ # Success message
423
+ console.print("\n[bold green]🎉 Installation Complete![/bold green]")
454
424
 
455
- progress.update(task, completed=True)
456
- print_success(" Project initialized successfully")
457
-
458
- # ========================================================================
459
- # STEP 2: Index Codebase (unless --no-index)
460
- # ========================================================================
461
- indexed = False
462
- if not no_index:
463
- with Progress(
464
- SpinnerColumn(),
465
- TextColumn("[progress.description]{task.description}"),
466
- console=console,
467
- ) as progress:
468
- task = progress.add_task("🔍 Indexing codebase...", total=None)
469
-
470
- # Import and run indexing
471
- from .index import run_indexing
472
-
473
- try:
474
- asyncio.run(
475
- run_indexing(
476
- project_root=project_root,
477
- force_reindex=False,
478
- show_progress=False, # We handle progress here
479
- )
480
- )
481
- indexed = True
482
- progress.update(task, completed=True)
483
- print_success("✅ Codebase indexed successfully")
484
- except Exception as e:
485
- print_error(f"❌ Indexing failed: {e}")
486
- print_info("You can run 'mcp-vector-search index' later")
487
- else:
488
- print_info("⏭️ Indexing skipped (--no-index)")
489
-
490
- # ========================================================================
491
- # STEP 3: Configure MCP Integration (unless --no-mcp)
492
- # ========================================================================
493
- mcp_results = {}
494
- if not no_mcp:
495
- enable_watch = not no_watch
496
- mcp_results = setup_mcp_integration(
497
- project_root=project_root,
498
- mcp_tool=mcp_tool,
499
- enable_watch=enable_watch,
500
- interactive=True, # Allow interactive tool selection
425
+ next_steps = [
426
+ "[cyan]mcp-vector-search search 'your query'[/cyan] - Search your code",
427
+ "[cyan]mcp-vector-search status[/cyan] - View project status",
428
+ ]
429
+
430
+ if not with_mcp:
431
+ next_steps.append(
432
+ "[cyan]mcp-vector-search install claude-code[/cyan] - Add MCP integration"
501
433
  )
502
434
 
503
- if not mcp_results:
504
- print_info("⏭️ MCP integration skipped")
505
- else:
506
- print_info("⏭️ MCP integration skipped (--no-mcp)")
435
+ print_next_steps(next_steps, title="Ready to Use")
507
436
 
508
- # ========================================================================
509
- # STEP 4: Verification
510
- # ========================================================================
511
- console.print("\n[bold blue]✅ Verifying installation...[/bold blue]")
437
+ except ProjectInitializationError as e:
438
+ print_error(f"Installation failed: {e}")
439
+ raise typer.Exit(1)
440
+ except Exception as e:
441
+ logger.error(f"Unexpected error during installation: {e}")
442
+ print_error(f"Unexpected error: {e}")
443
+ raise typer.Exit(1)
512
444
 
513
- # Check project initialized
514
- if project_manager.is_initialized():
515
- print_success(" ✅ Project configuration created")
516
445
 
517
- # Check index created
518
- if indexed:
519
- print_success(" ✅ Index created and populated")
446
+ # ==============================================================================
447
+ # Platform-Specific Installation Commands
448
+ # ==============================================================================
520
449
 
521
- # Check MCP configured
522
- if mcp_results:
523
- successful_tools = [
524
- tool for tool, success in mcp_results.items() if success
525
- ]
526
- if successful_tools:
527
- print_success(f" ✅ MCP configured for: {', '.join(successful_tools)}")
528
-
529
- # ========================================================================
530
- # STEP 5: Print Next Steps
531
- # ========================================================================
532
- print_next_steps(
533
- project_root=project_root,
534
- indexed=indexed,
535
- mcp_results=mcp_results,
450
+
451
+ @install_app.command("claude-code")
452
+ def install_claude_code(
453
+ ctx: typer.Context,
454
+ enable_watch: bool = typer.Option(
455
+ True,
456
+ "--watch/--no-watch",
457
+ help="Enable file watching for auto-reindex",
458
+ ),
459
+ force: bool = typer.Option(
460
+ False,
461
+ "--force",
462
+ "-f",
463
+ help="Force overwrite existing configuration",
464
+ ),
465
+ ) -> None:
466
+ """Install Claude Code MCP integration (project-scoped).
467
+
468
+ Creates .mcp.json in the project root for team sharing.
469
+ This file should be committed to version control.
470
+ """
471
+ project_root = ctx.obj.get("project_root") or Path.cwd()
472
+
473
+ console.print(
474
+ Panel.fit(
475
+ "[bold cyan]Installing Claude Code Integration[/bold cyan]\n"
476
+ "📁 Project-scoped configuration",
477
+ border_style="cyan",
536
478
  )
479
+ )
537
480
 
538
- except Exception as e:
539
- logger.error(f"Installation failed: {e}")
540
- print_error(f"❌ Installation failed: {e}")
481
+ success = configure_platform(
482
+ "claude-code", project_root, enable_watch=enable_watch, force=force
483
+ )
541
484
 
542
- # Provide recovery instructions
543
- console.print("\n[bold]Recovery steps:[/bold]")
544
- console.print(" 1. Check that the project directory exists and is writable")
485
+ if success:
545
486
  console.print(
546
- " 2. Ensure required dependencies are installed: [code]pip install mcp-vector-search[/code]"
487
+ "\n[bold green]✨ Claude Code Integration Installed![/bold green]"
547
488
  )
548
- console.print(
549
- " 3. Try running with --force to override existing configuration"
489
+ console.print("\n[bold blue]Next Steps:[/bold blue]")
490
+ console.print(" 1. Open Claude Code in this project directory")
491
+ console.print(" 2. The MCP server will be available automatically")
492
+ console.print(" 3. Try: 'Search my code for authentication functions'")
493
+ console.print("\n[dim]💡 Commit .mcp.json to share with your team[/dim]")
494
+ else:
495
+ raise typer.Exit(1)
496
+
497
+
498
+ @install_app.command("cursor")
499
+ def install_cursor(
500
+ ctx: typer.Context,
501
+ enable_watch: bool = typer.Option(True, "--watch/--no-watch"),
502
+ force: bool = typer.Option(False, "--force", "-f"),
503
+ ) -> None:
504
+ """Install Cursor IDE MCP integration (global)."""
505
+ project_root = ctx.obj.get("project_root") or Path.cwd()
506
+
507
+ console.print(
508
+ Panel.fit(
509
+ "[bold cyan]Installing Cursor Integration[/bold cyan]\n"
510
+ "🌐 Global configuration (~/.cursor/mcp.json)",
511
+ border_style="cyan",
550
512
  )
551
- console.print(" 4. Check logs with --verbose flag for more details")
513
+ )
552
514
 
515
+ success = configure_platform(
516
+ "cursor", project_root, enable_watch=enable_watch, force=force
517
+ )
518
+
519
+ if success:
520
+ console.print("\n[bold green]✨ Cursor Integration Installed![/bold green]")
521
+ console.print("\n[bold blue]Next Steps:[/bold blue]")
522
+ console.print(" 1. Restart Cursor IDE")
523
+ console.print(" 2. Open this project in Cursor")
524
+ console.print(" 3. MCP tools should be available")
525
+ else:
553
526
  raise typer.Exit(1)
554
527
 
555
528
 
556
- @install_app.command("demo")
557
- def demo(
558
- project_root: Path | None = typer.Option(
559
- None,
560
- "--project-root",
561
- "-p",
562
- help="Project root directory (auto-detected if not specified)",
563
- exists=True,
564
- file_okay=False,
565
- dir_okay=True,
566
- readable=True,
567
- ),
529
+ @install_app.command("windsurf")
530
+ def install_windsurf(
531
+ ctx: typer.Context,
532
+ enable_watch: bool = typer.Option(True, "--watch/--no-watch"),
533
+ force: bool = typer.Option(False, "--force", "-f"),
568
534
  ) -> None:
569
- """Run installation demo with sample project."""
570
- try:
571
- import tempfile
535
+ """Install Windsurf IDE MCP integration (global)."""
536
+ project_root = ctx.obj.get("project_root") or Path.cwd()
537
+
538
+ console.print(
539
+ Panel.fit(
540
+ "[bold cyan]Installing Windsurf Integration[/bold cyan]\n"
541
+ "🌐 Global configuration (~/.codeium/windsurf/mcp_config.json)",
542
+ border_style="cyan",
543
+ )
544
+ )
572
545
 
573
- print_info("🎬 Running mcp-vector-search installation demo...")
546
+ success = configure_platform(
547
+ "windsurf", project_root, enable_watch=enable_watch, force=force
548
+ )
574
549
 
575
- # Create temporary demo directory
576
- with tempfile.TemporaryDirectory(prefix="mcp-demo-") as temp_dir:
577
- demo_dir = Path(temp_dir) / "demo-project"
578
- demo_dir.mkdir()
550
+ if success:
551
+ console.print("\n[bold green]✨ Windsurf Integration Installed![/bold green]")
552
+ console.print("\n[bold blue]Next Steps:[/bold blue]")
553
+ console.print(" 1. Restart Windsurf IDE")
554
+ console.print(" 2. Open this project in Windsurf")
555
+ console.print(" 3. MCP tools should be available")
556
+ else:
557
+ raise typer.Exit(1)
579
558
 
580
- # Create sample files
581
- (demo_dir / "main.py").write_text("""
582
- def main():
583
- '''Main entry point for the application.'''
584
- print("Hello, World!")
585
- user_service = UserService()
586
- user_service.create_user("Alice", "alice@example.com")
587
559
 
588
- class UserService:
589
- '''Service for managing users.'''
560
+ @install_app.command("claude-desktop")
561
+ def install_claude_desktop(
562
+ ctx: typer.Context,
563
+ enable_watch: bool = typer.Option(True, "--watch/--no-watch"),
564
+ force: bool = typer.Option(False, "--force", "-f"),
565
+ ) -> None:
566
+ """Install Claude Desktop MCP integration (global)."""
567
+ project_root = ctx.obj.get("project_root") or Path.cwd()
568
+
569
+ console.print(
570
+ Panel.fit(
571
+ "[bold cyan]Installing Claude Desktop Integration[/bold cyan]\n"
572
+ "🌐 Global configuration (~/.claude/config.json)",
573
+ border_style="cyan",
574
+ )
575
+ )
576
+
577
+ success = configure_platform(
578
+ "claude-desktop", project_root, enable_watch=enable_watch, force=force
579
+ )
590
580
 
591
- def create_user(self, name: str, email: str):
592
- '''Create a new user with the given name and email.'''
593
- print(f"Creating user: {name} ({email})")
594
- return {"name": name, "email": email}
581
+ if success:
582
+ console.print(
583
+ "\n[bold green]✨ Claude Desktop Integration Installed![/bold green]"
584
+ )
585
+ console.print("\n[bold blue]Next Steps:[/bold blue]")
586
+ console.print(" 1. Restart Claude Desktop")
587
+ console.print(" 2. The mcp-vector-search server will be available")
588
+ console.print(" 3. Open conversations in the project directory")
589
+ else:
590
+ raise typer.Exit(1)
595
591
 
596
- def authenticate_user(self, email: str, password: str):
597
- '''Authenticate user with email and password.'''
598
- # Simple authentication logic
599
- return email.endswith("@example.com")
600
592
 
601
- if __name__ == "__main__":
602
- main()
603
- """)
593
+ @install_app.command("vscode")
594
+ def install_vscode(
595
+ ctx: typer.Context,
596
+ enable_watch: bool = typer.Option(True, "--watch/--no-watch"),
597
+ force: bool = typer.Option(False, "--force", "-f"),
598
+ ) -> None:
599
+ """Install VS Code MCP integration (global)."""
600
+ project_root = ctx.obj.get("project_root") or Path.cwd()
604
601
 
605
- (demo_dir / "utils.py").write_text("""
606
- import json
607
- from typing import Dict, Any
602
+ console.print(
603
+ Panel.fit(
604
+ "[bold cyan]Installing VS Code Integration[/bold cyan]\n"
605
+ "🌐 Global configuration (~/.vscode/mcp.json)",
606
+ border_style="cyan",
607
+ )
608
+ )
608
609
 
609
- def load_config(config_path: str) -> Dict[str, Any]:
610
- '''Load configuration from JSON file.'''
611
- with open(config_path, 'r') as f:
612
- return json.load(f)
610
+ success = configure_platform(
611
+ "vscode", project_root, enable_watch=enable_watch, force=force
612
+ )
613
613
 
614
- def validate_email(email: str) -> bool:
615
- '''Validate email address format.'''
616
- return "@" in email and "." in email.split("@")[1]
614
+ if success:
615
+ console.print("\n[bold green]✨ VS Code Integration Installed![/bold green]")
616
+ console.print("\n[bold blue]Next Steps:[/bold blue]")
617
+ console.print(" 1. Restart VS Code")
618
+ console.print(" 2. Open this project in VS Code")
619
+ console.print(" 3. MCP tools should be available")
620
+ else:
621
+ raise typer.Exit(1)
617
622
 
618
- def hash_password(password: str) -> str:
619
- '''Hash password for secure storage.'''
620
- import hashlib
621
- return hashlib.sha256(password.encode()).hexdigest()
622
- """)
623
623
 
624
- console.print(
625
- f"\n[bold blue]📁 Created demo project at:[/bold blue] {demo_dir}"
626
- )
624
+ @install_app.command("list")
625
+ def list_platforms(ctx: typer.Context) -> None:
626
+ """List all supported MCP platforms and their installation status."""
627
+ project_root = ctx.obj.get("project_root") or Path.cwd()
627
628
 
628
- # Run installation
629
- print_info("Installing mcp-vector-search in demo project...")
630
-
631
- # Use subprocess to run the install command
632
- result = subprocess.run(
633
- [
634
- sys.executable,
635
- "-m",
636
- "mcp_vector_search.cli.main",
637
- "--project-root",
638
- str(demo_dir),
639
- "install",
640
- str(demo_dir),
641
- "--extensions",
642
- ".py",
643
- "--no-mcp", # Skip MCP for demo
644
- ],
645
- capture_output=True,
646
- text=True,
647
- )
629
+ console.print(
630
+ Panel.fit("[bold cyan]MCP Platform Status[/bold cyan]", border_style="cyan")
631
+ )
648
632
 
649
- if result.returncode == 0:
650
- print_success(" Demo installation completed!")
651
-
652
- # Run a sample search
653
- print_info("Running sample search: 'user authentication'...")
654
-
655
- search_result = subprocess.run(
656
- [
657
- sys.executable,
658
- "-m",
659
- "mcp_vector_search.cli.main",
660
- "--project-root",
661
- str(demo_dir),
662
- "search",
663
- "user authentication",
664
- "--limit",
665
- "3",
666
- ],
667
- capture_output=True,
668
- text=True,
669
- )
633
+ table = Table(show_header=True, header_style="bold cyan")
634
+ table.add_column("Platform", style="cyan")
635
+ table.add_column("Name")
636
+ table.add_column("Status")
637
+ table.add_column("Config Location")
670
638
 
671
- if search_result.returncode == 0:
672
- console.print(
673
- "\n[bold green]🔍 Sample search results:[/bold green]"
674
- )
675
- console.print(search_result.stdout)
676
- else:
677
- print_warning("Search demo failed, but installation was successful")
678
-
679
- console.print("\n[bold blue]🎉 Demo completed![/bold blue]")
680
- console.print(f"Demo project was created at: [cyan]{demo_dir}[/cyan]")
681
- console.print(
682
- "The temporary directory will be cleaned up automatically."
683
- )
639
+ detected = detect_installed_platforms()
684
640
 
685
- else:
686
- print_error(f"Demo installation failed: {result.stderr}")
687
- raise typer.Exit(1)
641
+ for platform, info in SUPPORTED_PLATFORMS.items():
642
+ config_path = get_platform_config_path(platform, project_root)
688
643
 
689
- except Exception as e:
690
- logger.error(f"Demo failed: {e}")
691
- print_error(f"Demo failed: {e}")
692
- raise typer.Exit(1)
644
+ # Check if configured
645
+ is_configured = False
646
+ if config_path.exists():
647
+ try:
648
+ with open(config_path) as f:
649
+ config = json.load(f)
650
+ is_configured = "mcp-vector-search" in config.get("mcpServers", {})
651
+ except Exception:
652
+ pass
653
+
654
+ status = (
655
+ "✅ Configured"
656
+ if is_configured
657
+ else ("⚠️ Available" if platform in detected else "❌ Not Found")
658
+ )
659
+
660
+ table.add_row(
661
+ platform,
662
+ info["name"],
663
+ status,
664
+ str(config_path) if info["scope"] == "project" else info["config_path"],
665
+ )
666
+
667
+ console.print(table)
668
+
669
+ console.print("\n[bold blue]Installation Commands:[/bold blue]")
670
+ for platform in SUPPORTED_PLATFORMS:
671
+ console.print(f" mcp-vector-search install {platform}")
693
672
 
694
673
 
695
674
  if __name__ == "__main__":