mcp-vector-search 0.8.2__py3-none-any.whl → 0.8.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/visualize.py +150 -25
- mcp_vector_search/core/models.py +7 -1
- {mcp_vector_search-0.8.2.dist-info → mcp_vector_search-0.8.4.dist-info}/METADATA +1 -1
- {mcp_vector_search-0.8.2.dist-info → mcp_vector_search-0.8.4.dist-info}/RECORD +8 -8
- {mcp_vector_search-0.8.2.dist-info → mcp_vector_search-0.8.4.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.8.2.dist-info → mcp_vector_search-0.8.4.dist-info}/entry_points.txt +0 -0
- {mcp_vector_search-0.8.2.dist-info → mcp_vector_search-0.8.4.dist-info}/licenses/LICENSE +0 -0
mcp_vector_search/__init__.py
CHANGED
|
@@ -166,9 +166,30 @@ def serve(
|
|
|
166
166
|
"""
|
|
167
167
|
import http.server
|
|
168
168
|
import os
|
|
169
|
+
import socket
|
|
169
170
|
import socketserver
|
|
170
171
|
import webbrowser
|
|
171
172
|
|
|
173
|
+
# Find free port in range 8080-8099
|
|
174
|
+
def find_free_port(start_port: int = 8080, end_port: int = 8099) -> int:
|
|
175
|
+
"""Find a free port in the given range."""
|
|
176
|
+
for test_port in range(start_port, end_port + 1):
|
|
177
|
+
try:
|
|
178
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
179
|
+
s.bind(("", test_port))
|
|
180
|
+
return test_port
|
|
181
|
+
except OSError:
|
|
182
|
+
continue
|
|
183
|
+
raise OSError(f"No free ports available in range {start_port}-{end_port}")
|
|
184
|
+
|
|
185
|
+
# Use specified port or find free one
|
|
186
|
+
if port == 8080: # Default port, try to find free one
|
|
187
|
+
try:
|
|
188
|
+
port = find_free_port(8080, 8099)
|
|
189
|
+
except OSError as e:
|
|
190
|
+
console.print(f"[red]✗ {e}[/red]")
|
|
191
|
+
raise typer.Exit(1)
|
|
192
|
+
|
|
172
193
|
# Get visualization directory
|
|
173
194
|
viz_dir = Path(__file__).parent.parent.parent / "visualization"
|
|
174
195
|
|
|
@@ -364,9 +385,8 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
364
385
|
<div id="controls">
|
|
365
386
|
<h1>🔍 Code Graph</h1>
|
|
366
387
|
|
|
367
|
-
<div class="control-group">
|
|
368
|
-
<label
|
|
369
|
-
<input type="file" id="fileInput" accept=".json">
|
|
388
|
+
<div class="control-group" id="loading">
|
|
389
|
+
<label>⏳ Loading graph data...</label>
|
|
370
390
|
</div>
|
|
371
391
|
|
|
372
392
|
<h3>Legend</h3>
|
|
@@ -408,34 +428,79 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
408
428
|
const g = svg.append("g");
|
|
409
429
|
const tooltip = d3.select("#tooltip");
|
|
410
430
|
let simulation;
|
|
431
|
+
let allNodes = [];
|
|
432
|
+
let allLinks = [];
|
|
433
|
+
let visibleNodes = new Set();
|
|
434
|
+
let collapsedNodes = new Set();
|
|
411
435
|
|
|
412
436
|
function visualizeGraph(data) {
|
|
413
437
|
g.selectAll("*").remove();
|
|
414
438
|
|
|
415
|
-
|
|
416
|
-
|
|
439
|
+
allNodes = data.nodes;
|
|
440
|
+
allLinks = data.links;
|
|
441
|
+
|
|
442
|
+
// Find root nodes (nodes without parents or depth 0/1)
|
|
443
|
+
const rootNodes = allNodes.filter(n =>
|
|
444
|
+
!n.parent_id || n.depth === 0 || n.depth === 1 || n.type === 'module'
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
// Start with only root nodes visible
|
|
448
|
+
visibleNodes = new Set(rootNodes.map(n => n.id));
|
|
449
|
+
collapsedNodes = new Set(rootNodes.map(n => n.id));
|
|
450
|
+
|
|
451
|
+
renderGraph();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function renderGraph() {
|
|
455
|
+
const visibleNodesList = allNodes.filter(n => visibleNodes.has(n.id));
|
|
456
|
+
const visibleLinks = allLinks.filter(l =>
|
|
457
|
+
visibleNodes.has(l.source.id || l.source) &&
|
|
458
|
+
visibleNodes.has(l.target.id || l.target)
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
simulation = d3.forceSimulation(visibleNodesList)
|
|
462
|
+
.force("link", d3.forceLink(visibleLinks).id(d => d.id).distance(100))
|
|
417
463
|
.force("charge", d3.forceManyBody().strength(-400))
|
|
418
464
|
.force("center", d3.forceCenter(width / 2, height / 2))
|
|
419
465
|
.force("collision", d3.forceCollide().radius(40));
|
|
420
466
|
|
|
467
|
+
g.selectAll("*").remove();
|
|
468
|
+
|
|
421
469
|
const link = g.append("g")
|
|
422
470
|
.selectAll("line")
|
|
423
|
-
.data(
|
|
471
|
+
.data(visibleLinks)
|
|
424
472
|
.join("line")
|
|
425
473
|
.attr("class", "link");
|
|
426
474
|
|
|
427
475
|
const node = g.append("g")
|
|
428
476
|
.selectAll("g")
|
|
429
|
-
.data(
|
|
477
|
+
.data(visibleNodesList)
|
|
430
478
|
.join("g")
|
|
431
479
|
.attr("class", d => `node ${d.type}`)
|
|
432
480
|
.call(drag(simulation))
|
|
481
|
+
.on("click", toggleNode)
|
|
433
482
|
.on("mouseover", showTooltip)
|
|
434
483
|
.on("mouseout", hideTooltip);
|
|
435
484
|
|
|
485
|
+
// Add circles with expand indicator
|
|
436
486
|
node.append("circle")
|
|
437
|
-
.attr("r", d => d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12)
|
|
438
|
-
|
|
487
|
+
.attr("r", d => d.complexity ? Math.min(8 + d.complexity * 2, 25) : 12)
|
|
488
|
+
.attr("stroke", d => hasChildren(d) ? "#ffffff" : "none")
|
|
489
|
+
.attr("stroke-width", d => hasChildren(d) ? 2 : 0);
|
|
490
|
+
|
|
491
|
+
// Add expand/collapse indicator
|
|
492
|
+
node.filter(d => hasChildren(d))
|
|
493
|
+
.append("text")
|
|
494
|
+
.attr("class", "expand-indicator")
|
|
495
|
+
.attr("text-anchor", "middle")
|
|
496
|
+
.attr("dy", 5)
|
|
497
|
+
.style("font-size", "16px")
|
|
498
|
+
.style("font-weight", "bold")
|
|
499
|
+
.style("fill", "#ffffff")
|
|
500
|
+
.style("pointer-events", "none")
|
|
501
|
+
.text(d => collapsedNodes.has(d.id) ? "+" : "−");
|
|
502
|
+
|
|
503
|
+
// Add labels
|
|
439
504
|
node.append("text")
|
|
440
505
|
.text(d => d.name)
|
|
441
506
|
.attr("dy", 30);
|
|
@@ -450,7 +515,61 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
450
515
|
node.attr("transform", d => `translate(${d.x},${d.y})`);
|
|
451
516
|
});
|
|
452
517
|
|
|
453
|
-
updateStats(
|
|
518
|
+
updateStats({nodes: visibleNodesList, links: visibleLinks, metadata: {total_files: allNodes.length}});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function hasChildren(node) {
|
|
522
|
+
return allLinks.some(l => (l.source.id || l.source) === node.id);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function toggleNode(event, d) {
|
|
526
|
+
event.stopPropagation();
|
|
527
|
+
|
|
528
|
+
if (!hasChildren(d)) return;
|
|
529
|
+
|
|
530
|
+
if (collapsedNodes.has(d.id)) {
|
|
531
|
+
// Expand: show children
|
|
532
|
+
expandNode(d);
|
|
533
|
+
} else {
|
|
534
|
+
// Collapse: hide children
|
|
535
|
+
collapseNode(d);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
renderGraph();
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function expandNode(node) {
|
|
542
|
+
collapsedNodes.delete(node.id);
|
|
543
|
+
|
|
544
|
+
// Find direct children
|
|
545
|
+
const children = allLinks
|
|
546
|
+
.filter(l => (l.source.id || l.source) === node.id)
|
|
547
|
+
.map(l => allNodes.find(n => n.id === (l.target.id || l.target)))
|
|
548
|
+
.filter(n => n);
|
|
549
|
+
|
|
550
|
+
children.forEach(child => {
|
|
551
|
+
visibleNodes.add(child.id);
|
|
552
|
+
collapsedNodes.add(child.id); // Children start collapsed
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function collapseNode(node) {
|
|
557
|
+
collapsedNodes.add(node.id);
|
|
558
|
+
|
|
559
|
+
// Hide all descendants recursively
|
|
560
|
+
function hideDescendants(parentId) {
|
|
561
|
+
const children = allLinks
|
|
562
|
+
.filter(l => (l.source.id || l.source) === parentId)
|
|
563
|
+
.map(l => l.target.id || l.target);
|
|
564
|
+
|
|
565
|
+
children.forEach(childId => {
|
|
566
|
+
visibleNodes.delete(childId);
|
|
567
|
+
collapsedNodes.delete(childId);
|
|
568
|
+
hideDescendants(childId);
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
hideDescendants(node.id);
|
|
454
573
|
}
|
|
455
574
|
|
|
456
575
|
function showTooltip(event, d) {
|
|
@@ -504,23 +623,29 @@ def _create_visualization_html(html_file: Path) -> None:
|
|
|
504
623
|
`);
|
|
505
624
|
}
|
|
506
625
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
626
|
+
// Auto-load graph data on page load
|
|
627
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
628
|
+
const loadingEl = document.getElementById('loading');
|
|
629
|
+
|
|
630
|
+
fetch("chunk-graph.json")
|
|
631
|
+
.then(response => {
|
|
632
|
+
if (!response.ok) {
|
|
633
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
634
|
+
}
|
|
635
|
+
return response.json();
|
|
636
|
+
})
|
|
637
|
+
.then(data => {
|
|
638
|
+
loadingEl.innerHTML = '<label style="color: #238636;">✓ Graph loaded successfully</label>';
|
|
639
|
+
setTimeout(() => loadingEl.style.display = 'none', 2000);
|
|
513
640
|
visualizeGraph(data);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
|
|
641
|
+
})
|
|
642
|
+
.catch(err => {
|
|
643
|
+
loadingEl.innerHTML = `<label style="color: #f85149;">✗ Failed to load graph data</label><br>` +
|
|
644
|
+
`<small style="color: #8b949e;">${err.message}</small><br>` +
|
|
645
|
+
`<small style="color: #8b949e;">Run: mcp-vector-search visualize export</small>`;
|
|
646
|
+
console.error("Failed to load graph:", err);
|
|
647
|
+
});
|
|
517
648
|
});
|
|
518
|
-
|
|
519
|
-
// Try to load default data
|
|
520
|
-
fetch("chunk-graph.json")
|
|
521
|
-
.then(response => response.json())
|
|
522
|
-
.then(data => visualizeGraph(data))
|
|
523
|
-
.catch(err => console.log("No default graph found. Please load a JSON file."));
|
|
524
649
|
</script>
|
|
525
650
|
</body>
|
|
526
651
|
</html>'''
|
mcp_vector_search/core/models.py
CHANGED
|
@@ -53,7 +53,13 @@ class CodeChunk:
|
|
|
53
53
|
# Generate chunk ID if not provided
|
|
54
54
|
if self.chunk_id is None:
|
|
55
55
|
import hashlib
|
|
56
|
-
|
|
56
|
+
import uuid
|
|
57
|
+
|
|
58
|
+
# Include name to differentiate chunks at same location
|
|
59
|
+
name = self.function_name or self.class_name or ""
|
|
60
|
+
# Add UUID to guarantee uniqueness even for identical chunks
|
|
61
|
+
unique_suffix = str(uuid.uuid4())[:8]
|
|
62
|
+
id_string = f"{self.file_path}:{self.chunk_type}:{name}:{self.start_line}:{self.end_line}:{unique_suffix}"
|
|
57
63
|
self.chunk_id = hashlib.sha256(id_string.encode()).hexdigest()[:16]
|
|
58
64
|
|
|
59
65
|
@property
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-vector-search
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.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,4 +1,4 @@
|
|
|
1
|
-
mcp_vector_search/__init__.py,sha256=
|
|
1
|
+
mcp_vector_search/__init__.py,sha256=M5nv5AoHPpQkDpjs3z7LVlatwiz3GoyAtx5eDyhiAx0,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
|
|
@@ -19,7 +19,7 @@ mcp_vector_search/cli/commands/mcp.py,sha256=Mk4g43R9yRiJVMxsDFUsZldKqY0yi2coQmh
|
|
|
19
19
|
mcp_vector_search/cli/commands/reset.py,sha256=bsIT6zjDf6gsvIkVaRaUClYzlTyNe--8t0NWkBY0ldU,13724
|
|
20
20
|
mcp_vector_search/cli/commands/search.py,sha256=yyou7wO9qZ_w2oiKdyOrk2WUxvkFpc-Up8hpflxYlyw,24802
|
|
21
21
|
mcp_vector_search/cli/commands/status.py,sha256=sa_0QHioCmPF5A7obqV2ls-9kmX_JYo7nq3XUe1dmrg,19630
|
|
22
|
-
mcp_vector_search/cli/commands/visualize.py,sha256=
|
|
22
|
+
mcp_vector_search/cli/commands/visualize.py,sha256=tipe_QLjkZboqEz8SfIx5mjYrAenqrKsQPnXkgG7GBg,21398
|
|
23
23
|
mcp_vector_search/cli/commands/watch.py,sha256=2pyWRoo4fIppFnyQ4sW4IBLHmpb_IwnTjRnzHkVBPcQ,8927
|
|
24
24
|
mcp_vector_search/config/__init__.py,sha256=r_qAQkU5gc0EQ2pv8EQARACe4klhrR_WRJqCb9lfGc0,54
|
|
25
25
|
mcp_vector_search/config/constants.py,sha256=afXR6SvLLd8QYY4MG4s1vq-hCJiQsE5PhnE-XG9lvb4,1092
|
|
@@ -34,7 +34,7 @@ mcp_vector_search/core/exceptions.py,sha256=3bCjT8wmrLz_0e_Tayr90049zNTKYFWZa19k
|
|
|
34
34
|
mcp_vector_search/core/factory.py,sha256=tM6Ft-V9buF7nn9xbRMU1ngji-BJOKt6BhtfQhFLmF4,10384
|
|
35
35
|
mcp_vector_search/core/git_hooks.py,sha256=xOfPpzgKoNTwM-vbhAihUucgudBQk45bCAVR5zJOFlQ,10878
|
|
36
36
|
mcp_vector_search/core/indexer.py,sha256=IpCzP50wLOttWuUI-NE0qwYq-LlbDo5lrGfVMFMzwAM,29089
|
|
37
|
-
mcp_vector_search/core/models.py,sha256=
|
|
37
|
+
mcp_vector_search/core/models.py,sha256=ynhb6-YuY7m4FwQBHdDbts3hYbJdr8UeYmQkag3EEKA,8814
|
|
38
38
|
mcp_vector_search/core/project.py,sha256=l81uc5B4CB8VXDbcHzF-_CagxIERDh23tH0iNqTePTs,10403
|
|
39
39
|
mcp_vector_search/core/scheduler.py,sha256=PBSlu-ieDYCXOMGYY7QKv9UReFEDPHNmwnUv_xb4vxg,11761
|
|
40
40
|
mcp_vector_search/core/search.py,sha256=9OC8-KwWdbw4y4QPQ-VXfz0encVHTJWYLtah3_chqG8,33682
|
|
@@ -57,8 +57,8 @@ mcp_vector_search/utils/__init__.py,sha256=Eq6lY-oPMfCt-GpPUbg9QbmTHuQVmTaVDBMU2
|
|
|
57
57
|
mcp_vector_search/utils/gitignore.py,sha256=GiHQu9kv9PRLsWuNS8kbpXsTaBdhlsSHTu1NrZ8Ug5Y,8162
|
|
58
58
|
mcp_vector_search/utils/timing.py,sha256=THC7mfbTYnUpnnDcblgQacYMzbEkfFoIShx6plmhCgg,11285
|
|
59
59
|
mcp_vector_search/utils/version.py,sha256=d7fS-CLemxb8UzZ9j18zH0Y0Ud097ljKKYYOPulnGPE,1138
|
|
60
|
-
mcp_vector_search-0.8.
|
|
61
|
-
mcp_vector_search-0.8.
|
|
62
|
-
mcp_vector_search-0.8.
|
|
63
|
-
mcp_vector_search-0.8.
|
|
64
|
-
mcp_vector_search-0.8.
|
|
60
|
+
mcp_vector_search-0.8.4.dist-info/METADATA,sha256=MZyBEwQ8cB6X5VBBPWdoAqnj_VLrD5hTLuJchLIo0IA,19120
|
|
61
|
+
mcp_vector_search-0.8.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
62
|
+
mcp_vector_search-0.8.4.dist-info/entry_points.txt,sha256=y3Ygtc_JiBchNEIL-tPABo7EbzBExGAxwGdkkeP5D2I,86
|
|
63
|
+
mcp_vector_search-0.8.4.dist-info/licenses/LICENSE,sha256=FqZUgGJH_tZKZLQsMCpXaLawRyLmyFKRVfMwYyEcyTs,1072
|
|
64
|
+
mcp_vector_search-0.8.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|