docusaurus-plugin-mcp-server 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import path2 from 'path';
1
+ import path from 'path';
2
2
  import fs3 from 'fs-extra';
3
3
  import pMap from 'p-map';
4
4
  import { unified } from 'unified';
@@ -34,7 +34,10 @@ var DEFAULT_OPTIONS = {
34
34
  name: "docs-mcp-server",
35
35
  version: "1.0.0"
36
36
  },
37
- excludeRoutes: ["/404*", "/search*"]
37
+ excludeRoutes: ["/404*", "/search*"],
38
+ indexers: void 0,
39
+ // Default: ['flexsearch'] applied at runtime
40
+ search: "flexsearch"
38
41
  };
39
42
  function filterRoutes(routes, excludePatterns) {
40
43
  return routes.filter((route) => {
@@ -50,15 +53,15 @@ async function discoverHtmlFiles(outDir) {
50
53
  async function scanDirectory(dir) {
51
54
  const entries = await fs3.readdir(dir, { withFileTypes: true });
52
55
  for (const entry of entries) {
53
- const fullPath = path2.join(dir, entry.name);
56
+ const fullPath = path.join(dir, entry.name);
54
57
  if (entry.isDirectory()) {
55
58
  if (["assets", "img", "static"].includes(entry.name)) {
56
59
  continue;
57
60
  }
58
61
  await scanDirectory(fullPath);
59
62
  } else if (entry.name === "index.html") {
60
- const relativePath = path2.relative(outDir, fullPath);
61
- let routePath = "/" + path2.dirname(relativePath).replace(/\\/g, "/");
63
+ const relativePath = path.relative(outDir, fullPath);
64
+ let routePath = "/" + path.dirname(relativePath).replace(/\\/g, "/");
62
65
  if (routePath === "/.") {
63
66
  routePath = "/";
64
67
  }
@@ -489,6 +492,201 @@ async function importSearchIndex(data) {
489
492
  return index;
490
493
  }
491
494
 
495
+ // src/providers/indexers/flexsearch-indexer.ts
496
+ var FlexSearchIndexer = class {
497
+ name = "flexsearch";
498
+ docsIndex = {};
499
+ exportedIndex = null;
500
+ docCount = 0;
501
+ /**
502
+ * FlexSearch indexer always runs by default.
503
+ * It respects the indexers configuration - if not included, it won't run.
504
+ */
505
+ shouldRun() {
506
+ return true;
507
+ }
508
+ async initialize(_context) {
509
+ this.docsIndex = {};
510
+ this.exportedIndex = null;
511
+ this.docCount = 0;
512
+ }
513
+ async indexDocuments(docs) {
514
+ this.docCount = docs.length;
515
+ for (const doc of docs) {
516
+ this.docsIndex[doc.route] = doc;
517
+ }
518
+ console.log("[FlexSearch] Building search index...");
519
+ const searchIndex2 = buildSearchIndex(docs);
520
+ this.exportedIndex = await exportSearchIndex(searchIndex2);
521
+ console.log(`[FlexSearch] Indexed ${this.docCount} documents`);
522
+ }
523
+ async finalize() {
524
+ const artifacts = /* @__PURE__ */ new Map();
525
+ artifacts.set("docs.json", this.docsIndex);
526
+ artifacts.set("search-index.json", this.exportedIndex);
527
+ return artifacts;
528
+ }
529
+ async getManifestData() {
530
+ return {
531
+ searchEngine: "flexsearch"
532
+ };
533
+ }
534
+ };
535
+ var FlexSearchProvider = class {
536
+ name = "flexsearch";
537
+ docs = null;
538
+ searchIndex = null;
539
+ ready = false;
540
+ async initialize(_context, initData) {
541
+ if (!initData) {
542
+ throw new Error("[FlexSearch] SearchProviderInitData required for FlexSearch provider");
543
+ }
544
+ if (initData.docs && initData.indexData) {
545
+ this.docs = initData.docs;
546
+ this.searchIndex = await importSearchIndex(initData.indexData);
547
+ this.ready = true;
548
+ return;
549
+ }
550
+ if (initData.docsPath && initData.indexPath) {
551
+ if (await fs3.pathExists(initData.docsPath)) {
552
+ this.docs = await fs3.readJson(initData.docsPath);
553
+ } else {
554
+ throw new Error(`[FlexSearch] Docs file not found: ${initData.docsPath}`);
555
+ }
556
+ if (await fs3.pathExists(initData.indexPath)) {
557
+ const indexData = await fs3.readJson(initData.indexPath);
558
+ this.searchIndex = await importSearchIndex(indexData);
559
+ } else {
560
+ throw new Error(`[FlexSearch] Search index not found: ${initData.indexPath}`);
561
+ }
562
+ this.ready = true;
563
+ return;
564
+ }
565
+ throw new Error(
566
+ "[FlexSearch] Invalid init data: must provide either file paths (docsPath, indexPath) or pre-loaded data (docs, indexData)"
567
+ );
568
+ }
569
+ isReady() {
570
+ return this.ready && this.docs !== null && this.searchIndex !== null;
571
+ }
572
+ async search(query, options) {
573
+ if (!this.isReady() || !this.docs || !this.searchIndex) {
574
+ throw new Error("[FlexSearch] Provider not initialized");
575
+ }
576
+ const limit = options?.limit ?? 5;
577
+ return searchIndex(this.searchIndex, this.docs, query, { limit });
578
+ }
579
+ async getDocument(route) {
580
+ if (!this.docs) {
581
+ throw new Error("[FlexSearch] Provider not initialized");
582
+ }
583
+ if (this.docs[route]) {
584
+ return this.docs[route];
585
+ }
586
+ const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
587
+ const withoutSlash = route.startsWith("/") ? route.slice(1) : route;
588
+ return this.docs[normalizedRoute] ?? this.docs[withoutSlash] ?? null;
589
+ }
590
+ async healthCheck() {
591
+ if (!this.isReady()) {
592
+ return { healthy: false, message: "FlexSearch provider not initialized" };
593
+ }
594
+ const docCount = this.docs ? Object.keys(this.docs).length : 0;
595
+ return {
596
+ healthy: true,
597
+ message: `FlexSearch provider ready with ${docCount} documents`
598
+ };
599
+ }
600
+ /**
601
+ * Get all loaded documents (for compatibility with existing server code)
602
+ */
603
+ getDocs() {
604
+ return this.docs;
605
+ }
606
+ /**
607
+ * Get the FlexSearch index (for compatibility with existing server code)
608
+ */
609
+ getSearchIndex() {
610
+ return this.searchIndex;
611
+ }
612
+ };
613
+
614
+ // src/providers/loader.ts
615
+ async function loadIndexer(specifier) {
616
+ if (specifier === "flexsearch") {
617
+ return new FlexSearchIndexer();
618
+ }
619
+ try {
620
+ const module = await import(specifier);
621
+ const IndexerClass = module.default;
622
+ if (typeof IndexerClass === "function") {
623
+ const instance = new IndexerClass();
624
+ if (!isContentIndexer(instance)) {
625
+ throw new Error(
626
+ `Invalid indexer module "${specifier}": does not implement ContentIndexer interface`
627
+ );
628
+ }
629
+ return instance;
630
+ }
631
+ if (isContentIndexer(IndexerClass)) {
632
+ return IndexerClass;
633
+ }
634
+ throw new Error(
635
+ `Invalid indexer module "${specifier}": must export a default class or ContentIndexer instance`
636
+ );
637
+ } catch (error) {
638
+ if (error instanceof Error && error.message.includes("Cannot find module")) {
639
+ throw new Error(`Indexer module not found: "${specifier}". Check the path or package name.`);
640
+ }
641
+ throw error;
642
+ }
643
+ }
644
+ async function loadSearchProvider(specifier) {
645
+ if (specifier === "flexsearch") {
646
+ return new FlexSearchProvider();
647
+ }
648
+ try {
649
+ const module = await import(specifier);
650
+ const ProviderClass = module.default;
651
+ if (typeof ProviderClass === "function") {
652
+ const instance = new ProviderClass();
653
+ if (!isSearchProvider(instance)) {
654
+ throw new Error(
655
+ `Invalid search provider module "${specifier}": does not implement SearchProvider interface`
656
+ );
657
+ }
658
+ return instance;
659
+ }
660
+ if (isSearchProvider(ProviderClass)) {
661
+ return ProviderClass;
662
+ }
663
+ throw new Error(
664
+ `Invalid search provider module "${specifier}": must export a default class or SearchProvider instance`
665
+ );
666
+ } catch (error) {
667
+ if (error instanceof Error && error.message.includes("Cannot find module")) {
668
+ throw new Error(
669
+ `Search provider module not found: "${specifier}". Check the path or package name.`
670
+ );
671
+ }
672
+ throw error;
673
+ }
674
+ }
675
+ function isContentIndexer(obj) {
676
+ if (!obj || typeof obj !== "object") {
677
+ return false;
678
+ }
679
+ const indexer = obj;
680
+ return typeof indexer.name === "string" && typeof indexer.initialize === "function" && typeof indexer.indexDocuments === "function" && typeof indexer.finalize === "function";
681
+ }
682
+ function isSearchProvider(obj) {
683
+ if (!obj || typeof obj !== "object") {
684
+ return false;
685
+ }
686
+ const provider = obj;
687
+ return typeof provider.name === "string" && typeof provider.initialize === "function" && typeof provider.isReady === "function" && typeof provider.search === "function";
688
+ }
689
+
492
690
  // src/plugin/docusaurus-plugin.ts
493
691
  function resolveOptions(options) {
494
692
  return {
@@ -545,6 +743,10 @@ function mcpServerPlugin(context, options) {
545
743
  async postBuild({ outDir }) {
546
744
  console.log("[MCP] Starting MCP artifact generation...");
547
745
  const startTime = Date.now();
746
+ if (resolvedOptions.indexers === false) {
747
+ console.log("[MCP] Indexing disabled, skipping artifact generation");
748
+ return;
749
+ }
548
750
  const routes = await collectRoutes(outDir, resolvedOptions.excludeRoutes);
549
751
  console.log(`[MCP] Found ${routes.length} routes to process`);
550
752
  if (routes.length === 0) {
@@ -569,27 +771,47 @@ function mcpServerPlugin(context, options) {
569
771
  console.warn("[MCP] No valid documents to index");
570
772
  return;
571
773
  }
572
- const docsIndex = {};
573
- for (const doc of validDocs) {
574
- docsIndex[doc.route] = doc;
575
- }
576
- console.log("[MCP] Building search index...");
577
- const searchIndex2 = buildSearchIndex(validDocs);
578
- const exportedIndex = await exportSearchIndex(searchIndex2);
579
- const manifest = {
580
- version: resolvedOptions.server.version,
581
- buildTime: (/* @__PURE__ */ new Date()).toISOString(),
582
- docCount: validDocs.length,
774
+ const mcpOutputDir = path.join(outDir, resolvedOptions.outputDir);
775
+ const providerContext = {
776
+ baseUrl: context.siteConfig.url,
583
777
  serverName: resolvedOptions.server.name,
584
- baseUrl: context.siteConfig.url
778
+ serverVersion: resolvedOptions.server.version,
779
+ outputDir: mcpOutputDir
585
780
  };
586
- const mcpOutputDir = path2.join(outDir, resolvedOptions.outputDir);
781
+ const indexerSpecs = resolvedOptions.indexers ?? ["flexsearch"];
587
782
  await fs3.ensureDir(mcpOutputDir);
588
- await Promise.all([
589
- fs3.writeJson(path2.join(mcpOutputDir, "docs.json"), docsIndex, { spaces: 0 }),
590
- fs3.writeJson(path2.join(mcpOutputDir, "search-index.json"), exportedIndex, { spaces: 0 }),
591
- fs3.writeJson(path2.join(mcpOutputDir, "manifest.json"), manifest, { spaces: 2 })
592
- ]);
783
+ const indexerNames = [];
784
+ for (const indexerSpec of indexerSpecs) {
785
+ try {
786
+ const indexer = await loadIndexer(indexerSpec);
787
+ if (indexer.shouldRun && !indexer.shouldRun()) {
788
+ console.log(`[MCP] Skipping indexer: ${indexer.name}`);
789
+ continue;
790
+ }
791
+ console.log(`[MCP] Running indexer: ${indexer.name}`);
792
+ await indexer.initialize(providerContext);
793
+ await indexer.indexDocuments(validDocs);
794
+ const artifacts = await indexer.finalize();
795
+ for (const [filename, content] of artifacts) {
796
+ await fs3.writeJson(path.join(mcpOutputDir, filename), content, { spaces: 0 });
797
+ }
798
+ indexerNames.push(indexer.name);
799
+ } catch (error) {
800
+ console.error(`[MCP] Error running indexer "${indexerSpec}":`, error);
801
+ throw error;
802
+ }
803
+ }
804
+ if (indexerNames.length > 0) {
805
+ const manifest = {
806
+ version: resolvedOptions.server.version,
807
+ buildTime: (/* @__PURE__ */ new Date()).toISOString(),
808
+ docCount: validDocs.length,
809
+ serverName: resolvedOptions.server.name,
810
+ baseUrl: context.siteConfig.url,
811
+ indexers: indexerNames
812
+ };
813
+ await fs3.writeJson(path.join(mcpOutputDir, "manifest.json"), manifest, { spaces: 2 });
814
+ }
593
815
  const elapsed = Date.now() - startTime;
594
816
  console.log(`[MCP] Artifacts written to ${mcpOutputDir}`);
595
817
  console.log(`[MCP] Generation complete in ${elapsed}ms`);
@@ -617,17 +839,6 @@ var docsSearchTool = {
617
839
  required: ["query"]
618
840
  }
619
841
  };
620
- function executeDocsSearch(params, index, docs) {
621
- const { query, limit = 5 } = params;
622
- if (!query || typeof query !== "string" || query.trim().length === 0) {
623
- throw new Error("Query parameter is required and must be a non-empty string");
624
- }
625
- const effectiveLimit = Math.min(Math.max(1, limit), 20);
626
- const results = searchIndex(index, docs, query.trim(), {
627
- limit: effectiveLimit
628
- });
629
- return results;
630
- }
631
842
  function formatSearchResults(results, baseUrl) {
632
843
  if (results.length === 0) {
633
844
  return "No matching documents found.";
@@ -667,28 +878,6 @@ var docsGetPageTool = {
667
878
  required: ["route"]
668
879
  }
669
880
  };
670
- function executeDocsGetPage(params, docs) {
671
- const { route } = params;
672
- if (!route || typeof route !== "string") {
673
- throw new Error("Route parameter is required and must be a string");
674
- }
675
- let normalizedRoute = route.trim();
676
- if (!normalizedRoute.startsWith("/")) {
677
- normalizedRoute = "/" + normalizedRoute;
678
- }
679
- if (normalizedRoute.length > 1 && normalizedRoute.endsWith("/")) {
680
- normalizedRoute = normalizedRoute.slice(0, -1);
681
- }
682
- const doc = docs[normalizedRoute];
683
- if (!doc) {
684
- const altRoute = normalizedRoute.slice(1);
685
- if (docs[altRoute]) {
686
- return docs[altRoute] ?? null;
687
- }
688
- return null;
689
- }
690
- return doc;
691
- }
692
881
  function formatPageContent(doc, baseUrl) {
693
882
  if (!doc) {
694
883
  return "Page not found. Please check the route path and try again.";
@@ -742,52 +931,6 @@ var docsGetSectionTool = {
742
931
  required: ["route", "headingId"]
743
932
  }
744
933
  };
745
- function executeDocsGetSection(params, docs) {
746
- const { route, headingId } = params;
747
- if (!route || typeof route !== "string") {
748
- throw new Error("Route parameter is required and must be a string");
749
- }
750
- if (!headingId || typeof headingId !== "string") {
751
- throw new Error("HeadingId parameter is required and must be a string");
752
- }
753
- let normalizedRoute = route.trim();
754
- if (!normalizedRoute.startsWith("/")) {
755
- normalizedRoute = "/" + normalizedRoute;
756
- }
757
- if (normalizedRoute.length > 1 && normalizedRoute.endsWith("/")) {
758
- normalizedRoute = normalizedRoute.slice(0, -1);
759
- }
760
- const doc = docs[normalizedRoute];
761
- if (!doc) {
762
- return {
763
- content: null,
764
- doc: null,
765
- headingText: null,
766
- availableHeadings: []
767
- };
768
- }
769
- const availableHeadings = doc.headings.map((h) => ({
770
- id: h.id,
771
- text: h.text,
772
- level: h.level
773
- }));
774
- const heading = doc.headings.find((h) => h.id === headingId.trim());
775
- if (!heading) {
776
- return {
777
- content: null,
778
- doc,
779
- headingText: null,
780
- availableHeadings
781
- };
782
- }
783
- const content = extractSection(doc.markdown, headingId.trim(), doc.headings);
784
- return {
785
- content,
786
- doc,
787
- headingText: heading.text,
788
- availableHeadings
789
- };
790
- }
791
934
  function formatSectionContent(result, headingId, baseUrl) {
792
935
  if (!result.doc) {
793
936
  return "Page not found. Please check the route path and try again.";
@@ -824,8 +967,7 @@ function isDataConfig(config) {
824
967
  }
825
968
  var McpDocsServer = class {
826
969
  config;
827
- docs = null;
828
- searchIndex = null;
970
+ searchProvider = null;
829
971
  mcpServer;
830
972
  initialized = false;
831
973
  constructor(config) {
@@ -858,18 +1000,26 @@ var McpDocsServer = class {
858
1000
  },
859
1001
  async ({ query, limit }) => {
860
1002
  await this.initialize();
861
- if (!this.docs || !this.searchIndex) {
1003
+ if (!this.searchProvider || !this.searchProvider.isReady()) {
862
1004
  return {
863
1005
  content: [{ type: "text", text: "Server not initialized. Please try again." }],
864
1006
  isError: true
865
1007
  };
866
1008
  }
867
- const results = executeDocsSearch({ query, limit }, this.searchIndex, this.docs);
868
- return {
869
- content: [
870
- { type: "text", text: formatSearchResults(results, this.config.baseUrl) }
871
- ]
872
- };
1009
+ try {
1010
+ const results = await this.searchProvider.search(query, { limit });
1011
+ return {
1012
+ content: [
1013
+ { type: "text", text: formatSearchResults(results, this.config.baseUrl) }
1014
+ ]
1015
+ };
1016
+ } catch (error) {
1017
+ console.error("[MCP] Search error:", error);
1018
+ return {
1019
+ content: [{ type: "text", text: `Search error: ${String(error)}` }],
1020
+ isError: true
1021
+ };
1022
+ }
873
1023
  }
874
1024
  );
875
1025
  this.mcpServer.registerTool(
@@ -882,16 +1032,24 @@ var McpDocsServer = class {
882
1032
  },
883
1033
  async ({ route }) => {
884
1034
  await this.initialize();
885
- if (!this.docs) {
1035
+ if (!this.searchProvider || !this.searchProvider.isReady()) {
886
1036
  return {
887
1037
  content: [{ type: "text", text: "Server not initialized. Please try again." }],
888
1038
  isError: true
889
1039
  };
890
1040
  }
891
- const doc = executeDocsGetPage({ route }, this.docs);
892
- return {
893
- content: [{ type: "text", text: formatPageContent(doc, this.config.baseUrl) }]
894
- };
1041
+ try {
1042
+ const doc = await this.getDocument(route);
1043
+ return {
1044
+ content: [{ type: "text", text: formatPageContent(doc, this.config.baseUrl) }]
1045
+ };
1046
+ } catch (error) {
1047
+ console.error("[MCP] Get page error:", error);
1048
+ return {
1049
+ content: [{ type: "text", text: `Error getting page: ${String(error)}` }],
1050
+ isError: true
1051
+ };
1052
+ }
895
1053
  }
896
1054
  );
897
1055
  this.mcpServer.registerTool(
@@ -907,26 +1065,95 @@ var McpDocsServer = class {
907
1065
  },
908
1066
  async ({ route, headingId }) => {
909
1067
  await this.initialize();
910
- if (!this.docs) {
1068
+ if (!this.searchProvider || !this.searchProvider.isReady()) {
911
1069
  return {
912
1070
  content: [{ type: "text", text: "Server not initialized. Please try again." }],
913
1071
  isError: true
914
1072
  };
915
1073
  }
916
- const result = executeDocsGetSection({ route, headingId }, this.docs);
917
- return {
918
- content: [
919
- {
920
- type: "text",
921
- text: formatSectionContent(result, headingId, this.config.baseUrl)
922
- }
923
- ]
924
- };
1074
+ try {
1075
+ const doc = await this.getDocument(route);
1076
+ if (!doc) {
1077
+ return {
1078
+ content: [
1079
+ {
1080
+ type: "text",
1081
+ text: formatSectionContent(
1082
+ { content: null, doc: null, headingText: null, availableHeadings: [] },
1083
+ headingId,
1084
+ this.config.baseUrl
1085
+ )
1086
+ }
1087
+ ]
1088
+ };
1089
+ }
1090
+ const availableHeadings = doc.headings.map((h) => ({
1091
+ id: h.id,
1092
+ text: h.text,
1093
+ level: h.level
1094
+ }));
1095
+ const heading = doc.headings.find((h) => h.id === headingId.trim());
1096
+ if (!heading) {
1097
+ return {
1098
+ content: [
1099
+ {
1100
+ type: "text",
1101
+ text: formatSectionContent(
1102
+ { content: null, doc, headingText: null, availableHeadings },
1103
+ headingId,
1104
+ this.config.baseUrl
1105
+ )
1106
+ }
1107
+ ]
1108
+ };
1109
+ }
1110
+ const sectionContent = extractSection(doc.markdown, headingId.trim(), doc.headings);
1111
+ return {
1112
+ content: [
1113
+ {
1114
+ type: "text",
1115
+ text: formatSectionContent(
1116
+ { content: sectionContent, doc, headingText: heading.text, availableHeadings },
1117
+ headingId,
1118
+ this.config.baseUrl
1119
+ )
1120
+ }
1121
+ ]
1122
+ };
1123
+ } catch (error) {
1124
+ console.error("[MCP] Get section error:", error);
1125
+ return {
1126
+ content: [{ type: "text", text: `Error getting section: ${String(error)}` }],
1127
+ isError: true
1128
+ };
1129
+ }
925
1130
  }
926
1131
  );
927
1132
  }
928
1133
  /**
929
- * Load docs and search index
1134
+ * Get a document by route using the search provider
1135
+ */
1136
+ async getDocument(route) {
1137
+ if (!this.searchProvider) {
1138
+ return null;
1139
+ }
1140
+ if (this.searchProvider.getDocument) {
1141
+ return this.searchProvider.getDocument(route);
1142
+ }
1143
+ if (this.searchProvider instanceof FlexSearchProvider) {
1144
+ const docs = this.searchProvider.getDocs();
1145
+ if (!docs) return null;
1146
+ if (docs[route]) {
1147
+ return docs[route];
1148
+ }
1149
+ const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
1150
+ const withoutSlash = route.startsWith("/") ? route.slice(1) : route;
1151
+ return docs[normalizedRoute] ?? docs[withoutSlash] ?? null;
1152
+ }
1153
+ return null;
1154
+ }
1155
+ /**
1156
+ * Load docs and search index using the configured search provider
930
1157
  *
931
1158
  * For file-based config: reads from disk
932
1159
  * For data config: uses pre-loaded data directly
@@ -936,24 +1163,26 @@ var McpDocsServer = class {
936
1163
  return;
937
1164
  }
938
1165
  try {
1166
+ const searchSpecifier = this.config.search ?? "flexsearch";
1167
+ this.searchProvider = await loadSearchProvider(searchSpecifier);
1168
+ const providerContext = {
1169
+ baseUrl: this.config.baseUrl ?? "",
1170
+ serverName: this.config.name,
1171
+ serverVersion: this.config.version ?? "1.0.0",
1172
+ outputDir: ""
1173
+ // Not relevant for runtime
1174
+ };
1175
+ const initData = {};
939
1176
  if (isDataConfig(this.config)) {
940
- this.docs = this.config.docs;
941
- this.searchIndex = await importSearchIndex(this.config.searchIndexData);
1177
+ initData.docs = this.config.docs;
1178
+ initData.indexData = this.config.searchIndexData;
942
1179
  } else if (isFileConfig(this.config)) {
943
- if (await fs3.pathExists(this.config.docsPath)) {
944
- this.docs = await fs3.readJson(this.config.docsPath);
945
- } else {
946
- throw new Error(`Docs file not found: ${this.config.docsPath}`);
947
- }
948
- if (await fs3.pathExists(this.config.indexPath)) {
949
- const indexData = await fs3.readJson(this.config.indexPath);
950
- this.searchIndex = await importSearchIndex(indexData);
951
- } else {
952
- throw new Error(`Search index not found: ${this.config.indexPath}`);
953
- }
1180
+ initData.docsPath = this.config.docsPath;
1181
+ initData.indexPath = this.config.indexPath;
954
1182
  } else {
955
1183
  throw new Error("Invalid server config: must provide either file paths or pre-loaded data");
956
1184
  }
1185
+ await this.searchProvider.initialize(providerContext, initData);
957
1186
  this.initialized = true;
958
1187
  } catch (error) {
959
1188
  console.error("[MCP] Failed to initialize:", error);
@@ -1014,12 +1243,18 @@ var McpDocsServer = class {
1014
1243
  * Useful for health checks and debugging
1015
1244
  */
1016
1245
  async getStatus() {
1246
+ let docCount = 0;
1247
+ if (this.searchProvider instanceof FlexSearchProvider) {
1248
+ const docs = this.searchProvider.getDocs();
1249
+ docCount = docs ? Object.keys(docs).length : 0;
1250
+ }
1017
1251
  return {
1018
1252
  name: this.config.name,
1019
1253
  version: this.config.version ?? "1.0.0",
1020
1254
  initialized: this.initialized,
1021
- docCount: this.docs ? Object.keys(this.docs).length : 0,
1022
- baseUrl: this.config.baseUrl
1255
+ docCount,
1256
+ baseUrl: this.config.baseUrl,
1257
+ searchProvider: this.searchProvider?.name
1023
1258
  };
1024
1259
  }
1025
1260
  /**
@@ -1032,6 +1267,6 @@ var McpDocsServer = class {
1032
1267
  }
1033
1268
  };
1034
1269
 
1035
- export { DEFAULT_OPTIONS, McpDocsServer, buildSearchIndex, collectRoutes, mcpServerPlugin as default, discoverHtmlFiles, docsGetPageTool, docsGetSectionTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
1270
+ export { DEFAULT_OPTIONS, FlexSearchIndexer, FlexSearchProvider, McpDocsServer, buildSearchIndex, collectRoutes, mcpServerPlugin as default, discoverHtmlFiles, docsGetPageTool, docsGetSectionTool, docsSearchTool, exportSearchIndex, extractContent, extractHeadingsFromMarkdown, extractSection, htmlToMarkdown, importSearchIndex, loadIndexer, loadSearchProvider, mcpServerPlugin, parseHtml, parseHtmlFile, searchIndex };
1036
1271
  //# sourceMappingURL=index.mjs.map
1037
1272
  //# sourceMappingURL=index.mjs.map