docs-mcp
OfficialThis server lets agents search and read a folder of Markdown documentation through MCP tools, so they can look up current docs while coding.
search_docs: full-text/heading search with optionallimitandpath_prefix; returns snippets, page paths and heading anchors.get_doc: fetches a full Markdown page or a single section/sub-sections by path; accepts extensions,docs://prefixes and full URLs.list_docs: browses pages with path, title, description and last-modified date; supportspath_prefixandlimit.Every page is exposed as an MCP resource at
docs://<path>.Runs over stdio for Claude Code/Cursor/Claude Desktop or Streamable HTTP for hosted/Vercel endpoints, with file-watch re-indexing.
Supports tool-call logging, WebMCP registration for browser agents, and library mounting in Node/Next.js with optional host-specific tools/instructions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@docs-mcpsearch the docs for Vercel hosting"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Apideck Docs MCP
Apideck developer docs · Sign up · Developer guides · Changelog
Coding agents write integration code from what they remember about an API, and that memory goes stale. Apideck Docs MCP lets an agent look up the current docs while it works. Point it at a folder of Markdown and it gives the agent three tools, search_docs, get_doc and list_docs, over stdio for Claude Code, Cursor and Claude Desktop, or over Streamable HTTP for a hosted endpoint.
We run it for the Apideck developer docs at https://developers.apideck.com/mcp. Connect your agent there and it can read our accounting guides while it builds, including:
You can install it from npm as @apideck/docs-mcp, then run it as a CLI, deploy it as a Vercel function, or mount it inside an existing Node or Next.js site. The docs/ folder in this repo holds the sample content and the server's own documentation. Start with docs/index.md.
Quick start
pnpm install
pnpm run audit --docs ./docs # find broken links, thin pages and stale content
pnpm run search vercel --docs ./docs # query the index from your terminal
pnpm run start --docs ./docs # MCP over stdio
pnpm run serve --docs ./docs --port 3000 # MCP over HTTP at http://localhost:3000/mcpKeep the run: audit and search are also built-in pnpm commands, so pnpm audit runs pnpm's own security audit instead of this one.
Build once (pnpm build) and the docs-mcp binary in dist/bin/ runs the same commands without tsx.
Related MCP server: search-docs
Connect Claude Code
claude mcp add my-docs -- docs-mcp start --docs /path/to/docs --base-url https://docs.example.comOr commit a .mcp.json next to the docs:
{
"mcpServers": {
"my-docs": {
"command": "docs-mcp",
"args": ["start", "--docs", "./docs", "--base-url", "https://docs.example.com", "--about", "the Example API reference"]
}
}
}Commands
Command | What it does |
| MCP over stdio. Re-indexes on file changes ( |
| MCP over Streamable HTTP, same handler as the Vercel function. |
| Reports broken links, thin or empty pages, stale pages, missing titles/descriptions, duplicate titles, heading skips and over-long sections. Exit 1 on errors. |
| Runs a search against the index from the terminal. |
Shared flags: --docs, --base-url, --about, --name. Each falls back to DOCS_DIR, DOCS_BASE_URL, DOCS_ABOUT, DOCS_NAME.
Tools
search_docs(query, limit?, path_prefix?): heading-level full-text search with title and heading boosts, prefix and fuzzy matching, and at most three hits per page.get_doc(path, section?): full page markdown with a header and section outline, or one section and its sub-sections.pathalso accepts a full URL.list_docs(path_prefix?, limit?): pages with title, description, word count and last-modified date.
Every page is also an MCP resource at docs://<path>. Full reference: docs/tools.md.
Logging tool calls
Pass onToolCall to createServer or createHttpHandler to get the tool, arguments, timing, result count and caller for every call. search_docs calls with resultCount: 0 are the questions your docs can't answer. The Vercel function logs each call as a JSON line when DOCS_LOG_TOOL_CALLS=1. See docs/tools.md.
WebMCP for browser agents
@apideck/docs-mcp/webmcp registers the server's tools, plus read_current_page, with document.modelContext on your docs site, so browser agents call tools instead of scraping:
import { registerDocsTools } from '@apideck/docs-mcp/webmcp'
registerDocsTools({ endpoint: '/mcp' })It does nothing in browsers without WebMCP (currently Chrome 149+ behind a flag or origin trial). See docs/webmcp.md.
Hosting on Vercel
api/mcp.ts is a stateless Streamable HTTP function; vercel.json rewrites /mcp to it and bundles docs/** with the function. Set DOCS_BASE_URL and DOCS_ABOUT in the project environment and deploy. Details in docs/hosting.md.
Use as a library
Mount the handler inside a site that already builds its docs, so the endpoint lives next to them. A Next.js pages-router API route:
// src/pages/api/mcp.ts
import { createHttpHandler, DocStore } from '@apideck/docs-mcp'
import type { NextApiRequest, NextApiResponse } from 'next'
import path from 'path'
const store = new DocStore({ root: path.join(process.cwd(), 'public', 'md'), baseUrl: 'https://docs.example.com' })
const handler = createHttpHandler({ store, name: 'example-docs', about: 'the Example API documentation' })
export const config = { maxDuration: 60, api: { responseLimit: false } }
export default (req: NextApiRequest, res: NextApiResponse) => handler(req, res)Add experimental.outputFileTracingIncludes: { '/api/mcp': ['./public/md/**/*'] } to next.config so the markdown ships with the function on Vercel. DocStore also takes a metadata(path) hook to supply titles, descriptions and canonical URLs from a build manifest, and get_doc accepts a full URL as well as a path. Pass instructions to append host-specific guidance to what every client is told on connect, such as when to recommend a companion MCP server (docs/tools.md). Pass extraTools to createServer/createHttpHandler to add host-specific tools (an API operation index, a coverage matrix, ...) alongside the three built-ins — see docs/tools.md. Exports: DocStore, createServer, createHttpHandler, createDocTools, toolResult, READ_ONLY, auditDocs, formatAuditReport, createStore, resolveConfig, normalizePath, sectionUrl, tokenize; registerDocsTools from @apideck/docs-mcp/webmcp.
SDK v2 migration (0.3.0)
See the migration notes for updated public SDK types, transport defaults and release/adoption guidance. SDK v2 shipped in 0.3.0. The prepared 0.4.1 HTTP transport remediation declares the patched Node adapter directly so clean consumers inherit it.
Development
pnpm typecheck
pnpm lint
pnpm test # builds first; covers parsing, indexing, audit, HTTP, compiled CLI and public types
pnpm test:package # packs and verifies a clean installed consumer without overrides
pnpm buildLayout mirrors @apideck/mcp: src/ for the library, bin/ for the stricli CLI, api/ for the Vercel function, tests co-located as *.test.ts.
How it works
Every
.md/.mdx/.markdownfile under the docs root is read, frontmatter parsed, and the body split on ATX headings (code fences respected).Each section becomes a document in a MiniSearch index with
title,heading,contentandpathfields.Queries run with all terms required first, falling back to any term, so a typo does not return nothing.
In
startandserve, a recursive file watcher rebuilds the index 300 ms after the last change. On Vercel the index is built once per function instance and refreshed by each deploy.
License
MIT
Available Tools
3 toolsget_docGet documentation pageARead-onlyIdempotent
Return the full markdown of a documentation page by path, or a single section of it. Use search_docs or list_docs to find paths.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Page path from search_docs or list_docs, e.g. "guides/getting-started" (extensions and "docs://" prefix are accepted), or a full https:// URL to the page, optionally with a #fragment. | |
| section | No | Return only this section: an anchor ("#install" or "install") or the heading text. Defaults to the #fragment of `path` when `path` is a URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and closed-world, so safety is covered; the description adds the genuinely useful behavioral fact that the payload is markdown and can be narrowed to one section. It does not cover error behavior for missing paths, so it is not fully complete.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero waste: the capability and the section variant come first, and the sibling routing comes second. Nothing could be removed without losing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool with no output schema, the description supplies the essential missing piece (return format = markdown, optionally one section) on top of fully documented params and annotations. Only edge behavior on invalid paths is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself documents path formats, URL/fragment acceptance and section anchor/heading forms in more detail than the description. The description only restates 'by path, or a single section', so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return the full markdown of a documentation page') plus the scope variants (whole page or single section). Together with naming search_docs/list_docs as path finders, an agent can distinguish it from its siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes discovery to search_docs or list_docs and reserves get_doc for fetching content by path, which gives clear usage context. It stops short of stating exclusions or failure conditions (e.g., what to do if the path is unknown).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_docsList documentation pagesARead-onlyIdempotent
List documentation pages with their path, title, description and last-modified date. Useful to browse the structure before searching or to find pages under a prefix.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of pages to list. | |
| path_prefix | No | Only list pages under this path prefix. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered. The description adds value beyond that by disclosing the return shape (path, title, description, last-modified), which matters since no output schema exists. It does not mention truncation at limit=200 or whether listing is paginated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, with the returned fields and the use case both front-loaded. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-optional-parameter read tool with full annotations and full schema coverage, the description covers purpose, return fields and usage context. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented in the schema. The description only implies path_prefix behavior via 'pages under a prefix' and says nothing about limit semantics, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (list) and resource (documentation pages), and names the fields returned (path, title, description, last-modified date). It signals the browse-vs-search distinction implicitly ('before searching') but never names the sibling search_docs, so sibling differentiation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear usage contexts: browsing structure before searching, or finding pages under a prefix. There are no explicit exclusions or named alternatives (search_docs, get_doc), so an agent must infer when to switch tools rather than being told.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_docsSearch documentationARead-onlyIdempotent
Full-text search over the documentation. Returns matching sections with a snippet, the page path and heading anchor. Call get_doc with a returned path to read the full page or a single section.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results. | |
| query | Yes | Free-text query. Prefix matching and light fuzzy matching are applied per term. | |
| path_prefix | No | Only search pages whose path starts with this prefix, e.g. "guides" or "api/reference". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so safety is covered. The description adds value beyond them by disclosing the return shape (snippet, page path, heading anchor), which matters because there is no output schema. It does not mention ranking or token-size characteristics of results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences: what it does, what it returns, and what to do next. Zero redundancy and the highest-value information (return shape and the get_doc handoff) comes early.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the missing return-value context, and it covers the follow-up navigation to get_doc. For a three-parameter read-only search tool with fully documented params, nothing an agent needs to invoke it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so query, limit and path_prefix are all documented in the schema itself, including the prefix/fuzzy matching behavior. The description adds no parameter-level detail beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Full-text search over the documentation') and immediately clarifies the result scope: matching sections with snippet, page path and heading anchor. This distinguishes it from get_doc (full page reads) by describing exactly what kind of object each returns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly prescribes the follow-up workflow: 'Call get_doc with a returned path to read the full page or a single section,' which is the key routing decision for this tool pair. It lacks an explicit negative case (e.g., when to use list_docs instead of searching), so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.4.1- Changed
get_doc3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - changed
Input schema / properties / path / descriptionPrevious value: -"Page path from search_docs or list_docs, e.g. \"guides/getting-started\". Extensions and \"docs://\" prefix are accepted."New value: +"Page path from search_docs or list_docs, e.g. \"guides/getting-started\" (extensions and \"docs://\" prefix are accepted), or a full https:// URL to the page, optionally with a #fragment." - changed
Input schema / properties / section / descriptionPrevious value: -"Return only this section: an anchor (\"#install\" or \"install\") or the heading text."New value: +"Return only this section: an anchor (\"#install\" or \"install\") or the heading text. Defaults to the #fragment of `path` when `path` is a URL."
- Changed
list_docs1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
search_docs1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
3 tool updates
v0.1.0- First observed
get_doc - First observed
list_docs - First observed
search_docs
TDQS
Scored across 3 tools
Each tool has a clearly distinct purpose: search_docs performs full-text search, get_doc retrieves a specific page or section by path, and list_docs browses page metadata. The descriptions explicitly clarify when to use each and how they relate, leaving little room for misselection.
All three tools follow a consistent snake_case verb_noun convention: search_docs, get_doc, list_docs. The pattern is predictable and readable across the entire set.
Three tools are well-scoped for a documentation server: search, retrieve, and list form a compact and complete read-only surface. No tool feels redundant or missing at this scope.
For a read-only documentation server, the surface covers discovery (list_docs), search (search_docs), and retrieval of full pages or sections (get_doc). There are no obvious operational gaps for the stated purpose.
Maintenance
Related MCP Connectors
Open-source Obsidian for MDX - edit local docs with agent assistance
Personal context for every AI: search, read, and write back to your private Markdown library.
Markdown workspace for AI agents: read, write, organize, and share markdown documents.
Versioned documentation registry and semantic search for AI tools and coding assistants.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI assistants to navigate and query hierarchical documentation structures, supporting markdown files with YAML metadata and OpenAPI 3.x specifications. It features intelligent full-text search, metadata filtering, and a built-in web interface for both human and AI-driven documentation access.6MIT
- AlicenseAqualityAmaintenanceEnables AI agents to search local Markdown documents using natural language, with automatic indexing and section-level retrieval.106 npm1MIT
- AlicenseNot gradedqualityDmaintenanceGives AI agents full-text search over any Markdown/MDX documentation folder.4 npmMIT
- AlicenseAqualityAmaintenanceIndexes your project's markdown documentation and exposes it to AI agents via local hybrid search (lexical + semantic) with progressive disclosure tools.397 npm5MIT