mcp-code-indexer 3.5.3__tar.gz → 3.5.5__tar.gz

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.
Files changed (39) hide show
  1. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/PKG-INFO +3 -3
  2. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/README.md +2 -2
  3. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/pyproject.toml +1 -1
  4. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/commands/makelocal.py +11 -0
  5. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/server/mcp_server.py +94 -49
  6. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/LICENSE +0 -0
  7. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/__init__.py +0 -0
  8. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/__main__.py +0 -0
  9. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/ask_handler.py +0 -0
  10. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/claude_api_handler.py +0 -0
  11. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/cleanup_manager.py +0 -0
  12. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/commands/__init__.py +0 -0
  13. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/data/stop_words_english.txt +0 -0
  14. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/__init__.py +0 -0
  15. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/connection_health.py +0 -0
  16. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/database.py +0 -0
  17. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/database_factory.py +0 -0
  18. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/exceptions.py +0 -0
  19. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/models.py +0 -0
  20. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/path_resolver.py +0 -0
  21. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/database/retry_executor.py +0 -0
  22. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/deepask_handler.py +0 -0
  23. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/error_handler.py +0 -0
  24. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/file_scanner.py +0 -0
  25. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/git_hook_handler.py +0 -0
  26. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/logging_config.py +0 -0
  27. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/main.py +0 -0
  28. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/middleware/__init__.py +0 -0
  29. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/middleware/error_middleware.py +0 -0
  30. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/migrations/001_initial.sql +0 -0
  31. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/migrations/002_performance_indexes.sql +0 -0
  32. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/migrations/003_project_overviews.sql +0 -0
  33. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/migrations/004_remove_branch_dependency.sql +0 -0
  34. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/migrations/005_remove_git_remotes.sql +0 -0
  35. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/query_preprocessor.py +0 -0
  36. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/server/__init__.py +0 -0
  37. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  38. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/token_counter.py +0 -0
  39. {mcp_code_indexer-3.5.3 → mcp_code_indexer-3.5.5}/src/mcp_code_indexer/tools/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mcp-code-indexer
3
- Version: 3.5.3
3
+ Version: 3.5.5
4
4
  Summary: MCP server that tracks file descriptions across codebases, enabling AI agents to efficiently navigate and understand code through searchable summaries and token-aware overviews.
5
5
  License: MIT
6
6
  Keywords: mcp,model-context-protocol,code-indexer,ai-tools,codebase-navigation,file-descriptions,llm-tools
@@ -40,8 +40,8 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  # MCP Code Indexer 🚀
42
42
 
43
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?38)](https://badge.fury.io/py/mcp-code-indexer)
44
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?38)](https://pypi.org/project/mcp-code-indexer/)
43
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?40)](https://badge.fury.io/py/mcp-code-indexer)
44
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?40)](https://pypi.org/project/mcp-code-indexer/)
45
45
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
46
46
 
47
47
  A production-ready **Model Context Protocol (MCP) server** that revolutionizes how AI agents navigate and understand codebases. Built for high-concurrency environments with advanced database resilience, the server provides instant access to intelligent descriptions, semantic search, and context-aware recommendations while maintaining 800+ writes/sec throughput.
@@ -1,7 +1,7 @@
1
1
  # MCP Code Indexer 🚀
2
2
 
3
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?38)](https://badge.fury.io/py/mcp-code-indexer)
4
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?38)](https://pypi.org/project/mcp-code-indexer/)
3
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?40)](https://badge.fury.io/py/mcp-code-indexer)
4
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?40)](https://pypi.org/project/mcp-code-indexer/)
5
5
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  A production-ready **Model Context Protocol (MCP) server** that revolutionizes how AI agents navigate and understand codebases. Built for high-concurrency environments with advanced database resilience, the server provides instant access to intelligent descriptions, semantic search, and context-aware recommendations while maintaining 800+ writes/sec throughput.
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "mcp-code-indexer"
7
- version = "3.5.3"
7
+ version = "3.5.5"
8
8
  description = "MCP server that tracks file descriptions across codebases, enabling AI agents to efficiently navigate and understand code through searchable summaries and token-aware overviews."
9
9
  authors = ["MCP Code Indexer Contributors"]
10
10
  maintainers = ["MCP Code Indexer Contributors"]
@@ -98,6 +98,10 @@ class MakeLocalCommand:
98
98
  # Create local database manager (this will initialize schema)
99
99
  local_db_manager = await self.db_factory.get_database_manager(str(folder_path_obj))
100
100
 
101
+ # For local databases, we'll create a project with a machine-independent approach
102
+ # We'll store the current folder path in aliases for reference, but the project
103
+ # will be found by being the single project in the local database
104
+
101
105
  # Migrate data
102
106
  await self._migrate_project_data(
103
107
  local_db_manager, project, file_descriptions, project_overview
@@ -159,12 +163,19 @@ class MakeLocalCommand:
159
163
  """
160
164
  Migrate project data to the local database.
161
165
 
166
+ For local databases, we update the project aliases to include the current
167
+ folder path since local database projects are found by being the single
168
+ project in the database rather than by path matching.
169
+
162
170
  Args:
163
171
  local_db_manager: Local database manager
164
172
  project: Project to migrate
165
173
  file_descriptions: File descriptions to migrate
166
174
  project_overview: Project overview to migrate (if any)
167
175
  """
176
+ # Update project aliases to include current folder path for reference
177
+ # Note: This will be machine-specific but that's OK for local databases
178
+
168
179
  # Create project in local database
169
180
  await local_db_manager.create_project(project)
170
181
  logger.info(f"Created project in local database: {project.name}")
@@ -742,40 +742,63 @@ class MCPCodeIndexServer:
742
742
  """
743
743
  Get or create a project ID using intelligent matching.
744
744
 
745
- Matches projects based on identification factors:
746
- 1. Project name (normalized, case-insensitive)
747
- 2. Folder path in aliases
748
-
749
- Projects are now identified primarily by name without git coupling.
745
+ For local databases: Uses the single project in the database (ignores paths).
746
+ For global databases: Matches projects based on name and folder path aliases.
750
747
  """
751
748
  project_name = arguments["projectName"]
752
749
  folder_path = arguments["folderPath"]
753
750
 
754
751
  # Get the appropriate database manager for this folder
755
752
  db_manager = await self.db_factory.get_database_manager(folder_path)
756
-
757
- # Normalize project name for case-insensitive matching
758
- normalized_name = project_name.lower()
759
-
760
- # Find potential project matches
761
- project = await self._find_matching_project(normalized_name, folder_path, db_manager)
762
- if project:
763
- # Update project metadata and aliases
764
- await self._update_existing_project(project, normalized_name, folder_path, db_manager)
753
+
754
+ # Check if this is a local database
755
+ is_local = self.db_factory.get_path_resolver().is_local_database(folder_path)
756
+
757
+ if is_local:
758
+ # For local databases: just get the single project (there should only be one)
759
+ all_projects = await db_manager.get_all_projects()
760
+ if all_projects:
761
+ project = all_projects[0] # Use the first (and should be only) project
762
+ # Update last accessed time
763
+ await db_manager.update_project_access_time(project.id)
764
+ logger.info(f"Using existing local project: {project.name} (ID: {project.id})")
765
+ return project.id
766
+ else:
767
+ # No project in local database - create one
768
+ project_id = str(uuid.uuid4())
769
+ project = Project(
770
+ id=project_id,
771
+ name=project_name.lower(),
772
+ aliases=[folder_path], # Store for reference but don't rely on it for matching
773
+ created=datetime.utcnow(),
774
+ last_accessed=datetime.utcnow(),
775
+ )
776
+ await db_manager.create_project(project)
777
+ logger.info(f"Created new local project: {project_name} (ID: {project_id})")
778
+ return project_id
765
779
  else:
766
- # Create new project with UUID
767
- project_id = str(uuid.uuid4())
768
- project = Project(
769
- id=project_id,
770
- name=normalized_name,
771
- aliases=[folder_path],
772
- created=datetime.utcnow(),
773
- last_accessed=datetime.utcnow(),
774
- )
775
- await db_manager.create_project(project)
776
- logger.info(f"Created new project: {normalized_name} ({project_id})")
780
+ # For global databases: use the existing matching logic
781
+ normalized_name = project_name.lower()
782
+
783
+ # Find potential project matches
784
+ project = await self._find_matching_project(normalized_name, folder_path, db_manager)
785
+ if project:
786
+ # Update project metadata and aliases
787
+ await self._update_existing_project(project, normalized_name, folder_path, db_manager)
788
+ else:
789
+ # Create new project with UUID
790
+ project_id = str(uuid.uuid4())
791
+ project = Project(
792
+ id=project_id,
793
+ name=normalized_name,
794
+ aliases=[folder_path],
795
+ created=datetime.utcnow(),
796
+ last_accessed=datetime.utcnow(),
797
+ )
798
+ await db_manager.create_project(project)
799
+ logger.info(f"Created new global project: {normalized_name} (ID: {project_id})")
777
800
 
778
- return project.id
801
+ return project.id
779
802
 
780
803
  async def _find_matching_project(
781
804
  self, normalized_name: str, folder_path: str, db_manager: DatabaseManager
@@ -850,8 +873,11 @@ class MCPCodeIndexServer:
850
873
  if not current_basenames:
851
874
  return False
852
875
 
876
+ # Get appropriate database manager for this folder
877
+ db_manager = await self.db_factory.get_database_manager(folder_path)
878
+
853
879
  # Get files already indexed for this project
854
- indexed_files = await self.db_manager.get_all_file_descriptions(project.id)
880
+ indexed_files = await db_manager.get_all_file_descriptions(project.id)
855
881
  indexed_basenames = {Path(fd.file_path).name for fd in indexed_files}
856
882
 
857
883
  if not indexed_basenames:
@@ -974,19 +1000,21 @@ class MCPCodeIndexServer:
974
1000
  )
975
1001
  logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
976
1002
 
1003
+ folder_path = arguments["folderPath"]
1004
+ db_manager = await self.db_factory.get_database_manager(folder_path)
977
1005
  project_id = await self._get_or_create_project_id(arguments)
978
- folder_path = Path(arguments["folderPath"])
1006
+ folder_path_obj = Path(folder_path)
979
1007
 
980
1008
  logger.info(f"Resolved project_id: {project_id}")
981
1009
 
982
1010
  # Run cleanup if needed (respects 30-minute cooldown)
983
1011
  cleaned_up_count = await self._run_cleanup_if_needed(
984
- project_id=project_id, project_root=folder_path
1012
+ project_id=project_id, project_root=folder_path_obj
985
1013
  )
986
1014
 
987
1015
  # Get file descriptions for this project (after cleanup)
988
1016
  logger.info("Retrieving file descriptions...")
989
- file_descriptions = await self.db_manager.get_all_file_descriptions(
1017
+ file_descriptions = await db_manager.get_all_file_descriptions(
990
1018
  project_id=project_id
991
1019
  )
992
1020
  logger.info(f"Found {len(file_descriptions)} file descriptions")
@@ -1001,7 +1029,7 @@ class MCPCodeIndexServer:
1001
1029
  )
1002
1030
 
1003
1031
  # Get overview tokens if available
1004
- overview = await self.db_manager.get_project_overview(project_id)
1032
+ overview = await db_manager.get_project_overview(project_id)
1005
1033
  overview_tokens = 0
1006
1034
  if overview and overview.overview:
1007
1035
  overview_tokens = self.token_counter.count_tokens(overview.overview)
@@ -1041,26 +1069,28 @@ class MCPCodeIndexServer:
1041
1069
  )
1042
1070
  logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
1043
1071
 
1072
+ folder_path = arguments["folderPath"]
1073
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1044
1074
  project_id = await self._get_or_create_project_id(arguments)
1045
- folder_path = Path(arguments["folderPath"])
1075
+ folder_path_obj = Path(folder_path)
1046
1076
 
1047
1077
  logger.info(f"Resolved project_id: {project_id}")
1048
1078
 
1049
1079
  # Get existing file descriptions
1050
1080
  logger.info("Retrieving existing file descriptions...")
1051
- existing_descriptions = await self.db_manager.get_all_file_descriptions(
1081
+ existing_descriptions = await db_manager.get_all_file_descriptions(
1052
1082
  project_id=project_id
1053
1083
  )
1054
1084
  existing_paths = {desc.file_path for desc in existing_descriptions}
1055
1085
  logger.info(f"Found {len(existing_paths)} existing descriptions")
1056
1086
 
1057
1087
  # Scan directory for files
1058
- logger.info(f"Scanning project directory: {folder_path}")
1059
- scanner = FileScanner(folder_path)
1088
+ logger.info(f"Scanning project directory: {folder_path_obj}")
1089
+ scanner = FileScanner(folder_path_obj)
1060
1090
  if not scanner.is_valid_project_directory():
1061
- logger.error(f"Invalid or inaccessible project directory: {folder_path}")
1091
+ logger.error(f"Invalid or inaccessible project directory: {folder_path_obj}")
1062
1092
  return {
1063
- "error": f"Invalid or inaccessible project directory: {folder_path}"
1093
+ "error": f"Invalid or inaccessible project directory: {folder_path_obj}"
1064
1094
  }
1065
1095
 
1066
1096
  missing_files = scanner.find_missing_files(existing_paths)
@@ -1097,11 +1127,13 @@ class MCPCodeIndexServer:
1097
1127
  self, arguments: Dict[str, Any]
1098
1128
  ) -> Dict[str, Any]:
1099
1129
  """Handle search_descriptions tool calls."""
1130
+ folder_path = arguments["folderPath"]
1131
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1100
1132
  project_id = await self._get_or_create_project_id(arguments)
1101
1133
  max_results = arguments.get("maxResults", 20)
1102
1134
 
1103
1135
  # Perform search
1104
- search_results = await self.db_manager.search_file_descriptions(
1136
+ search_results = await db_manager.search_file_descriptions(
1105
1137
  project_id=project_id, query=arguments["query"], max_results=max_results
1106
1138
  )
1107
1139
 
@@ -1127,10 +1159,12 @@ class MCPCodeIndexServer:
1127
1159
  self, arguments: Dict[str, Any]
1128
1160
  ) -> Dict[str, Any]:
1129
1161
  """Handle get_codebase_overview tool calls."""
1162
+ folder_path = arguments["folderPath"]
1163
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1130
1164
  project_id = await self._get_or_create_project_id(arguments)
1131
1165
 
1132
1166
  # Get all file descriptions
1133
- file_descriptions = await self.db_manager.get_all_file_descriptions(
1167
+ file_descriptions = await db_manager.get_all_file_descriptions(
1134
1168
  project_id=project_id
1135
1169
  )
1136
1170
 
@@ -1195,10 +1229,12 @@ class MCPCodeIndexServer:
1195
1229
  self, arguments: Dict[str, Any]
1196
1230
  ) -> Dict[str, Any]:
1197
1231
  """Handle get_codebase_overview tool calls for condensed overviews."""
1232
+ folder_path = arguments["folderPath"]
1233
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1198
1234
  project_id = await self._get_or_create_project_id(arguments)
1199
1235
 
1200
1236
  # Try to get existing overview
1201
- overview = await self.db_manager.get_project_overview(project_id)
1237
+ overview = await db_manager.get_project_overview(project_id)
1202
1238
 
1203
1239
  if overview:
1204
1240
  return {
@@ -1219,10 +1255,12 @@ class MCPCodeIndexServer:
1219
1255
  self, arguments: Dict[str, Any]
1220
1256
  ) -> Dict[str, Any]:
1221
1257
  """Handle update_codebase_overview tool calls."""
1258
+ folder_path = arguments["folderPath"]
1259
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1222
1260
  project_id = await self._get_or_create_project_id(arguments)
1223
1261
 
1224
1262
  # Get current file count and total tokens for context
1225
- file_descriptions = await self.db_manager.get_all_file_descriptions(
1263
+ file_descriptions = await db_manager.get_all_file_descriptions(
1226
1264
  project_id=project_id
1227
1265
  )
1228
1266
 
@@ -1238,7 +1276,7 @@ class MCPCodeIndexServer:
1238
1276
  total_tokens=total_tokens,
1239
1277
  )
1240
1278
 
1241
- await self.db_manager.create_project_overview(overview)
1279
+ await db_manager.create_project_overview(overview)
1242
1280
 
1243
1281
  return {
1244
1282
  "success": True,
@@ -1252,11 +1290,13 @@ class MCPCodeIndexServer:
1252
1290
  self, arguments: Dict[str, Any]
1253
1291
  ) -> Dict[str, Any]:
1254
1292
  """Handle get_word_frequency tool calls."""
1293
+ folder_path = arguments["folderPath"]
1294
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1255
1295
  project_id = await self._get_or_create_project_id(arguments)
1256
1296
  limit = arguments.get("limit", 200)
1257
1297
 
1258
1298
  # Analyze word frequency
1259
- result = await self.db_manager.analyze_word_frequency(
1299
+ result = await db_manager.analyze_word_frequency(
1260
1300
  project_id=project_id, limit=limit
1261
1301
  )
1262
1302
 
@@ -1273,11 +1313,13 @@ class MCPCodeIndexServer:
1273
1313
  self, arguments: Dict[str, Any]
1274
1314
  ) -> Dict[str, Any]:
1275
1315
  """Handle search_codebase_overview tool calls."""
1316
+ folder_path = arguments["folderPath"]
1317
+ db_manager = await self.db_factory.get_database_manager(folder_path)
1276
1318
  project_id = await self._get_or_create_project_id(arguments)
1277
1319
  search_word = arguments["searchWord"].lower()
1278
1320
 
1279
1321
  # Get the overview
1280
- overview = await self.db_manager.get_project_overview(project_id)
1322
+ overview = await db_manager.get_project_overview(project_id)
1281
1323
 
1282
1324
  if not overview or not overview.overview:
1283
1325
  return {
@@ -1541,9 +1583,10 @@ class MCPCodeIndexServer:
1541
1583
  total_cleaned = 0
1542
1584
 
1543
1585
  if project_id and project_root:
1544
- # Single project cleanup
1586
+ # Single project cleanup - use appropriate database for this project's folder
1545
1587
  try:
1546
- missing_files = await self.db_manager.cleanup_missing_files(
1588
+ folder_db_manager = await self.db_factory.get_database_manager(str(project_root))
1589
+ missing_files = await folder_db_manager.cleanup_missing_files(
1547
1590
  project_id=project_id, project_root=project_root
1548
1591
  )
1549
1592
  total_cleaned = len(missing_files)
@@ -1561,7 +1604,7 @@ class MCPCodeIndexServer:
1561
1604
  except Exception as e:
1562
1605
  logger.error(f"Error during cleanup: {e}")
1563
1606
  else:
1564
- # All projects cleanup (for periodic task)
1607
+ # All projects cleanup (for periodic task) - start with global database
1565
1608
  projects = await self.db_manager.get_all_projects()
1566
1609
 
1567
1610
  for project in projects:
@@ -1574,8 +1617,10 @@ class MCPCodeIndexServer:
1574
1617
  folder_path = Path(project.aliases[0])
1575
1618
  if not folder_path.exists():
1576
1619
  continue
1577
-
1578
- missing_files = await self.db_manager.cleanup_missing_files(
1620
+
1621
+ # Get appropriate database manager for this project's folder
1622
+ project_db_manager = await self.db_factory.get_database_manager(str(folder_path))
1623
+ missing_files = await project_db_manager.cleanup_missing_files(
1579
1624
  project_id=project.id, project_root=folder_path
1580
1625
  )
1581
1626
  total_cleaned += len(missing_files)