Skip to content

feat: mcp docs search tools - #289

Merged
Zacgoose merged 3 commits into
devfrom
preview/mcp-docs-search
Aug 14, 2026
Merged

feat: mcp docs search tools#289
Zacgoose merged 3 commits into
devfrom
preview/mcp-docs-search

Conversation

@Zacgoose

Copy link
Copy Markdown
Contributor

No description provided.

Adds SearchDocs and GetDoc as always-advertised gateway tools, so an agent can
answer "how does CIPP do X" instead of guessing. Every other tool returns tenant
data; these explain the product, which is what a model needs before it knows
which data tool to reach for. Leaving them to be discovered via SearchTools
would mean already suspecting the docs exist.

The GitBook tree ships in the image (~2 MB of markdown) rather than being
fetched from docs.cipp.app: there is no GitBook search API, llms-full.txt is
capped at 100 of the 427 pages, and a crawl would put outbound internet in the
request path. Shipping it also version-matches the docs to the build, and
results still carry live docs.cipp.app links.

Indexing lives in CIPPSharp for two measured reasons. Tokenising the corpus in
PowerShell took 26s against ~2s in .NET, and the index is a host-scoped static,
so it builds once per host rather than once per runspace - a PowerShell $script:
cache would have rebuilt it for every worker in the pool. Retrieval is BM25 over
heading-delimited sections with domain synonyms and fuzzy matching; results
deep-link to the heading that matched.

Link derivation is pinned against all 427 published URLs. One rule is not
guessable from a path: a folder with no README.md is a GitBook grouping folder
and is dropped from the URL, so email/resources/management/equipment/edit.md is
served at email/management/equipment/edit. Seven pages would otherwise have had
confidently wrong links. Pages GitBook does not publish get a GitHub link and no
docsUrl rather than a URL that 404s.

Also mounts docs/ into the dev containers at the same path the image uses, and
un-excludes docs/ from the context-root .dockerignore - that file is what
Dockerfile.release resolves to, so without it the release build fails on the new
COPY while dev builds fine.
Update `Get-CippDocsRoot` to prefer `CIPPDocsPath` and only accept candidate folders that actually contain markdown, preventing empty `backend/Docs` mountpoints from shadowing real docs and causing zero-result searches. Align dev compose files to mount docs at `/app/Docs` and set `CIPPDocsPath`, add targeted Pester coverage for docs root selection behavior, and refresh the generated OpenAPI spec to reflect related endpoint metadata updates.
Config/DocsPublishedPages.txt decides whether a SearchDocs result gets a
docs.cipp.app link or falls back to GitHub, and only docs.cipp.app/llms.txt
knows which pages are actually live. Until now that list was whatever someone
last committed, so a page published after the snapshot stayed unlinkable until
a human remembered to re-run the script.

A build-docspages stage now refreshes it from the live site and overwrites the
committed copy in the image, alongside how openapi.json and
function-parameters.json are already generated. The committed file becomes the
fallback rather than the source of truth.

The fetch must never take the build down with it, so -AllowFallback warns and
leaves the committed list in place instead of throwing. That covers both a
failed request and a request that succeeds but parses to nothing - a captive
portal or an error page answers 200 with a body yielding zero slugs, and
overwriting a good list with that would strip the docs link off every result.

ARG BUILD_DATE is declared in the stage purely to bust the layer cache. Its only
other inputs are the script and the committed list, so without it Docker would
reuse an earlier layer and ship a stale list despite the stage existing. The
stage is tiny and independent, so unlike the version args near the frontend
build it invalidates nothing expensive.
@Zacgoose
Zacgoose merged commit a888ae8 into dev Aug 14, 2026
5 of 7 checks passed
@JohnDuprey
JohnDuprey deleted the preview/mcp-docs-search branch August 15, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant