mcp-vector-search 0.7.2__py3-none-any.whl → 0.7.4__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 +360 -0
- mcp_vector_search/cli/commands/index.py +14 -4
- mcp_vector_search/cli/commands/init.py +0 -85
- mcp_vector_search/cli/main.py +13 -17
- mcp_vector_search/core/database.py +20 -23
- {mcp_vector_search-0.7.2.dist-info → mcp_vector_search-0.7.4.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.7.2.dist-info → mcp_vector_search-0.7.4.dist-info}/RECORD +11 -10
- {mcp_vector_search-0.7.2.dist-info → mcp_vector_search-0.7.4.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.7.2.dist-info → mcp_vector_search-0.7.4.dist-info}/entry_points.txt +0 -0
- {mcp_vector_search-0.7.2.dist-info → mcp_vector_search-0.7.4.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/__init__.py
CHANGED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"""Demo command for mcp-vector-search."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from loguru import logger
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from ..output import print_error, print_info, print_success, print_warning
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
demo_app = typer.Typer(
|
|
17
|
+
name="demo",
|
|
18
|
+
help="🎬 Run interactive demo with sample project",
|
|
19
|
+
add_completion=False,
|
|
20
|
+
rich_markup_mode="rich",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@demo_app.callback(invoke_without_command=True)
|
|
25
|
+
def demo(
|
|
26
|
+
ctx: typer.Context,
|
|
27
|
+
quick: bool = typer.Option(
|
|
28
|
+
False,
|
|
29
|
+
"--quick",
|
|
30
|
+
"-q",
|
|
31
|
+
help="Skip search demo, only show installation",
|
|
32
|
+
),
|
|
33
|
+
keep_files: bool = typer.Option(
|
|
34
|
+
False,
|
|
35
|
+
"--keep",
|
|
36
|
+
"-k",
|
|
37
|
+
help="Keep demo files (don't auto-cleanup)",
|
|
38
|
+
),
|
|
39
|
+
) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Run installation demo with sample project.
|
|
42
|
+
|
|
43
|
+
[bold cyan]What this does:[/bold cyan]
|
|
44
|
+
1. Creates a temporary project with sample Python files
|
|
45
|
+
2. Initializes mcp-vector-search in the demo project
|
|
46
|
+
3. Indexes the sample code
|
|
47
|
+
4. Runs a sample semantic search
|
|
48
|
+
5. Shows you the results
|
|
49
|
+
|
|
50
|
+
[bold cyan]Examples:[/bold cyan]
|
|
51
|
+
[green]mcp-vector-search demo[/green]
|
|
52
|
+
Run full interactive demo
|
|
53
|
+
|
|
54
|
+
[green]mcp-vector-search demo --quick[/green]
|
|
55
|
+
Skip search demo, only show installation
|
|
56
|
+
|
|
57
|
+
[green]mcp-vector-search demo --keep[/green]
|
|
58
|
+
Keep demo files for inspection
|
|
59
|
+
|
|
60
|
+
[dim]Perfect for first-time users to see how semantic search works![/dim]
|
|
61
|
+
"""
|
|
62
|
+
# If subcommand was invoked, don't run the main demo
|
|
63
|
+
if ctx.invoked_subcommand is not None:
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
print_info("🎬 Running mcp-vector-search installation demo...")
|
|
68
|
+
console.print(
|
|
69
|
+
"\n[bold]This demo will:[/bold]\n"
|
|
70
|
+
" 1. Create a sample Python project\n"
|
|
71
|
+
" 2. Initialize and index it\n"
|
|
72
|
+
" 3. Run a semantic search\n"
|
|
73
|
+
" 4. Show you the results\n"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Create temporary demo directory
|
|
77
|
+
temp_context = tempfile.TemporaryDirectory(prefix="mcp-demo-")
|
|
78
|
+
temp_dir = temp_context.__enter__()
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
demo_dir = Path(temp_dir) / "demo-project"
|
|
82
|
+
demo_dir.mkdir()
|
|
83
|
+
|
|
84
|
+
# Create sample files
|
|
85
|
+
console.print("[bold blue]📝 Creating sample files...[/bold blue]")
|
|
86
|
+
|
|
87
|
+
(demo_dir / "main.py").write_text(
|
|
88
|
+
'''"""Main application module."""
|
|
89
|
+
|
|
90
|
+
def main():
|
|
91
|
+
"""Main entry point for the application."""
|
|
92
|
+
print("Hello, World!")
|
|
93
|
+
user_service = UserService()
|
|
94
|
+
user_service.create_user("Alice", "alice@example.com")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class UserService:
|
|
98
|
+
"""Service for managing users."""
|
|
99
|
+
|
|
100
|
+
def create_user(self, name: str, email: str):
|
|
101
|
+
"""Create a new user with the given name and email.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
name: The user's full name
|
|
105
|
+
email: The user's email address
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
dict: User object with name and email
|
|
109
|
+
"""
|
|
110
|
+
print(f"Creating user: {name} ({email})")
|
|
111
|
+
return {"name": name, "email": email}
|
|
112
|
+
|
|
113
|
+
def authenticate_user(self, email: str, password: str):
|
|
114
|
+
"""Authenticate user with email and password.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
email: User's email address
|
|
118
|
+
password: User's password
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
bool: True if authentication successful
|
|
122
|
+
"""
|
|
123
|
+
# Simple authentication logic
|
|
124
|
+
return email.endswith("@example.com")
|
|
125
|
+
|
|
126
|
+
def reset_password(self, email: str):
|
|
127
|
+
"""Send password reset email to user.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
email: User's email address
|
|
131
|
+
"""
|
|
132
|
+
print(f"Sending password reset to {email}")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == "__main__":
|
|
136
|
+
main()
|
|
137
|
+
'''
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
(demo_dir / "utils.py").write_text(
|
|
141
|
+
'''"""Utility functions for the application."""
|
|
142
|
+
|
|
143
|
+
import hashlib
|
|
144
|
+
import json
|
|
145
|
+
from typing import Any, Dict
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def load_config(config_path: str) -> Dict[str, Any]:
|
|
149
|
+
"""Load configuration from JSON file.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
config_path: Path to JSON configuration file
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
dict: Configuration dictionary
|
|
156
|
+
"""
|
|
157
|
+
with open(config_path, "r") as f:
|
|
158
|
+
return json.load(f)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def validate_email(email: str) -> bool:
|
|
162
|
+
"""Validate email address format.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
email: Email address to validate
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
bool: True if email format is valid
|
|
169
|
+
"""
|
|
170
|
+
return "@" in email and "." in email.split("@")[1]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def hash_password(password: str) -> str:
|
|
174
|
+
"""Hash password for secure storage.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
password: Plain text password
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
str: Hexadecimal hash of password
|
|
181
|
+
"""
|
|
182
|
+
return hashlib.sha256(password.encode()).hexdigest()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def validate_password_strength(password: str) -> bool:
|
|
186
|
+
"""Check if password meets security requirements.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
password: Password to validate
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
bool: True if password is strong enough
|
|
193
|
+
"""
|
|
194
|
+
return len(password) >= 8 and any(c.isdigit() for c in password)
|
|
195
|
+
'''
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
(demo_dir / "api.py").write_text(
|
|
199
|
+
'''"""API endpoints for user management."""
|
|
200
|
+
|
|
201
|
+
from typing import Dict, List
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class UserAPI:
|
|
205
|
+
"""REST API endpoints for user operations."""
|
|
206
|
+
|
|
207
|
+
def get_user(self, user_id: int) -> Dict:
|
|
208
|
+
"""Get user by ID.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
user_id: Unique user identifier
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
dict: User object
|
|
215
|
+
"""
|
|
216
|
+
return {"id": user_id, "name": "Example User"}
|
|
217
|
+
|
|
218
|
+
def list_users(self, limit: int = 10) -> List[Dict]:
|
|
219
|
+
"""List all users with pagination.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
limit: Maximum number of users to return
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
list: List of user objects
|
|
226
|
+
"""
|
|
227
|
+
return [{"id": i, "name": f"User {i}"} for i in range(limit)]
|
|
228
|
+
|
|
229
|
+
def create_user_endpoint(self, name: str, email: str) -> Dict:
|
|
230
|
+
"""Create a new user via API.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
name: User's full name
|
|
234
|
+
email: User's email address
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
dict: Created user object with ID
|
|
238
|
+
"""
|
|
239
|
+
return {"id": 1, "name": name, "email": email}
|
|
240
|
+
'''
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
console.print(f"[green]✅ Created 3 sample files in:[/green] {demo_dir}\n")
|
|
244
|
+
|
|
245
|
+
# Run initialization
|
|
246
|
+
print_info("🔧 Initializing mcp-vector-search in demo project...")
|
|
247
|
+
|
|
248
|
+
result = subprocess.run(
|
|
249
|
+
[
|
|
250
|
+
sys.executable,
|
|
251
|
+
"-m",
|
|
252
|
+
"mcp_vector_search.cli.main",
|
|
253
|
+
"--project-root",
|
|
254
|
+
str(demo_dir),
|
|
255
|
+
"init",
|
|
256
|
+
"--extensions",
|
|
257
|
+
".py",
|
|
258
|
+
"--no-mcp", # Skip MCP for demo
|
|
259
|
+
"--auto-index", # Auto-index after init
|
|
260
|
+
],
|
|
261
|
+
input="y\n", # Auto-confirm the setup
|
|
262
|
+
capture_output=True,
|
|
263
|
+
text=True,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if result.returncode != 0:
|
|
267
|
+
print_error(f"Demo initialization failed: {result.stderr}")
|
|
268
|
+
raise typer.Exit(1)
|
|
269
|
+
|
|
270
|
+
print_success("✅ Demo project initialized and indexed!")
|
|
271
|
+
|
|
272
|
+
if not quick:
|
|
273
|
+
# Give the index a moment to settle
|
|
274
|
+
import time
|
|
275
|
+
|
|
276
|
+
time.sleep(1)
|
|
277
|
+
|
|
278
|
+
# Run sample searches to demonstrate different features
|
|
279
|
+
searches = [
|
|
280
|
+
("user authentication", "Finding authentication-related code"),
|
|
281
|
+
("password", "Finding password-related functions"),
|
|
282
|
+
("email validation", "Finding email validation logic"),
|
|
283
|
+
]
|
|
284
|
+
|
|
285
|
+
for query, description in searches:
|
|
286
|
+
console.print(f"\n[bold blue]🔍 {description}:[/bold blue]")
|
|
287
|
+
console.print(f"[dim]Query: '{query}'[/dim]\n")
|
|
288
|
+
|
|
289
|
+
search_result = subprocess.run(
|
|
290
|
+
[
|
|
291
|
+
sys.executable,
|
|
292
|
+
"-m",
|
|
293
|
+
"mcp_vector_search.cli.main",
|
|
294
|
+
"--project-root",
|
|
295
|
+
str(demo_dir),
|
|
296
|
+
"search",
|
|
297
|
+
"--limit",
|
|
298
|
+
"2",
|
|
299
|
+
query,
|
|
300
|
+
],
|
|
301
|
+
capture_output=True,
|
|
302
|
+
text=True,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if search_result.returncode == 0 and search_result.stdout.strip():
|
|
306
|
+
console.print(search_result.stdout)
|
|
307
|
+
else:
|
|
308
|
+
# Show a friendly message if search didn't return results
|
|
309
|
+
console.print(
|
|
310
|
+
"[dim]Note: Search completed but may need more time "
|
|
311
|
+
"for the index to fully settle.[/dim]"
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Show summary
|
|
315
|
+
console.print("\n" + "=" * 70)
|
|
316
|
+
console.print("[bold green]🎉 Demo completed successfully![/bold green]")
|
|
317
|
+
console.print("=" * 70 + "\n")
|
|
318
|
+
|
|
319
|
+
console.print("[bold]What you just saw:[/bold]")
|
|
320
|
+
console.print(" ✅ Sample project creation")
|
|
321
|
+
console.print(" ✅ Automatic code indexing")
|
|
322
|
+
if not quick:
|
|
323
|
+
console.print(" ✅ Semantic code search in action")
|
|
324
|
+
console.print(
|
|
325
|
+
" ✅ Finding code by meaning (not just keywords)\n"
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
console.print("[bold cyan]Next steps to use in your project:[/bold cyan]")
|
|
329
|
+
console.print(" 1. [green]cd /your/project[/green]")
|
|
330
|
+
console.print(" 2. [green]mcp-vector-search init[/green]")
|
|
331
|
+
console.print(" 3. [green]mcp-vector-search search 'your query'[/green]\n")
|
|
332
|
+
|
|
333
|
+
if keep_files:
|
|
334
|
+
console.print(
|
|
335
|
+
f"[bold]Demo files saved at:[/bold] [cyan]{demo_dir}[/cyan]"
|
|
336
|
+
)
|
|
337
|
+
console.print(
|
|
338
|
+
"[yellow]Note: This is still in a temp directory, "
|
|
339
|
+
"copy files if you want to keep them![/yellow]\n"
|
|
340
|
+
)
|
|
341
|
+
else:
|
|
342
|
+
console.print(
|
|
343
|
+
"[dim]Demo files will be cleaned up automatically.[/dim]\n"
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
finally:
|
|
347
|
+
if not keep_files:
|
|
348
|
+
temp_context.__exit__(None, None, None)
|
|
349
|
+
else:
|
|
350
|
+
# Keep the context manager open
|
|
351
|
+
pass
|
|
352
|
+
|
|
353
|
+
except Exception as e:
|
|
354
|
+
logger.error(f"Demo failed: {e}")
|
|
355
|
+
print_error(f"Demo failed: {e}")
|
|
356
|
+
raise typer.Exit(1)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
if __name__ == "__main__":
|
|
360
|
+
demo_app()
|
|
@@ -217,10 +217,15 @@ async def _run_batch_indexing(
|
|
|
217
217
|
show_progress=show_progress,
|
|
218
218
|
)
|
|
219
219
|
|
|
220
|
-
print_success(f"Indexed {indexed_count} files")
|
|
221
|
-
|
|
222
220
|
# Show statistics
|
|
223
221
|
stats = await indexer.get_indexing_stats()
|
|
222
|
+
|
|
223
|
+
# Display success message with chunk count for clarity
|
|
224
|
+
total_chunks = stats.get("total_chunks", 0)
|
|
225
|
+
print_success(
|
|
226
|
+
f"Processed {indexed_count} files ({total_chunks} searchable chunks created)"
|
|
227
|
+
)
|
|
228
|
+
|
|
224
229
|
print_index_stats(stats)
|
|
225
230
|
|
|
226
231
|
# Add next-step hints
|
|
@@ -381,10 +386,15 @@ async def _reindex_entire_project(project_root: Path) -> None:
|
|
|
381
386
|
|
|
382
387
|
progress.update(task, completed=indexed_count, total=indexed_count)
|
|
383
388
|
|
|
384
|
-
print_success(f"Successfully reindexed {indexed_count} files")
|
|
385
|
-
|
|
386
389
|
# Show statistics
|
|
387
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
|
+
|
|
388
398
|
print_index_stats(stats)
|
|
389
399
|
|
|
390
400
|
except Exception as e:
|
|
@@ -6,7 +6,6 @@ import typer
|
|
|
6
6
|
from loguru import logger
|
|
7
7
|
|
|
8
8
|
from ...config.constants import (
|
|
9
|
-
SUBPROCESS_INSTALL_TIMEOUT,
|
|
10
9
|
SUBPROCESS_MCP_TIMEOUT,
|
|
11
10
|
SUBPROCESS_TEST_TIMEOUT,
|
|
12
11
|
)
|
|
@@ -143,90 +142,6 @@ def main(
|
|
|
143
142
|
|
|
144
143
|
print_info(f"Initializing project at: {project_root}")
|
|
145
144
|
|
|
146
|
-
# Step 1: Install mcp-vector-search in the current project
|
|
147
|
-
console.print("\n[bold blue]📦 Installing mcp-vector-search...[/bold blue]")
|
|
148
|
-
|
|
149
|
-
# Find the development source directory
|
|
150
|
-
import mcp_vector_search
|
|
151
|
-
|
|
152
|
-
dev_source_path = Path(mcp_vector_search.__file__).parent.parent.parent
|
|
153
|
-
|
|
154
|
-
try:
|
|
155
|
-
import shutil
|
|
156
|
-
import subprocess
|
|
157
|
-
import sys
|
|
158
|
-
|
|
159
|
-
# Try different installation methods based on available tools
|
|
160
|
-
install_success = False
|
|
161
|
-
|
|
162
|
-
# Method 1: Try pip directly
|
|
163
|
-
if shutil.which("pip"):
|
|
164
|
-
install_cmd = ["pip", "install", "-e", str(dev_source_path)]
|
|
165
|
-
try:
|
|
166
|
-
result = subprocess.run(
|
|
167
|
-
install_cmd,
|
|
168
|
-
capture_output=True,
|
|
169
|
-
text=True,
|
|
170
|
-
timeout=SUBPROCESS_INSTALL_TIMEOUT,
|
|
171
|
-
)
|
|
172
|
-
if result.returncode == 0:
|
|
173
|
-
install_success = True
|
|
174
|
-
except (subprocess.TimeoutExpired, OSError, ValueError) as e:
|
|
175
|
-
logger.debug(f"pip install method failed: {e}")
|
|
176
|
-
pass
|
|
177
|
-
|
|
178
|
-
# Method 2: Try python -m pip
|
|
179
|
-
if not install_success:
|
|
180
|
-
install_cmd = [
|
|
181
|
-
sys.executable,
|
|
182
|
-
"-m",
|
|
183
|
-
"pip",
|
|
184
|
-
"install",
|
|
185
|
-
"-e",
|
|
186
|
-
str(dev_source_path),
|
|
187
|
-
]
|
|
188
|
-
try:
|
|
189
|
-
result = subprocess.run(
|
|
190
|
-
install_cmd,
|
|
191
|
-
capture_output=True,
|
|
192
|
-
text=True,
|
|
193
|
-
timeout=SUBPROCESS_INSTALL_TIMEOUT,
|
|
194
|
-
)
|
|
195
|
-
if result.returncode == 0:
|
|
196
|
-
install_success = True
|
|
197
|
-
except (subprocess.TimeoutExpired, OSError, ValueError) as e:
|
|
198
|
-
logger.debug(f"python -m pip install method failed: {e}")
|
|
199
|
-
pass
|
|
200
|
-
|
|
201
|
-
# Method 3: Try uv if available
|
|
202
|
-
if not install_success and shutil.which("uv"):
|
|
203
|
-
install_cmd = ["uv", "add", "--editable", str(dev_source_path)]
|
|
204
|
-
try:
|
|
205
|
-
result = subprocess.run(
|
|
206
|
-
install_cmd,
|
|
207
|
-
capture_output=True,
|
|
208
|
-
text=True,
|
|
209
|
-
timeout=SUBPROCESS_INSTALL_TIMEOUT,
|
|
210
|
-
)
|
|
211
|
-
if result.returncode == 0:
|
|
212
|
-
install_success = True
|
|
213
|
-
except (subprocess.TimeoutExpired, OSError, ValueError) as e:
|
|
214
|
-
logger.debug(f"uv add method failed: {e}")
|
|
215
|
-
pass
|
|
216
|
-
|
|
217
|
-
if install_success:
|
|
218
|
-
print_success("✅ mcp-vector-search installed successfully!")
|
|
219
|
-
else:
|
|
220
|
-
print_warning(
|
|
221
|
-
"⚠️ Could not install automatically - you may need to install manually"
|
|
222
|
-
)
|
|
223
|
-
print_info(f"💡 Try: pip install -e {dev_source_path}")
|
|
224
|
-
print_info("Continuing with setup...")
|
|
225
|
-
|
|
226
|
-
except Exception as e:
|
|
227
|
-
print_warning(f"⚠️ Installation encountered an issue: {e}")
|
|
228
|
-
print_info("Continuing with setup...")
|
|
229
|
-
|
|
230
145
|
# Create project manager
|
|
231
146
|
project_manager = ProjectManager(project_root)
|
|
232
147
|
|
mcp_vector_search/cli/main.py
CHANGED
|
@@ -34,6 +34,7 @@ unfamiliar codebases, finding similar patterns, and integrating with AI tools.
|
|
|
34
34
|
|
|
35
35
|
[bold cyan]Main Commands:[/bold cyan]
|
|
36
36
|
init 🔧 Initialize project
|
|
37
|
+
demo 🎬 Run interactive demo
|
|
37
38
|
doctor 🩺 Check system health
|
|
38
39
|
status 📊 Show project status
|
|
39
40
|
search 🔍 Search code semantically
|
|
@@ -51,6 +52,7 @@ unfamiliar codebases, finding similar patterns, and integrating with AI tools.
|
|
|
51
52
|
|
|
52
53
|
# Import command modules
|
|
53
54
|
from .commands.config import config_app # noqa: E402
|
|
55
|
+
from .commands.demo import demo_app # noqa: E402
|
|
54
56
|
from .commands.index import index_app # noqa: E402
|
|
55
57
|
from .commands.init import init_app # noqa: E402
|
|
56
58
|
from .commands.mcp import mcp_app # noqa: E402
|
|
@@ -65,29 +67,32 @@ from .commands.status import main as status_main # noqa: E402
|
|
|
65
67
|
# Use Typer group for init to support both direct call and subcommands
|
|
66
68
|
app.add_typer(init_app, name="init", help="🔧 Initialize project for semantic search")
|
|
67
69
|
|
|
68
|
-
# 2.
|
|
70
|
+
# 2. DEMO - Interactive demo
|
|
71
|
+
app.add_typer(demo_app, name="demo", help="🎬 Run interactive demo with sample project")
|
|
72
|
+
|
|
73
|
+
# 3. DOCTOR - System health check
|
|
69
74
|
# (defined below inline)
|
|
70
75
|
|
|
71
|
-
#
|
|
76
|
+
# 4. STATUS - Project status
|
|
72
77
|
app.command("status", help="📊 Show project status and statistics")(status_main)
|
|
73
78
|
|
|
74
|
-
#
|
|
79
|
+
# 5. SEARCH - Search code
|
|
75
80
|
# Register search as both a command and a typer group
|
|
76
81
|
app.add_typer(search_app, name="search", help="🔍 Search code semantically")
|
|
77
82
|
|
|
78
|
-
#
|
|
83
|
+
# 6. INDEX - Index codebase
|
|
79
84
|
app.add_typer(index_app, name="index", help="📇 Index codebase for semantic search")
|
|
80
85
|
|
|
81
|
-
#
|
|
86
|
+
# 7. MCP - MCP integration
|
|
82
87
|
app.add_typer(mcp_app, name="mcp", help="🤖 Manage Claude Code MCP integration")
|
|
83
88
|
|
|
84
|
-
#
|
|
89
|
+
# 8. CONFIG - Configuration
|
|
85
90
|
app.add_typer(config_app, name="config", help="⚙️ Manage project configuration")
|
|
86
91
|
|
|
87
|
-
#
|
|
92
|
+
# 9. HELP - Enhanced help
|
|
88
93
|
# (defined below inline)
|
|
89
94
|
|
|
90
|
-
#
|
|
95
|
+
# 10. VERSION - Version info
|
|
91
96
|
# (defined below inline)
|
|
92
97
|
|
|
93
98
|
|
|
@@ -117,15 +122,6 @@ def deprecated_install():
|
|
|
117
122
|
_deprecated_command("install", "init")()
|
|
118
123
|
|
|
119
124
|
|
|
120
|
-
# Deprecated: demo -> removed
|
|
121
|
-
@app.command("demo", hidden=True)
|
|
122
|
-
def deprecated_demo():
|
|
123
|
-
"""[DEPRECATED] Command removed."""
|
|
124
|
-
print_warning(
|
|
125
|
-
"⚠️ The 'demo' command has been removed.\n"
|
|
126
|
-
" Use [cyan]mcp-vector-search init --help[/cyan] for setup instructions."
|
|
127
|
-
)
|
|
128
|
-
raise typer.Exit(1)
|
|
129
125
|
|
|
130
126
|
|
|
131
127
|
# Deprecated: find -> search
|
|
@@ -377,39 +377,36 @@ class ChromaVectorDatabase(VectorDatabase):
|
|
|
377
377
|
# Get total count
|
|
378
378
|
count = self._collection.count()
|
|
379
379
|
|
|
380
|
-
# Get
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
include=["metadatas"],
|
|
384
|
-
)
|
|
380
|
+
# Get ALL metadata to analyze (not just a sample)
|
|
381
|
+
# Only fetch metadata, not embeddings, for performance
|
|
382
|
+
results = self._collection.get(include=["metadatas"])
|
|
385
383
|
|
|
386
|
-
|
|
387
|
-
|
|
384
|
+
# Count unique files from all chunks
|
|
385
|
+
files = {m.get("file_path", "") for m in results.get("metadatas", [])}
|
|
388
386
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
lang = metadata.get("language", "unknown")
|
|
393
|
-
languages[lang] = languages.get(lang, 0) + 1
|
|
387
|
+
# Count languages and file types
|
|
388
|
+
language_counts = {}
|
|
389
|
+
file_type_counts = {}
|
|
394
390
|
|
|
395
|
-
|
|
396
|
-
|
|
391
|
+
for metadata in results.get("metadatas", []):
|
|
392
|
+
# Count languages
|
|
393
|
+
lang = metadata.get("language", "unknown")
|
|
394
|
+
language_counts[lang] = language_counts.get(lang, 0) + 1
|
|
395
|
+
|
|
396
|
+
# Count file types
|
|
397
|
+
file_path = metadata.get("file_path", "")
|
|
398
|
+
if file_path:
|
|
397
399
|
ext = Path(file_path).suffix or "no_extension"
|
|
398
|
-
|
|
400
|
+
file_type_counts[ext] = file_type_counts.get(ext, 0) + 1
|
|
399
401
|
|
|
400
402
|
# Estimate index size (rough approximation)
|
|
401
403
|
index_size_mb = count * 0.001 # Rough estimate
|
|
402
404
|
|
|
403
405
|
return IndexStats(
|
|
404
|
-
total_files=len(
|
|
405
|
-
{
|
|
406
|
-
m.get("file_path", "")
|
|
407
|
-
for m in sample_results.get("metadatas", [])
|
|
408
|
-
}
|
|
409
|
-
),
|
|
406
|
+
total_files=len(files),
|
|
410
407
|
total_chunks=count,
|
|
411
|
-
languages=
|
|
412
|
-
file_types=
|
|
408
|
+
languages=language_counts,
|
|
409
|
+
file_types=file_type_counts,
|
|
413
410
|
index_size_mb=index_size_mb,
|
|
414
411
|
last_updated="unknown", # TODO: Track this
|
|
415
412
|
embedding_model="unknown", # TODO: Track this
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-vector-search
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Summary: CLI-first semantic code search with MCP integration
|
|
5
5
|
Project-URL: Homepage, https://github.com/bobmatnyc/mcp-vector-search
|
|
6
6
|
Project-URL: Documentation, https://mcp-vector-search.readthedocs.io
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
mcp_vector_search/__init__.py,sha256=
|
|
1
|
+
mcp_vector_search/__init__.py,sha256=dwjtm9sE-mB8ai4WJ0qaTi2dWD55TXfdknB0YzqYGzQ,299
|
|
2
2
|
mcp_vector_search/py.typed,sha256=lCKeV9Qcn9sGtbRsgg-LJO2ZwWRuknnnlmomq3bJFH0,43
|
|
3
3
|
mcp_vector_search/cli/__init__.py,sha256=TNB7CaOASz8u3yHWLbNmo8-GtHF0qwUjVKWAuNphKgo,40
|
|
4
4
|
mcp_vector_search/cli/didyoumean.py,sha256=F_ss-EX4F9RgnMsEhdTwLpyNCah9SqnBZc2tBtzASck,15918
|
|
5
5
|
mcp_vector_search/cli/export.py,sha256=iluxuRT2KELdKlQeDAlVkteiel4GGrng153UAw9H0as,10804
|
|
6
6
|
mcp_vector_search/cli/history.py,sha256=6wRrSfxpUe9hJXuaEeVxOVkFlcpqkIiGfwzDgd5N6c8,9323
|
|
7
7
|
mcp_vector_search/cli/interactive.py,sha256=T7P4dAdvbglznzQYgiePv5YNyOx9FeE57Y3OKYnnbYE,12744
|
|
8
|
-
mcp_vector_search/cli/main.py,sha256=
|
|
8
|
+
mcp_vector_search/cli/main.py,sha256=5BJeueirPMGqNNf9NYZ8x6NhKOgu_EUkuRYNaP25I80,14495
|
|
9
9
|
mcp_vector_search/cli/output.py,sha256=7ShIk_UKzhDzRGxI6JluPu0gGkbmKOevqgIAKR4oCa0,12560
|
|
10
10
|
mcp_vector_search/cli/suggestions.py,sha256=h-UaxoLcHmFbhZSm0WG7nKJXAIRIqhv7aGsXijp7vA8,13273
|
|
11
11
|
mcp_vector_search/cli/commands/__init__.py,sha256=vQls-YKZ54YEwmf7g1dL0T2SS9D4pdQljXzsUChG_V4,42
|
|
12
12
|
mcp_vector_search/cli/commands/auto_index.py,sha256=imVVbxWRlA128NPdK9BetNNl3ELrsdq-hqcsLqyAmoM,12712
|
|
13
13
|
mcp_vector_search/cli/commands/config.py,sha256=mKE8gUgAOqCM__4yzEEu9HJPbx9X15lN264zkDJBRxg,12399
|
|
14
|
-
mcp_vector_search/cli/commands/
|
|
15
|
-
mcp_vector_search/cli/commands/
|
|
14
|
+
mcp_vector_search/cli/commands/demo.py,sha256=HOa5g4vDu_zjSq77bMcFaCck7RN9YsYgsIknAfeYIC8,10683
|
|
15
|
+
mcp_vector_search/cli/commands/index.py,sha256=tqn6KjDygAHam5mINthYFBm-hA6I8QYDjrSVRmUtXLE,18213
|
|
16
|
+
mcp_vector_search/cli/commands/init.py,sha256=2kdjtIPPeutKUXs65-6W1VQPF_BQrbV6_U3TCE7U5mw,23242
|
|
16
17
|
mcp_vector_search/cli/commands/install.py,sha256=phk7Eb7UOU5IsRfJyaDPdOfdUWli9gyA4cHjhgXcNEI,24609
|
|
17
18
|
mcp_vector_search/cli/commands/mcp.py,sha256=FKZNxYrDc7HfPTFBUEypCv-8atsrHEdbtU6Yfg9QUMA,18569
|
|
18
19
|
mcp_vector_search/cli/commands/reset.py,sha256=bsIT6zjDf6gsvIkVaRaUClYzlTyNe--8t0NWkBY0ldU,13724
|
|
@@ -26,7 +27,7 @@ mcp_vector_search/config/settings.py,sha256=m8o8j-tvWcuzrnNL6YWbi2fFbcB3lZY1kMNi
|
|
|
26
27
|
mcp_vector_search/core/__init__.py,sha256=bWKtKmmaFs7gG5XPCbrx77UYIVeO1FF8wIJxpj1dLNw,48
|
|
27
28
|
mcp_vector_search/core/auto_indexer.py,sha256=0S4lZXaUgqEytMSA2FxQsh5hN7V1mbSLYVzEf_dslYQ,10307
|
|
28
29
|
mcp_vector_search/core/connection_pool.py,sha256=Yo-gUQQbHawtuvh6OcJiAlbbvWQGQBd31QZOvs498fg,11224
|
|
29
|
-
mcp_vector_search/core/database.py,sha256=
|
|
30
|
+
mcp_vector_search/core/database.py,sha256=fMcclsO2dGOfsUSN38rJDRGVNEuPvGKHZlSSuuyIKag,35512
|
|
30
31
|
mcp_vector_search/core/embeddings.py,sha256=wSMUNxZcuGPMxxQ1AbKqA1a3-0c6AiOqmuuI7OqTyaQ,10578
|
|
31
32
|
mcp_vector_search/core/exceptions.py,sha256=3bCjT8wmrLz_0e_Tayr90049zNTKYFWZa19kl0saKz8,1597
|
|
32
33
|
mcp_vector_search/core/factory.py,sha256=tM6Ft-V9buF7nn9xbRMU1ngji-BJOKt6BhtfQhFLmF4,10384
|
|
@@ -55,8 +56,8 @@ mcp_vector_search/utils/__init__.py,sha256=Eq6lY-oPMfCt-GpPUbg9QbmTHuQVmTaVDBMU2
|
|
|
55
56
|
mcp_vector_search/utils/gitignore.py,sha256=bzie3V5gOGIN7j3FNVLLCx8O_hfZJDUqqAy5T3lT3Ek,7685
|
|
56
57
|
mcp_vector_search/utils/timing.py,sha256=THC7mfbTYnUpnnDcblgQacYMzbEkfFoIShx6plmhCgg,11285
|
|
57
58
|
mcp_vector_search/utils/version.py,sha256=d7fS-CLemxb8UzZ9j18zH0Y0Ud097ljKKYYOPulnGPE,1138
|
|
58
|
-
mcp_vector_search-0.7.
|
|
59
|
-
mcp_vector_search-0.7.
|
|
60
|
-
mcp_vector_search-0.7.
|
|
61
|
-
mcp_vector_search-0.7.
|
|
62
|
-
mcp_vector_search-0.7.
|
|
59
|
+
mcp_vector_search-0.7.4.dist-info/METADATA,sha256=k-RZl6CDcmhMyiS_w4oNCUzkrg7syOyIeKyCdYoereo,19120
|
|
60
|
+
mcp_vector_search-0.7.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
61
|
+
mcp_vector_search-0.7.4.dist-info/entry_points.txt,sha256=y3Ygtc_JiBchNEIL-tPABo7EbzBExGAxwGdkkeP5D2I,86
|
|
62
|
+
mcp_vector_search-0.7.4.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
|
|
63
|
+
mcp_vector_search-0.7.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|