mcpdoc: an MCP server that turns llms.txt files into auditable fetch_docs calls
Expose llms-txt to IDEs for development
At a glance
- What is it?
- mcpdoc wraps one or more llms.txt indexes behind a two-tool MCP server so IDEs such as Cursor, Windsurf and Claude Desktop retrieve documentation through calls you can inspect. The design is small and the domain allowlist is the part that decides whether it fits your setup.
- Who is it for?
- Adopt mcpdoc if you want IDE agents to read vendor documentation through tool calls you can see, and if the docs you need live on a small set of domains you can name in advance. Skip it if your questions routinely cross into arbitrary hosts, because the allowlist will block those fetches until you widen it with --allowed-domains, and skip it if you expect it to index or search a corpus rather than read URLs you already have.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 27 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem mcpdoc addresses: opaque documentation retrieval inside IDEs
The README frames the issue precisely. IDEs like Cursor and Windsurf, and apps like Claude Code and Claude Desktop, can already consume an llms.txt file to gather context, but each one uses its own built-in tooling to read and process that file. The retrieval path is not visible to the developer, and there is not always a way to audit either the tool calls or the context that comes back. That matters when an agent answers a question about a library and you cannot tell which page it read or whether it read anything at all.
mcpdoc takes the position that MCP is the escape hatch. Because MCP lets a developer define the tools an application may call, mcpdoc supplies a server that exposes a user-defined list of llms.txt files plus a single fetch_docs tool for reading URLs found inside them. The audience is therefore narrow and specific: developers using an MCP-capable host who want the documentation lookup step to be explicit rather than inferred by the host application. It is not a documentation generator, not a crawler and not a search engine.
Two tools, one allowlist: the mechanism inside mcpdoc
The surface area is deliberately small. The server exposes list_doc_sources, which returns the llms.txt files you configured, and fetch_docs, which reads a URL from within one of those files. The README's suggested Cursor rule spells out the intended loop: call list_doc_sources to see available indexes, call fetch_docs to read one, reason over the URLs it contains alongside the user's question, then call fetch_docs again on the URLs that look relevant. The agent does the selection; mcpdoc does the retrieval and the logging.
The retrieval is gated by a domain allowlist, and this is the most consequential design decision in the project. When you pass a remote llms.txt URL, mcpdoc adds only that specific domain to the allowed list, so a LangGraph index at langchain-ai.github.io permits fetches on langchain-ai.github.io and nothing else. When you pass a local llms.txt file instead, no domain is added automatically, and you must name the domains yourself with --allowed-domains. Passing --allowed-domains '*' opens everything, and the README flags that as something to use with caution. The stated purpose is to prevent access to domains the user has not approved.
The consequence is that the tool's usefulness is bounded by the index it reads. If an llms.txt file links to a separate host, fetch_docs will not follow it unless that host was added. That is a real constraint, not a theoretical one, and it is the first thing to check when a fetch fails.
Running mcpdoc locally: uvx, --urls, --transport and the inspector
The README's quickstart assumes uv. The install command it gives is the standard shell installer:
curl -LsSf https://astral.sh/uv/install.sh | sh
From there you can run the server without a permanent install. The documented example starts an SSE server on port 8082 with two sources:
uvx --from mcpdoc mcpdoc --urls "LangGraph:https://langchain-ai.github.io/langgraph/llms.txt" "LangChain:https://python.langchain.com/llms.txt" --transport sse --port 8082 --host localhost
The label before the colon is the name the source appears under; the URL after it is the index. The README says this should run at http://localhost:8082. To exercise the tools, it points at the MCP inspector via npx @modelcontextprotocol/inspector, which is where you can confirm that list_doc_sources and fetch_docs behave as expected before committing the server to an editor config.
For editor integration the transport changes to stdio. The Cursor snippet in the README writes to ~/.cursor/mcp.json and uses the same uvx invocation with --transport stdio, registering the server under the name langgraph-docs-mcp. Windsurf uses ~/.codeium/windsurf/mcp_config.json with the same server entry. Note the argument formatting in that JSON: both URLs sit inside a single string separated by a space, which is easy to get wrong when you add a third source. The README also recommends pairing the server with editor rules that instruct the agent to call list_doc_sources first and fetch_docs afterwards, since the tools do nothing on their own.
Where mcpdoc breaks down: local files, cross-domain links and no search
The local-file case is the sharpest edge. If you point mcpdoc at an llms.txt file on disk, the README states that no domains are added automatically and you must specify them explicitly with --allowed-domains. A user who copies the remote example, swaps in a local path and expects the same behaviour will find that fetch_docs refuses URLs the index clearly lists. The failure is silent in the sense that the server is running and list_doc_sources works; only the fetch step fails.
Cross-domain indexes are the second limitation. Because only the domain of the remote llms.txt is auto-allowed, any index that links to a second host requires an extra --allowed-domains entry. Loosening this to '*' removes the protection the feature exists to provide, so the choice is between maintenance overhead and a wider fetch surface.
Third, mcpdoc does not search. There is no embedding index, no ranking and no chunking described in the material. The agent reads the index, picks URLs, and reads them. For a large documentation set that means the quality of the answer depends on the agent's ability to choose URLs from a flat list, which is a different proposition from a retrieval system that scores passages. If your problem is finding a needle in a large corpus, mcpdoc is the wrong layer.
How mcpdoc differs from letting the IDE read llms.txt itself
The obvious alternative is to use the host application's built-in llms.txt handling, which is exactly what the README describes as the status quo. Cursor, Windsurf and Claude Desktop can already retrieve context from an llms.txt file. The difference is control and observability. With the built-in path, the README says the retrieval process can be opaque and there is not always a way to audit the tool calls or the context returned. With mcpdoc, the same retrieval happens through named tools that appear in the host's tool-call log, and the domain allowlist constrains where those calls can go.
That is a meaningful difference for a team that needs to explain how an agent arrived at an answer, or that wants to restrict documentation reads to approved hosts. It is a much smaller difference for an individual developer who just wants the agent to know about LangGraph and does not care to inspect the calls. In that case the built-in path is less configuration: no uv, no mcp.json entry, no editor rules to maintain. mcpdoc trades setup effort for an audit trail and a policy boundary.
Version cadence, licence and what upgrading involves
The project is MIT licensed, which permits commercial use and modification, though this is not legal advice and the licence text is the authority. Releases move slowly: mcpdoc==0.0.8 in March 2025, 0.0.9 in July 2025, and 0.0.10 later in July 2025. The 0.0.x versioning is a fair signal that the interface is not yet frozen, so pinning matters.
Upgrade cost depends on how you invoked it. The uvx --from mcpdoc form in the README resolves the package at launch, which means an editor restart can pull a newer build without any change on your side. If you want the version you tested, pin it in the uvx argument rather than relying on the default. The config file itself is small (a command, an args array and a transport), so the migration surface is the --urls string and the --allowed-domains list, both of which live in that one JSON block per editor. The editor rules that tell the agent to call list_doc_sources before fetch_docs are separate text in a different settings pane, and they can drift out of sync with the server config when you add or rename a source.
Editorial conclusion
Adopt mcpdoc if you want IDE agents to read vendor documentation through tool calls you can see, and if the docs you need live on a small set of domains you can name in advance. Skip it if your questions routinely cross into arbitrary hosts, because the allowlist will block those fetches until you widen it with --allowed-domains, and skip it if you expect it to index or search a corpus rather than read URLs you already have. Before wiring it into a team config, run the uvx command with --transport sse on port 8082 and point the MCP inspector at it to confirm that list_doc_sources returns the sources you passed and that fetch_docs resolves a URL on the auto-added domain.
Community notes