mcp-code-indexer 1.5.0__py3-none-any.whl → 1.6.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.
- mcp_code_indexer/__init__.py +1 -1
- mcp_code_indexer/git_hook_handler.py +110 -4
- mcp_code_indexer/main.py +28 -8
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/METADATA +25 -3
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/RECORD +9 -9
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/WHEEL +0 -0
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/entry_points.txt +0 -0
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_code_indexer-1.5.0.dist-info → mcp_code_indexer-1.6.0.dist-info}/top_level.txt +0 -0
mcp_code_indexer/__init__.py
CHANGED
@@ -6,7 +6,7 @@ intelligent codebase navigation through searchable file descriptions,
|
|
6
6
|
token-aware overviews, and advanced merge capabilities.
|
7
7
|
"""
|
8
8
|
|
9
|
-
__version__ = "1.
|
9
|
+
__version__ = "1.6.0"
|
10
10
|
__author__ = "MCP Code Indexer Contributors"
|
11
11
|
__email__ = ""
|
12
12
|
__license__ = "MIT"
|
@@ -73,19 +73,34 @@ class GitHookHandler:
|
|
73
73
|
if not self.api_key:
|
74
74
|
raise GitHookError("OPENROUTER_API_KEY environment variable is required for git hook mode")
|
75
75
|
|
76
|
-
async def run_githook_mode(
|
76
|
+
async def run_githook_mode(
|
77
|
+
self,
|
78
|
+
commit_hash: Optional[str] = None,
|
79
|
+
commit_range: Optional[Tuple[str, str]] = None
|
80
|
+
) -> None:
|
77
81
|
"""
|
78
82
|
Run in git hook mode - analyze changes and update descriptions.
|
79
83
|
|
84
|
+
Args:
|
85
|
+
commit_hash: Process a specific commit by hash
|
86
|
+
commit_range: Process commits in range (start_hash, end_hash)
|
87
|
+
|
80
88
|
This is the main entry point for git hook functionality.
|
81
89
|
"""
|
82
90
|
try:
|
83
91
|
# Get git info from current directory
|
84
92
|
project_info = await self._identify_project_from_git()
|
85
93
|
|
86
|
-
# Get git diff and commit message
|
87
|
-
|
88
|
-
|
94
|
+
# Get git diff and commit message based on mode
|
95
|
+
if commit_hash:
|
96
|
+
git_diff = await self._get_git_diff_for_commit(commit_hash)
|
97
|
+
commit_message = await self._get_commit_message_for_commit(commit_hash)
|
98
|
+
elif commit_range:
|
99
|
+
git_diff = await self._get_git_diff_for_range(commit_range[0], commit_range[1])
|
100
|
+
commit_message = await self._get_commit_messages_for_range(commit_range[0], commit_range[1])
|
101
|
+
else:
|
102
|
+
git_diff = await self._get_git_diff()
|
103
|
+
commit_message = await self._get_commit_message()
|
89
104
|
|
90
105
|
if not git_diff or len(git_diff) > self.config["max_diff_size"]:
|
91
106
|
self.logger.info(f"Skipping git hook update - diff too large or empty")
|
@@ -224,6 +239,97 @@ class GitHookHandler:
|
|
224
239
|
except subprocess.CalledProcessError:
|
225
240
|
# If no commits exist yet, return empty string
|
226
241
|
return ""
|
242
|
+
|
243
|
+
async def _get_git_diff_for_commit(self, commit_hash: str) -> str:
|
244
|
+
"""
|
245
|
+
Get git diff for a specific commit.
|
246
|
+
|
247
|
+
Args:
|
248
|
+
commit_hash: The commit hash to analyze
|
249
|
+
|
250
|
+
Returns:
|
251
|
+
Git diff content as string
|
252
|
+
"""
|
253
|
+
try:
|
254
|
+
# Get diff for the specific commit compared to its parent
|
255
|
+
diff_result = await self._run_git_command([
|
256
|
+
"diff", "--no-color", "--no-ext-diff", f"{commit_hash}~1..{commit_hash}"
|
257
|
+
])
|
258
|
+
return diff_result
|
259
|
+
|
260
|
+
except subprocess.CalledProcessError:
|
261
|
+
# If parent doesn't exist (first commit), diff against empty tree
|
262
|
+
try:
|
263
|
+
diff_result = await self._run_git_command([
|
264
|
+
"diff", "--no-color", "--no-ext-diff", "4b825dc642cb6eb9a060e54bf8d69288fbee4904", commit_hash
|
265
|
+
])
|
266
|
+
return diff_result
|
267
|
+
except subprocess.CalledProcessError as e:
|
268
|
+
raise GitHookError(f"Failed to get git diff for commit {commit_hash}: {e}")
|
269
|
+
|
270
|
+
async def _get_git_diff_for_range(self, start_hash: str, end_hash: str) -> str:
|
271
|
+
"""
|
272
|
+
Get git diff for a range of commits.
|
273
|
+
|
274
|
+
Args:
|
275
|
+
start_hash: Starting commit hash (exclusive)
|
276
|
+
end_hash: Ending commit hash (inclusive)
|
277
|
+
|
278
|
+
Returns:
|
279
|
+
Git diff content as string
|
280
|
+
"""
|
281
|
+
try:
|
282
|
+
diff_result = await self._run_git_command([
|
283
|
+
"diff", "--no-color", "--no-ext-diff", f"{start_hash}..{end_hash}"
|
284
|
+
])
|
285
|
+
return diff_result
|
286
|
+
except subprocess.CalledProcessError as e:
|
287
|
+
raise GitHookError(f"Failed to get git diff for range {start_hash}..{end_hash}: {e}")
|
288
|
+
|
289
|
+
async def _get_commit_message_for_commit(self, commit_hash: str) -> str:
|
290
|
+
"""
|
291
|
+
Get the commit message for a specific commit.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
commit_hash: The commit hash
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
Commit message as string
|
298
|
+
"""
|
299
|
+
try:
|
300
|
+
message_result = await self._run_git_command([
|
301
|
+
"log", "-1", "--pretty=%B", commit_hash
|
302
|
+
])
|
303
|
+
return message_result.strip()
|
304
|
+
except subprocess.CalledProcessError as e:
|
305
|
+
raise GitHookError(f"Failed to get commit message for {commit_hash}: {e}")
|
306
|
+
|
307
|
+
async def _get_commit_messages_for_range(self, start_hash: str, end_hash: str) -> str:
|
308
|
+
"""
|
309
|
+
Get commit messages for a range of commits.
|
310
|
+
|
311
|
+
Args:
|
312
|
+
start_hash: Starting commit hash (exclusive)
|
313
|
+
end_hash: Ending commit hash (inclusive)
|
314
|
+
|
315
|
+
Returns:
|
316
|
+
Combined commit messages as string
|
317
|
+
"""
|
318
|
+
try:
|
319
|
+
# Get all commit messages in the range
|
320
|
+
message_result = await self._run_git_command([
|
321
|
+
"log", "--pretty=%B", f"{start_hash}..{end_hash}"
|
322
|
+
])
|
323
|
+
|
324
|
+
# Clean up and format the messages
|
325
|
+
messages = message_result.strip()
|
326
|
+
if messages:
|
327
|
+
return f"Combined commit messages for range {start_hash}..{end_hash}:\n\n{messages}"
|
328
|
+
else:
|
329
|
+
return f"No commits found in range {start_hash}..{end_hash}"
|
330
|
+
|
331
|
+
except subprocess.CalledProcessError as e:
|
332
|
+
raise GitHookError(f"Failed to get commit messages for range {start_hash}..{end_hash}: {e}")
|
227
333
|
|
228
334
|
def _extract_changed_files(self, git_diff: str) -> List[str]:
|
229
335
|
"""
|
mcp_code_indexer/main.py
CHANGED
@@ -82,8 +82,11 @@ def parse_arguments() -> argparse.Namespace:
|
|
82
82
|
|
83
83
|
parser.add_argument(
|
84
84
|
"--githook",
|
85
|
-
|
86
|
-
|
85
|
+
nargs="*",
|
86
|
+
metavar="COMMIT_HASH",
|
87
|
+
help="Git hook mode: auto-update descriptions based on git diff using OpenRouter API. "
|
88
|
+
"Usage: --githook (current changes), --githook HASH (specific commit), "
|
89
|
+
"--githook HASH1 HASH2 (commit range from HASH1 to HASH2)"
|
87
90
|
)
|
88
91
|
|
89
92
|
parser.add_argument(
|
@@ -462,12 +465,16 @@ async def handle_githook(args: argparse.Namespace) -> None:
|
|
462
465
|
from .database.database import DatabaseManager
|
463
466
|
from .git_hook_handler import GitHookHandler
|
464
467
|
|
468
|
+
# Process commit hash arguments
|
469
|
+
commit_hashes = args.githook if args.githook else []
|
470
|
+
|
465
471
|
logger.info("Starting git hook execution", extra={
|
466
472
|
"structured_data": {
|
467
473
|
"args": {
|
468
474
|
"db_path": str(args.db_path),
|
469
475
|
"cache_dir": str(args.cache_dir),
|
470
|
-
"token_limit": args.token_limit
|
476
|
+
"token_limit": args.token_limit,
|
477
|
+
"commit_hashes": commit_hashes
|
471
478
|
}
|
472
479
|
}
|
473
480
|
})
|
@@ -497,7 +504,17 @@ async def handle_githook(args: argparse.Namespace) -> None:
|
|
497
504
|
|
498
505
|
# Run git hook analysis
|
499
506
|
logger.info("Starting git hook analysis")
|
500
|
-
|
507
|
+
if len(commit_hashes) == 0:
|
508
|
+
# Process current staged changes
|
509
|
+
await git_handler.run_githook_mode()
|
510
|
+
elif len(commit_hashes) == 1:
|
511
|
+
# Process specific commit
|
512
|
+
await git_handler.run_githook_mode(commit_hash=commit_hashes[0])
|
513
|
+
elif len(commit_hashes) == 2:
|
514
|
+
# Process commit range
|
515
|
+
await git_handler.run_githook_mode(commit_range=(commit_hashes[0], commit_hashes[1]))
|
516
|
+
else:
|
517
|
+
raise ValueError("--githook accepts 0, 1, or 2 commit hashes")
|
501
518
|
logger.info("Git hook analysis completed successfully")
|
502
519
|
|
503
520
|
except Exception as e:
|
@@ -682,15 +699,18 @@ def generate_project_markdown(project, branch, overview, files, logger):
|
|
682
699
|
|
683
700
|
markdown_lines = []
|
684
701
|
|
685
|
-
# Project header
|
686
|
-
|
702
|
+
# Project header with sentence case
|
703
|
+
project_name = project.name.title() if project.name.islower() else project.name
|
704
|
+
markdown_lines.append(f"# {project_name}")
|
687
705
|
markdown_lines.append("")
|
688
706
|
|
689
707
|
# Project metadata
|
690
708
|
if project.remote_origin:
|
691
709
|
markdown_lines.append(f"**Repository:** {project.remote_origin}")
|
710
|
+
markdown_lines.append("")
|
692
711
|
if project.upstream_origin:
|
693
712
|
markdown_lines.append(f"**Upstream:** {project.upstream_origin}")
|
713
|
+
markdown_lines.append("")
|
694
714
|
markdown_lines.append(f"**Branch:** {branch}")
|
695
715
|
markdown_lines.append("")
|
696
716
|
|
@@ -768,8 +788,8 @@ async def main() -> None:
|
|
768
788
|
"""Main entry point for the MCP server."""
|
769
789
|
args = parse_arguments()
|
770
790
|
|
771
|
-
# Handle git hook command
|
772
|
-
if args.githook:
|
791
|
+
# Handle git hook command
|
792
|
+
if args.githook is not None:
|
773
793
|
await handle_githook(args)
|
774
794
|
return
|
775
795
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-code-indexer
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.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
|
@@ -57,8 +57,8 @@ Dynamic: requires-python
|
|
57
57
|
|
58
58
|
# MCP Code Indexer 🚀
|
59
59
|
|
60
|
-
[](https://badge.fury.io/py/mcp-code-indexer)
|
61
|
+
[](https://pypi.org/project/mcp-code-indexer/)
|
62
62
|
[](https://opensource.org/licenses/MIT)
|
63
63
|
|
64
64
|
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.
|
@@ -246,6 +246,28 @@ The server provides **11 powerful MCP tools** for intelligent codebase managemen
|
|
246
246
|
|
247
247
|
💡 **Pro Tip**: Always start with `check_codebase_size` to get personalized recommendations for navigating your specific codebase.
|
248
248
|
|
249
|
+
## 🔗 Git Hook Integration
|
250
|
+
|
251
|
+
Keep your codebase documentation automatically synchronized with automated analysis on every commit, rebase, or merge:
|
252
|
+
|
253
|
+
```bash
|
254
|
+
# Analyze current staged changes
|
255
|
+
mcp-code-indexer --githook
|
256
|
+
|
257
|
+
# Analyze a specific commit
|
258
|
+
mcp-code-indexer --githook abc123def
|
259
|
+
|
260
|
+
# Analyze a commit range (perfect for rebases)
|
261
|
+
mcp-code-indexer --githook abc123 def456
|
262
|
+
```
|
263
|
+
|
264
|
+
**🎯 Perfect for**:
|
265
|
+
- **Automated documentation** that never goes stale
|
266
|
+
- **Rebase-aware analysis** that handles complex git operations
|
267
|
+
- **Zero-effort maintenance** with background processing
|
268
|
+
|
269
|
+
See the **[Git Hook Setup Guide](docs/git-hook-setup.md)** for complete installation instructions including post-commit, post-merge, and post-rewrite hooks.
|
270
|
+
|
249
271
|
## 🏗️ Architecture Highlights
|
250
272
|
|
251
273
|
### Performance Optimized
|
@@ -1,10 +1,10 @@
|
|
1
|
-
mcp_code_indexer/__init__.py,sha256=
|
1
|
+
mcp_code_indexer/__init__.py,sha256=DKmuPpw8URDyojC4T1bttK8kGMI9lv_-B9UYP8dqb90,473
|
2
2
|
mcp_code_indexer/__main__.py,sha256=4Edinoe0ug43hobuLYcjTmGp2YJnlFYN4_8iKvUBJ0Q,213
|
3
3
|
mcp_code_indexer/error_handler.py,sha256=cNSUFFrGBMLDv4qa78c7495L1wSl_dXCRbzCJOidx-Q,11590
|
4
4
|
mcp_code_indexer/file_scanner.py,sha256=ctXeZMROgDThEtjzsANTK9TbK-fhTScMBd4iyuleBT4,11734
|
5
|
-
mcp_code_indexer/git_hook_handler.py,sha256=
|
5
|
+
mcp_code_indexer/git_hook_handler.py,sha256=P3WxHH2BYotJqzhrbgEot6fiycevVsCkyMZLfvuJhMM,25475
|
6
6
|
mcp_code_indexer/logging_config.py,sha256=yCGQD-xx9oobS-YctOFcaE1Q3iiuOj2E6cTfKHbh_wc,7358
|
7
|
-
mcp_code_indexer/main.py,sha256=
|
7
|
+
mcp_code_indexer/main.py,sha256=7k00hj2C1CxTDDErbq2Ee072MbvqEAsRqrMHH-w1oM0,31538
|
8
8
|
mcp_code_indexer/merge_handler.py,sha256=lJR8eVq2qSrF6MW9mR3Fy8UzrNAaQ7RsI2FMNXne3vQ,14692
|
9
9
|
mcp_code_indexer/token_counter.py,sha256=WrifOkbF99nWWHlRlhCHAB2KN7qr83GOHl7apE-hJcE,8460
|
10
10
|
mcp_code_indexer/data/stop_words_english.txt,sha256=7Zdd9ameVgA6tN_zuXROvHXD4hkWeELVywPhb7FJEkw,6343
|
@@ -17,9 +17,9 @@ mcp_code_indexer/server/__init__.py,sha256=16xMcuriUOBlawRqWNBk6niwrvtv_JD5xvI36
|
|
17
17
|
mcp_code_indexer/server/mcp_server.py,sha256=bRl5JTFWlQ0MrIulkts6fDws6kPqfy6kKoQdenMOk04,61290
|
18
18
|
mcp_code_indexer/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4,sha256=Ijkht27pm96ZW3_3OFE-7xAPtR0YyTWXoRO8_-hlsqc,1681126
|
19
19
|
mcp_code_indexer/tools/__init__.py,sha256=m01mxML2UdD7y5rih_XNhNSCMzQTz7WQ_T1TeOcYlnE,49
|
20
|
-
mcp_code_indexer-1.
|
21
|
-
mcp_code_indexer-1.
|
22
|
-
mcp_code_indexer-1.
|
23
|
-
mcp_code_indexer-1.
|
24
|
-
mcp_code_indexer-1.
|
25
|
-
mcp_code_indexer-1.
|
20
|
+
mcp_code_indexer-1.6.0.dist-info/licenses/LICENSE,sha256=JN9dyPPgYwH9C-UjYM7FLNZjQ6BF7kAzpF3_4PwY4rY,1086
|
21
|
+
mcp_code_indexer-1.6.0.dist-info/METADATA,sha256=0UMPFE12KQsdGMdGN5SCRFcY5LCOTfTH6gLt8V5RF5A,17453
|
22
|
+
mcp_code_indexer-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
23
|
+
mcp_code_indexer-1.6.0.dist-info/entry_points.txt,sha256=8HqWOw1Is7jOP1bvIgaSwouvT9z_Boe-9hd4NzyJOhY,68
|
24
|
+
mcp_code_indexer-1.6.0.dist-info/top_level.txt,sha256=yKYCM-gMGt-cnupGfAhnZaoEsROLB6DQ1KFUuyKx4rw,17
|
25
|
+
mcp_code_indexer-1.6.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|