pip install git+https://github.com/jgravelle/jcodemunch-mcp.gitOr from source:
git clone https://github.com/jgravelle/jcodemunch-mcp.git
cd jcodemunch-mcp
pip install -e .Add to your claude_desktop_config.json:
{
"mcpServers": {
"jcodemunch": {
"command": "jcodemunch-mcp",
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx",
"ANTHROPIC_API_KEY": "sk-ant-xxxxxxxx"
}
}
}
}Both environment variables are optional:
GITHUB_TOKENenables private repositories and higher GitHub API rate limits.ANTHROPIC_API_KEYenables AI-generated summaries via Claude Haiku.GOOGLE_API_KEYenables AI-generated summaries via Gemini Flash (used ifANTHROPIC_API_KEYis not set).- If neither key is set, summaries fall back to docstrings or signatures.
Add to .vscode/settings.json:
{
"mcp.servers": {
"jcodemunch": {
"command": "jcodemunch-mcp",
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx"
}
}
}
}If you use Claude Code, you can display a live token savings counter in the status bar:
Claude Sonnet 4.6 | my-project | ░░░░░░░░░░ 0% | 1,280,837 tkns saved · $6.40 saved on Opus
Ask Claude Code to set it up:
"Add jcodemunch token savings to my status line"
Claude Code will add a segment that reads ~/.code-index/_savings.json and calculates cost avoided at the Claude Opus rate ($25.00 / 1M tokens). The counter updates automatically after every jcodemunch tool call — no restart required.
To add it manually, read ~/.code-index/_savings.json and extract total_tokens_saved:
// Node.js snippet for a statusline hook
const f = path.join(os.homedir(), '.code-index', '_savings.json');
const total = fs.existsSync(f) ? JSON.parse(fs.readFileSync(f)).total_tokens_saved ?? 0 : 0;
const cost = (total * 25.00 / 1_000_000).toFixed(2);
if (total > 0) output += ` │ ${total.toLocaleString()} tkns saved · $${cost} saved on Opus`;- Open the Agent pane → click the
⋯menu → MCP Servers → Manage MCP Servers - Click View raw config to open
mcp_config.json - Add the entry below, save, then restart the MCP server from the Manage MCPs pane
{
"mcpServers": {
"jcodemunch": {
"command": "jcodemunch-mcp",
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxx",
"ANTHROPIC_API_KEY": "sk-ant-xxxxxxxx"
}
}
}
}index_repo: { "url": "fastapi/fastapi" }
get_repo_outline: { "repo": "fastapi/fastapi" }
get_file_tree: { "repo": "fastapi/fastapi", "path_prefix": "fastapi" }
get_file_outline: { "repo": "fastapi/fastapi", "file_path": "fastapi/main.py" }
index_folder: { "path": "/home/user/myproject" }
get_repo_outline: { "repo": "local-myproject" }
search_symbols: { "repo": "local-myproject", "query": "main" }
search_symbols: { "repo": "owner/repo", "query": "authenticate", "kind": "function" }
get_symbol: { "repo": "owner/repo", "symbol_id": "src/auth.py::authenticate#function" }
get_file_outline: { "repo": "owner/repo", "file_path": "src/auth.py" }
get_symbols: {
"repo": "owner/repo",
"symbol_ids": [
"src/auth.py::AuthHandler.login#method",
"src/auth.py::AuthHandler.logout#method"
]
}
get_symbol: {
"repo": "owner/repo",
"symbol_id": "src/main.py::process#function",
"verify": true
}
The response _meta.content_verified will be true if the source matches the stored hash and false if it has drifted.
search_text: { "repo": "owner/repo", "query": "TODO", "file_pattern": "*.py" }
Use search_text for string literals, comments, configuration values, or anything that is not a symbol name.
invalidate_cache: { "repo": "owner/repo" }
index_repo: { "url": "owner/repo" }
| Tool | Purpose | Key Parameters |
|---|---|---|
index_repo |
Index GitHub repository | url, use_ai_summaries |
index_folder |
Index local folder | path, extra_ignore_patterns, follow_symlinks |
list_repos |
List all indexed repositories | — |
get_file_tree |
Browse file structure | repo, path_prefix |
get_file_outline |
Symbols in a file | repo, file_path |
get_symbol |
Full source of one symbol | repo, symbol_id, verify, context_lines |
get_symbols |
Batch retrieve symbols | repo, symbol_ids |
search_symbols |
Search symbols | repo, query, kind, language, file_pattern, max_results |
search_text |
Full-text search | repo, query, file_pattern, max_results |
get_repo_outline |
High-level overview | repo |
invalidate_cache |
Delete cached index | repo |
Symbol IDs follow the format:
{file_path}::{qualified_name}#{kind}
Examples:
src/main.py::UserService#class
src/main.py::UserService.login#method
src/utils.py::authenticate#function
config.py::MAX_RETRIES#constant
IDs are returned by get_file_outline, search_symbols, and search_text. Pass them to get_symbol or get_symbols to retrieve source code.
jCodeMunch contributes an anonymous token savings delta to a live global counter at j.gravelle.us with each tool call. Only two values are ever sent: the tokens saved (a number) and a random anonymous install ID. No code, paths, repo names, or anything identifying is transmitted. Network failures are silent and never affect tool performance.
The anonymous install ID is generated once and stored locally in ~/.code-index/_savings.json.
To disable, set JCODEMUNCH_SHARE_SAVINGS=0 in your MCP server env:
{
"mcpServers": {
"jcodemunch": {
"command": "jcodemunch-mcp",
"env": {
"JCODEMUNCH_SHARE_SAVINGS": "0"
}
}
}
}"Repository not found"
Check the URL format (owner/repo or full GitHub URL). For private repositories, set GITHUB_TOKEN.
"No source files found"
The repository may not contain supported language files (.py, .js, .ts, .go, .rs, .java), or files may be excluded by skip patterns.
Rate limiting
Set GITHUB_TOKEN to increase GitHub API limits (5,000 requests/hour vs 60 unauthenticated).
AI summaries not working
Set ANTHROPIC_API_KEY (Claude Haiku) or GOOGLE_API_KEY (Gemini Flash). Anthropic takes priority if both are set. Without either, summaries fall back to docstrings or signatures.
Stale index
Use invalidate_cache followed by index_repo or index_folder to force a clean re-index.
Encoding issues Files with invalid UTF-8 are handled safely using replacement characters.
Indexes are stored at ~/.code-index/ (override with the CODE_INDEX_PATH environment variable):
~/.code-index/
├── owner-repo.json # Index metadata + symbols
└── owner-repo/ # Raw source files
└── src/main.py
- Start with
get_repo_outlineto quickly understand the repository structure. - Use
get_file_outlinebefore reading source to understand the API surface first. - Narrow searches using
kind,language, andfile_pattern. - Batch-retrieve related symbols with
get_symbolsinstead of repeatedget_symbolcalls. - Use
search_textwhen symbol search does not locate the needed content. - Use
verify: trueonget_symbolto detect source drift since indexing.