docusaurus-plugin-mcp-server 0.6.0 → 0.8.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/adapters-entry.d.mts +1 -1
- package/dist/adapters-entry.d.ts +1 -1
- package/dist/adapters-entry.js +195 -177
- package/dist/adapters-entry.js.map +1 -1
- package/dist/adapters-entry.mjs +194 -176
- package/dist/adapters-entry.mjs.map +1 -1
- package/dist/cli/verify.js +192 -175
- package/dist/cli/verify.js.map +1 -1
- package/dist/cli/verify.mjs +192 -175
- package/dist/cli/verify.mjs.map +1 -1
- package/dist/{index-CzA4FjeE.d.mts → index-4g0ZZK3z.d.mts} +33 -0
- package/dist/{index-CzA4FjeE.d.ts → index-4g0ZZK3z.d.ts} +33 -0
- package/dist/index.d.mts +289 -31
- package/dist/index.d.ts +289 -31
- package/dist/index.js +328 -213
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +323 -211
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/adapters-entry.d.ts
CHANGED
package/dist/adapters-entry.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fs = require('fs-extra');
|
|
4
3
|
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
5
4
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
6
5
|
var webStandardStreamableHttp_js = require('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js');
|
|
7
6
|
var zod = require('zod');
|
|
8
7
|
var FlexSearch = require('flexsearch');
|
|
8
|
+
var fs = require('fs-extra');
|
|
9
|
+
require('http');
|
|
9
10
|
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
12
|
|
|
12
|
-
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
13
13
|
var FlexSearch__default = /*#__PURE__*/_interopDefault(FlexSearch);
|
|
14
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
14
15
|
|
|
15
16
|
// src/mcp/server.ts
|
|
16
17
|
var FIELD_WEIGHTS = {
|
|
@@ -143,19 +144,126 @@ async function importSearchIndex(data) {
|
|
|
143
144
|
}
|
|
144
145
|
return index;
|
|
145
146
|
}
|
|
147
|
+
var FlexSearchProvider = class {
|
|
148
|
+
name = "flexsearch";
|
|
149
|
+
docs = null;
|
|
150
|
+
searchIndex = null;
|
|
151
|
+
ready = false;
|
|
152
|
+
async initialize(_context, initData) {
|
|
153
|
+
if (!initData) {
|
|
154
|
+
throw new Error("[FlexSearch] SearchProviderInitData required for FlexSearch provider");
|
|
155
|
+
}
|
|
156
|
+
if (initData.docs && initData.indexData) {
|
|
157
|
+
this.docs = initData.docs;
|
|
158
|
+
this.searchIndex = await importSearchIndex(initData.indexData);
|
|
159
|
+
this.ready = true;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (initData.docsPath && initData.indexPath) {
|
|
163
|
+
if (await fs__default.default.pathExists(initData.docsPath)) {
|
|
164
|
+
this.docs = await fs__default.default.readJson(initData.docsPath);
|
|
165
|
+
} else {
|
|
166
|
+
throw new Error(`[FlexSearch] Docs file not found: ${initData.docsPath}`);
|
|
167
|
+
}
|
|
168
|
+
if (await fs__default.default.pathExists(initData.indexPath)) {
|
|
169
|
+
const indexData = await fs__default.default.readJson(initData.indexPath);
|
|
170
|
+
this.searchIndex = await importSearchIndex(indexData);
|
|
171
|
+
} else {
|
|
172
|
+
throw new Error(`[FlexSearch] Search index not found: ${initData.indexPath}`);
|
|
173
|
+
}
|
|
174
|
+
this.ready = true;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
throw new Error(
|
|
178
|
+
"[FlexSearch] Invalid init data: must provide either file paths (docsPath, indexPath) or pre-loaded data (docs, indexData)"
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
isReady() {
|
|
182
|
+
return this.ready && this.docs !== null && this.searchIndex !== null;
|
|
183
|
+
}
|
|
184
|
+
async search(query, options) {
|
|
185
|
+
if (!this.isReady() || !this.docs || !this.searchIndex) {
|
|
186
|
+
throw new Error("[FlexSearch] Provider not initialized");
|
|
187
|
+
}
|
|
188
|
+
const limit = options?.limit ?? 5;
|
|
189
|
+
return searchIndex(this.searchIndex, this.docs, query, { limit });
|
|
190
|
+
}
|
|
191
|
+
async getDocument(route) {
|
|
192
|
+
if (!this.docs) {
|
|
193
|
+
throw new Error("[FlexSearch] Provider not initialized");
|
|
194
|
+
}
|
|
195
|
+
if (this.docs[route]) {
|
|
196
|
+
return this.docs[route];
|
|
197
|
+
}
|
|
198
|
+
const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
|
|
199
|
+
const withoutSlash = route.startsWith("/") ? route.slice(1) : route;
|
|
200
|
+
return this.docs[normalizedRoute] ?? this.docs[withoutSlash] ?? null;
|
|
201
|
+
}
|
|
202
|
+
async healthCheck() {
|
|
203
|
+
if (!this.isReady()) {
|
|
204
|
+
return { healthy: false, message: "FlexSearch provider not initialized" };
|
|
205
|
+
}
|
|
206
|
+
const docCount = this.docs ? Object.keys(this.docs).length : 0;
|
|
207
|
+
return {
|
|
208
|
+
healthy: true,
|
|
209
|
+
message: `FlexSearch provider ready with ${docCount} documents`
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get all loaded documents (for compatibility with existing server code)
|
|
214
|
+
*/
|
|
215
|
+
getDocs() {
|
|
216
|
+
return this.docs;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get the FlexSearch index (for compatibility with existing server code)
|
|
220
|
+
*/
|
|
221
|
+
getSearchIndex() {
|
|
222
|
+
return this.searchIndex;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/providers/loader.ts
|
|
227
|
+
async function loadSearchProvider(specifier) {
|
|
228
|
+
if (specifier === "flexsearch") {
|
|
229
|
+
return new FlexSearchProvider();
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
const module = await import(specifier);
|
|
233
|
+
const ProviderClass = module.default;
|
|
234
|
+
if (typeof ProviderClass === "function") {
|
|
235
|
+
const instance = new ProviderClass();
|
|
236
|
+
if (!isSearchProvider(instance)) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`Invalid search provider module "${specifier}": does not implement SearchProvider interface`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
return instance;
|
|
242
|
+
}
|
|
243
|
+
if (isSearchProvider(ProviderClass)) {
|
|
244
|
+
return ProviderClass;
|
|
245
|
+
}
|
|
246
|
+
throw new Error(
|
|
247
|
+
`Invalid search provider module "${specifier}": must export a default class or SearchProvider instance`
|
|
248
|
+
);
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (error instanceof Error && error.message.includes("Cannot find module")) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Search provider module not found: "${specifier}". Check the path or package name.`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function isSearchProvider(obj) {
|
|
259
|
+
if (!obj || typeof obj !== "object") {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
const provider = obj;
|
|
263
|
+
return typeof provider.name === "string" && typeof provider.initialize === "function" && typeof provider.isReady === "function" && typeof provider.search === "function";
|
|
264
|
+
}
|
|
146
265
|
|
|
147
266
|
// src/mcp/tools/docs-search.ts
|
|
148
|
-
function executeDocsSearch(params, index, docs) {
|
|
149
|
-
const { query, limit = 5 } = params;
|
|
150
|
-
if (!query || typeof query !== "string" || query.trim().length === 0) {
|
|
151
|
-
throw new Error("Query parameter is required and must be a non-empty string");
|
|
152
|
-
}
|
|
153
|
-
const effectiveLimit = Math.min(Math.max(1, limit), 20);
|
|
154
|
-
const results = searchIndex(index, docs, query.trim(), {
|
|
155
|
-
limit: effectiveLimit
|
|
156
|
-
});
|
|
157
|
-
return results;
|
|
158
|
-
}
|
|
159
267
|
function formatSearchResults(results, baseUrl) {
|
|
160
268
|
if (results.length === 0) {
|
|
161
269
|
return "No matching documents found.";
|
|
@@ -180,29 +288,7 @@ function formatSearchResults(results, baseUrl) {
|
|
|
180
288
|
return lines.join("\n");
|
|
181
289
|
}
|
|
182
290
|
|
|
183
|
-
// src/mcp/tools/docs-
|
|
184
|
-
function executeDocsGetPage(params, docs) {
|
|
185
|
-
const { route } = params;
|
|
186
|
-
if (!route || typeof route !== "string") {
|
|
187
|
-
throw new Error("Route parameter is required and must be a string");
|
|
188
|
-
}
|
|
189
|
-
let normalizedRoute = route.trim();
|
|
190
|
-
if (!normalizedRoute.startsWith("/")) {
|
|
191
|
-
normalizedRoute = "/" + normalizedRoute;
|
|
192
|
-
}
|
|
193
|
-
if (normalizedRoute.length > 1 && normalizedRoute.endsWith("/")) {
|
|
194
|
-
normalizedRoute = normalizedRoute.slice(0, -1);
|
|
195
|
-
}
|
|
196
|
-
const doc = docs[normalizedRoute];
|
|
197
|
-
if (!doc) {
|
|
198
|
-
const altRoute = normalizedRoute.slice(1);
|
|
199
|
-
if (docs[altRoute]) {
|
|
200
|
-
return docs[altRoute] ?? null;
|
|
201
|
-
}
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
return doc;
|
|
205
|
-
}
|
|
291
|
+
// src/mcp/tools/docs-fetch.ts
|
|
206
292
|
function formatPageContent(doc, baseUrl) {
|
|
207
293
|
if (!doc) {
|
|
208
294
|
return "Page not found. Please check the route path and try again.";
|
|
@@ -237,89 +323,6 @@ function formatPageContent(doc, baseUrl) {
|
|
|
237
323
|
return lines.join("\n");
|
|
238
324
|
}
|
|
239
325
|
|
|
240
|
-
// src/processing/heading-extractor.ts
|
|
241
|
-
function extractSection(markdown, headingId, headings) {
|
|
242
|
-
const heading = headings.find((h) => h.id === headingId);
|
|
243
|
-
if (!heading) {
|
|
244
|
-
return null;
|
|
245
|
-
}
|
|
246
|
-
return markdown.slice(heading.startOffset, heading.endOffset).trim();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// src/mcp/tools/docs-get-section.ts
|
|
250
|
-
function executeDocsGetSection(params, docs) {
|
|
251
|
-
const { route, headingId } = params;
|
|
252
|
-
if (!route || typeof route !== "string") {
|
|
253
|
-
throw new Error("Route parameter is required and must be a string");
|
|
254
|
-
}
|
|
255
|
-
if (!headingId || typeof headingId !== "string") {
|
|
256
|
-
throw new Error("HeadingId parameter is required and must be a string");
|
|
257
|
-
}
|
|
258
|
-
let normalizedRoute = route.trim();
|
|
259
|
-
if (!normalizedRoute.startsWith("/")) {
|
|
260
|
-
normalizedRoute = "/" + normalizedRoute;
|
|
261
|
-
}
|
|
262
|
-
if (normalizedRoute.length > 1 && normalizedRoute.endsWith("/")) {
|
|
263
|
-
normalizedRoute = normalizedRoute.slice(0, -1);
|
|
264
|
-
}
|
|
265
|
-
const doc = docs[normalizedRoute];
|
|
266
|
-
if (!doc) {
|
|
267
|
-
return {
|
|
268
|
-
content: null,
|
|
269
|
-
doc: null,
|
|
270
|
-
headingText: null,
|
|
271
|
-
availableHeadings: []
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
const availableHeadings = doc.headings.map((h) => ({
|
|
275
|
-
id: h.id,
|
|
276
|
-
text: h.text,
|
|
277
|
-
level: h.level
|
|
278
|
-
}));
|
|
279
|
-
const heading = doc.headings.find((h) => h.id === headingId.trim());
|
|
280
|
-
if (!heading) {
|
|
281
|
-
return {
|
|
282
|
-
content: null,
|
|
283
|
-
doc,
|
|
284
|
-
headingText: null,
|
|
285
|
-
availableHeadings
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
const content = extractSection(doc.markdown, headingId.trim(), doc.headings);
|
|
289
|
-
return {
|
|
290
|
-
content,
|
|
291
|
-
doc,
|
|
292
|
-
headingText: heading.text,
|
|
293
|
-
availableHeadings
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
function formatSectionContent(result, headingId, baseUrl) {
|
|
297
|
-
if (!result.doc) {
|
|
298
|
-
return "Page not found. Please check the route path and try again.";
|
|
299
|
-
}
|
|
300
|
-
if (!result.content) {
|
|
301
|
-
const lines2 = [`Section "${headingId}" not found in this document.`, "", "Available sections:"];
|
|
302
|
-
for (const heading of result.availableHeadings) {
|
|
303
|
-
const indent = " ".repeat(heading.level - 1);
|
|
304
|
-
lines2.push(`${indent}- ${heading.text} (id: ${heading.id})`);
|
|
305
|
-
}
|
|
306
|
-
return lines2.join("\n");
|
|
307
|
-
}
|
|
308
|
-
const lines = [];
|
|
309
|
-
const fullUrl = baseUrl ? `${baseUrl.replace(/\/$/, "")}${result.doc.route}#${headingId}` : null;
|
|
310
|
-
lines.push(`# ${result.headingText}`);
|
|
311
|
-
if (fullUrl) {
|
|
312
|
-
lines.push(`> From: ${result.doc.title} - ${fullUrl}`);
|
|
313
|
-
} else {
|
|
314
|
-
lines.push(`> From: ${result.doc.title} (${result.doc.route})`);
|
|
315
|
-
}
|
|
316
|
-
lines.push("");
|
|
317
|
-
lines.push("---");
|
|
318
|
-
lines.push("");
|
|
319
|
-
lines.push(result.content);
|
|
320
|
-
return lines.join("\n");
|
|
321
|
-
}
|
|
322
|
-
|
|
323
326
|
// src/mcp/server.ts
|
|
324
327
|
function isFileConfig(config) {
|
|
325
328
|
return "docsPath" in config && "indexPath" in config;
|
|
@@ -329,8 +332,7 @@ function isDataConfig(config) {
|
|
|
329
332
|
}
|
|
330
333
|
var McpDocsServer = class {
|
|
331
334
|
config;
|
|
332
|
-
|
|
333
|
-
searchIndex = null;
|
|
335
|
+
searchProvider = null;
|
|
334
336
|
mcpServer;
|
|
335
337
|
initialized = false;
|
|
336
338
|
constructor(config) {
|
|
@@ -363,75 +365,83 @@ var McpDocsServer = class {
|
|
|
363
365
|
},
|
|
364
366
|
async ({ query, limit }) => {
|
|
365
367
|
await this.initialize();
|
|
366
|
-
if (!this.
|
|
368
|
+
if (!this.searchProvider || !this.searchProvider.isReady()) {
|
|
367
369
|
return {
|
|
368
370
|
content: [{ type: "text", text: "Server not initialized. Please try again." }],
|
|
369
371
|
isError: true
|
|
370
372
|
};
|
|
371
373
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
374
|
+
try {
|
|
375
|
+
const results = await this.searchProvider.search(query, { limit });
|
|
376
|
+
return {
|
|
377
|
+
content: [
|
|
378
|
+
{ type: "text", text: formatSearchResults(results, this.config.baseUrl) }
|
|
379
|
+
]
|
|
380
|
+
};
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error("[MCP] Search error:", error);
|
|
383
|
+
return {
|
|
384
|
+
content: [{ type: "text", text: `Search error: ${String(error)}` }],
|
|
385
|
+
isError: true
|
|
386
|
+
};
|
|
387
|
+
}
|
|
378
388
|
}
|
|
379
389
|
);
|
|
380
390
|
this.mcpServer.registerTool(
|
|
381
|
-
"
|
|
391
|
+
"docs_fetch",
|
|
382
392
|
{
|
|
383
|
-
description: "
|
|
393
|
+
description: "Fetch the complete content of a documentation page. Use this when you need the full content of a specific page.",
|
|
384
394
|
inputSchema: {
|
|
385
395
|
route: zod.z.string().min(1).describe('The page route path (e.g., "/docs/getting-started" or "/api/reference")')
|
|
386
396
|
}
|
|
387
397
|
},
|
|
388
398
|
async ({ route }) => {
|
|
389
399
|
await this.initialize();
|
|
390
|
-
if (!this.
|
|
400
|
+
if (!this.searchProvider || !this.searchProvider.isReady()) {
|
|
391
401
|
return {
|
|
392
402
|
content: [{ type: "text", text: "Server not initialized. Please try again." }],
|
|
393
403
|
isError: true
|
|
394
404
|
};
|
|
395
405
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
content: [{ type: "text", text: formatPageContent(doc, this.config.baseUrl) }]
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
);
|
|
402
|
-
this.mcpServer.registerTool(
|
|
403
|
-
"docs_get_section",
|
|
404
|
-
{
|
|
405
|
-
description: "Retrieve a specific section from a documentation page by its heading ID. Use this when you need only a portion of a page rather than the entire content.",
|
|
406
|
-
inputSchema: {
|
|
407
|
-
route: zod.z.string().min(1).describe("The page route path"),
|
|
408
|
-
headingId: zod.z.string().min(1).describe(
|
|
409
|
-
'The heading ID of the section to extract (e.g., "installation", "api-reference")'
|
|
410
|
-
)
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
async ({ route, headingId }) => {
|
|
414
|
-
await this.initialize();
|
|
415
|
-
if (!this.docs) {
|
|
406
|
+
try {
|
|
407
|
+
const doc = await this.getDocument(route);
|
|
416
408
|
return {
|
|
417
|
-
content: [{ type: "text", text:
|
|
409
|
+
content: [{ type: "text", text: formatPageContent(doc, this.config.baseUrl) }]
|
|
410
|
+
};
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.error("[MCP] Get page error:", error);
|
|
413
|
+
return {
|
|
414
|
+
content: [{ type: "text", text: `Error getting page: ${String(error)}` }],
|
|
418
415
|
isError: true
|
|
419
416
|
};
|
|
420
417
|
}
|
|
421
|
-
const result = executeDocsGetSection({ route, headingId }, this.docs);
|
|
422
|
-
return {
|
|
423
|
-
content: [
|
|
424
|
-
{
|
|
425
|
-
type: "text",
|
|
426
|
-
text: formatSectionContent(result, headingId, this.config.baseUrl)
|
|
427
|
-
}
|
|
428
|
-
]
|
|
429
|
-
};
|
|
430
418
|
}
|
|
431
419
|
);
|
|
432
420
|
}
|
|
433
421
|
/**
|
|
434
|
-
*
|
|
422
|
+
* Get a document by route using the search provider
|
|
423
|
+
*/
|
|
424
|
+
async getDocument(route) {
|
|
425
|
+
if (!this.searchProvider) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
if (this.searchProvider.getDocument) {
|
|
429
|
+
return this.searchProvider.getDocument(route);
|
|
430
|
+
}
|
|
431
|
+
if (this.searchProvider instanceof FlexSearchProvider) {
|
|
432
|
+
const docs = this.searchProvider.getDocs();
|
|
433
|
+
if (!docs) return null;
|
|
434
|
+
if (docs[route]) {
|
|
435
|
+
return docs[route];
|
|
436
|
+
}
|
|
437
|
+
const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
|
|
438
|
+
const withoutSlash = route.startsWith("/") ? route.slice(1) : route;
|
|
439
|
+
return docs[normalizedRoute] ?? docs[withoutSlash] ?? null;
|
|
440
|
+
}
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Load docs and search index using the configured search provider
|
|
435
445
|
*
|
|
436
446
|
* For file-based config: reads from disk
|
|
437
447
|
* For data config: uses pre-loaded data directly
|
|
@@ -441,24 +451,26 @@ var McpDocsServer = class {
|
|
|
441
451
|
return;
|
|
442
452
|
}
|
|
443
453
|
try {
|
|
454
|
+
const searchSpecifier = this.config.search ?? "flexsearch";
|
|
455
|
+
this.searchProvider = await loadSearchProvider(searchSpecifier);
|
|
456
|
+
const providerContext = {
|
|
457
|
+
baseUrl: this.config.baseUrl ?? "",
|
|
458
|
+
serverName: this.config.name,
|
|
459
|
+
serverVersion: this.config.version ?? "1.0.0",
|
|
460
|
+
outputDir: ""
|
|
461
|
+
// Not relevant for runtime
|
|
462
|
+
};
|
|
463
|
+
const initData = {};
|
|
444
464
|
if (isDataConfig(this.config)) {
|
|
445
|
-
|
|
446
|
-
|
|
465
|
+
initData.docs = this.config.docs;
|
|
466
|
+
initData.indexData = this.config.searchIndexData;
|
|
447
467
|
} else if (isFileConfig(this.config)) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
} else {
|
|
451
|
-
throw new Error(`Docs file not found: ${this.config.docsPath}`);
|
|
452
|
-
}
|
|
453
|
-
if (await fs__default.default.pathExists(this.config.indexPath)) {
|
|
454
|
-
const indexData = await fs__default.default.readJson(this.config.indexPath);
|
|
455
|
-
this.searchIndex = await importSearchIndex(indexData);
|
|
456
|
-
} else {
|
|
457
|
-
throw new Error(`Search index not found: ${this.config.indexPath}`);
|
|
458
|
-
}
|
|
468
|
+
initData.docsPath = this.config.docsPath;
|
|
469
|
+
initData.indexPath = this.config.indexPath;
|
|
459
470
|
} else {
|
|
460
471
|
throw new Error("Invalid server config: must provide either file paths or pre-loaded data");
|
|
461
472
|
}
|
|
473
|
+
await this.searchProvider.initialize(providerContext, initData);
|
|
462
474
|
this.initialized = true;
|
|
463
475
|
} catch (error) {
|
|
464
476
|
console.error("[MCP] Failed to initialize:", error);
|
|
@@ -519,12 +531,18 @@ var McpDocsServer = class {
|
|
|
519
531
|
* Useful for health checks and debugging
|
|
520
532
|
*/
|
|
521
533
|
async getStatus() {
|
|
534
|
+
let docCount = 0;
|
|
535
|
+
if (this.searchProvider instanceof FlexSearchProvider) {
|
|
536
|
+
const docs = this.searchProvider.getDocs();
|
|
537
|
+
docCount = docs ? Object.keys(docs).length : 0;
|
|
538
|
+
}
|
|
522
539
|
return {
|
|
523
540
|
name: this.config.name,
|
|
524
541
|
version: this.config.version ?? "1.0.0",
|
|
525
542
|
initialized: this.initialized,
|
|
526
|
-
docCount
|
|
527
|
-
baseUrl: this.config.baseUrl
|
|
543
|
+
docCount,
|
|
544
|
+
baseUrl: this.config.baseUrl,
|
|
545
|
+
searchProvider: this.searchProvider?.name
|
|
528
546
|
};
|
|
529
547
|
}
|
|
530
548
|
/**
|