Skip to main content

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.fieldBoosts accepts title, slug, headings, description, and content. The new search has no build-time options.
  • The plugin's search option never chose the runtime provider. That is chosen where the server runs, through the server config's search. 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. query accepts 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 with isError: true.
  • initialize reports tools.listChanged: false. The tool list is fixed per deploy.
  • tools/list:
    • inputSchema declares JSON Schema 2020-12 instead of draft-07.
    • Each tool has annotations (readOnlyHint, openWorldHint).
    • execution.taskSupport is 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 Accepted responses to notifications have no Content-Type.
  • GET status adds skillCount, and returns 500 with the reason if the deployment can't start (for example, a stale index).
  • When skills are served, initialize also advertises resources, and instructions ends 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 only Content-Type, Authorization.

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.

  1. In package.json:
    • Set docusaurus-plugin-mcp-server to ^2.0.0 and zod to ^4.2.0.
    • If engines.node is set below 22, raise it to >=22.
    • If CI or .nvmrc/.node-version/mise.toml pins Node 20, move it to 22 or later.
  2. Search the repo for flexsearch (case-insensitive):
    • In docusaurus.config.*, remove a flexsearch plugin option. Remove 'flexsearch' from indexers; if the array is then ['local'] or empty, delete it. Remove search: 'flexsearch'.
    • In handler code (createWebRequestHandler, createNodeServer, createNodeHandler, new McpDocsServer), remove search: 'flexsearch'. Replace a flexsearch: { fieldWeights } option with localSearch: { fieldBoosts: {} }, or drop it. Do not copy the numeric weights; they aren't compatible.
    • Rename the types FlexSearchConfig to LocalSearchConfig and BuiltinIndexerOptions to BuiltinSearchOptions.
    • Remove the second argument from loadIndexer(...). For loadSearchProvider(spec, { flexsearch }), use { localSearch }.
  3. Search for docsSearchTool.inputSchema and docsFetchTool.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.
  4. Search tests for isError assertions on unknown tool names. Assert a JSON-RPC error with code -32602 instead.
  5. If tests assert exact tools/list output, CORS headers, or status JSON, update them for the differences in step 7.
  6. Optional: to serve skills, import build/mcp/skills.json and pass it as skills (web handler), or pass skillsPath (Node).
  7. Run docusaurus build. Confirm build/mcp/ has docs.json, search-index.json, skills.json, and manifest.json. Then run npx docusaurus-mcp-verify if the project uses it.
  8. Tell the user to deploy the new build/mcp/ together with the upgraded package. A 1.x search-index.json does not work with 2.0.