Skip to content

Commit 8348e2b

Browse files
committed
feat: enhance find_files with filename search and performance improvements
- Add support for filename-only pattern matching (e.g., "test_*.py" finds files in any directory) - Implement directory tree traversal for better search performance - Fix Windows path separator issues by using forward slashes consistently - Add dual matching logic: both full path and filename pattern matching Breaking changes: None - fully backward compatible Performance: Significant improvement for large projects with deep directory structures
1 parent 7a2a820 commit 8348e2b

File tree

3 files changed

+54
-17
lines changed

3 files changed

+54
-17
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "code-index-mcp"
7-
version = "1.1.1"
7+
version = "1.2.0"
88
description = "Code indexing and analysis tools for LLMs using MCP"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/code_index_mcp/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
A Model Context Protocol server for code indexing, searching, and analysis.
44
"""
55

6-
__version__ = "1.1.1"
6+
__version__ = "1.2.0"

src/code_index_mcp/services/index_service.py

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import fnmatch
99
import json
1010
import logging
11+
import os
1112
import threading
1213
import time
13-
from typing import Dict, Any, Optional, Callable
14+
import traceback
15+
from typing import Dict, Any
1416
from mcp.server.fastmcp import Context
1517

1618
from .base_service import BaseService
@@ -98,13 +100,14 @@ def find_files_by_pattern(self, pattern: str) -> Dict[str, Any]:
98100
if not self.index_cache:
99101
self._index_project(self.base_path)
100102

101-
# Search using current index
103+
# Search using directory tree
102104
matching_files = []
103-
if self.index_cache and 'files' in self.index_cache:
104-
for file_entry in self.index_cache['files']:
105-
file_path = file_entry.get('path', '')
106-
if fnmatch.fnmatch(file_path, pattern):
107-
matching_files.append(file_path)
105+
if self.index_cache and 'directory_tree' in self.index_cache:
106+
matching_files = self._search_directory_tree(
107+
self.index_cache['directory_tree'],
108+
pattern,
109+
""
110+
)
108111

109112
# Return results - file watcher now handles all index updates proactively
110113
return ResponseFormatter.file_list_response(
@@ -220,15 +223,13 @@ def run_sync_rebuild():
220223
file_count = self._index_project(self.base_path)
221224

222225
duration = time.time() - start_time
223-
message = f"Background rebuild completed in {duration:.2f}s with {file_count} files"
224-
self.logger.info(message)
226+
self.logger.info("Background rebuild completed in %.2fs with %d files",
227+
duration, file_count)
225228

226229
return True
227230

228231
except Exception as e:
229-
error_msg = f"Background rebuild failed: {e}"
230-
self.logger.error(error_msg)
231-
import traceback
232+
self.logger.error("Background rebuild failed: %s", e)
232233
self.logger.error("Traceback: %s", traceback.format_exc())
233234
return False
234235
finally:
@@ -249,7 +250,7 @@ def on_complete(fut):
249250
else:
250251
self.logger.error("Background rebuild failed")
251252
except Exception as e:
252-
self.logger.error(f"Background rebuild thread failed: {e}")
253+
self.logger.error("Background rebuild thread failed: %s", e)
253254

254255
future.add_done_callback(on_complete)
255256

@@ -261,8 +262,7 @@ def on_complete(fut):
261262
with self._rebuild_lock:
262263
self.is_rebuilding = False
263264

264-
self.logger.error(f"Failed to start background rebuild: {e}")
265-
import traceback
265+
self.logger.error("Failed to start background rebuild: %s", e)
266266
self.logger.error("Traceback: %s", traceback.format_exc())
267267
return False
268268

@@ -293,3 +293,40 @@ def get_rebuild_status(self) -> dict:
293293
"is_rebuilding": is_rebuilding,
294294
"index_cache_size": len(self.index_cache.get('files', [])) if self.index_cache else 0
295295
}
296+
297+
def _search_directory_tree(self, tree: dict, pattern: str, current_path: str) -> list:
298+
"""
299+
Search files in directory tree using glob pattern.
300+
301+
Args:
302+
tree: Directory tree dictionary
303+
pattern: Glob pattern to match
304+
current_path: Current path being traversed
305+
306+
Returns:
307+
List of matching file paths
308+
"""
309+
matching_files = []
310+
311+
for name, subtree in tree.items():
312+
# Build the full path using forward slashes for consistency
313+
if current_path:
314+
full_path = f"{current_path}/{name}"
315+
else:
316+
full_path = name
317+
318+
if subtree is None:
319+
# This is a file
320+
# Try matching against full path
321+
if fnmatch.fnmatch(full_path, pattern):
322+
matching_files.append(full_path)
323+
# Also try matching against just the filename
324+
elif fnmatch.fnmatch(name, pattern):
325+
matching_files.append(full_path)
326+
else:
327+
# This is a directory, recurse into it
328+
matching_files.extend(
329+
self._search_directory_tree(subtree, pattern, full_path)
330+
)
331+
332+
return matching_files

0 commit comments

Comments
 (0)