jcodemunch-mcp: Token-Efficient Code Exploration Server
jcodemunch-mcp is a Python library providing a token-efficient MCP (Multi-language Code Processing) server for deep source code exploration. It leverages tree-sitter for AST parsing across 70+ languages, offering tools like cross-language AST pattern matching, symbol provenance, project intelligence, and tectonic analysis. The current version is 1.52.0, with a rapid release cadence focusing on new analysis capabilities and performance improvements.
Common errors
-
ImportError: cannot import name 'Client' from 'jcodemunch_mcp'
cause Attempting to import the main client class using an incorrect name, `Client`.fixThe primary client class is `MCPClient`. Use `from jcodemunch_mcp import MCPClient`. -
ValueError: Path '/usr/src' too shallow for indexing. Minimum 2 components required in container environments.
cause Attempting to index a repository path with insufficient depth (e.g., '/app' or '/usr/src') when running inside a container, which is restricted by design to prevent accidental indexing of system roots.fixProvide a more specific path (e.g., `/app/my-repo`) to `client.index_folder()`, or use the `trusted_folders` parameter in the `MCPClient` constructor or `index_folder` method to explicitly allow shallow paths (e.g., `client = MCPClient(trusted_folders=['/usr/src'])`). -
jcodemunch_mcp.exceptions.IndexingError: Maximum memory limit exceeded during repository indexing. Consider reducing scope or increasing resources.
cause Indexing a very large or highly complex repository (e.g., monorepo with thousands of files) consumed too much memory or hit an internal limit, especially in resource-constrained environments.fixFor very large repositories, try indexing smaller sub-sections if possible. If running in a container, increase the allocated memory for the container. The library is optimized for token efficiency, but initial AST parsing can still be memory-intensive. Consider filtering paths with a `.codemunchignore` file or using `trusted_folders` to limit the indexing scope.
Warnings
- gotcha Path depth requirements for `index_folder` in container environments changed.
- gotcha Branch-Aware Delta Indexing introduced, changing indexing behavior and resource usage.
- gotcha Misusing `search_ast` queries with language-specific AST node types.
Install
-
pip install jcodemunch-mcp
Imports
- MCPClient
from jcodemunch_mcp import Client
from jcodemunch_mcp import MCPClient
Quickstart
import os
from jcodemunch_mcp import MCPClient
# Initialize the client. This assumes a local server or embedded functionality.
# For advanced setups, authentication or server URL might be configured via env vars or constructor args.
client = MCPClient()
# Define the repository path to analyze (e.g., the current directory).
# For real-world use, replace with your target repository path.
repo_path = os.getcwd()
print(f"Indexing repository at '{repo_path}' for analysis...")
# It's good practice to explicitly index the folder first.
# Note: This might take time for large repositories.
client.index_folder(repo_path=repo_path)
print("Indexing complete.")
# Example 1: Search for a common anti-pattern (e.g., 'empty_catch') using cross-language AST matching.
print(f"\nSearching for 'empty_catch' anti-pattern...")
results_ast = client.search_ast(repo_path=repo_path, query='empty_catch')
if results_ast:
print(f"Found {len(results_ast)} 'empty_catch' instances. Showing first 3:")
for r in results_ast[:3]:
print(f"- {r['file']}:{r['line']} (Lang: {r['lang']}):\n ```\n{r['snippet']}\n ```")
else:
print("No 'empty_catch' instances found.")
# Example 2: Get project intelligence (e.g., Dockerfiles, CI/CD configs).
print(f"\nGetting project intelligence for '{repo_path}'...")
project_intel = client.get_project_intel(repo_path=repo_path)
if project_intel and 'dockerfiles' in project_intel:
print(f"Found {len(project_intel['dockerfiles'])} Dockerfiles.")
for df in project_intel['dockerfiles'][:1]: # Show details for the first Dockerfile
print(f"- Dockerfile at: {df['path']}")
print(f" Entrypoint: {df.get('entrypoint', 'N/A')}")
print(f" Stages: {', '.join([s['name'] for s in df.get('stages', [])])}")
else:
print("No Dockerfiles or significant project intelligence found.")