BC Code Intelligence MCP Server
Business Central and AL development guidance from a bundled knowledge base of specialist personas
Indexes documentation by heading so a coding agent can fetch one section instead of a whole file
By J. Gravelle (individual) Python Local · stdio Developer toolsKnowledge and memory
56 popularity score ★ 206 ↓ 5.5k/mo
Opens the app, which asks before it adds the server.
claude mcp add jdocmunch -- uvx jdocmunch-mcp{
"mcpServers": {
"jdocmunch": {
"command": "uvx",
"args": [
"jdocmunch-mcp"
]
}
}
}{
"mcpServers": {
"jdocmunch": {
"command": "uvx",
"args": [
"jdocmunch-mcp"
]
}
}
}{
"servers": {
"jdocmunch": {
"type": "stdio",
"command": "uvx",
"args": [
"jdocmunch-mcp"
]
}
}
}[mcp_servers.jdocmunch]
command = "uvx"
args = ["jdocmunch-mcp"]gemini mcp add --scope user jdocmunch uvx -- jdocmunch-mcpGITHUB_TOKEN secret |
Optional: GitHub token for higher API limits and private repositories. |
|---|---|
DOC_INDEX_PATH |
Optional: Folder where indexes are stored. |
JDOCMUNCH_SHARE_SAVINGS |
Optional: Set to 0 to stop the anonymous savings counter. |
| Set together: summaries | |
ANTHROPIC_API_KEY secret |
Optional: Claude key for section summaries, used only when the provider is named or JDOCMUNCH_ALLOW_PAID_SUMMARIES=1. |
JDOCMUNCH_SUMMARIZER_PROVIDER |
Optional: Names the summary provider, which also allows a paid one. |
| Set together: embeddings | |
GOOGLE_API_KEY secret |
Optional: Gemini key for summaries or embeddings, used only when the provider is named or the matching JDOCMUNCH_ALLOW_PAID setting is 1. |
OPENAI_API_KEY secret |
Optional: OpenAI key for summaries or embeddings, used only when the provider is named or the matching JDOCMUNCH_ALLOW_PAID setting is 1. |
JDOCMUNCH_EMBEDDING_PROVIDER |
Optional: Names the embedding provider: gemini, openai, openai-compatible, fastembed, sentence-transformers or none. |
| Set together: ocr | |
JDOCMUNCH_OCR |
Optional: Set to 1 to allow OCR of scanned PDFs (the call must also ask for it). |
JDOCMUNCH_TESSERACT_PATH |
Optional: Path to a Tesseract program, checked before PATH. |
JDOCMUNCH_OCR_ENGINE |
Optional: OCR engine: auto, tesseract or windows. |
JDOCMUNCH_OCR_LANG |
Optional: Installed Tesseract languages to use. |
jDocMunch MCP is a local Python server that breaks a documentation set into a tree of sections keyed by headings. For each section it records byte offsets into the source file. An agent can then search the docs, pick the section it wants and read just that part instead of the whole file.
You point it at a local folder or at the docs of a GitHub repository. Local folders can hold Markdown/MDX, reStructuredText, AsciiDoc, Jupyter notebooks, HTML, plain text, OpenAPI YAML, JSON, XML and Godot scenes. PDF, DOCX, PPTX and EPUB need the optional [office] extra. Since 1.149.0 there is also an [ocr] extra for scanned PDFs, which uses Tesseract or the built-in Windows OCR if one is already installed. Search is BM25 keyword ranking until you configure an embedding provider (Gemini, OpenAI, an OpenAI-compatible endpoint, or a local FastEmbed or sentence-transformers model), and then it ranks by both. Other tools walk the heading tree, query OpenAPI specs and report doc health such as broken links and orphan pages.
Version 1.150.1 registers 64 tools in server.py. JDOCMUNCH_TOOL_PROFILE (core, standard or full, with full as the default) and JDOCMUNCH_DISABLED_TOOLS cut that list down. A folder too big to index within a client's tool timeout can be indexed from a shell with `jdocmunch-mcp index-local`, which writes to the same store. Indexes live under ~/.doc-index/ unless DOC_INDEX_PATH is set.
The code is stricter about paid providers than the README lets on. A cloud key sitting in the environment is ignored for summaries and embeddings unless you name the provider in JDOCMUNCH_SUMMARIZER_PROVIDER or JDOCMUNCH_EMBEDDING_PROVIDER, or set JDOCMUNCH_ALLOW_PAID_SUMMARIES=1 or JDOCMUNCH_ALLOW_PAID_EMBEDDINGS=1 (summarizer/batch_summarize.py and embeddings/provider.py at v1.150.1).
It is dual-licensed. Personal and non-commercial use is free, and commercial use needs a paid one-time licence from jMunch LLC.
| Runtime | Python 3.10+ |
|---|---|
| Runs on | macOS, Windows, Linux |
| Also |
|
Local indexing and keyword search need no account or key. GITHUB_TOKEN raises the GitHub API limit. Cloud summaries or embeddings need a key plus the provider named (JDOCMUNCH_SUMMARIZER_PROVIDER, JDOCMUNCH_EMBEDDING_PROVIDER) or JDOCMUNCH_ALLOW_PAID_SUMMARIES=1 / JDOCMUNCH_ALLOW_PAID_EMBEDDINGS=1. OpenAI-compatible summarizers need `uvx --with openai jdocmunch-mcp`. Local embeddings need the [fastembed] extra and a one-time model download. Office formats need the [office] extra. Scanned PDFs need the [ocr] extra, an engine already installed, JDOCMUNCH_OCR=1 and ocr=true on the call. Commercial use needs a paid licence.
Indexing a GitHub repository with doc_index_repo picks up only .md and .txt files; the other formats and the office formats work only for local folders (server.py at v1.146.0). Files over 5 MB are skipped by default (JDOCMUNCH_MAX_FILE_SIZE). Without an embedding provider, search is keyword-only and weaker on paraphrased questions. Section retrieval saves little on small files with one heading. Freshness is reported, not guaranteed: a section whose source can't be checked is marked unknown. It doesn't parse source code; its makers point to jcodemunch-mcp for code and jdatamunch-mcp for tabular data. Hooks need an installed copy (uv tool install, pipx or pip), not uvx.
Suits developers whose agents read large documentation sets, such as framework docs, internal wikis or OpenAPI specs, who want section-sized reads and want everything kept on their own machine. Keyword search works offline with no keys. It suits personal and non-commercial projects without cost; a company using it needs a paid licence. For code symbols, its makers point to jcodemunch-mcp, and for tabular data to jdatamunch-mcp, both from the same author. On small doc sets with few headings it adds little over reading the files directly.
55 only read, 4 change things, 1 can delete or overwrite. A ? marks an optional parameter.
index_local changespath: stringuse_ai_summaries?: booleanuse_embeddings?: anyextra_ignore_patterns?: arrayocr?: booleanocr_budget_seconds?: numberocr_max_pages?: integerinclude_dot_dirs?: arrayfollow_symlinks?: booleanmax_files?: integersort_by?: enumname?: stringincremental?: booleanautotune?: booleanpaths?: arrayworktree_mode?: enumlegacy_reconcile?: enumdoc_index_repo changesurl: stringref?: stringuse_ai_summaries?: booleanuse_embeddings?: anyname?: stringincremental?: booleandoc_list_reposget_index_overviewrepo: stringtop_n?: integerget_docrepo: stringdoc_path: stringlist_docsrepo: stringpath_glob?: stringlimit?: integeroffset?: integerget_tocrepo: stringpath_glob?: stringlimit?: integeroffset?: integerget_toc_treerepo: stringpath_glob?: stringlimit?: integeroffset?: integerget_document_outlinerepo: stringdoc_path: stringsearch_sectionsrepo?: stringquery: stringdoc_path?: stringpath_glob?: stringmax_results?: integersemantic?: booleansemantic_only?: booleansemantic_weight?: numberrole?: stringprofile?: enumdedupe?: booleanmin_answerability?: numbermin_quotability?: numbermin_level?: integermax_level?: integertags?: arrayexclude_tags?: arrayroles?: arrayexclude_roles?: arraymin_byte_length?: integercount_sectionsrepo: stringdoc_path?: stringpath_glob?: stringrole?: stringroles?: arrayexclude_roles?: arraytags?: arrayexclude_tags?: arraymin_level?: integermax_level?: integermin_byte_length?: integermax_byte_length?: integersearch_titlesrepo: stringquery: stringmax_results?: integerget_sectionrepo: stringsection_id: stringverify?: booleanstrip_boilerplate?: booleancompress_code?: booleanget_sectionsrepo: stringsection_ids: arrayverify?: booleanstrip_boilerplate?: booleancompress_code?: booleanget_section_contextrepo: stringsection_id: stringmax_tokens?: integerinclude_children?: booleaninclude_related?: booleanstrip_boilerplate?: booleandescribe_sectionrepo: stringsection_id: stringsection_neighborsrepo: stringsection_id: stringget_recent_changesrepo: stringinclude_stale?: booleaninclude_edited?: booleanlive_source?: booleanget_all_rolesrepo: stringsample_size?: integerget_all_tagsrepo: stringmin_section_count?: integerget_section_descendantsrepo: stringsection_id: stringmax_depth?: integerget_section_excerptsrepo: stringsection_ids: arraymax_bytes?: integerget_section_excerptrepo: stringsection_id: stringmax_bytes?: integerget_section_pathrepo: stringsection_id: stringget_orphan_sectionsrepo: stringinclude_same_doc?: booleanget_section_summaryrepo: stringsection_id: stringget_section_summariesrepo: stringsection_ids: arraydelete_index deletesrepo: stringget_broken_linksrepo: stringget_doc_coveragerepo: stringsymbol_ids: arrayget_backlinksrepo: stringdoc_path: stringget_stale_pagesrepo: stringsources_dir?: stringget_wiki_statsrepo: stringget_watch_statusfinalize_handoffrepo: stringtask: stringsections: arrayevidence_refs: arrayprofile?: stringappendices?: arrayfind_code_examplesrepo: stringquery: stringlang?: stringdoc_path?: stringpath_glob?: stringmax_results?: integerlink_code_to_symbolsrepo: stringcode_repo: stringmax_examples?: integermax_symbols_per_block?: integerresolve_related_code_reposrepo: stringdoc_resolve_repopath: stringfind_endpointrepo: stringpath?: stringmethod?: stringtag?: stringlist_endpoints_by_tagrepo: stringtag: stringfind_operations_using_schemarepo: stringschema_name: stringget_schema_graphrepo: stringschema_name: stringmax_depth?: integerlookup_termrepo: stringterm: stringlist_termsrepo: stringprefix?: stringmax_results?: integerget_related_sectionsrepo: stringsection_id: stringmode?: enumtop_n?: integermin_score?: numbermax_per_kind?: integerget_section_diffrepo: stringsection_id: stringget_doc_healthrepo: stringdoc_health_radarrepo: stringget_doc_pr_risk_profilerepo: stringchanged_sections: arrayget_tutorial_pathrepo: stringsection_id: stringget_undocumented_symbolsrepo: stringcode_repo: stringmax_symbols?: integerlist_repo_groupsdefine_repo_group changesname: stringrepos: arraytune_weights changesrepo?: stringmin_events?: integerdry_run?: booleanmax_age_days?: integerset_weight?: numberverify_indexrepo: stringsample?: integersource?: enumfind_similar_sectionsrepo: stringmin_score?: numbernear_duplicate_threshold?: numbermax_clusters?: integerexclude_same_doc?: booleanmax_sections?: integerget_section_blast_radiusrepo: stringsection_id: stringmax_depth?: integercheck_section_delete_saferepo: stringsection_id: stringtransitive_depth?: integerrecent_edit_days?: integerjdocmunch_guide