mcp-code-indexer 1.6.2__tar.gz → 1.6.4__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 (42) hide show
  1. {mcp_code_indexer-1.6.2/src/mcp_code_indexer.egg-info → mcp_code_indexer-1.6.4}/PKG-INFO +4 -3
  2. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/README.md +2 -2
  3. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/pyproject.toml +3 -2
  4. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/setup.py +3 -3
  5. mcp_code_indexer-1.6.4/src/mcp_code_indexer/__init__.py +39 -0
  6. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/git_hook_handler.py +49 -3
  7. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/server/mcp_server.py +58 -1
  8. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4/src/mcp_code_indexer.egg-info}/PKG-INFO +4 -3
  9. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer.egg-info/requires.txt +3 -0
  10. mcp_code_indexer-1.6.2/src/mcp_code_indexer/__init__.py +0 -16
  11. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/LICENSE +0 -0
  12. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/MANIFEST.in +0 -0
  13. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/docs/api-reference.md +0 -0
  14. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/docs/architecture.md +0 -0
  15. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/docs/configuration.md +0 -0
  16. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/docs/contributing.md +0 -0
  17. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/docs/git-hook-setup.md +0 -0
  18. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/migrations/001_initial.sql +0 -0
  19. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/migrations/002_performance_indexes.sql +0 -0
  20. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/migrations/003_project_overviews.sql +0 -0
  21. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/requirements.txt +0 -0
  22. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/setup.cfg +0 -0
  23. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/__main__.py +0 -0
  24. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/data/stop_words_english.txt +0 -0
  25. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/database/__init__.py +0 -0
  26. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/database/database.py +0 -0
  27. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/database/models.py +0 -0
  28. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/error_handler.py +0 -0
  29. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/file_scanner.py +0 -0
  30. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/logging_config.py +0 -0
  31. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/main.py +0 -0
  32. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/merge_handler.py +0 -0
  33. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/middleware/__init__.py +0 -0
  34. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/middleware/error_middleware.py +0 -0
  35. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/server/__init__.py +0 -0
  36. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  37. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/token_counter.py +0 -0
  38. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer/tools/__init__.py +0 -0
  39. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer.egg-info/SOURCES.txt +0 -0
  40. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer.egg-info/dependency_links.txt +0 -0
  41. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/src/mcp_code_indexer.egg-info/entry_points.txt +0 -0
  42. {mcp_code_indexer-1.6.2 → mcp_code_indexer-1.6.4}/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.6.2
3
+ Version: 1.6.4
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
@@ -37,6 +37,7 @@ Requires-Dist: aiofiles==23.2.0
37
37
  Requires-Dist: aiosqlite==0.19.0
38
38
  Requires-Dist: aiohttp>=3.8.0
39
39
  Requires-Dist: tenacity>=8.0.0
40
+ Requires-Dist: tomli>=1.2.0; python_version < "3.11"
40
41
  Provides-Extra: dev
41
42
  Requires-Dist: pytest>=8.0.0; extra == "dev"
42
43
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -57,8 +58,8 @@ Dynamic: requires-python
57
58
 
58
59
  # MCP Code Indexer 🚀
59
60
 
60
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?6)](https://badge.fury.io/py/mcp-code-indexer)
61
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?6)](https://pypi.org/project/mcp-code-indexer/)
61
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?8)](https://badge.fury.io/py/mcp-code-indexer)
62
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?8)](https://pypi.org/project/mcp-code-indexer/)
62
63
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
63
64
 
64
65
  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?6)](https://badge.fury.io/py/mcp-code-indexer)
4
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?6)](https://pypi.org/project/mcp-code-indexer/)
3
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?8)](https://badge.fury.io/py/mcp-code-indexer)
4
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?8)](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.6.2"
7
+ version = "1.6.4"
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"}
@@ -50,7 +50,8 @@ dependencies = [
50
50
  "aiofiles==23.2.0",
51
51
  "aiosqlite==0.19.0",
52
52
  "aiohttp>=3.8.0",
53
- "tenacity>=8.0.0"
53
+ "tenacity>=8.0.0",
54
+ "tomli>=1.2.0; python_version<'3.11'"
54
55
  ]
55
56
 
56
57
  [project.optional-dependencies]
@@ -19,9 +19,9 @@ def get_version():
19
19
  with open(this_directory / "pyproject.toml", "rb") as f:
20
20
  data = tomllib.load(f)
21
21
  return data["project"]["version"]
22
- except Exception:
23
- # Fallback version if reading fails
24
- return "1.6.2"
22
+ except Exception as e:
23
+ # Fail hard if version reading fails
24
+ raise RuntimeError(f"Could not read version from pyproject.toml: {e}")
25
25
 
26
26
  setup(
27
27
  name="mcp-code-indexer",
@@ -0,0 +1,39 @@
1
+ """
2
+ MCP Code Indexer - Intelligent codebase navigation for AI agents.
3
+
4
+ A production-ready Model Context Protocol (MCP) server that provides
5
+ intelligent codebase navigation through searchable file descriptions,
6
+ token-aware overviews, and advanced merge capabilities.
7
+ """
8
+
9
+ def _get_version() -> str:
10
+ """Read version from pyproject.toml."""
11
+ try:
12
+ from pathlib import Path
13
+ import sys
14
+
15
+ if sys.version_info >= (3, 11):
16
+ import tomllib
17
+ else:
18
+ try:
19
+ import tomli as tomllib
20
+ except ImportError:
21
+ # Fallback if tomli not available
22
+ return "1.6.3"
23
+
24
+ pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
25
+ with open(pyproject_path, "rb") as f:
26
+ data = tomllib.load(f)
27
+ return data["project"]["version"]
28
+ except Exception:
29
+ # Return dev version if reading fails - indicates something is wrong
30
+ return "dev"
31
+
32
+ __version__ = _get_version()
33
+ __author__ = "MCP Code Indexer Contributors"
34
+ __email__ = ""
35
+ __license__ = "MIT"
36
+
37
+ from .server.mcp_server import MCPCodeIndexServer
38
+
39
+ __all__ = ["MCPCodeIndexServer", "__version__"]
@@ -90,8 +90,17 @@ class GitHookHandler:
90
90
  This is the main entry point for git hook functionality.
91
91
  """
92
92
  try:
93
+ self.logger.info(f"=== Git Hook Analysis Started ===")
94
+ if commit_hash:
95
+ self.logger.info(f"Mode: Single commit ({commit_hash})")
96
+ elif commit_range:
97
+ self.logger.info(f"Mode: Commit range ({commit_range[0]}..{commit_range[1]})")
98
+ else:
99
+ self.logger.info(f"Mode: Staged changes")
100
+
93
101
  # Get git info from current directory
94
102
  project_info = await self._identify_project_from_git()
103
+ self.logger.info(f"Project identified: {project_info.get('name', 'Unknown')} at {project_info.get('folderPath', 'Unknown')}")
95
104
 
96
105
  # Get git diff and commit message based on mode
97
106
  if commit_hash:
@@ -104,11 +113,17 @@ class GitHookHandler:
104
113
  git_diff = await self._get_git_diff()
105
114
  commit_message = await self._get_commit_message()
106
115
 
116
+ # Log diff details
107
117
  if not git_diff:
108
118
  self.logger.info(f"Skipping git hook update - no git diff")
109
119
  return
110
120
 
121
+ diff_chars = len(git_diff)
122
+ diff_tokens = self.token_counter.count_tokens(git_diff)
123
+ self.logger.info(f"Git diff: {diff_chars} characters, {diff_tokens} tokens")
124
+
111
125
  # Fetch current state
126
+ self.logger.info("Fetching current project state...")
112
127
  current_overview = await self._get_project_overview(project_info)
113
128
  current_descriptions = await self._get_all_descriptions(project_info)
114
129
  changed_files = self._extract_changed_files(git_diff)
@@ -117,7 +132,12 @@ class GitHookHandler:
117
132
  self.logger.info("No changed files detected in git diff")
118
133
  return
119
134
 
135
+ self.logger.info(f"Found {len(changed_files)} changed files: {', '.join(changed_files)}")
136
+ self.logger.info(f"Current overview length: {len(current_overview) if current_overview else 0} characters")
137
+ self.logger.info(f"Current descriptions count: {len(current_descriptions)}")
138
+
120
139
  # Build prompt for OpenRouter
140
+ self.logger.info("Building analysis prompt...")
121
141
  prompt = self._build_githook_prompt(
122
142
  git_diff,
123
143
  commit_message,
@@ -126,22 +146,33 @@ class GitHookHandler:
126
146
  changed_files
127
147
  )
128
148
 
129
- # Check total prompt token count
149
+ # Log prompt details
150
+ prompt_chars = len(prompt)
130
151
  prompt_tokens = self.token_counter.count_tokens(prompt)
152
+ self.logger.info(f"Analysis prompt: {prompt_chars} characters, {prompt_tokens} tokens")
153
+
154
+ # Check total prompt token count
131
155
  if prompt_tokens > self.config["max_diff_tokens"]:
132
156
  self.logger.info(f"Skipping git hook update - prompt too large ({prompt_tokens} tokens > {self.config['max_diff_tokens']} limit)")
133
157
  return
134
158
 
159
+ self.logger.info(f"Prompt size OK ({prompt_tokens} <= {self.config['max_diff_tokens']} tokens), calling OpenRouter...")
160
+
135
161
  # Call OpenRouter API
136
162
  updates = await self._call_openrouter(prompt)
137
163
 
164
+ self.logger.info(f"OpenRouter response received, processing updates...")
165
+
138
166
  # Apply updates to database
139
167
  await self._apply_updates(project_info, updates)
140
168
 
141
- self.logger.info(f"Git hook update completed for {len(changed_files)} files")
169
+ self.logger.info(f"Git hook update completed successfully for {len(changed_files)} files")
142
170
 
143
171
  except Exception as e:
144
172
  self.logger.error(f"Git hook mode failed: {e}")
173
+ self.logger.error(f"Exception details: {type(e).__name__}: {str(e)}")
174
+ import traceback
175
+ self.logger.error(f"Full traceback:\n{traceback.format_exc()}")
145
176
  # Don't fail the git operation - just log the error
146
177
  raise GitHookError(f"Git hook processing failed: {e}")
147
178
 
@@ -547,6 +578,12 @@ Return ONLY the JSON, no other text."""
547
578
 
548
579
  timeout = aiohttp.ClientTimeout(total=self.config["timeout"])
549
580
 
581
+ self.logger.info(f"Sending request to OpenRouter API...")
582
+ self.logger.info(f" Model: {self.config['model']}")
583
+ self.logger.info(f" Temperature: {self.config['temperature']}")
584
+ self.logger.info(f" Max tokens: 24000")
585
+ self.logger.info(f" Timeout: {self.config['timeout']}s")
586
+
550
587
  try:
551
588
  async with aiohttp.ClientSession(timeout=timeout) as session:
552
589
  async with session.post(
@@ -555,8 +592,11 @@ Return ONLY the JSON, no other text."""
555
592
  json=payload
556
593
  ) as response:
557
594
 
595
+ self.logger.info(f"OpenRouter API response status: {response.status}")
596
+
558
597
  if response.status == 429:
559
598
  retry_after = int(response.headers.get("Retry-After", 60))
599
+ self.logger.warning(f"Rate limited by OpenRouter, retry after {retry_after}s")
560
600
  raise ThrottlingError(f"Rate limited. Retry after {retry_after}s")
561
601
 
562
602
  response.raise_for_status()
@@ -564,14 +604,20 @@ Return ONLY the JSON, no other text."""
564
604
  response_data = await response.json()
565
605
 
566
606
  if "choices" not in response_data:
607
+ self.logger.error(f"Invalid API response format: {response_data}")
567
608
  raise GitHookError(f"Invalid API response format: {response_data}")
568
609
 
569
610
  content = response_data["choices"][0]["message"]["content"]
611
+ self.logger.info(f"OpenRouter response content length: {len(content)} characters")
612
+
570
613
  return self._validate_githook_response(content)
571
614
 
572
615
  except aiohttp.ClientError as e:
616
+ self.logger.error(f"OpenRouter API request failed: {e}")
617
+ self.logger.error(f"ClientError details: {type(e).__name__}: {str(e)}")
573
618
  raise GitHookError(f"OpenRouter API request failed: {e}")
574
- except asyncio.TimeoutError:
619
+ except asyncio.TimeoutError as e:
620
+ self.logger.error(f"OpenRouter API request timed out after {self.config['timeout']}s")
575
621
  raise GitHookError("OpenRouter API request timed out")
576
622
 
577
623
  def _validate_githook_response(self, response_text: str) -> Dict[str, Any]:
@@ -437,6 +437,12 @@ src/
437
437
  @self.server.call_tool()
438
438
  async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent]:
439
439
  """Handle tool calls with middleware."""
440
+ import time
441
+ start_time = time.time()
442
+
443
+ logger.info(f"=== MCP Tool Call: {name} ===")
444
+ logger.info(f"Arguments: {', '.join(arguments.keys())}")
445
+
440
446
  # Map tool names to handler methods
441
447
  tool_handlers = {
442
448
  "get_file_description": self._handle_get_file_description,
@@ -452,6 +458,7 @@ src/
452
458
  }
453
459
 
454
460
  if name not in tool_handlers:
461
+ logger.error(f"Unknown tool requested: {name}")
455
462
  from ..error_handler import ValidationError
456
463
  raise ValidationError(f"Unknown tool: {name}")
457
464
 
@@ -460,7 +467,18 @@ src/
460
467
  lambda args: self._execute_tool_handler(tool_handlers[name], args)
461
468
  )
462
469
 
463
- return await wrapped_handler(arguments)
470
+ try:
471
+ result = await wrapped_handler(arguments)
472
+
473
+ elapsed_time = time.time() - start_time
474
+ logger.info(f"MCP Tool '{name}' completed successfully in {elapsed_time:.2f}s")
475
+
476
+ return result
477
+ except Exception as e:
478
+ elapsed_time = time.time() - start_time
479
+ logger.error(f"MCP Tool '{name}' failed after {elapsed_time:.2f}s: {e}")
480
+ logger.error(f"Exception details: {type(e).__name__}: {str(e)}")
481
+ raise
464
482
 
465
483
  async def _execute_tool_handler(self, handler, arguments: Dict[str, Any]) -> List[types.TextContent]:
466
484
  """Execute a tool handler and format the result."""
@@ -758,9 +776,18 @@ src/
758
776
 
759
777
  async def _handle_update_file_description(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
760
778
  """Handle update_file_description tool calls."""
779
+ logger.info(f"Updating file description for: {arguments['filePath']}")
780
+ logger.info(f"Project: {arguments.get('projectName', 'Unknown')}")
781
+ logger.info(f"Branch: {arguments.get('branch', 'Unknown')}")
782
+
783
+ description_length = len(arguments.get("description", ""))
784
+ logger.info(f"Description length: {description_length} characters")
785
+
761
786
  project_id = await self._get_or_create_project_id(arguments)
762
787
  resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
763
788
 
789
+ logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
790
+
764
791
  file_desc = FileDescription(
765
792
  project_id=project_id,
766
793
  branch=resolved_branch,
@@ -773,6 +800,8 @@ src/
773
800
 
774
801
  await self.db_manager.create_file_description(file_desc)
775
802
 
803
+ logger.info(f"Successfully updated description for: {arguments['filePath']}")
804
+
776
805
  return {
777
806
  "success": True,
778
807
  "message": f"Description updated for {arguments['filePath']}",
@@ -782,31 +811,46 @@ src/
782
811
 
783
812
  async def _handle_check_codebase_size(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
784
813
  """Handle check_codebase_size tool calls."""
814
+ logger.info(f"Checking codebase size for: {arguments.get('projectName', 'Unknown')}")
815
+ logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
816
+ logger.info(f"Branch: {arguments.get('branch', 'Unknown')}")
817
+
785
818
  project_id = await self._get_or_create_project_id(arguments)
786
819
  resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
787
820
  folder_path = Path(arguments["folderPath"])
788
821
 
822
+ logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
823
+
789
824
  # Clean up descriptions for files that no longer exist
825
+ logger.info("Cleaning up descriptions for missing files...")
790
826
  cleaned_up_files = await self.db_manager.cleanup_missing_files(
791
827
  project_id=project_id,
792
828
  branch=resolved_branch,
793
829
  project_root=folder_path
794
830
  )
831
+ logger.info(f"Cleaned up {len(cleaned_up_files)} missing files")
795
832
 
796
833
  # Get file descriptions for this project/branch (after cleanup)
834
+ logger.info("Retrieving file descriptions...")
797
835
  file_descriptions = await self.db_manager.get_all_file_descriptions(
798
836
  project_id=project_id,
799
837
  branch=resolved_branch
800
838
  )
839
+ logger.info(f"Found {len(file_descriptions)} file descriptions")
801
840
 
802
841
  # Use provided token limit or fall back to server default
803
842
  token_limit = arguments.get("tokenLimit", self.token_limit)
804
843
 
805
844
  # Calculate total tokens
845
+ logger.info("Calculating total token count...")
806
846
  total_tokens = self.token_counter.calculate_codebase_tokens(file_descriptions)
807
847
  is_large = total_tokens > token_limit
808
848
  recommendation = "use_search" if is_large else "use_overview"
809
849
 
850
+ logger.info(f"Codebase analysis complete: {total_tokens} tokens, {len(file_descriptions)} files")
851
+ logger.info(f"Size assessment: {'LARGE' if is_large else 'SMALL'} (limit: {token_limit})")
852
+ logger.info(f"Recommendation: {recommendation}")
853
+
810
854
  return {
811
855
  "totalTokens": total_tokens,
812
856
  "isLarge": is_large,
@@ -819,20 +863,29 @@ src/
819
863
 
820
864
  async def _handle_find_missing_descriptions(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
821
865
  """Handle find_missing_descriptions tool calls."""
866
+ logger.info(f"Finding missing descriptions for: {arguments.get('projectName', 'Unknown')}")
867
+ logger.info(f"Folder path: {arguments.get('folderPath', 'Unknown')}")
868
+
822
869
  project_id = await self._get_or_create_project_id(arguments)
823
870
  resolved_branch = await self._resolve_branch(project_id, arguments["branch"])
824
871
  folder_path = Path(arguments["folderPath"])
825
872
 
873
+ logger.info(f"Resolved project_id: {project_id}, branch: {resolved_branch}")
874
+
826
875
  # Get existing file descriptions
876
+ logger.info("Retrieving existing file descriptions...")
827
877
  existing_descriptions = await self.db_manager.get_all_file_descriptions(
828
878
  project_id=project_id,
829
879
  branch=resolved_branch
830
880
  )
831
881
  existing_paths = {desc.file_path for desc in existing_descriptions}
882
+ logger.info(f"Found {len(existing_paths)} existing descriptions")
832
883
 
833
884
  # Scan directory for files
885
+ logger.info(f"Scanning project directory: {folder_path}")
834
886
  scanner = FileScanner(folder_path)
835
887
  if not scanner.is_valid_project_directory():
888
+ logger.error(f"Invalid or inaccessible project directory: {folder_path}")
836
889
  return {
837
890
  "error": f"Invalid or inaccessible project directory: {folder_path}"
838
891
  }
@@ -840,14 +893,18 @@ src/
840
893
  missing_files = scanner.find_missing_files(existing_paths)
841
894
  missing_paths = [scanner.get_relative_path(f) for f in missing_files]
842
895
 
896
+ logger.info(f"Found {len(missing_paths)} files without descriptions")
897
+
843
898
  # Apply limit if specified
844
899
  limit = arguments.get("limit")
845
900
  total_missing = len(missing_paths)
846
901
  if limit is not None and isinstance(limit, int) and limit > 0:
847
902
  missing_paths = missing_paths[:limit]
903
+ logger.info(f"Applied limit {limit}, returning {len(missing_paths)} files")
848
904
 
849
905
  # Get project stats
850
906
  stats = scanner.get_project_stats()
907
+ logger.info(f"Project stats: {stats.get('total_files', 0)} total files")
851
908
 
852
909
  return {
853
910
  "missingFiles": missing_paths,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-code-indexer
3
- Version: 1.6.2
3
+ Version: 1.6.4
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
@@ -37,6 +37,7 @@ Requires-Dist: aiofiles==23.2.0
37
37
  Requires-Dist: aiosqlite==0.19.0
38
38
  Requires-Dist: aiohttp>=3.8.0
39
39
  Requires-Dist: tenacity>=8.0.0
40
+ Requires-Dist: tomli>=1.2.0; python_version < "3.11"
40
41
  Provides-Extra: dev
41
42
  Requires-Dist: pytest>=8.0.0; extra == "dev"
42
43
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -57,8 +58,8 @@ Dynamic: requires-python
57
58
 
58
59
  # MCP Code Indexer 🚀
59
60
 
60
- [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?6)](https://badge.fury.io/py/mcp-code-indexer)
61
- [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?6)](https://pypi.org/project/mcp-code-indexer/)
61
+ [![PyPI version](https://badge.fury.io/py/mcp-code-indexer.svg?8)](https://badge.fury.io/py/mcp-code-indexer)
62
+ [![Python](https://img.shields.io/pypi/pyversions/mcp-code-indexer.svg?8)](https://pypi.org/project/mcp-code-indexer/)
62
63
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
63
64
 
64
65
  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.
@@ -7,6 +7,9 @@ aiosqlite==0.19.0
7
7
  aiohttp>=3.8.0
8
8
  tenacity>=8.0.0
9
9
 
10
+ [:python_version < "3.11"]
11
+ tomli>=1.2.0
12
+
10
13
  [dev]
11
14
  pytest>=8.0.0
12
15
  pytest-asyncio>=0.21.0
@@ -1,16 +0,0 @@
1
- """
2
- MCP Code Indexer - Intelligent codebase navigation for AI agents.
3
-
4
- A production-ready Model Context Protocol (MCP) server that provides
5
- intelligent codebase navigation through searchable file descriptions,
6
- token-aware overviews, and advanced merge capabilities.
7
- """
8
-
9
- __version__ = "1.6.0"
10
- __author__ = "MCP Code Indexer Contributors"
11
- __email__ = ""
12
- __license__ = "MIT"
13
-
14
- from .server.mcp_server import MCPCodeIndexServer
15
-
16
- __all__ = ["MCPCodeIndexServer", "__version__"]