mcp-code-indexer 1.7.0__tar.gz → 1.8.0__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 (41) hide show
  1. {mcp_code_indexer-1.7.0/src/mcp_code_indexer.egg-info → mcp_code_indexer-1.8.0}/PKG-INFO +3 -3
  2. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/README.md +2 -2
  3. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/pyproject.toml +1 -1
  4. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/git_hook_handler.py +142 -93
  5. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0/src/mcp_code_indexer.egg-info}/PKG-INFO +3 -3
  6. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/LICENSE +0 -0
  7. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/MANIFEST.in +0 -0
  8. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/docs/api-reference.md +0 -0
  9. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/docs/architecture.md +0 -0
  10. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/docs/configuration.md +0 -0
  11. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/docs/contributing.md +0 -0
  12. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/docs/git-hook-setup.md +0 -0
  13. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/migrations/001_initial.sql +0 -0
  14. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/migrations/002_performance_indexes.sql +0 -0
  15. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/migrations/003_project_overviews.sql +0 -0
  16. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/requirements.txt +0 -0
  17. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/setup.cfg +0 -0
  18. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/setup.py +0 -0
  19. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/__init__.py +0 -0
  20. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/__main__.py +0 -0
  21. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/data/stop_words_english.txt +0 -0
  22. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/database/__init__.py +0 -0
  23. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/database/database.py +0 -0
  24. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/database/models.py +0 -0
  25. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/error_handler.py +0 -0
  26. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/file_scanner.py +0 -0
  27. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/logging_config.py +0 -0
  28. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/main.py +0 -0
  29. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/merge_handler.py +0 -0
  30. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/middleware/__init__.py +0 -0
  31. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/middleware/error_middleware.py +0 -0
  32. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/server/__init__.py +0 -0
  33. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/server/mcp_server.py +0 -0
  34. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  35. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/token_counter.py +0 -0
  36. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer/tools/__init__.py +0 -0
  37. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer.egg-info/SOURCES.txt +0 -0
  38. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer.egg-info/dependency_links.txt +0 -0
  39. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer.egg-info/entry_points.txt +0 -0
  40. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer.egg-info/requires.txt +0 -0
  41. {mcp_code_indexer-1.7.0 → mcp_code_indexer-1.8.0}/src/mcp_code_indexer.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-code-indexer
3
- Version: 1.7.0
3
+ Version: 1.8.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?9)](https://badge.fury.io/py/mcp-code-indexer)
63
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?9)](https://pypi.org/project/mcp-code-indexer/)
62
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?10)](https://badge.fury.io/py/mcp-code-indexer)
63
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?10)](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. Instead of repeatedly scanning files, agents get instant access to intelligent descriptions, semantic search, and context-aware recommendations.
@@ -1,7 +1,7 @@
1
1
  # MCP Code Indexer 🚀
2
2
 
3
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?9)](https://badge.fury.io/py/mcp-code-indexer)
4
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?9)](https://pypi.org/project/mcp-code-indexer/)
3
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?10)](https://badge.fury.io/py/mcp-code-indexer)
4
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?10)](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. Instead of repeatedly scanning files, agents get instant access to intelligent descriptions, semantic search, and context-aware recommendations.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcp-code-indexer"
7
- version = "1.7.0"
7
+ version = "1.8.0"
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
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -137,32 +137,26 @@ class GitHookHandler:
137
137
  self.logger.info(f"Current overview length: {len(current_overview) if current_overview else 0} characters")
138
138
  self.logger.info(f"Current descriptions count: {len(current_descriptions)}")
139
139
 
140
- # Build prompt for OpenRouter
141
- self.logger.info("Building analysis prompt...")
142
- prompt = self._build_githook_prompt(
143
- git_diff,
144
- commit_message,
145
- current_overview,
146
- current_descriptions,
147
- changed_files
148
- )
149
-
150
- # Log prompt details
151
- prompt_chars = len(prompt)
152
- prompt_tokens = self.token_counter.count_tokens(prompt)
153
- self.logger.info(f"Analysis prompt: {prompt_chars} characters, {prompt_tokens} tokens")
140
+ # Use two-stage approach for large codebases
141
+ self.logger.info("Starting two-stage analysis approach...")
154
142
 
155
- # Check total prompt token count
156
- if prompt_tokens > self.config["max_diff_tokens"]:
157
- self.logger.info(f"Skipping git hook update - prompt too large ({prompt_tokens} tokens > {self.config['max_diff_tokens']} limit)")
158
- return
143
+ # Stage 1: Check if overview needs updating
144
+ overview_updates = await self._analyze_overview_updates(
145
+ git_diff, commit_message, current_overview, changed_files
146
+ )
159
147
 
160
- self.logger.info(f"Prompt size OK ({prompt_tokens} <= {self.config['max_diff_tokens']} tokens), calling OpenRouter...")
148
+ # Stage 2: Update file descriptions
149
+ file_updates = await self._analyze_file_updates(
150
+ git_diff, commit_message, current_descriptions, changed_files
151
+ )
161
152
 
162
- # Call OpenRouter API
163
- updates = await self._call_openrouter(prompt)
153
+ # Combine updates
154
+ updates = {
155
+ "file_updates": file_updates.get("file_updates", {}),
156
+ "overview_update": overview_updates.get("overview_update")
157
+ }
164
158
 
165
- self.logger.info(f"OpenRouter response received, processing updates...")
159
+ self.logger.info(f"Two-stage analysis completed, processing updates...")
166
160
 
167
161
  # Apply updates to database
168
162
  await self._apply_updates(project_info, updates)
@@ -441,101 +435,143 @@ class GitHookHandler:
441
435
  self.logger.warning(f"Failed to get file descriptions: {e}")
442
436
  return {}
443
437
 
444
- def _build_githook_prompt(
445
- self,
446
- git_diff: str,
447
- commit_message: str,
448
- overview: str,
449
- descriptions: Dict[str, str],
438
+ async def _analyze_overview_updates(
439
+ self,
440
+ git_diff: str,
441
+ commit_message: str,
442
+ current_overview: str,
450
443
  changed_files: List[str]
451
- ) -> str:
444
+ ) -> Dict[str, Any]:
452
445
  """
453
- Build prompt for OpenRouter API to analyze git changes.
446
+ Stage 1: Analyze if project overview needs updating.
454
447
 
455
448
  Args:
456
449
  git_diff: Git diff content
457
450
  commit_message: Commit message explaining the changes
458
- overview: Current project overview
459
- descriptions: Current file descriptions
451
+ current_overview: Current project overview
460
452
  changed_files: List of changed file paths
461
453
 
462
454
  Returns:
463
- Formatted prompt for the API
455
+ Dict with overview_update key
464
456
  """
465
- return f"""Analyze this git commit and update the file descriptions and project overview as needed.
457
+ self.logger.info("Stage 1: Analyzing overview updates...")
458
+
459
+ prompt = f"""Analyze this git commit to determine if the project overview needs updating.
466
460
 
467
461
  COMMIT MESSAGE:
468
462
  {commit_message or "No commit message available"}
469
463
 
470
464
  CURRENT PROJECT OVERVIEW:
471
- {overview or "No overview available"}
465
+ {current_overview or "No overview available"}
472
466
 
473
- CURRENT FILE DESCRIPTIONS:
474
- {json.dumps(descriptions, indent=2)}
467
+ CHANGED FILES:
468
+ {', '.join(changed_files)}
475
469
 
476
470
  GIT DIFF:
477
471
  {git_diff}
478
472
 
479
- CHANGED FILES:
480
- {', '.join(changed_files)}
481
-
482
473
  INSTRUCTIONS:
483
474
 
484
- Use the COMMIT MESSAGE to understand the intent and context of the changes. The commit message explains what the developer was trying to accomplish.
475
+ Update project overview ONLY if there are major structural changes like:
476
+ - New major features or components (indicated by commit message or new directories)
477
+ - Architectural changes (new patterns, frameworks, or approaches)
478
+ - Significant dependency additions (Cargo.toml, package.json, requirements.txt changes)
479
+ - New API endpoints or workflows
480
+ - Changes to build/deployment processes
481
+
482
+ Do NOT update for: bug fixes, small refactors, documentation updates, version bumps.
483
+
484
+ If updating, provide comprehensive narrative (10-20 pages of text) with directory structure, architecture, components, and workflows.
485
485
 
486
- 1. **File Descriptions**: Update descriptions for any files that have changed significantly. Consider both the diff content and the commit message context. Only include files that need actual description updates.
486
+ Return ONLY a JSON object:
487
+ {{
488
+ "overview_update": "Updated overview text" or null
489
+ }}"""
490
+
491
+ # Log prompt details
492
+ prompt_chars = len(prompt)
493
+ prompt_tokens = self.token_counter.count_tokens(prompt)
494
+ self.logger.info(f"Stage 1 prompt: {prompt_chars} characters, {prompt_tokens} tokens")
495
+
496
+ if prompt_tokens > self.config["max_diff_tokens"]:
497
+ self.logger.warning(f"Stage 1 prompt too large ({prompt_tokens} tokens), skipping overview analysis")
498
+ return {"overview_update": None}
499
+
500
+ # Call OpenRouter API
501
+ result = await self._call_openrouter(prompt)
502
+ self.logger.info("Stage 1 completed: overview analysis")
503
+
504
+ return result
487
505
 
488
- 2. **Project Overview**: Update ONLY if there are major structural changes like:
489
- - New major features or components (which may be indicated by commit message)
490
- - Architectural changes (new patterns, frameworks, or approaches)
491
- - Significant dependency additions
492
- - New API endpoints or workflows
493
- - Changes to build/deployment processes
494
-
495
- Do NOT update overview for minor changes like bug fixes, small refactors, or documentation updates.
506
+ async def _analyze_file_updates(
507
+ self,
508
+ git_diff: str,
509
+ commit_message: str,
510
+ current_descriptions: Dict[str, str],
511
+ changed_files: List[str]
512
+ ) -> Dict[str, Any]:
513
+ """
514
+ Stage 2: Analyze file description updates.
515
+
516
+ Args:
517
+ git_diff: Git diff content
518
+ commit_message: Commit message explaining the changes
519
+ current_descriptions: Current file descriptions for changed files only
520
+ changed_files: List of changed file paths
521
+
522
+ Returns:
523
+ Dict with file_updates key
524
+ """
525
+ self.logger.info("Stage 2: Analyzing file description updates...")
526
+
527
+ # Only include descriptions for changed files to reduce token usage
528
+ relevant_descriptions = {
529
+ path: desc for path, desc in current_descriptions.items()
530
+ if path in changed_files
531
+ }
532
+
533
+ prompt = f"""Analyze this git commit and update file descriptions for changed files.
496
534
 
497
- 3. **Overview Format**: If updating the overview, follow this structure with comprehensive narrative (10-20 pages of text):
535
+ COMMIT MESSAGE:
536
+ {commit_message or "No commit message available"}
498
537
 
499
- ````
500
- ## Directory Structure
501
- ```
502
- src/
503
- ├── api/ # REST API endpoints and middleware
504
- ├── models/ # Database models and business logic
505
- ├── services/ # External service integrations
506
- ├── utils/ # Shared utilities and helpers
507
- └── tests/ # Test suites
508
- ```
538
+ CURRENT FILE DESCRIPTIONS (for changed files only):
539
+ {json.dumps(relevant_descriptions, indent=2)}
509
540
 
510
- ## Architecture Overview
511
- [Describe how components interact, data flow, key design decisions]
541
+ CHANGED FILES:
542
+ {', '.join(changed_files)}
512
543
 
513
- ## Core Components
514
- ### API Layer
515
- [Details about API structure, authentication, routing]
544
+ GIT DIFF:
545
+ {git_diff}
516
546
 
517
- ### Data Model
518
- [Key entities, relationships, database design]
547
+ INSTRUCTIONS:
519
548
 
520
- ## Key Workflows
521
- 1. User Authentication Flow
522
- [Step-by-step description]
523
- 2. Data Processing Pipeline
524
- [How data moves through the system]
549
+ Use the COMMIT MESSAGE to understand the intent and context of the changes.
525
550
 
526
- [Continue with other sections...]
527
- ````
551
+ Update descriptions for files that have changed significantly. Consider both the diff content and commit message context. Only include files that need actual description updates.
528
552
 
529
- Return ONLY a JSON object in this exact format:
553
+ Return ONLY a JSON object:
530
554
  {{
531
555
  "file_updates": {{
532
556
  "path/to/file1.py": "Updated description for file1",
533
557
  "path/to/file2.js": "Updated description for file2"
534
- }},
535
- "overview_update": "Updated project overview text (or null if no update needed)"
536
- }}
558
+ }}
559
+ }}"""
537
560
 
538
- Return ONLY the JSON, no other text."""
561
+ # Log prompt details
562
+ prompt_chars = len(prompt)
563
+ prompt_tokens = self.token_counter.count_tokens(prompt)
564
+ self.logger.info(f"Stage 2 prompt: {prompt_chars} characters, {prompt_tokens} tokens")
565
+
566
+ if prompt_tokens > self.config["max_diff_tokens"]:
567
+ self.logger.warning(f"Stage 2 prompt too large ({prompt_tokens} tokens), skipping file analysis")
568
+ return {"file_updates": {}}
569
+
570
+ # Call OpenRouter API
571
+ result = await self._call_openrouter(prompt)
572
+ self.logger.info("Stage 2 completed: file description analysis")
573
+
574
+ return result
539
575
 
540
576
  @retry(
541
577
  wait=wait_exponential(multiplier=1, min=4, max=60),
@@ -634,19 +670,32 @@ Return ONLY the JSON, no other text."""
634
670
  try:
635
671
  data = json.loads(response_text.strip())
636
672
 
637
- # Validate structure
638
- if "file_updates" not in data:
639
- raise ValueError("Missing 'file_updates' field")
640
- if "overview_update" not in data:
641
- raise ValueError("Missing 'overview_update' field")
642
-
643
- if not isinstance(data["file_updates"], dict):
644
- raise ValueError("'file_updates' must be a dictionary")
645
-
646
- # Validate descriptions
647
- for path, desc in data["file_updates"].items():
648
- if not isinstance(desc, str) or not desc.strip():
649
- raise ValueError(f"Invalid description for {path}")
673
+ # Handle both single-stage and two-stage responses
674
+ if "file_updates" in data and "overview_update" in data:
675
+ # Original single-stage format
676
+ if not isinstance(data["file_updates"], dict):
677
+ raise ValueError("'file_updates' must be a dictionary")
678
+
679
+ # Validate descriptions
680
+ for path, desc in data["file_updates"].items():
681
+ if not isinstance(desc, str) or not desc.strip():
682
+ raise ValueError(f"Invalid description for {path}")
683
+
684
+ elif "file_updates" in data:
685
+ # Stage 2 format (file updates only)
686
+ if not isinstance(data["file_updates"], dict):
687
+ raise ValueError("'file_updates' must be a dictionary")
688
+
689
+ # Validate descriptions
690
+ for path, desc in data["file_updates"].items():
691
+ if not isinstance(desc, str) or not desc.strip():
692
+ raise ValueError(f"Invalid description for {path}")
693
+
694
+ elif "overview_update" in data:
695
+ # Stage 1 format (overview only) - overview_update can be null
696
+ pass
697
+ else:
698
+ raise ValueError("Response must contain 'file_updates' and/or 'overview_update'")
650
699
 
651
700
  return data
652
701
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-code-indexer
3
- Version: 1.7.0
3
+ Version: 1.8.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?9)](https://badge.fury.io/py/mcp-code-indexer)
63
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?9)](https://pypi.org/project/mcp-code-indexer/)
62
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?10)](https://badge.fury.io/py/mcp-code-indexer)
63
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?10)](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. Instead of repeatedly scanning files, agents get instant access to intelligent descriptions, semantic search, and context-aware recommendations.