Migrating from 1.x to 2.0.0
2.0.0 moves the MCP server to the MCP TypeScript SDK v2 and protocol revision
2026-07-28, replaces the built-in FlexSearch search with a BM25 local search,
and can serve Agent Skills over MCP. Most sites only need to
upgrade the packages and
rebuild. The other steps apply only
if you use the option or API they name.
MCP clients need no changes: 2026-07-28 clients and 2025-era clients (the
initialize handshake) are both served from the same endpoint.
If you're an agent, go to For agents. It is a checklist you can run top to bottom.
1. Upgrade Node, zod, and the package
- Node.js >= 22. Node 20 reached end of life on 2026-04-30.
- zod >= 4.2 (peer dependency). The v2 SDK drops zod 3, and zod 4.2 or later is needed for tool schema descriptions to reach clients.
npm install docusaurus-plugin-mcp-server@^2 zod@^4.2
@modelcontextprotocol/sdk is no longer a dependency of this package. Keep it in
your own package.json only if your code imports it directly.
2. Rebuild the site and redeploy build/mcp/
The search-index.json format changed. A 1.x index is rejected with an error
that says to rebuild. The error comes back in every MCP response and in the
GET status, instead of the server returning no results. Run docusaurus build
and deploy the new build/mcp/ directory together with the new package version.
The build now writes a fourth artifact, build/mcp/skills.json (see
step 6).
3. Remove FlexSearch options
The built-in search is now 'local'. 'flexsearch' throws everywhere it was
accepted, and the error links to this guide.
// docusaurus.config.js
plugins: [
[
'docusaurus-plugin-mcp-server',
{
- indexers: ['flexsearch'],
- search: 'flexsearch',
- flexsearch: { tokenize: 'forward', fieldWeights: { title: 3 } },
+ // Omit indexers/search to use the built-in 'local' search.
},
],
],
createWebRequestHandler({
docs,
searchIndexData: searchIndex,
- search: 'flexsearch',
- flexsearch: { fieldWeights: { title: 3, headings: 2 } },
+ // Optional: tune ranking at runtime. Values are BM25 boosts, not 1.x
+ // position weights, so start from the defaults instead of copying old values.
+ localSearch: { fieldBoosts: { title: 3 } },
name: 'my-docs',
});
- The same applies to
createNodeServer/createNodeHandler/new McpDocsServer(...). localSearch.fieldBoostsacceptstitle,slug,headings,description, andcontent. The new search has no build-time options.- The plugin's
searchoption never chose the runtime provider. That is chosen where the server runs, through the server config'ssearch. The plugin option is still accepted but does nothing, except that'flexsearch'throws.
Renamed types and signatures
-import type { FlexSearchConfig, BuiltinIndexerOptions } from 'docusaurus-plugin-mcp-server';
+import type { LocalSearchConfig, BuiltinSearchOptions } from 'docusaurus-plugin-mcp-server';
-const indexer = await loadIndexer('flexsearch', { flexsearch: config });
+const indexer = await loadIndexer('local'); // no second argument
-const provider = await loadSearchProvider('flexsearch', { flexsearch: config });
+const provider = await loadSearchProvider('local', { localSearch: config });
New exports for edge runtimes that can't dynamically import a provider:
LocalSearchIndexer and LocalSearchProvider (search: new LocalSearchProvider()).
4. Check search behavior you depend on
- Matching is OR, ranked by BM25. 1.x required every word to match (AND). In 2.0, a page matching some of the words is still returned, ranked lower. Queries that returned no results in 1.x may now return some.
- English stemming and accent folding. "configuring" matches "configure", and "cafe" matches "café". Words of 3 or more letters also match as prefixes. For example, "auth" finds "authentication".
- CJK text is matched only as whole runs between spaces or punctuation.
部署到云端matches the same run, but部署alone does not. Emoji aren't indexed. - Query limits.
queryaccepts up to 500 characters. Only the first 16 distinct terms are searched, and only the first 8 match as prefixes. Real queries are well under these limits. They stop a long query from exhausting server memory.
5. Update code that uses the tool definitions
Skip this step if you only use the plugin and a handler.
import { docsSearchTool, docsSearchInputSchema } from 'docusaurus-plugin-mcp-server';
-const shape = docsSearchTool.inputSchema; // 1.x: a raw zod shape
-const schema = z.object(docsSearchTool.inputSchema);
+const schema = docsSearchTool.inputSchema; // 2.0: already a z.object(...)
+const shape = docsSearchInputSchema; // the raw shape is still exported
The same change applies to docsFetchTool / docsFetchInputSchema.
6. Optional: serve Agent Skills
The build packages a built-in docs-research skill into build/mcp/skills.json.
It teaches agents to search, fetch, and cite your docs. Skills are served only
if you pass the file to the handler:
+import skills from '../build/mcp/skills.json';
createWebRequestHandler({
docs,
searchIndexData: searchIndex,
+ skills,
name: 'my-docs',
});
For createNodeServer / createNodeHandler, pass skillsPath: './build/mcp/skills.json'.
To stop writing the file, set skills: false in the plugin options. To add your
own skills, see "Serving Agent Skills over MCP" in the README.
7. Review what changed on the wire
You don't need to do anything here unless you have tests or monitoring that match exact response bytes.
For 2025-era clients:
- Calling an unknown tool returns a JSON-RPC error (
-32602) instead of a tool result withisError: true. initializereportstools.listChanged: false. The tool list is fixed per deploy.tools/list:inputSchemadeclares JSON Schema 2020-12 instead of draft-07.- Each tool has
annotations(readOnlyHint,openWorldHint). execution.taskSupportis gone.
- Input validation error text changed, e.g.
Input validation error: ...: limit: Too big. - A body that isn't valid JSON-RPC returns
-32600(was-32700). 202 Acceptedresponses to notifications have noContent-Type.GETstatus addsskillCount, and returns500with the reason if the deployment can't start (for example, a stale index).- When skills are served,
initializealso advertisesresources, andinstructionsends with the skill URIs.
For everyone:
-
CORS: the web handler and Node server now share one header list.
- Allowed:
Content-Type, Accept, Authorization, MCP-Protocol-Version, Mcp-Method, Mcp-Name, Mcp-Session-Id, Last-Event-ID. - Exposed:
MCP-Protocol-Version, Mcp-Session-Id.
In 1.x the web handler allowed only
Content-Type, and the Node server onlyContent-Type, Authorization. - Allowed:
2026-07-28 clients are served statelessly. Cache hints (ttlMs of 5 minutes,
cacheScope: public) are sent on discovery, list, and read results.
For agents
To migrate a project from 1.x to 2.0.0, run this checklist in order. The error messages the package throws mention the step to take.
- In
package.json:- Set
docusaurus-plugin-mcp-serverto^2.0.0andzodto^4.2.0. - If
engines.nodeis set below 22, raise it to>=22. - If CI or
.nvmrc/.node-version/mise.tomlpins Node 20, move it to 22 or later.
- Set
- Search the repo for
flexsearch(case-insensitive):- In
docusaurus.config.*, remove aflexsearchplugin option. Remove'flexsearch'fromindexers; if the array is then['local']or empty, delete it. Removesearch: 'flexsearch'. - In handler code (
createWebRequestHandler,createNodeServer,createNodeHandler,new McpDocsServer), removesearch: 'flexsearch'. Replace aflexsearch: { fieldWeights }option withlocalSearch: { fieldBoosts: {} }, or drop it. Do not copy the numeric weights; they aren't compatible. - Rename the types
FlexSearchConfigtoLocalSearchConfigandBuiltinIndexerOptionstoBuiltinSearchOptions. - Remove the second argument from
loadIndexer(...). ForloadSearchProvider(spec, { flexsearch }), use{ localSearch }.
- In
- Search for
docsSearchTool.inputSchemaanddocsFetchTool.inputSchema:- Where the code wraps them in
z.object(...), remove the wrapper. - Where the code uses them as raw shapes (spreads them, reads keys), switch
to
docsSearchInputSchema/docsFetchInputSchema.
- Where the code wraps them in
- Search tests for
isErrorassertions on unknown tool names. Assert a JSON-RPC error with code-32602instead. - If tests assert exact
tools/listoutput, CORS headers, or status JSON, update them for the differences in step 7. - Optional: to serve skills, import
build/mcp/skills.jsonand pass it asskills(web handler), or passskillsPath(Node). - Run
docusaurus build. Confirmbuild/mcp/hasdocs.json,search-index.json,skills.json, andmanifest.json. Then runnpx docusaurus-mcp-verifyif the project uses it. - Tell the user to deploy the new
build/mcp/together with the upgraded package. A 1.xsearch-index.jsondoes not work with 2.0.