docusaurus-plugin-mcp-server 0.8.0 → 0.10.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/README.md +38 -36
- package/dist/adapters-entry.d.mts +48 -3
- package/dist/adapters-entry.d.ts +48 -3
- package/dist/adapters-entry.js +182 -74
- package/dist/adapters-entry.js.map +1 -1
- package/dist/adapters-entry.mjs +181 -75
- package/dist/adapters-entry.mjs.map +1 -1
- package/dist/cli/verify.js +45 -59
- package/dist/cli/verify.js.map +1 -1
- package/dist/cli/verify.mjs +45 -59
- package/dist/cli/verify.mjs.map +1 -1
- package/dist/{index-4g0ZZK3z.d.mts → index-j-CdaS6k.d.mts} +8 -15
- package/dist/{index-4g0ZZK3z.d.ts → index-j-CdaS6k.d.ts} +8 -15
- package/dist/index.d.mts +16 -29
- package/dist/index.d.ts +16 -29
- package/dist/index.js +51 -144
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -144
- package/dist/index.mjs.map +1 -1
- package/dist/theme/index.d.mts +5 -3
- package/dist/theme/index.d.ts +5 -3
- package/dist/theme/index.js +23 -27
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +24 -25
- package/dist/theme/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { unified } from 'unified';
|
|
|
5
5
|
import rehypeParse from 'rehype-parse';
|
|
6
6
|
import { select } from 'hast-util-select';
|
|
7
7
|
import { toString } from 'hast-util-to-string';
|
|
8
|
+
import { toHtml } from 'hast-util-to-html';
|
|
8
9
|
import rehypeRemark from 'rehype-remark';
|
|
9
10
|
import remarkStringify from 'remark-stringify';
|
|
10
11
|
import remarkGfm from 'remark-gfm';
|
|
@@ -182,7 +183,7 @@ async function extractContent(filePath, options) {
|
|
|
182
183
|
let contentHtml = "";
|
|
183
184
|
if (contentElement) {
|
|
184
185
|
const cleanedElement = cleanContentElement(contentElement, options.excludeSelectors);
|
|
185
|
-
contentHtml =
|
|
186
|
+
contentHtml = toHtml(cleanedElement);
|
|
186
187
|
}
|
|
187
188
|
return {
|
|
188
189
|
title,
|
|
@@ -190,57 +191,6 @@ async function extractContent(filePath, options) {
|
|
|
190
191
|
contentHtml
|
|
191
192
|
};
|
|
192
193
|
}
|
|
193
|
-
function serializeElement(element) {
|
|
194
|
-
const voidElements = /* @__PURE__ */ new Set([
|
|
195
|
-
"area",
|
|
196
|
-
"base",
|
|
197
|
-
"br",
|
|
198
|
-
"col",
|
|
199
|
-
"embed",
|
|
200
|
-
"hr",
|
|
201
|
-
"img",
|
|
202
|
-
"input",
|
|
203
|
-
"link",
|
|
204
|
-
"meta",
|
|
205
|
-
"param",
|
|
206
|
-
"source",
|
|
207
|
-
"track",
|
|
208
|
-
"wbr"
|
|
209
|
-
]);
|
|
210
|
-
function serialize(node) {
|
|
211
|
-
if (!node || typeof node !== "object") return "";
|
|
212
|
-
const n = node;
|
|
213
|
-
if (n.type === "text") {
|
|
214
|
-
return n.value ?? "";
|
|
215
|
-
}
|
|
216
|
-
if (n.type === "element" && n.tagName) {
|
|
217
|
-
const tagName = n.tagName;
|
|
218
|
-
const props = n.properties ?? {};
|
|
219
|
-
const attrs = [];
|
|
220
|
-
for (const [key, value] of Object.entries(props)) {
|
|
221
|
-
if (key === "className" && Array.isArray(value)) {
|
|
222
|
-
attrs.push(`class="${value.join(" ")}"`);
|
|
223
|
-
} else if (typeof value === "boolean") {
|
|
224
|
-
if (value) attrs.push(key);
|
|
225
|
-
} else if (value !== void 0 && value !== null) {
|
|
226
|
-
attrs.push(`${key}="${String(value)}"`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
const attrStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
|
|
230
|
-
if (voidElements.has(tagName)) {
|
|
231
|
-
return `<${tagName}${attrStr} />`;
|
|
232
|
-
}
|
|
233
|
-
const children = n.children ?? [];
|
|
234
|
-
const childrenHtml = children.map(serialize).join("");
|
|
235
|
-
return `<${tagName}${attrStr}>${childrenHtml}</${tagName}>`;
|
|
236
|
-
}
|
|
237
|
-
if (n.type === "root" && n.children) {
|
|
238
|
-
return n.children.map(serialize).join("");
|
|
239
|
-
}
|
|
240
|
-
return "";
|
|
241
|
-
}
|
|
242
|
-
return serialize(element);
|
|
243
|
-
}
|
|
244
194
|
async function htmlToMarkdown(html) {
|
|
245
195
|
if (!html || html.trim().length === 0) {
|
|
246
196
|
return "";
|
|
@@ -377,9 +327,10 @@ function createSearchIndex() {
|
|
|
377
327
|
}
|
|
378
328
|
});
|
|
379
329
|
}
|
|
380
|
-
function addDocumentToIndex(index, doc) {
|
|
330
|
+
function addDocumentToIndex(index, doc, baseUrl) {
|
|
331
|
+
const id = baseUrl ? `${baseUrl.replace(/\/$/, "")}${doc.route}` : doc.route;
|
|
381
332
|
const indexable = {
|
|
382
|
-
id
|
|
333
|
+
id,
|
|
383
334
|
title: doc.title,
|
|
384
335
|
content: doc.markdown,
|
|
385
336
|
headings: doc.headings.map((h) => h.text).join(" "),
|
|
@@ -387,10 +338,10 @@ function addDocumentToIndex(index, doc) {
|
|
|
387
338
|
};
|
|
388
339
|
index.add(indexable);
|
|
389
340
|
}
|
|
390
|
-
function buildSearchIndex(docs) {
|
|
341
|
+
function buildSearchIndex(docs, baseUrl) {
|
|
391
342
|
const index = createSearchIndex();
|
|
392
343
|
for (const doc of docs) {
|
|
393
|
-
addDocumentToIndex(index, doc);
|
|
344
|
+
addDocumentToIndex(index, doc, baseUrl);
|
|
394
345
|
}
|
|
395
346
|
return index;
|
|
396
347
|
}
|
|
@@ -421,6 +372,8 @@ function searchIndex(index, docs, query, options = {}) {
|
|
|
421
372
|
const doc = docs[docId];
|
|
422
373
|
if (!doc) continue;
|
|
423
374
|
results.push({
|
|
375
|
+
url: docId,
|
|
376
|
+
// docId is the full URL when indexed with baseUrl
|
|
424
377
|
route: doc.route,
|
|
425
378
|
title: doc.title,
|
|
426
379
|
score,
|
|
@@ -495,6 +448,7 @@ async function importSearchIndex(data) {
|
|
|
495
448
|
// src/providers/indexers/flexsearch-indexer.ts
|
|
496
449
|
var FlexSearchIndexer = class {
|
|
497
450
|
name = "flexsearch";
|
|
451
|
+
baseUrl = "";
|
|
498
452
|
docsIndex = {};
|
|
499
453
|
exportedIndex = null;
|
|
500
454
|
docCount = 0;
|
|
@@ -505,7 +459,8 @@ var FlexSearchIndexer = class {
|
|
|
505
459
|
shouldRun() {
|
|
506
460
|
return true;
|
|
507
461
|
}
|
|
508
|
-
async initialize(
|
|
462
|
+
async initialize(context) {
|
|
463
|
+
this.baseUrl = context.baseUrl.replace(/\/$/, "");
|
|
509
464
|
this.docsIndex = {};
|
|
510
465
|
this.exportedIndex = null;
|
|
511
466
|
this.docCount = 0;
|
|
@@ -513,10 +468,11 @@ var FlexSearchIndexer = class {
|
|
|
513
468
|
async indexDocuments(docs) {
|
|
514
469
|
this.docCount = docs.length;
|
|
515
470
|
for (const doc of docs) {
|
|
516
|
-
this.
|
|
471
|
+
const fullUrl = `${this.baseUrl}${doc.route}`;
|
|
472
|
+
this.docsIndex[fullUrl] = doc;
|
|
517
473
|
}
|
|
518
474
|
console.log("[FlexSearch] Building search index...");
|
|
519
|
-
const searchIndex2 = buildSearchIndex(docs);
|
|
475
|
+
const searchIndex2 = buildSearchIndex(docs, this.baseUrl);
|
|
520
476
|
this.exportedIndex = await exportSearchIndex(searchIndex2);
|
|
521
477
|
console.log(`[FlexSearch] Indexed ${this.docCount} documents`);
|
|
522
478
|
}
|
|
@@ -576,16 +532,11 @@ var FlexSearchProvider = class {
|
|
|
576
532
|
const limit = options?.limit ?? 5;
|
|
577
533
|
return searchIndex(this.searchIndex, this.docs, query, { limit });
|
|
578
534
|
}
|
|
579
|
-
async getDocument(
|
|
535
|
+
async getDocument(url) {
|
|
580
536
|
if (!this.docs) {
|
|
581
537
|
throw new Error("[FlexSearch] Provider not initialized");
|
|
582
538
|
}
|
|
583
|
-
|
|
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;
|
|
539
|
+
return this.docs[url] ?? null;
|
|
589
540
|
}
|
|
590
541
|
async healthCheck() {
|
|
591
542
|
if (!this.isReady()) {
|
|
@@ -818,28 +769,16 @@ function mcpServerPlugin(context, options) {
|
|
|
818
769
|
}
|
|
819
770
|
};
|
|
820
771
|
}
|
|
821
|
-
|
|
822
|
-
|
|
772
|
+
var docsSearchInputSchema = {
|
|
773
|
+
query: z.string().min(1).describe("The search query string"),
|
|
774
|
+
limit: z.number().int().min(1).max(20).optional().default(5).describe("Maximum number of results to return (1-20, default: 5)")
|
|
775
|
+
};
|
|
823
776
|
var docsSearchTool = {
|
|
824
777
|
name: "docs_search",
|
|
825
|
-
description: "Search
|
|
826
|
-
inputSchema:
|
|
827
|
-
type: "object",
|
|
828
|
-
properties: {
|
|
829
|
-
query: {
|
|
830
|
-
type: "string",
|
|
831
|
-
description: "Search query string"
|
|
832
|
-
},
|
|
833
|
-
limit: {
|
|
834
|
-
type: "number",
|
|
835
|
-
description: "Maximum number of results to return (default: 5, max: 20)",
|
|
836
|
-
default: 5
|
|
837
|
-
}
|
|
838
|
-
},
|
|
839
|
-
required: ["query"]
|
|
840
|
-
}
|
|
778
|
+
description: "Search the documentation for relevant pages. Returns matching documents with URLs, snippets, and relevance scores. Use this to find information across all documentation.",
|
|
779
|
+
inputSchema: docsSearchInputSchema
|
|
841
780
|
};
|
|
842
|
-
function formatSearchResults(results
|
|
781
|
+
function formatSearchResults(results) {
|
|
843
782
|
if (results.length === 0) {
|
|
844
783
|
return "No matching documents found.";
|
|
845
784
|
}
|
|
@@ -849,38 +788,29 @@ function formatSearchResults(results, baseUrl) {
|
|
|
849
788
|
const result = results[i];
|
|
850
789
|
if (!result) continue;
|
|
851
790
|
lines.push(`${i + 1}. **${result.title}**`);
|
|
852
|
-
|
|
853
|
-
const fullUrl = `${baseUrl.replace(/\/$/, "")}${result.route}`;
|
|
854
|
-
lines.push(` URL: ${fullUrl}`);
|
|
855
|
-
}
|
|
856
|
-
lines.push(` Route: ${result.route}`);
|
|
791
|
+
lines.push(` URL: ${result.url}`);
|
|
857
792
|
if (result.matchingHeadings && result.matchingHeadings.length > 0) {
|
|
858
793
|
lines.push(` Matching sections: ${result.matchingHeadings.join(", ")}`);
|
|
859
794
|
}
|
|
860
795
|
lines.push(` ${result.snippet}`);
|
|
861
796
|
lines.push("");
|
|
862
797
|
}
|
|
798
|
+
lines.push("Use docs_fetch with the URL to retrieve the full page content.");
|
|
863
799
|
return lines.join("\n");
|
|
864
800
|
}
|
|
865
|
-
|
|
866
|
-
|
|
801
|
+
var docsFetchInputSchema = {
|
|
802
|
+
url: z.string().url().describe(
|
|
803
|
+
'The full URL of the page to fetch (e.g., "https://docs.example.com/docs/getting-started")'
|
|
804
|
+
)
|
|
805
|
+
};
|
|
867
806
|
var docsFetchTool = {
|
|
868
807
|
name: "docs_fetch",
|
|
869
|
-
description: "Fetch the complete content of a documentation page. Use this after searching to get full
|
|
870
|
-
inputSchema:
|
|
871
|
-
type: "object",
|
|
872
|
-
properties: {
|
|
873
|
-
route: {
|
|
874
|
-
type: "string",
|
|
875
|
-
description: "The route path of the page (e.g., /docs/getting-started)"
|
|
876
|
-
}
|
|
877
|
-
},
|
|
878
|
-
required: ["route"]
|
|
879
|
-
}
|
|
808
|
+
description: "Fetch the complete content of a documentation page. Use this after searching to get the full markdown content of a specific page.",
|
|
809
|
+
inputSchema: docsFetchInputSchema
|
|
880
810
|
};
|
|
881
|
-
function formatPageContent(doc
|
|
811
|
+
function formatPageContent(doc) {
|
|
882
812
|
if (!doc) {
|
|
883
|
-
return "Page not found. Please check the
|
|
813
|
+
return "Page not found. Please check the URL and try again.";
|
|
884
814
|
}
|
|
885
815
|
const lines = [];
|
|
886
816
|
lines.push(`# ${doc.title}`);
|
|
@@ -889,12 +819,6 @@ function formatPageContent(doc, baseUrl) {
|
|
|
889
819
|
lines.push(`> ${doc.description}`);
|
|
890
820
|
lines.push("");
|
|
891
821
|
}
|
|
892
|
-
if (baseUrl) {
|
|
893
|
-
const fullUrl = `${baseUrl.replace(/\/$/, "")}${doc.route}`;
|
|
894
|
-
lines.push(`**URL:** ${fullUrl}`);
|
|
895
|
-
}
|
|
896
|
-
lines.push(`**Route:** ${doc.route}`);
|
|
897
|
-
lines.push("");
|
|
898
822
|
if (doc.headings.length > 0) {
|
|
899
823
|
lines.push("## Contents");
|
|
900
824
|
lines.push("");
|
|
@@ -940,17 +864,14 @@ var McpDocsServer = class {
|
|
|
940
864
|
this.registerTools();
|
|
941
865
|
}
|
|
942
866
|
/**
|
|
943
|
-
* Register all MCP tools using
|
|
867
|
+
* Register all MCP tools using definitions from tool files
|
|
944
868
|
*/
|
|
945
869
|
registerTools() {
|
|
946
870
|
this.mcpServer.registerTool(
|
|
947
|
-
|
|
871
|
+
docsSearchTool.name,
|
|
948
872
|
{
|
|
949
|
-
description:
|
|
950
|
-
inputSchema:
|
|
951
|
-
query: z.string().min(1).describe("The search query string"),
|
|
952
|
-
limit: z.number().int().min(1).max(20).optional().default(5).describe("Maximum number of results to return (1-20, default: 5)")
|
|
953
|
-
}
|
|
873
|
+
description: docsSearchTool.description,
|
|
874
|
+
inputSchema: docsSearchTool.inputSchema
|
|
954
875
|
},
|
|
955
876
|
async ({ query, limit }) => {
|
|
956
877
|
await this.initialize();
|
|
@@ -963,9 +884,7 @@ var McpDocsServer = class {
|
|
|
963
884
|
try {
|
|
964
885
|
const results = await this.searchProvider.search(query, { limit });
|
|
965
886
|
return {
|
|
966
|
-
content: [
|
|
967
|
-
{ type: "text", text: formatSearchResults(results, this.config.baseUrl) }
|
|
968
|
-
]
|
|
887
|
+
content: [{ type: "text", text: formatSearchResults(results) }]
|
|
969
888
|
};
|
|
970
889
|
} catch (error) {
|
|
971
890
|
console.error("[MCP] Search error:", error);
|
|
@@ -977,14 +896,12 @@ var McpDocsServer = class {
|
|
|
977
896
|
}
|
|
978
897
|
);
|
|
979
898
|
this.mcpServer.registerTool(
|
|
980
|
-
|
|
899
|
+
docsFetchTool.name,
|
|
981
900
|
{
|
|
982
|
-
description:
|
|
983
|
-
inputSchema:
|
|
984
|
-
route: z.string().min(1).describe('The page route path (e.g., "/docs/getting-started" or "/api/reference")')
|
|
985
|
-
}
|
|
901
|
+
description: docsFetchTool.description,
|
|
902
|
+
inputSchema: docsFetchTool.inputSchema
|
|
986
903
|
},
|
|
987
|
-
async ({
|
|
904
|
+
async ({ url }) => {
|
|
988
905
|
await this.initialize();
|
|
989
906
|
if (!this.searchProvider || !this.searchProvider.isReady()) {
|
|
990
907
|
return {
|
|
@@ -993,14 +910,14 @@ var McpDocsServer = class {
|
|
|
993
910
|
};
|
|
994
911
|
}
|
|
995
912
|
try {
|
|
996
|
-
const doc = await this.getDocument(
|
|
913
|
+
const doc = await this.getDocument(url);
|
|
997
914
|
return {
|
|
998
|
-
content: [{ type: "text", text: formatPageContent(doc
|
|
915
|
+
content: [{ type: "text", text: formatPageContent(doc) }]
|
|
999
916
|
};
|
|
1000
917
|
} catch (error) {
|
|
1001
|
-
console.error("[MCP]
|
|
918
|
+
console.error("[MCP] Fetch error:", error);
|
|
1002
919
|
return {
|
|
1003
|
-
content: [{ type: "text", text: `Error
|
|
920
|
+
content: [{ type: "text", text: `Error fetching page: ${String(error)}` }],
|
|
1004
921
|
isError: true
|
|
1005
922
|
};
|
|
1006
923
|
}
|
|
@@ -1008,24 +925,14 @@ var McpDocsServer = class {
|
|
|
1008
925
|
);
|
|
1009
926
|
}
|
|
1010
927
|
/**
|
|
1011
|
-
* Get a document by
|
|
928
|
+
* Get a document by URL using the search provider
|
|
1012
929
|
*/
|
|
1013
|
-
async getDocument(
|
|
930
|
+
async getDocument(url) {
|
|
1014
931
|
if (!this.searchProvider) {
|
|
1015
932
|
return null;
|
|
1016
933
|
}
|
|
1017
934
|
if (this.searchProvider.getDocument) {
|
|
1018
|
-
return this.searchProvider.getDocument(
|
|
1019
|
-
}
|
|
1020
|
-
if (this.searchProvider instanceof FlexSearchProvider) {
|
|
1021
|
-
const docs = this.searchProvider.getDocs();
|
|
1022
|
-
if (!docs) return null;
|
|
1023
|
-
if (docs[route]) {
|
|
1024
|
-
return docs[route];
|
|
1025
|
-
}
|
|
1026
|
-
const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
|
|
1027
|
-
const withoutSlash = route.startsWith("/") ? route.slice(1) : route;
|
|
1028
|
-
return docs[normalizedRoute] ?? docs[withoutSlash] ?? null;
|
|
935
|
+
return this.searchProvider.getDocument(url);
|
|
1029
936
|
}
|
|
1030
937
|
return null;
|
|
1031
938
|
}
|