mcp-code-indexer 2.4.0__py3-none-any.whl → 3.0.0__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.
@@ -32,7 +32,7 @@ from mcp_code_indexer.database.models import (
32
32
  from mcp_code_indexer.error_handler import setup_error_handling, ErrorHandler
33
33
  from mcp_code_indexer.middleware.error_middleware import create_tool_middleware, AsyncTaskManager
34
34
  from mcp_code_indexer.logging_config import get_logger
35
- from mcp_code_indexer.merge_handler import MergeHandler
35
+
36
36
 
37
37
  logger = logging.getLogger(__name__)
38
38
 
@@ -104,7 +104,6 @@ class MCPCodeIndexServer:
104
104
  retry_jitter=retry_jitter
105
105
  )
106
106
  self.token_counter = TokenCounter(token_limit)
107
- self.merge_handler = MergeHandler(self.db_manager)
108
107
 
109
108
  # Setup error handling
110
109
  self.logger = get_logger(__name__)
@@ -248,10 +247,7 @@ class MCPCodeIndexServer:
248
247
  "type": "string",
249
248
  "description": "Absolute path to the project folder on disk"
250
249
  },
251
- "branch": {
252
- "type": "string",
253
- "description": "Git branch name (e.g., 'main', 'develop')"
254
- },
250
+
255
251
  "remoteOrigin": {
256
252
  "type": "string",
257
253
  "description": "Git remote origin URL if available"
@@ -265,7 +261,7 @@ class MCPCodeIndexServer:
265
261
  "description": "Relative path to the file from project root"
266
262
  }
267
263
  },
268
- "required": ["projectName", "folderPath", "branch", "filePath"],
264
+ "required": ["projectName", "folderPath", "filePath"],
269
265
  "additionalProperties": False
270
266
  }
271
267
  ),
@@ -277,31 +273,29 @@ class MCPCodeIndexServer:
277
273
  "properties": {
278
274
  "projectName": {"type": "string", "description": "The name of the project"},
279
275
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
280
- "branch": {"type": "string", "description": "Git branch name"},
281
276
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
282
277
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
283
278
  "filePath": {"type": "string", "description": "Relative path to the file from project root"},
284
279
  "description": {"type": "string", "description": "Detailed description of the file's contents"},
285
280
  "fileHash": {"type": "string", "description": "SHA-256 hash of the file contents (optional)"}
286
281
  },
287
- "required": ["projectName", "folderPath", "branch", "filePath", "description"],
282
+ "required": ["projectName", "folderPath", "filePath", "description"],
288
283
  "additionalProperties": False
289
284
  }
290
285
  ),
291
286
  types.Tool(
292
287
  name="check_codebase_size",
293
- description="Checks the total token count of a codebase's file structure and descriptions - if you're in a git repo be sure to run `git rev-parse --abbrev-ref HEAD` to see what branch you're on before running this tool. Returns whether the codebase is 'large' and recommends using search instead of the full overview.",
288
+ description="Checks the total token count of a codebase's file structure and descriptions. Returns whether the codebase is 'large' and recommends using search instead of the full overview.",
294
289
  inputSchema={
295
290
  "type": "object",
296
291
  "properties": {
297
292
  "projectName": {"type": "string", "description": "The name of the project"},
298
293
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
299
- "branch": {"type": "string", "description": "Git branch name"},
300
294
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
301
295
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
302
296
  "tokenLimit": {"type": "integer", "description": "Optional token limit override (defaults to server configuration)"}
303
297
  },
304
- "required": ["projectName", "folderPath", "branch"],
298
+ "required": ["projectName", "folderPath"],
305
299
  "additionalProperties": False
306
300
  }
307
301
  ),
@@ -313,12 +307,11 @@ class MCPCodeIndexServer:
313
307
  "properties": {
314
308
  "projectName": {"type": "string", "description": "The name of the project"},
315
309
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
316
- "branch": {"type": "string", "description": "Git branch name"},
317
310
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
318
311
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
319
312
  "limit": {"type": "integer", "description": "Maximum number of missing files to return (optional)"}
320
313
  },
321
- "required": ["projectName", "folderPath", "branch"],
314
+ "required": ["projectName", "folderPath"],
322
315
  "additionalProperties": False
323
316
  }
324
317
  ),
@@ -330,13 +323,12 @@ class MCPCodeIndexServer:
330
323
  "properties": {
331
324
  "projectName": {"type": "string", "description": "The name of the project"},
332
325
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
333
- "branch": {"type": "string", "description": "Git branch to search in"},
334
326
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
335
327
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
336
328
  "query": {"type": "string", "description": "Search query (e.g., 'authentication middleware', 'database models')"},
337
329
  "maxResults": {"type": "integer", "default": 20, "description": "Maximum number of results to return"}
338
330
  },
339
- "required": ["projectName", "folderPath", "branch", "query"],
331
+ "required": ["projectName", "folderPath", "query"],
340
332
  "additionalProperties": False
341
333
  }
342
334
  ),
@@ -348,57 +340,25 @@ class MCPCodeIndexServer:
348
340
  "properties": {
349
341
  "projectName": {"type": "string", "description": "The name of the project"},
350
342
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
351
- "branch": {"type": "string", "description": "Git branch name"},
352
343
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
353
344
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"}
354
345
  },
355
- "required": ["projectName", "folderPath", "branch"],
356
- "additionalProperties": False
357
- }
358
- ),
359
- types.Tool(
360
- name="merge_branch_descriptions",
361
- description="Merges file descriptions from one branch to another. This is a two-stage process: first call without resolutions returns conflicts where the same file has different descriptions in each branch. Second call with resolutions completes the merge.",
362
- inputSchema={
363
- "type": "object",
364
- "properties": {
365
- "projectName": {"type": "string", "description": "The name of the project"},
366
- "folderPath": {"type": "string", "description": "Absolute path to the project folder"},
367
- "remoteOrigin": {"type": "string", "description": "Git remote origin URL"},
368
- "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
369
- "sourceBranch": {"type": "string", "description": "Branch to merge from (e.g., 'feature/new-ui')"},
370
- "targetBranch": {"type": "string", "description": "Branch to merge into (e.g., 'main')"},
371
- "conflictResolutions": {
372
- "type": ["array", "null"],
373
- "description": "Array of resolved conflicts (only for second stage)",
374
- "items": {
375
- "type": "object",
376
- "properties": {
377
- "conflictId": {"type": "string", "description": "ID of the conflict to resolve"},
378
- "resolvedDescription": {"type": "string", "description": "Final description to use after merge"}
379
- },
380
- "required": ["conflictId", "resolvedDescription"],
381
- "additionalProperties": False
382
- }
383
- }
384
- },
385
- "required": ["projectName", "folderPath", "sourceBranch", "targetBranch"],
346
+ "required": ["projectName", "folderPath"],
386
347
  "additionalProperties": False
387
348
  }
388
349
  ),
389
350
  types.Tool(
390
351
  name="get_codebase_overview",
391
- description="Returns a condensed, interpretive overview of the entire codebase - if you're in a git repo be sure to run `git rev-parse --abbrev-ref HEAD` to see what branch you're on before running this tool. This is a single comprehensive narrative that captures the architecture, key components, relationships, and design patterns. Unlike get_all_descriptions which lists every file, this provides a holistic view suitable for understanding the codebase's structure and purpose. If no overview exists, returns empty string.",
352
+ description="Returns a condensed, interpretive overview of the entire codebase. This is a single comprehensive narrative that captures the architecture, key components, relationships, and design patterns. Unlike get_all_descriptions which lists every file, this provides a holistic view suitable for understanding the codebase's structure and purpose. If no overview exists, returns empty string.",
392
353
  inputSchema={
393
354
  "type": "object",
394
355
  "properties": {
395
356
  "projectName": {"type": "string", "description": "The name of the project"},
396
357
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
397
- "branch": {"type": "string", "description": "Git branch name"},
398
358
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
399
359
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"}
400
360
  },
401
- "required": ["projectName", "folderPath", "branch"],
361
+ "required": ["projectName", "folderPath"],
402
362
  "additionalProperties": False
403
363
  }
404
364
  ),
@@ -444,29 +404,27 @@ src/
444
404
  "properties": {
445
405
  "projectName": {"type": "string", "description": "The name of the project"},
446
406
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
447
- "branch": {"type": "string", "description": "Git branch name"},
448
407
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
449
408
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
450
409
  "overview": {"type": "string", "description": "Comprehensive narrative overview of the codebase (10-30k tokens recommended)"}
451
410
  },
452
- "required": ["projectName", "folderPath", "branch", "overview"],
411
+ "required": ["projectName", "folderPath", "overview"],
453
412
  "additionalProperties": False
454
413
  }
455
414
  ),
456
415
  types.Tool(
457
416
  name="get_word_frequency",
458
- description="Analyzes all file descriptions to find the most frequently used technical terms - if you're in a git repo be sure to run `git rev-parse --abbrev-ref HEAD` to see what branch you're on before running this tool. Filters out common English stop words and symbols, returning the top 200 meaningful terms. Useful for understanding the codebase's domain vocabulary and finding all functions/files related to specific concepts.",
417
+ description="Analyzes all file descriptions to find the most frequently used technical terms. Filters out common English stop words and symbols, returning the top 200 meaningful terms. Useful for understanding the codebase's domain vocabulary and finding all functions/files related to specific concepts.",
459
418
  inputSchema={
460
419
  "type": "object",
461
420
  "properties": {
462
421
  "projectName": {"type": "string", "description": "The name of the project"},
463
422
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
464
- "branch": {"type": "string", "description": "Git branch name"},
465
423
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
466
424
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
467
425
  "limit": {"type": "integer", "default": 200, "description": "Number of top terms to return"}
468
426
  },
469
- "required": ["projectName", "folderPath", "branch"],
427
+ "required": ["projectName", "folderPath"],
470
428
  "additionalProperties": False
471
429
  }
472
430
  ),
@@ -487,12 +445,11 @@ src/
487
445
  "properties": {
488
446
  "projectName": {"type": "string", "description": "The name of the project"},
489
447
  "folderPath": {"type": "string", "description": "Absolute path to the project folder on disk"},
490
- "branch": {"type": "string", "description": "Git branch name"},
491
448
  "remoteOrigin": {"type": "string", "description": "Git remote origin URL if available"},
492
449
  "upstreamOrigin": {"type": "string", "description": "Upstream repository URL if this is a fork"},
493
450
  "searchWord": {"type": "string", "description": "Single word to search for in the overview"}
494
451
  },
495
- "required": ["projectName", "folderPath", "branch", "searchWord"],
452
+ "required": ["projectName", "folderPath", "searchWord"],
496
453
  "additionalProperties": False
497
454
  }
498
455
  )
@@ -518,7 +475,7 @@ src/
518
475
  "get_codebase_overview": self._handle_get_condensed_overview,
519
476
  "update_codebase_overview": self._handle_update_codebase_overview,
520
477
  "get_word_frequency": self._handle_get_word_frequency,
521
- "merge_branch_descriptions": self._handle_merge_branch_descriptions,
478
+
522
479
  "check_database_health": self._handle_check_database_health,
523
480
  "search_codebase_overview": self._handle_search_codebase_overview,
524
481
  }
@@ -574,7 +531,7 @@ src/
574
531
  remote_origin = arguments.get("remoteOrigin")
575
532
  upstream_origin = arguments.get("upstreamOrigin")
576
533
  folder_path = arguments["folderPath"]
577
- branch = arguments.get("branch", "main")
534
+
578
535
 
579
536
  # Normalize project name for case-insensitive matching
580
537
  normalized_name = project_name.lower()
@@ -590,7 +547,7 @@ src/
590
547
  # Check if upstream inheritance is needed
591
548
  if upstream_origin and await self.db_manager.check_upstream_inheritance_needed(project):
592
549
  try:
593
- inherited_count = await self.db_manager.inherit_from_upstream(project, branch)
550
+ inherited_count = await self.db_manager.inherit_from_upstream(project)
594
551
  if inherited_count > 0:
595
552
  logger.info(f"Auto-inherited {inherited_count} descriptions from upstream for {normalized_name}")
596
553
  except Exception as e:
@@ -613,7 +570,7 @@ src/
613
570
  # Auto-inherit from upstream if needed
614
571
  if upstream_origin:
615
572
  try:
616
- inherited_count = await self.db_manager.inherit_from_upstream(project, branch)
573
+ inherited_count = await self.db_manager.inherit_from_upstream(project)
617
574
  if inherited_count > 0:
618
575
  logger.info(f"Auto-inherited {inherited_count} descriptions from upstream for {normalized_name}")
619
576
  except Exception as e:
@@ -707,7 +664,7 @@ src/
707
664
  return False
708
665
 
709
666
  # Get files already indexed for this project
710
- indexed_files = await self.db_manager.get_all_file_descriptions(project.id, "main")
667
+ indexed_files = await self.db_manager.get_all_file_descriptions(project.id)
711
668
  indexed_basenames = {Path(fd.file_path).name for fd in indexed_files}
712
669
 
713
670
  if not indexed_basenames:
@@ -764,65 +721,14 @@ src/
764
721
  await self.db_manager.update_project(project)
765
722
  logger.debug(f"Updated project metadata for {project.name}")
766
723
 
767
- async def _resolve_branch(self, project_id: str, requested_branch: str) -> str:
768
- """
769
- Resolve the actual branch to use for operations.
770
-
771
- For new projects or branches with no existing files, uses the requested branch.
772
- For existing projects, tries to find a consistent branch to avoid data fragmentation.
773
-
774
- Returns the resolved branch name.
775
- """
776
- try:
777
- # Get all branches and their file counts for this project
778
- branch_counts = await self.db_manager.get_branch_file_counts(project_id)
779
-
780
- # If no existing data, use the requested branch
781
- if not branch_counts:
782
- return requested_branch
783
-
784
- # If requested branch has files, use it
785
- if requested_branch in branch_counts and branch_counts[requested_branch] > 0:
786
- return requested_branch
787
-
788
- # Try common branch name variations to find existing data
789
- common_variations = {
790
- 'main': ['master', 'develop', 'development', 'dev'],
791
- 'master': ['main', 'develop', 'development', 'dev'],
792
- 'develop': ['development', 'main', 'master', 'dev'],
793
- 'development': ['develop', 'main', 'master', 'dev'],
794
- 'dev': ['develop', 'development', 'main', 'master']
795
- }
796
-
797
- # Try variations of the requested branch
798
- if requested_branch.lower() in common_variations:
799
- for variation in common_variations[requested_branch.lower()]:
800
- if variation in branch_counts and branch_counts[variation] > 0:
801
- logger.info(f"Resolved branch '{requested_branch}' to existing branch '{variation}' with {branch_counts[variation]} files")
802
- return variation
803
-
804
- # If no variations found, check if we should use the main data branch
805
- # (to avoid fragmenting data across multiple branches)
806
- best_branch = max(branch_counts.items(), key=lambda x: x[1])
807
- if best_branch[1] > 10: # Only if there's substantial existing data
808
- logger.info(f"Using primary branch '{best_branch[0]}' instead of '{requested_branch}' to avoid data fragmentation")
809
- return best_branch[0]
810
-
811
- # Fall back to requested branch for new/small projects
812
- return requested_branch
813
-
814
- except Exception as e:
815
- logger.warning(f"Error resolving branch: {e}")
816
- return requested_branch
724
+
817
725
 
818
726
  async def _handle_get_file_description(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
819
727
  """Handle get_file_description tool calls."""
820
728
  project_id = await self._get_or_create_project_id(arguments)
821
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
822
729
 
823
730
  file_desc = await self.db_manager.get_file_description(
824
731
  project_id=project_id,
825
- branch=resolved_branch,
826
732
  file_path=arguments["filePath"]
827
733
  )
828
734
 
@@ -844,19 +750,16 @@ src/
844
750
  """Handle update_file_description tool calls."""
845
751
  logger.info(f"Updating file description for: {arguments['filePath']}")
846
752
  logger.info(f"Project: {arguments.get('projectName', 'Unknown')}")
847
- logger.info(f"Branch: {arguments.get('branch', 'Unknown')}")
848
753
 
849
754
  description_length = len(arguments.get("description", ""))
850
755
  logger.info(f"Description length: {description_length} characters")
851
756
 
852
757
  project_id = await self._get_or_create_project_id(arguments)
853
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
854
758
 
855
- logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
759
+ logger.info(f"Resolved project_id: {project_id}")
856
760
 
857
761
  file_desc = FileDescription(
858
762
  project_id=project_id,
859
- branch=resolved_branch,
860
763
  file_path=arguments["filePath"],
861
764
  description=arguments["description"],
862
765
  file_hash=arguments.get("fileHash"),
@@ -879,28 +782,24 @@ src/
879
782
  """Handle check_codebase_size tool calls."""
880
783
  logger.info(f"Checking codebase size for: {arguments.get('projectName', 'Unknown')}")
881
784
  logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
882
- logger.info(f"Branch: {arguments.get('branch', 'Unknown')}")
883
785
 
884
786
  project_id = await self._get_or_create_project_id(arguments)
885
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
886
787
  folder_path = Path(arguments["folderPath"])
887
788
 
888
- logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
789
+ logger.info(f"Resolved project_id: {project_id}")
889
790
 
890
791
  # Clean up descriptions for files that no longer exist
891
792
  logger.info("Cleaning up descriptions for missing files...")
892
793
  cleaned_up_files = await self.db_manager.cleanup_missing_files(
893
794
  project_id=project_id,
894
- branch=resolved_branch,
895
795
  project_root=folder_path
896
796
  )
897
797
  logger.info(f"Cleaned up {len(cleaned_up_files)} missing files")
898
798
 
899
- # Get file descriptions for this project/branch (after cleanup)
799
+ # Get file descriptions for this project (after cleanup)
900
800
  logger.info("Retrieving file descriptions...")
901
801
  file_descriptions = await self.db_manager.get_all_file_descriptions(
902
- project_id=project_id,
903
- branch=resolved_branch
802
+ project_id=project_id
904
803
  )
905
804
  logger.info(f"Found {len(file_descriptions)} file descriptions")
906
805
 
@@ -912,7 +811,7 @@ src/
912
811
  descriptions_tokens = self.token_counter.calculate_codebase_tokens(file_descriptions)
913
812
 
914
813
  # Get overview tokens if available
915
- overview = await self.db_manager.get_project_overview(project_id, resolved_branch)
814
+ overview = await self.db_manager.get_project_overview(project_id)
916
815
  overview_tokens = 0
917
816
  if overview and overview.overview:
918
817
  overview_tokens = self.token_counter.count_tokens(overview.overview)
@@ -943,16 +842,14 @@ src/
943
842
  logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
944
843
 
945
844
  project_id = await self._get_or_create_project_id(arguments)
946
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
947
845
  folder_path = Path(arguments["folderPath"])
948
846
 
949
- logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
847
+ logger.info(f"Resolved project_id: {project_id}")
950
848
 
951
849
  # Get existing file descriptions
952
850
  logger.info("Retrieving existing file descriptions...")
953
851
  existing_descriptions = await self.db_manager.get_all_file_descriptions(
954
- project_id=project_id,
955
- branch=resolved_branch
852
+ project_id=project_id
956
853
  )
957
854
  existing_paths = {desc.file_path for desc in existing_descriptions}
958
855
  logger.info(f"Found {len(existing_paths)} existing descriptions")
@@ -993,13 +890,11 @@ src/
993
890
  async def _handle_search_descriptions(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
994
891
  """Handle search_descriptions tool calls."""
995
892
  project_id = await self._get_or_create_project_id(arguments)
996
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
997
893
  max_results = arguments.get("maxResults", 20)
998
894
 
999
895
  # Perform search
1000
896
  search_results = await self.db_manager.search_file_descriptions(
1001
897
  project_id=project_id,
1002
- branch=resolved_branch,
1003
898
  query=arguments["query"],
1004
899
  max_results=max_results
1005
900
  )
@@ -1023,12 +918,10 @@ src/
1023
918
  async def _handle_get_codebase_overview(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1024
919
  """Handle get_codebase_overview tool calls."""
1025
920
  project_id = await self._get_or_create_project_id(arguments)
1026
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
1027
921
 
1028
922
  # Get all file descriptions
1029
923
  file_descriptions = await self.db_manager.get_all_file_descriptions(
1030
- project_id=project_id,
1031
- branch=resolved_branch
924
+ project_id=project_id
1032
925
  )
1033
926
 
1034
927
  # Calculate total tokens
@@ -1040,8 +933,6 @@ src/
1040
933
 
1041
934
  return {
1042
935
  "projectName": arguments["projectName"],
1043
- "branch": resolved_branch,
1044
- "requestedBranch": arguments["branch"] if arguments["branch"] != resolved_branch else None,
1045
936
  "totalFiles": len(file_descriptions),
1046
937
  "totalTokens": total_tokens,
1047
938
  "isLarge": is_large,
@@ -1092,77 +983,14 @@ src/
1092
983
 
1093
984
  return convert_structure(root)
1094
985
 
1095
- async def _handle_merge_branch_descriptions(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1096
- """Handle merge_branch_descriptions tool calls."""
1097
- project_id = await self._get_or_create_project_id(arguments)
1098
- source_branch = arguments["sourceBranch"]
1099
- target_branch = arguments["targetBranch"]
1100
- conflict_resolutions = arguments.get("conflictResolutions")
1101
-
1102
- if conflict_resolutions is None:
1103
- # Phase 1: Detect conflicts
1104
- session = await self.merge_handler.start_merge_phase1(
1105
- project_id, source_branch, target_branch
1106
- )
1107
-
1108
- if session.get_conflict_count() == 0:
1109
- # No conflicts, can merge immediately
1110
- return {
1111
- "phase": "completed",
1112
- "conflicts": [],
1113
- "message": f"No conflicts detected. Merge from {source_branch} to {target_branch} can proceed automatically.",
1114
- "sourceBranch": source_branch,
1115
- "targetBranch": target_branch,
1116
- "conflictCount": 0
1117
- }
1118
- else:
1119
- # Return conflicts for resolution
1120
- return {
1121
- "phase": "conflicts_detected",
1122
- "sessionId": session.session_id,
1123
- "conflicts": [conflict.to_dict() for conflict in session.conflicts],
1124
- "conflictCount": session.get_conflict_count(),
1125
- "sourceBranch": source_branch,
1126
- "targetBranch": target_branch,
1127
- "message": f"Found {session.get_conflict_count()} conflicts that need resolution."
1128
- }
1129
- else:
1130
- # Phase 2: Apply resolutions
1131
- # Find the session ID from conflict resolutions
1132
- if not conflict_resolutions:
1133
- from ..error_handler import ValidationError
1134
- raise ValidationError("Conflict resolutions required for phase 2")
1135
-
1136
- # For simplicity, create a new session and resolve immediately
1137
- # In a production system, you'd want to track session IDs properly
1138
- session = await self.merge_handler.start_merge_phase1(
1139
- project_id, source_branch, target_branch
1140
- )
1141
-
1142
- if session.get_conflict_count() == 0:
1143
- return {
1144
- "phase": "completed",
1145
- "message": "No conflicts to resolve",
1146
- "sourceBranch": source_branch,
1147
- "targetBranch": target_branch
1148
- }
1149
-
1150
- result = await self.merge_handler.complete_merge_phase2(
1151
- session.session_id, conflict_resolutions
1152
- )
1153
-
1154
- return {
1155
- "phase": "completed",
1156
- **result
1157
- }
986
+
1158
987
 
1159
988
  async def _handle_get_condensed_overview(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1160
989
  """Handle get_codebase_overview tool calls for condensed overviews."""
1161
990
  project_id = await self._get_or_create_project_id(arguments)
1162
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
1163
991
 
1164
992
  # Try to get existing overview
1165
- overview = await self.db_manager.get_project_overview(project_id, resolved_branch)
993
+ overview = await self.db_manager.get_project_overview(project_id)
1166
994
 
1167
995
  if overview:
1168
996
  return {
@@ -1182,13 +1010,11 @@ src/
1182
1010
  async def _handle_update_codebase_overview(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1183
1011
  """Handle update_codebase_overview tool calls."""
1184
1012
  project_id = await self._get_or_create_project_id(arguments)
1185
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
1186
1013
  folder_path = Path(arguments["folderPath"])
1187
1014
 
1188
1015
  # Get current file count and total tokens for context
1189
1016
  file_descriptions = await self.db_manager.get_all_file_descriptions(
1190
- project_id=project_id,
1191
- branch=resolved_branch
1017
+ project_id=project_id
1192
1018
  )
1193
1019
 
1194
1020
  total_files = len(file_descriptions)
@@ -1197,7 +1023,6 @@ src/
1197
1023
  # Create overview record
1198
1024
  overview = ProjectOverview(
1199
1025
  project_id=project_id,
1200
- branch=resolved_branch,
1201
1026
  overview=arguments["overview"],
1202
1027
  last_modified=datetime.utcnow(),
1203
1028
  total_files=total_files,
@@ -1217,13 +1042,11 @@ src/
1217
1042
  async def _handle_get_word_frequency(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1218
1043
  """Handle get_word_frequency tool calls."""
1219
1044
  project_id = await self._get_or_create_project_id(arguments)
1220
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
1221
1045
  limit = arguments.get("limit", 200)
1222
1046
 
1223
1047
  # Analyze word frequency
1224
1048
  result = await self.db_manager.analyze_word_frequency(
1225
1049
  project_id=project_id,
1226
- branch=resolved_branch,
1227
1050
  limit=limit
1228
1051
  )
1229
1052
 
@@ -1236,11 +1059,10 @@ src/
1236
1059
  async def _handle_search_codebase_overview(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
1237
1060
  """Handle search_codebase_overview tool calls."""
1238
1061
  project_id = await self._get_or_create_project_id(arguments)
1239
- resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
1240
1062
  search_word = arguments["searchWord"].lower()
1241
1063
 
1242
1064
  # Get the overview
1243
- overview = await self.db_manager.get_project_overview(project_id, resolved_branch)
1065
+ overview = await self.db_manager.get_project_overview(project_id)
1244
1066
 
1245
1067
  if not overview or not overview.overview:
1246
1068
  return {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-code-indexer
3
- Version: 2.4.0
3
+ Version: 3.0.0
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
  Author: MCP Code Indexer Contributors
6
6
  Maintainer: MCP Code Indexer Contributors
@@ -59,8 +59,8 @@ Dynamic: requires-python
59
59
 
60
60
  # MCP Code Indexer 🚀
61
61
 
62
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?18)](https://badge.fury.io/py/mcp-code-indexer)
63
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?18)](https://pypi.org/project/mcp-code-indexer/)
62
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?19)](https://badge.fury.io/py/mcp-code-indexer)
63
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?19)](https://pypi.org/project/mcp-code-indexer/)
64
64
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
65
65
 
66
66
  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,11 +1,12 @@
1
1
  mcp_code_indexer/__init__.py,sha256=GhY2NLQ6lH3n5mxqw0t8T1gmZGKhM6KvjhZH8xW5O-A,1686
2
2
  mcp_code_indexer/__main__.py,sha256=4Edinoe0ug43hobuLYcjTmGp2YJnlFYN4_8iKvUBJ0Q,213
3
- mcp_code_indexer/ask_handler.py,sha256=71hwd3FLMBBxplmNMQMki03BFpeCy0sf4HtdTrVe4ks,8598
4
- mcp_code_indexer/claude_api_handler.py,sha256=s69aZVQx4SUFXuGvqKVBLYtEsSFHY9_uTCzDT-kpgcE,13660
5
- mcp_code_indexer/deepask_handler.py,sha256=bNwZFuiSzU8s7gYM_TB-3QyY7jRy38k752MRrj-s7_s,18634
3
+ mcp_code_indexer/ask_handler.py,sha256=rFljJtqP_YL3E9H2Hgk04yURzHw_sqm6muB5RTlP_-o,8397
4
+ mcp_code_indexer/claude_api_handler.py,sha256=4lgp-KsDMOmjrln3QhdJuM5pHvaB3kUwHOUk9l5adi4,13628
5
+ mcp_code_indexer/cleanup_manager.py,sha256=1x2de8Mr9dL92q4ubEebsWSF_2n8Yxk549ZohYHNIkU,9358
6
+ mcp_code_indexer/deepask_handler.py,sha256=iAFA1pKfAnurHBprIyP1TaecPzZ5YhBs-oR8Eccxoe4,18323
6
7
  mcp_code_indexer/error_handler.py,sha256=cNSUFFrGBMLDv4qa78c7495L1wSl_dXCRbzCJOidx-Q,11590
7
8
  mcp_code_indexer/file_scanner.py,sha256=ctXeZMROgDThEtjzsANTK9TbK-fhTScMBd4iyuleBT4,11734
8
- mcp_code_indexer/git_hook_handler.py,sha256=k6QpoLI-5D9EvrLQrHWMII2qNu21daRX_jXlk9U6bGI,36976
9
+ mcp_code_indexer/git_hook_handler.py,sha256=OMPfQlykqR2_cE5IxGqbAI92afLOOJxsvXbAQIZrdLU,36579
9
10
  mcp_code_indexer/logging_config.py,sha256=tf_U-Zz_axDXRV9s7TfHEeUrBjT1QBWkzPuiyZMffBU,10252
10
11
  mcp_code_indexer/main.py,sha256=abCHbNFUYjkJcNYsU0EPdZQI-_Gz9cQCH7dYJ5Jp7I8,31627
11
12
  mcp_code_indexer/merge_handler.py,sha256=lJR8eVq2qSrF6MW9mR3Fy8UzrNAaQ7RsI2FMNXne3vQ,14692
@@ -14,19 +15,19 @@ mcp_code_indexer/token_counter.py,sha256=WrifOkbF99nWWHlRlhCHAB2KN7qr83GOHl7apE-
14
15
  mcp_code_indexer/data/stop_words_english.txt,sha256=7Zdd9ameVgA6tN_zuXROvHXD4hkWeELVywPhb7FJEkw,6343
15
16
  mcp_code_indexer/database/__init__.py,sha256=aPq_aaRp0aSwOBIq9GkuMNjmLxA411zg2vhdrAuHm-w,38
16
17
  mcp_code_indexer/database/connection_health.py,sha256=s2r9L_KipH5NlemAUDnhBQO90Dn4b_0Ht9UDs7F6QPk,24432
17
- mcp_code_indexer/database/database.py,sha256=7B1Pq9CFwIgU0k8ObcgtGxqdnGPZnDhaYuTTdjf7AV0,51334
18
+ mcp_code_indexer/database/database.py,sha256=RAlQ9sgE_aMnj6Nu_bRIgghYXq5yejaA7hnXTww_BFU,50962
18
19
  mcp_code_indexer/database/exceptions.py,sha256=AgpRA9Z5R-GoWYdQSPeSdYvAXDopFCQkLGN3jD7Ha4E,10215
19
- mcp_code_indexer/database/models.py,sha256=_vCmJnPXZSiInRzyvs4c7QUWuNNW8qsOoDlGX8J-Gnk,7124
20
+ mcp_code_indexer/database/models.py,sha256=FbNtP9Z0bDCoe8JjsYT1HWp0uYsxgZFHR0Blt3d8TBY,7054
20
21
  mcp_code_indexer/database/retry_executor.py,sha256=QUayjkCk8OsckVMYiJ_HBQ9NTUss-H8GQeUIUbbw4_U,13419
21
22
  mcp_code_indexer/middleware/__init__.py,sha256=p-mP0pMsfiU2yajCPvokCUxUEkh_lu4XJP1LyyMW2ug,220
22
23
  mcp_code_indexer/middleware/error_middleware.py,sha256=5agJTAkkPogfPGnja1V9JtG9RG-BiOALIJYctK3byJQ,11730
23
24
  mcp_code_indexer/server/__init__.py,sha256=16xMcuriUOBlawRqWNBk6niwrvtv_JD5xvI36X1Vsmk,41
24
- mcp_code_indexer/server/mcp_server.py,sha256=BqRPF2pBQhNbPN-LrNq1IMYJzqDKD-A6BSHwQ_5dgK8,74382
25
+ mcp_code_indexer/server/mcp_server.py,sha256=EQnwRbjF17AdPvO_HPb6d7cmpxUN51qbyMuhQXrtetU,63168
25
26
  mcp_code_indexer/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4,sha256=Ijkht27pm96ZW3_3OFE-7xAPtR0YyTWXoRO8_-hlsqc,1681126
26
27
  mcp_code_indexer/tools/__init__.py,sha256=m01mxML2UdD7y5rih_XNhNSCMzQTz7WQ_T1TeOcYlnE,49
27
- mcp_code_indexer-2.4.0.dist-info/licenses/LICENSE,sha256=JN9dyPPgYwH9C-UjYM7FLNZjQ6BF7kAzpF3_4PwY4rY,1086
28
- mcp_code_indexer-2.4.0.dist-info/METADATA,sha256=6fbCl9tjJUT0x7EF77w-znQumIQw2fVkRes3FcN1Av4,20165
29
- mcp_code_indexer-2.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- mcp_code_indexer-2.4.0.dist-info/entry_points.txt,sha256=8HqWOw1Is7jOP1bvIgaSwouvT9z_Boe-9hd4NzyJOhY,68
31
- mcp_code_indexer-2.4.0.dist-info/top_level.txt,sha256=yKYCM-gMGt-cnupGfAhnZaoEsROLB6DQ1KFUuyKx4rw,17
32
- mcp_code_indexer-2.4.0.dist-info/RECORD,,
28
+ mcp_code_indexer-3.0.0.dist-info/licenses/LICENSE,sha256=JN9dyPPgYwH9C-UjYM7FLNZjQ6BF7kAzpF3_4PwY4rY,1086
29
+ mcp_code_indexer-3.0.0.dist-info/METADATA,sha256=yRCsAbs-iHhIOFjihh6PZcgB7yDzihTqxkU3nsdaBZM,20165
30
+ mcp_code_indexer-3.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ mcp_code_indexer-3.0.0.dist-info/entry_points.txt,sha256=8HqWOw1Is7jOP1bvIgaSwouvT9z_Boe-9hd4NzyJOhY,68
32
+ mcp_code_indexer-3.0.0.dist-info/top_level.txt,sha256=yKYCM-gMGt-cnupGfAhnZaoEsROLB6DQ1KFUuyKx4rw,17
33
+ mcp_code_indexer-3.0.0.dist-info/RECORD,,