mcp-vector-search 0.15.7__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.

Files changed (86) hide show
  1. mcp_vector_search/__init__.py +10 -0
  2. mcp_vector_search/cli/__init__.py +1 -0
  3. mcp_vector_search/cli/commands/__init__.py +1 -0
  4. mcp_vector_search/cli/commands/auto_index.py +397 -0
  5. mcp_vector_search/cli/commands/chat.py +534 -0
  6. mcp_vector_search/cli/commands/config.py +393 -0
  7. mcp_vector_search/cli/commands/demo.py +358 -0
  8. mcp_vector_search/cli/commands/index.py +762 -0
  9. mcp_vector_search/cli/commands/init.py +658 -0
  10. mcp_vector_search/cli/commands/install.py +869 -0
  11. mcp_vector_search/cli/commands/install_old.py +700 -0
  12. mcp_vector_search/cli/commands/mcp.py +1254 -0
  13. mcp_vector_search/cli/commands/reset.py +393 -0
  14. mcp_vector_search/cli/commands/search.py +796 -0
  15. mcp_vector_search/cli/commands/setup.py +1133 -0
  16. mcp_vector_search/cli/commands/status.py +584 -0
  17. mcp_vector_search/cli/commands/uninstall.py +404 -0
  18. mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
  19. mcp_vector_search/cli/commands/visualize/cli.py +265 -0
  20. mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
  21. mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
  22. mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
  23. mcp_vector_search/cli/commands/visualize/graph_builder.py +709 -0
  24. mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
  25. mcp_vector_search/cli/commands/visualize/server.py +201 -0
  26. mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
  27. mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
  28. mcp_vector_search/cli/commands/visualize/templates/base.py +218 -0
  29. mcp_vector_search/cli/commands/visualize/templates/scripts.py +3670 -0
  30. mcp_vector_search/cli/commands/visualize/templates/styles.py +779 -0
  31. mcp_vector_search/cli/commands/visualize.py.original +2536 -0
  32. mcp_vector_search/cli/commands/watch.py +287 -0
  33. mcp_vector_search/cli/didyoumean.py +520 -0
  34. mcp_vector_search/cli/export.py +320 -0
  35. mcp_vector_search/cli/history.py +295 -0
  36. mcp_vector_search/cli/interactive.py +342 -0
  37. mcp_vector_search/cli/main.py +484 -0
  38. mcp_vector_search/cli/output.py +414 -0
  39. mcp_vector_search/cli/suggestions.py +375 -0
  40. mcp_vector_search/config/__init__.py +1 -0
  41. mcp_vector_search/config/constants.py +24 -0
  42. mcp_vector_search/config/defaults.py +200 -0
  43. mcp_vector_search/config/settings.py +146 -0
  44. mcp_vector_search/core/__init__.py +1 -0
  45. mcp_vector_search/core/auto_indexer.py +298 -0
  46. mcp_vector_search/core/config_utils.py +394 -0
  47. mcp_vector_search/core/connection_pool.py +360 -0
  48. mcp_vector_search/core/database.py +1237 -0
  49. mcp_vector_search/core/directory_index.py +318 -0
  50. mcp_vector_search/core/embeddings.py +294 -0
  51. mcp_vector_search/core/exceptions.py +89 -0
  52. mcp_vector_search/core/factory.py +318 -0
  53. mcp_vector_search/core/git_hooks.py +345 -0
  54. mcp_vector_search/core/indexer.py +1002 -0
  55. mcp_vector_search/core/llm_client.py +453 -0
  56. mcp_vector_search/core/models.py +294 -0
  57. mcp_vector_search/core/project.py +350 -0
  58. mcp_vector_search/core/scheduler.py +330 -0
  59. mcp_vector_search/core/search.py +952 -0
  60. mcp_vector_search/core/watcher.py +322 -0
  61. mcp_vector_search/mcp/__init__.py +5 -0
  62. mcp_vector_search/mcp/__main__.py +25 -0
  63. mcp_vector_search/mcp/server.py +752 -0
  64. mcp_vector_search/parsers/__init__.py +8 -0
  65. mcp_vector_search/parsers/base.py +296 -0
  66. mcp_vector_search/parsers/dart.py +605 -0
  67. mcp_vector_search/parsers/html.py +413 -0
  68. mcp_vector_search/parsers/javascript.py +643 -0
  69. mcp_vector_search/parsers/php.py +694 -0
  70. mcp_vector_search/parsers/python.py +502 -0
  71. mcp_vector_search/parsers/registry.py +223 -0
  72. mcp_vector_search/parsers/ruby.py +678 -0
  73. mcp_vector_search/parsers/text.py +186 -0
  74. mcp_vector_search/parsers/utils.py +265 -0
  75. mcp_vector_search/py.typed +1 -0
  76. mcp_vector_search/utils/__init__.py +42 -0
  77. mcp_vector_search/utils/gitignore.py +250 -0
  78. mcp_vector_search/utils/gitignore_updater.py +212 -0
  79. mcp_vector_search/utils/monorepo.py +339 -0
  80. mcp_vector_search/utils/timing.py +338 -0
  81. mcp_vector_search/utils/version.py +47 -0
  82. mcp_vector_search-0.15.7.dist-info/METADATA +884 -0
  83. mcp_vector_search-0.15.7.dist-info/RECORD +86 -0
  84. mcp_vector_search-0.15.7.dist-info/WHEEL +4 -0
  85. mcp_vector_search-0.15.7.dist-info/entry_points.txt +3 -0
  86. mcp_vector_search-0.15.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,8 @@
1
+ """Language parsers for MCP Vector Search."""
2
+
3
+ from .dart import DartParser
4
+ from .html import HTMLParser
5
+ from .php import PHPParser
6
+ from .ruby import RubyParser
7
+
8
+ __all__ = ["DartParser", "HTMLParser", "PHPParser", "RubyParser"]
@@ -0,0 +1,296 @@
1
+ """Base parser interface for MCP Vector Search."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from pathlib import Path
5
+
6
+ from ..config.constants import DEFAULT_CHUNK_SIZE
7
+ from ..core.models import CodeChunk
8
+ from . import utils
9
+
10
+
11
+ class BaseParser(ABC):
12
+ """Abstract base class for language parsers."""
13
+
14
+ def __init__(self, language: str) -> None:
15
+ """Initialize parser for a specific language.
16
+
17
+ Args:
18
+ language: Programming language name
19
+ """
20
+ self.language = language
21
+
22
+ @abstractmethod
23
+ async def parse_file(self, file_path: Path) -> list[CodeChunk]:
24
+ """Parse a file and extract code chunks.
25
+
26
+ Args:
27
+ file_path: Path to the file to parse
28
+
29
+ Returns:
30
+ List of code chunks extracted from the file
31
+ """
32
+ ...
33
+
34
+ @abstractmethod
35
+ async def parse_content(self, content: str, file_path: Path) -> list[CodeChunk]:
36
+ """Parse content and extract code chunks.
37
+
38
+ Args:
39
+ content: File content to parse
40
+ file_path: Path to the source file (for metadata)
41
+
42
+ Returns:
43
+ List of code chunks extracted from the content
44
+ """
45
+ ...
46
+
47
+ def supports_file(self, file_path: Path) -> bool:
48
+ """Check if this parser supports the given file.
49
+
50
+ Args:
51
+ file_path: Path to check
52
+
53
+ Returns:
54
+ True if this parser can handle the file
55
+ """
56
+ return file_path.suffix.lower() in self.get_supported_extensions()
57
+
58
+ @abstractmethod
59
+ def get_supported_extensions(self) -> list[str]:
60
+ """Get list of file extensions supported by this parser.
61
+
62
+ Returns:
63
+ List of file extensions (including the dot)
64
+ """
65
+ ...
66
+
67
+ def _calculate_complexity(self, node, language: str | None = None) -> float:
68
+ """Calculate cyclomatic complexity from AST node.
69
+
70
+ Cyclomatic complexity = Number of decision points + 1
71
+
72
+ Args:
73
+ node: AST node (tree-sitter)
74
+ language: Programming language for language-specific patterns (defaults to self.language)
75
+
76
+ Returns:
77
+ Complexity score (1.0 = simple, 10+ = complex)
78
+ """
79
+ if language is None:
80
+ language = self.language
81
+
82
+ if not hasattr(node, "children"):
83
+ return 1.0
84
+
85
+ complexity = 1.0 # Base complexity
86
+
87
+ # Language-specific decision node types
88
+ decision_nodes = {
89
+ "python": {
90
+ "if_statement",
91
+ "elif_clause",
92
+ "while_statement",
93
+ "for_statement",
94
+ "except_clause",
95
+ "with_statement",
96
+ "conditional_expression",
97
+ "boolean_operator", # and, or
98
+ },
99
+ "javascript": {
100
+ "if_statement",
101
+ "while_statement",
102
+ "for_statement",
103
+ "for_in_statement",
104
+ "switch_case",
105
+ "catch_clause",
106
+ "conditional_expression",
107
+ "ternary_expression",
108
+ },
109
+ "typescript": {
110
+ "if_statement",
111
+ "while_statement",
112
+ "for_statement",
113
+ "for_in_statement",
114
+ "switch_case",
115
+ "catch_clause",
116
+ "conditional_expression",
117
+ "ternary_expression",
118
+ },
119
+ "dart": {
120
+ "if_statement",
121
+ "while_statement",
122
+ "for_statement",
123
+ "for_in_statement",
124
+ "switch_case",
125
+ "catch_clause",
126
+ "conditional_expression",
127
+ },
128
+ "php": {
129
+ "if_statement",
130
+ "elseif_clause",
131
+ "while_statement",
132
+ "foreach_statement",
133
+ "for_statement",
134
+ "switch_case",
135
+ "catch_clause",
136
+ "ternary_expression",
137
+ },
138
+ "ruby": {
139
+ "if",
140
+ "unless",
141
+ "while",
142
+ "until",
143
+ "for",
144
+ "case",
145
+ "rescue",
146
+ "conditional",
147
+ },
148
+ }
149
+
150
+ nodes_to_count = decision_nodes.get(
151
+ language, decision_nodes.get("python", set())
152
+ )
153
+
154
+ def count_decision_points(n):
155
+ nonlocal complexity
156
+ if hasattr(n, "type") and n.type in nodes_to_count:
157
+ complexity += 1
158
+ if hasattr(n, "children"):
159
+ for child in n.children:
160
+ count_decision_points(child)
161
+
162
+ count_decision_points(node)
163
+ return complexity
164
+
165
+ def _create_chunk(
166
+ self,
167
+ content: str,
168
+ file_path: Path,
169
+ start_line: int,
170
+ end_line: int,
171
+ chunk_type: str = "code",
172
+ function_name: str | None = None,
173
+ class_name: str | None = None,
174
+ docstring: str | None = None,
175
+ complexity_score: float = 0.0,
176
+ decorators: list[str] | None = None,
177
+ parameters: list[dict] | None = None,
178
+ return_type: str | None = None,
179
+ chunk_id: str | None = None,
180
+ parent_chunk_id: str | None = None,
181
+ chunk_depth: int = 0,
182
+ ) -> CodeChunk:
183
+ """Create a code chunk with metadata.
184
+
185
+ Args:
186
+ content: Code content
187
+ file_path: Source file path
188
+ start_line: Starting line number (1-based)
189
+ end_line: Ending line number (1-based)
190
+ chunk_type: Type of chunk (code, function, class, etc.)
191
+ function_name: Function name if applicable
192
+ class_name: Class name if applicable
193
+ docstring: Docstring if applicable
194
+ complexity_score: Cyclomatic complexity score
195
+ decorators: List of decorators/annotations
196
+ parameters: List of function parameters with metadata
197
+ return_type: Return type annotation
198
+ chunk_id: Unique chunk identifier
199
+ parent_chunk_id: Parent chunk ID for hierarchical relationships
200
+ chunk_depth: Nesting level in code hierarchy
201
+
202
+ Returns:
203
+ CodeChunk instance
204
+ """
205
+ return CodeChunk(
206
+ content=content.strip(),
207
+ file_path=file_path,
208
+ start_line=start_line,
209
+ end_line=end_line,
210
+ language=self.language,
211
+ chunk_type=chunk_type,
212
+ function_name=function_name,
213
+ class_name=class_name,
214
+ docstring=docstring,
215
+ complexity_score=complexity_score,
216
+ decorators=decorators or [],
217
+ parameters=parameters or [],
218
+ return_type=return_type,
219
+ chunk_id=chunk_id,
220
+ parent_chunk_id=parent_chunk_id,
221
+ chunk_depth=chunk_depth,
222
+ )
223
+
224
+ def _split_into_lines(self, content: str) -> list[str]:
225
+ """Split content into lines, preserving line endings.
226
+
227
+ Args:
228
+ content: Content to split
229
+
230
+ Returns:
231
+ List of lines
232
+ """
233
+ return utils.split_into_lines(content)
234
+
235
+ def _get_line_range(self, lines: list[str], start_line: int, end_line: int) -> str:
236
+ """Extract a range of lines from content.
237
+
238
+ Args:
239
+ lines: List of lines
240
+ start_line: Starting line number (1-based)
241
+ end_line: Ending line number (1-based)
242
+
243
+ Returns:
244
+ Content for the specified line range
245
+ """
246
+ return utils.get_line_range(lines, start_line, end_line)
247
+
248
+
249
+ class FallbackParser(BaseParser):
250
+ """Fallback parser for unsupported languages using simple text chunking."""
251
+
252
+ def __init__(self, language: str = "text") -> None:
253
+ """Initialize fallback parser."""
254
+ super().__init__(language)
255
+
256
+ async def parse_file(self, file_path: Path) -> list[CodeChunk]:
257
+ """Parse file using simple text chunking."""
258
+ try:
259
+ with open(file_path, encoding="utf-8") as f:
260
+ content = f.read()
261
+ return await self.parse_content(content, file_path)
262
+ except Exception:
263
+ # Return empty list if file can't be read
264
+ return []
265
+
266
+ async def parse_content(self, content: str, file_path: Path) -> list[CodeChunk]:
267
+ """Parse content using simple text chunking."""
268
+ if not content.strip():
269
+ return []
270
+
271
+ lines = self._split_into_lines(content)
272
+ chunks = []
273
+
274
+ # Simple chunking: split into chunks of ~50 lines
275
+ chunk_size = DEFAULT_CHUNK_SIZE
276
+ for i in range(0, len(lines), chunk_size):
277
+ start_line = i + 1
278
+ end_line = min(i + chunk_size, len(lines))
279
+
280
+ chunk_content = self._get_line_range(lines, start_line, end_line)
281
+
282
+ if chunk_content.strip():
283
+ chunk = self._create_chunk(
284
+ content=chunk_content,
285
+ file_path=file_path,
286
+ start_line=start_line,
287
+ end_line=end_line,
288
+ chunk_type="text",
289
+ )
290
+ chunks.append(chunk)
291
+
292
+ return chunks
293
+
294
+ def get_supported_extensions(self) -> list[str]:
295
+ """Fallback parser supports all extensions."""
296
+ return ["*"] # Special marker for "all extensions"