@arabold/docs-mcp-server 1.12.3 → 1.13.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/db/migrations/001-add-indexed-at-column.sql +1 -1
- package/dist/{DocumentManagementService-BupnR1eC.js → DocumentManagementService-BGW9iWNn.js} +281 -209
- package/dist/DocumentManagementService-BGW9iWNn.js.map +1 -0
- package/dist/{EmbeddingFactory-DZKXkqOe.js → EmbeddingFactory-0Z5e_g1J.js} +4 -3
- package/dist/EmbeddingFactory-0Z5e_g1J.js.map +1 -0
- package/dist/{FindVersionTool-BcnLvjlo.js → FindVersionTool-DhhmoGU7.js} +34 -64
- package/dist/FindVersionTool-DhhmoGU7.js.map +1 -0
- package/dist/{RemoveTool-Bqpr8F9m.js → RemoveTool-BZPTXvhj.js} +2 -2
- package/dist/{RemoveTool-Bqpr8F9m.js.map → RemoveTool-BZPTXvhj.js.map} +1 -1
- package/dist/cli.js +3 -3
- package/dist/server.js +4 -3
- package/dist/server.js.map +1 -1
- package/dist/web.js +3 -2
- package/dist/web.js.map +1 -1
- package/package.json +1 -1
- package/dist/DocumentManagementService-BupnR1eC.js.map +0 -1
- package/dist/EmbeddingFactory-DZKXkqOe.js.map +0 -1
- package/dist/FindVersionTool-BcnLvjlo.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { BedrockEmbeddings } from "@langchain/aws";
|
|
|
2
2
|
import { GoogleGenerativeAIEmbeddings } from "@langchain/google-genai";
|
|
3
3
|
import { VertexAIEmbeddings } from "@langchain/google-vertexai";
|
|
4
4
|
import { AzureOpenAIEmbeddings, OpenAIEmbeddings } from "@langchain/openai";
|
|
5
|
-
import {
|
|
5
|
+
import { q as DimensionError, r as VECTOR_DIMENSION } from "./DocumentManagementService-BGW9iWNn.js";
|
|
6
6
|
import { Embeddings } from "@langchain/core/embeddings";
|
|
7
7
|
class FixedDimensionEmbeddings extends Embeddings {
|
|
8
8
|
constructor(embeddings, targetDimension, providerAndModel, allowTruncate = false) {
|
|
@@ -59,7 +59,8 @@ class ModelConfigurationError extends Error {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
function createEmbeddingModel(providerAndModel) {
|
|
62
|
-
const [providerOrModel,
|
|
62
|
+
const [providerOrModel, ...modelNameParts] = providerAndModel.split(":");
|
|
63
|
+
const modelName = modelNameParts.join(":");
|
|
63
64
|
const provider = modelName ? providerOrModel : "openai";
|
|
64
65
|
const model = modelName || providerOrModel;
|
|
65
66
|
const baseConfig = { stripNewLines: true };
|
|
@@ -171,4 +172,4 @@ export {
|
|
|
171
172
|
UnsupportedProviderError,
|
|
172
173
|
createEmbeddingModel
|
|
173
174
|
};
|
|
174
|
-
//# sourceMappingURL=EmbeddingFactory-
|
|
175
|
+
//# sourceMappingURL=EmbeddingFactory-0Z5e_g1J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmbeddingFactory-0Z5e_g1J.js","sources":["../src/store/embeddings/FixedDimensionEmbeddings.ts","../src/store/embeddings/EmbeddingFactory.ts"],"sourcesContent":["import { Embeddings } from \"@langchain/core/embeddings\";\nimport { DimensionError } from \"../errors\";\n\n/**\n * Wrapper around an Embeddings implementation that ensures vectors have a fixed dimension.\n * - If a vector's dimension is greater than the target and truncation is allowed,\n * the vector is truncated (e.g., for models that support MRL - Matryoshka\n * Representation Learning).\n * - If a vector's dimension is greater than the target and truncation is not\n * allowed, a DimensionError is thrown.\n * - If a vector's dimension is less than the target, it is padded with zeros.\n */\nexport class FixedDimensionEmbeddings extends Embeddings {\n private provider: string;\n private model: string;\n\n constructor(\n private readonly embeddings: Embeddings,\n private readonly targetDimension: number,\n providerAndModel: string,\n private readonly allowTruncate: boolean = false,\n ) {\n super({});\n // Parse provider and model from string (e.g., \"gemini:embedding-001\" or just \"text-embedding-3-small\")\n const [providerOrModel, modelName] = providerAndModel.split(\":\");\n this.provider = modelName ? providerOrModel : \"openai\"; // Default to openai if no provider specified\n this.model = modelName || providerOrModel;\n }\n\n /**\n * Normalize a vector to the target dimension by truncating (for MRL models) or padding.\n * @throws {DimensionError} If vector is too large and provider doesn't support MRL\n */\n private normalizeVector(vector: number[]): number[] {\n const dimension = vector.length;\n\n if (dimension > this.targetDimension) {\n // If truncation is allowed (e.g., for MRL models like Gemini), truncate the vector\n if (this.allowTruncate) {\n return vector.slice(0, this.targetDimension);\n }\n // Otherwise, throw an error\n throw new DimensionError(\n `${this.provider}:${this.model}`,\n dimension,\n this.targetDimension,\n );\n }\n\n if (dimension < this.targetDimension) {\n // Pad with zeros to reach target dimension\n return [...vector, ...new Array(this.targetDimension - dimension).fill(0)];\n }\n\n return vector;\n }\n\n async embedQuery(text: string): Promise<number[]> {\n const vector = await this.embeddings.embedQuery(text);\n return this.normalizeVector(vector);\n }\n\n async embedDocuments(documents: string[]): Promise<number[][]> {\n const vectors = await this.embeddings.embedDocuments(documents);\n return vectors.map((vector) => this.normalizeVector(vector));\n }\n}\n","import { BedrockEmbeddings } from \"@langchain/aws\";\nimport type { Embeddings } from \"@langchain/core/embeddings\";\nimport { GoogleGenerativeAIEmbeddings } from \"@langchain/google-genai\";\nimport { VertexAIEmbeddings } from \"@langchain/google-vertexai\";\nimport {\n AzureOpenAIEmbeddings,\n type ClientOptions,\n OpenAIEmbeddings,\n type OpenAIEmbeddingsParams,\n} from \"@langchain/openai\";\nimport { VECTOR_DIMENSION } from \"../types\";\nimport { FixedDimensionEmbeddings } from \"./FixedDimensionEmbeddings\";\n\n/**\n * Supported embedding model providers. Each provider requires specific environment\n * variables to be set for API access.\n */\nexport type EmbeddingProvider = \"openai\" | \"vertex\" | \"gemini\" | \"aws\" | \"microsoft\";\n\n/**\n * Error thrown when an invalid or unsupported embedding provider is specified.\n */\nexport class UnsupportedProviderError extends Error {\n constructor(provider: string) {\n super(`Unsupported embedding provider: ${provider}`);\n this.name = \"UnsupportedProviderError\";\n }\n}\n\n/**\n * Error thrown when there's an issue with the model configuration or missing environment variables.\n */\nexport class ModelConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ModelConfigurationError\";\n }\n}\n\n/**\n * Creates an embedding model instance based on the specified provider and model name.\n * The provider and model name should be specified in the format \"provider:model_name\"\n * (e.g., \"google:text-embedding-004\"). If no provider is specified (i.e., just \"model_name\"),\n * OpenAI is used as the default provider.\n *\n * Environment variables required per provider:\n * - OpenAI: OPENAI_API_KEY (and optionally OPENAI_API_BASE, OPENAI_ORG_ID)\n * - Google Cloud Vertex AI: GOOGLE_APPLICATION_CREDENTIALS (path to service account JSON)\n * - Google GenAI (Gemini): GOOGLE_API_KEY\n * - AWS: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION (or BEDROCK_AWS_REGION)\n * - Microsoft: AZURE_OPENAI_API_KEY, AZURE_OPENAI_API_INSTANCE_NAME, AZURE_OPENAI_API_DEPLOYMENT_NAME, AZURE_OPENAI_API_VERSION\n *\n * @param providerAndModel - The provider and model name in the format \"provider:model_name\"\n * or just \"model_name\" for OpenAI models.\n * @returns A configured instance of the appropriate Embeddings implementation.\n * @throws {UnsupportedProviderError} If an unsupported provider is specified.\n * @throws {ModelConfigurationError} If there's an issue with the model configuration.\n */\nexport function createEmbeddingModel(providerAndModel: string): Embeddings {\n // Parse provider and model name\n const [providerOrModel, ...modelNameParts] = providerAndModel.split(\":\");\n const modelName = modelNameParts.join(\":\");\n const provider = modelName ? (providerOrModel as EmbeddingProvider) : \"openai\";\n const model = modelName || providerOrModel;\n\n // Default configuration for each provider\n const baseConfig = { stripNewLines: true };\n\n switch (provider) {\n case \"openai\": {\n const config: Partial<OpenAIEmbeddingsParams> & { configuration?: ClientOptions } =\n {\n ...baseConfig,\n modelName: model,\n batchSize: 512, // OpenAI supports large batches\n };\n // Add custom base URL if specified\n const baseURL = process.env.OPENAI_API_BASE;\n if (baseURL) {\n config.configuration = { baseURL };\n }\n return new OpenAIEmbeddings(config);\n }\n\n case \"vertex\": {\n if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {\n throw new ModelConfigurationError(\n \"GOOGLE_APPLICATION_CREDENTIALS environment variable is required for Google Cloud Vertex AI\",\n );\n }\n return new VertexAIEmbeddings({\n ...baseConfig,\n model: model, // e.g., \"text-embedding-004\"\n });\n }\n\n case \"gemini\": {\n if (!process.env.GOOGLE_API_KEY) {\n throw new ModelConfigurationError(\n \"GOOGLE_API_KEY environment variable is required for Google AI (Gemini)\",\n );\n }\n // Create base embeddings and wrap with FixedDimensionEmbeddings since Gemini\n // supports MRL (Matryoshka Representation Learning) for safe truncation\n const baseEmbeddings = new GoogleGenerativeAIEmbeddings({\n ...baseConfig,\n apiKey: process.env.GOOGLE_API_KEY,\n model: model, // e.g., \"gemini-embedding-exp-03-07\"\n });\n return new FixedDimensionEmbeddings(\n baseEmbeddings,\n VECTOR_DIMENSION,\n providerAndModel,\n true,\n );\n }\n\n case \"aws\": {\n // For AWS, model should be the full Bedrock model ID\n const region = process.env.BEDROCK_AWS_REGION || process.env.AWS_REGION;\n if (!region) {\n throw new ModelConfigurationError(\n \"BEDROCK_AWS_REGION or AWS_REGION environment variable is required for AWS Bedrock\",\n );\n }\n if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {\n throw new ModelConfigurationError(\n \"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables are required for AWS Bedrock\",\n );\n }\n\n return new BedrockEmbeddings({\n ...baseConfig,\n model: model, // e.g., \"amazon.titan-embed-text-v1\"\n region,\n credentials: {\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n sessionToken: process.env.AWS_SESSION_TOKEN,\n },\n });\n }\n\n case \"microsoft\": {\n // For Azure, model name corresponds to the deployment name\n if (!process.env.AZURE_OPENAI_API_KEY) {\n throw new ModelConfigurationError(\n \"AZURE_OPENAI_API_KEY environment variable is required for Azure OpenAI\",\n );\n }\n if (!process.env.AZURE_OPENAI_API_INSTANCE_NAME) {\n throw new ModelConfigurationError(\n \"AZURE_OPENAI_API_INSTANCE_NAME environment variable is required for Azure OpenAI\",\n );\n }\n if (!process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME) {\n throw new ModelConfigurationError(\n \"AZURE_OPENAI_API_DEPLOYMENT_NAME environment variable is required for Azure OpenAI\",\n );\n }\n if (!process.env.AZURE_OPENAI_API_VERSION) {\n throw new ModelConfigurationError(\n \"AZURE_OPENAI_API_VERSION environment variable is required for Azure OpenAI\",\n );\n }\n\n return new AzureOpenAIEmbeddings({\n ...baseConfig,\n azureOpenAIApiKey: process.env.AZURE_OPENAI_API_KEY,\n azureOpenAIApiInstanceName: process.env.AZURE_OPENAI_API_INSTANCE_NAME,\n azureOpenAIApiDeploymentName: process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME,\n azureOpenAIApiVersion: process.env.AZURE_OPENAI_API_VERSION,\n deploymentName: model,\n });\n }\n\n default:\n throw new UnsupportedProviderError(provider);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { j as ScrapeMode, T as ToolError,
|
|
2
|
-
import "node:vm";
|
|
3
|
-
import "jsdom";
|
|
1
|
+
import { j as ScrapeMode, T as ToolError, k as HtmlPipeline, M as MarkdownPipeline, l as logger, m as ScraperError, V as VersionNotFoundError } from "./DocumentManagementService-BGW9iWNn.js";
|
|
4
2
|
class FetchUrlTool {
|
|
5
3
|
/**
|
|
6
4
|
* Collection of fetchers that will be tried in order for a given URL.
|
|
@@ -26,86 +24,57 @@ class FetchUrlTool {
|
|
|
26
24
|
);
|
|
27
25
|
}
|
|
28
26
|
const fetcher = this.fetchers[fetcherIndex];
|
|
29
|
-
const
|
|
27
|
+
const htmlPipeline = new HtmlPipeline();
|
|
28
|
+
const markdownPipeline = new MarkdownPipeline();
|
|
29
|
+
const pipelines = [htmlPipeline, markdownPipeline];
|
|
30
30
|
try {
|
|
31
31
|
logger.info(`📡 Fetching ${url}...`);
|
|
32
32
|
const rawContent = await fetcher.fetch(url, {
|
|
33
33
|
followRedirects: options.followRedirects ?? true,
|
|
34
34
|
maxRetries: 3
|
|
35
|
-
// Keep retries for fetching
|
|
36
35
|
});
|
|
37
36
|
logger.info("🔄 Processing content...");
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
scope: "subpages",
|
|
60
|
-
// Default, though not used for single page fetch
|
|
61
|
-
followRedirects: options.followRedirects ?? true,
|
|
62
|
-
excludeSelectors: void 0,
|
|
63
|
-
// Not currently configurable via this tool
|
|
64
|
-
ignoreErrors: false,
|
|
65
|
-
scrapeMode
|
|
66
|
-
// Pass the scrapeMode
|
|
37
|
+
let processed;
|
|
38
|
+
for (const pipeline of pipelines) {
|
|
39
|
+
if (pipeline.canProcess(rawContent)) {
|
|
40
|
+
processed = await pipeline.process(
|
|
41
|
+
rawContent,
|
|
42
|
+
{
|
|
43
|
+
url,
|
|
44
|
+
library: "",
|
|
45
|
+
version: "",
|
|
46
|
+
maxDepth: 0,
|
|
47
|
+
maxPages: 1,
|
|
48
|
+
maxConcurrency: 1,
|
|
49
|
+
scope: "subpages",
|
|
50
|
+
followRedirects: options.followRedirects ?? true,
|
|
51
|
+
excludeSelectors: void 0,
|
|
52
|
+
ignoreErrors: false,
|
|
53
|
+
scrapeMode
|
|
54
|
+
},
|
|
55
|
+
fetcher
|
|
56
|
+
);
|
|
57
|
+
break;
|
|
67
58
|
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (initialContext.contentType.startsWith("text/html")) {
|
|
71
|
-
const htmlPipelineSteps = [
|
|
72
|
-
playwrightMiddleware,
|
|
73
|
-
// Use the instantiated middleware
|
|
74
|
-
new HtmlCheerioParserMiddleware(),
|
|
75
|
-
// Always runs after content is finalized
|
|
76
|
-
new HtmlMetadataExtractorMiddleware(),
|
|
77
|
-
// Keep for potential future use
|
|
78
|
-
// No Link Extractor needed for this tool
|
|
79
|
-
new HtmlSanitizerMiddleware(),
|
|
80
|
-
// Element remover
|
|
81
|
-
new HtmlToMarkdownMiddleware()
|
|
82
|
-
];
|
|
83
|
-
pipeline = new ContentProcessingPipeline(htmlPipelineSteps);
|
|
84
|
-
} else if (initialContext.contentType === "text/markdown" || initialContext.contentType === "text/plain") {
|
|
85
|
-
pipeline = new ContentProcessingPipeline([
|
|
86
|
-
new MarkdownMetadataExtractorMiddleware()
|
|
87
|
-
// Extract title (though not used)
|
|
88
|
-
// No further processing needed for Markdown/Plain text for this tool
|
|
89
|
-
]);
|
|
90
|
-
} else {
|
|
59
|
+
}
|
|
60
|
+
if (!processed) {
|
|
91
61
|
logger.warn(
|
|
92
|
-
`Unsupported content type "${
|
|
62
|
+
`Unsupported content type "${rawContent.mimeType}" for ${url}. Returning raw content.`
|
|
93
63
|
);
|
|
94
64
|
const contentString = typeof rawContent.content === "string" ? rawContent.content : Buffer.from(rawContent.content).toString("utf-8");
|
|
95
65
|
return contentString;
|
|
96
66
|
}
|
|
97
|
-
const
|
|
98
|
-
for (const err of finalContext.errors) {
|
|
67
|
+
for (const err of processed.errors) {
|
|
99
68
|
logger.warn(`Processing error for ${url}: ${err.message}`);
|
|
100
69
|
}
|
|
101
|
-
if (typeof
|
|
70
|
+
if (typeof processed.textContent !== "string" || !processed.textContent.trim()) {
|
|
102
71
|
throw new ToolError(
|
|
103
72
|
`Processing resulted in empty content for ${url}`,
|
|
104
73
|
this.constructor.name
|
|
105
74
|
);
|
|
106
75
|
}
|
|
107
76
|
logger.info(`✅ Successfully processed ${url}`);
|
|
108
|
-
return
|
|
77
|
+
return processed.textContent;
|
|
109
78
|
} catch (error) {
|
|
110
79
|
if (error instanceof ScraperError || error instanceof ToolError) {
|
|
111
80
|
throw new ToolError(
|
|
@@ -118,7 +87,8 @@ class FetchUrlTool {
|
|
|
118
87
|
this.constructor.name
|
|
119
88
|
);
|
|
120
89
|
} finally {
|
|
121
|
-
await
|
|
90
|
+
await htmlPipeline.close();
|
|
91
|
+
await markdownPipeline.close();
|
|
122
92
|
}
|
|
123
93
|
}
|
|
124
94
|
}
|
|
@@ -167,4 +137,4 @@ export {
|
|
|
167
137
|
FetchUrlTool as F,
|
|
168
138
|
FindVersionTool as a
|
|
169
139
|
};
|
|
170
|
-
//# sourceMappingURL=FindVersionTool-
|
|
140
|
+
//# sourceMappingURL=FindVersionTool-DhhmoGU7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FindVersionTool-DhhmoGU7.js","sources":["../src/tools/FetchUrlTool.ts","../src/tools/FindVersionTool.ts"],"sourcesContent":["import type {\n ContentFetcher,\n FileFetcher,\n HttpFetcher,\n RawContent,\n} from \"../scraper/fetcher\";\nimport { HtmlPipeline } from \"../scraper/pipelines/HtmlPipeline\";\nimport { MarkdownPipeline } from \"../scraper/pipelines/MarkdownPipeline\";\nimport { ScrapeMode } from \"../scraper/types\";\nimport { ScraperError } from \"../utils/errors\";\nimport { logger } from \"../utils/logger\";\nimport { ToolError } from \"./errors\";\n\nexport interface FetchUrlToolOptions {\n /**\n * The URL to fetch and convert to markdown.\n * Must be a valid HTTP/HTTPS URL or file:// URL.\n */\n url: string;\n\n /**\n * Whether to follow HTTP redirects.\n * @default true\n */\n followRedirects?: boolean;\n\n /**\n * Determines the HTML processing strategy.\n * - 'fetch': Use a simple DOM parser (faster, less JS support).\n * - 'playwright': Use a headless browser (slower, full JS support).\n * - 'auto': Automatically select the best strategy (currently defaults to 'playwright').\n * @default ScrapeMode.Auto\n */\n scrapeMode?: ScrapeMode;\n}\n\n/**\n * Tool for fetching a single URL and converting its content to Markdown.\n * Unlike scrape_docs, this tool only processes one page without crawling\n * or storing the content.\n *\n * Supports both HTTP/HTTPS URLs and local file URLs (file://).\n */\nexport class FetchUrlTool {\n /**\n * Collection of fetchers that will be tried in order for a given URL.\n */\n private readonly fetchers: ContentFetcher[];\n\n constructor(httpFetcher: HttpFetcher, fileFetcher: FileFetcher) {\n this.fetchers = [httpFetcher, fileFetcher];\n }\n\n /**\n * Fetches content from a URL and converts it to Markdown.\n * Supports both HTTP/HTTPS URLs and local file URLs (file://).\n * @returns The processed Markdown content\n * @throws {ToolError} If fetching or processing fails\n */\n async execute(options: FetchUrlToolOptions): Promise<string> {\n const { url, scrapeMode = ScrapeMode.Auto } = options;\n\n const canFetchResults = this.fetchers.map((f) => f.canFetch(url));\n const fetcherIndex = canFetchResults.findIndex((result) => result === true);\n if (fetcherIndex === -1) {\n throw new ToolError(\n `Invalid URL: ${url}. Must be an HTTP/HTTPS URL or a file:// URL.`,\n this.constructor.name,\n );\n }\n\n const fetcher = this.fetchers[fetcherIndex];\n const htmlPipeline = new HtmlPipeline();\n const markdownPipeline = new MarkdownPipeline();\n const pipelines = [htmlPipeline, markdownPipeline];\n\n try {\n logger.info(`📡 Fetching ${url}...`);\n const rawContent: RawContent = await fetcher.fetch(url, {\n followRedirects: options.followRedirects ?? true,\n maxRetries: 3,\n });\n\n logger.info(\"🔄 Processing content...\");\n\n let processed: Awaited<ReturnType<(typeof htmlPipeline)[\"process\"]>> | undefined;\n for (const pipeline of pipelines) {\n if (pipeline.canProcess(rawContent)) {\n processed = await pipeline.process(\n rawContent,\n {\n url,\n library: \"\",\n version: \"\",\n maxDepth: 0,\n maxPages: 1,\n maxConcurrency: 1,\n scope: \"subpages\",\n followRedirects: options.followRedirects ?? true,\n excludeSelectors: undefined,\n ignoreErrors: false,\n scrapeMode,\n },\n fetcher,\n );\n break;\n }\n }\n\n if (!processed) {\n logger.warn(\n `Unsupported content type \"${rawContent.mimeType}\" for ${url}. Returning raw content.`,\n );\n const contentString =\n typeof rawContent.content === \"string\"\n ? rawContent.content\n : Buffer.from(rawContent.content).toString(\"utf-8\");\n return contentString;\n }\n\n for (const err of processed.errors) {\n logger.warn(`Processing error for ${url}: ${err.message}`);\n }\n\n if (typeof processed.textContent !== \"string\" || !processed.textContent.trim()) {\n throw new ToolError(\n `Processing resulted in empty content for ${url}`,\n this.constructor.name,\n );\n }\n\n logger.info(`✅ Successfully processed ${url}`);\n return processed.textContent;\n } catch (error) {\n if (error instanceof ScraperError || error instanceof ToolError) {\n throw new ToolError(\n `Failed to fetch or process URL: ${error.message}`,\n this.constructor.name,\n );\n }\n throw new ToolError(\n `Failed to fetch or process URL: ${error instanceof Error ? error.message : String(error)}`,\n this.constructor.name,\n );\n } finally {\n await htmlPipeline.close();\n await markdownPipeline.close();\n }\n }\n}\n","import type { DocumentManagementService } from \"../store\";\nimport { logger } from \"../utils/logger\";\nimport { VersionNotFoundError } from \"./errors\";\n\nexport interface FindVersionToolOptions {\n library: string;\n targetVersion?: string;\n}\n\n/**\n * Tool for finding the best matching version of a library in the store.\n * Supports exact version matches and X-Range patterns (e.g., '5.x', '5.2.x').\n */\nexport class FindVersionTool {\n private docService: DocumentManagementService;\n\n constructor(docService: DocumentManagementService) {\n this.docService = docService;\n }\n\n /**\n * Executes the tool to find the best matching version and checks for unversioned docs.\n * @returns A descriptive string indicating the best match and unversioned status, or an error message.\n */\n async execute(options: FindVersionToolOptions): Promise<string> {\n const { library, targetVersion } = options;\n const targetVersionString = targetVersion ? `@${targetVersion}` : \"\";\n\n try {\n const { bestMatch, hasUnversioned } = await this.docService.findBestVersion(\n library,\n targetVersion,\n );\n\n let message = \"\";\n if (bestMatch) {\n message = `Best match: ${bestMatch}.`;\n if (hasUnversioned) {\n message += \" Unversioned docs also available.\";\n }\n } else if (hasUnversioned) {\n message = `No matching version found for ${library}${targetVersionString}, but unversioned docs exist.`;\n } else {\n // This case should ideally be caught by VersionNotFoundError below,\n // but added for completeness.\n message = `No matching version or unversioned documents found for ${library}${targetVersionString}.`;\n }\n return message;\n } catch (error) {\n if (error instanceof VersionNotFoundError) {\n // This error is thrown when no semver versions AND no unversioned docs exist.\n logger.info(`ℹ️ Version not found: ${error.message}`);\n return `No matching version or unversioned documents found for ${library}${targetVersionString}. Available: ${\n error.availableVersions.length > 0\n ? error.availableVersions.map((v) => v.version).join(\", \")\n : \"None\"\n }.`;\n }\n // Re-throw unexpected errors\n logger.error(\n `❌ Error finding version for ${library}${targetVersionString}: ${error instanceof Error ? error.message : error}`,\n );\n throw error;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as logger, T as ToolError } from "./DocumentManagementService-
|
|
1
|
+
import { l as logger, T as ToolError } from "./DocumentManagementService-BGW9iWNn.js";
|
|
2
2
|
class ListJobsTool {
|
|
3
3
|
manager;
|
|
4
4
|
// Change property name and type
|
|
@@ -62,4 +62,4 @@ export {
|
|
|
62
62
|
ListJobsTool as L,
|
|
63
63
|
RemoveTool as R
|
|
64
64
|
};
|
|
65
|
-
//# sourceMappingURL=RemoveTool-
|
|
65
|
+
//# sourceMappingURL=RemoveTool-BZPTXvhj.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoveTool-
|
|
1
|
+
{"version":3,"file":"RemoveTool-BZPTXvhj.js","sources":["../src/tools/ListJobsTool.ts","../src/tools/RemoveTool.ts"],"sourcesContent":["import type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport type { PipelineJob, PipelineJobStatus } from \"../pipeline/types\";\nimport type { JobInfo } from \"./GetJobInfoTool\"; // Import JobInfo\n\n/**\n * Input parameters for the ListJobsTool.\n */\nexport interface ListJobsInput {\n /** Optional status to filter jobs by. */\n status?: PipelineJobStatus;\n}\n\n/**\n * Response structure for the ListJobsTool.\n */\nexport interface ListJobsToolResponse {\n jobs: JobInfo[];\n}\n\n/**\n * Tool for listing pipeline jobs managed by the PipelineManager.\n * Allows filtering jobs by their status.\n */\nexport class ListJobsTool {\n private manager: PipelineManager; // Change property name and type\n\n /**\n * Creates an instance of ListJobsTool.\n * @param manager The PipelineManager instance.\n */\n constructor(manager: PipelineManager) {\n // Change constructor parameter\n this.manager = manager;\n }\n\n /**\n * Executes the tool to retrieve a list of pipeline jobs.\n * @param input - The input parameters, optionally including a status filter.\n * @returns A promise that resolves with the list of simplified job objects.\n * @throws {PipelineStateError} If the pipeline manager is somehow unavailable.\n */\n async execute(input: ListJobsInput): Promise<ListJobsToolResponse> {\n const jobs = await this.manager.getJobs(input.status);\n\n // Transform jobs into simplified objects\n const simplifiedJobs: JobInfo[] = jobs.map(\n (job: PipelineJob): JobInfo => ({\n id: job.id,\n library: job.library,\n version: job.version,\n status: job.status,\n createdAt: job.createdAt.toISOString(),\n startedAt: job.startedAt?.toISOString() ?? null,\n finishedAt: job.finishedAt?.toISOString() ?? null,\n error: job.error?.message ?? null,\n }),\n );\n\n return { jobs: simplifiedJobs };\n }\n}\n","import type { DocumentManagementService } from \"../store\";\nimport { logger } from \"../utils/logger\";\nimport { ToolError } from \"./errors\";\n\n/**\n * Represents the arguments for the remove_docs tool.\n * The MCP server should validate the input against RemoveToolInputSchema before calling execute.\n */\nexport interface RemoveToolArgs {\n library: string;\n version?: string;\n}\n\n/**\n * Tool to remove indexed documentation for a specific library version.\n * This class provides the core logic, intended to be called by the McpServer.\n */\nexport class RemoveTool {\n constructor(private readonly documentManagementService: DocumentManagementService) {}\n\n /**\n * Executes the tool to remove the specified library version documents.\n * Assumes args have been validated by the caller (McpServer) against inputSchema.\n * Returns a simple success message or throws an error.\n */\n async execute(args: RemoveToolArgs): Promise<{ message: string }> {\n const { library, version } = args;\n\n logger.info(\n `Removing library: ${library}${version ? `, version: ${version}` : \" (unversioned)\"}`,\n );\n\n try {\n // Core logic: Call the document management service\n await this.documentManagementService.removeAllDocuments(library, version);\n\n const message = `Successfully removed documents for ${library}${version ? `@${version}` : \" (unversioned)\"}.`;\n logger.info(message);\n // Return a simple success object, the McpServer will format the final response\n return { message };\n } catch (error) {\n const errorMessage = `Failed to remove documents for ${library}${version ? `@${version}` : \" (unversioned)\"}: ${error instanceof Error ? error.message : String(error)}`;\n logger.error(`Error removing library: ${errorMessage}`);\n // Re-throw the error for the McpServer to handle and format\n throw new ToolError(errorMessage, this.constructor.name);\n }\n }\n}\n"],"names":[],"mappings":";AAuBO,MAAM,aAAa;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY,SAA0B;AAEpC,SAAK,UAAU;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjB,MAAM,QAAQ,OAAqD;AACjE,UAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,MAAM,MAAM;AAGpD,UAAM,iBAA4B,KAAK;AAAA,MACrC,CAAC,SAA+B;AAAA,QAC9B,IAAI,IAAI;AAAA,QACR,SAAS,IAAI;AAAA,QACb,SAAS,IAAI;AAAA,QACb,QAAQ,IAAI;AAAA,QACZ,WAAW,IAAI,UAAU,YAAY;AAAA,QACrC,WAAW,IAAI,WAAW,YAAiB,KAAA;AAAA,QAC3C,YAAY,IAAI,YAAY,YAAiB,KAAA;AAAA,QAC7C,OAAO,IAAI,OAAO,WAAW;AAAA,MAC/B;AAAA,IACF;AAEO,WAAA,EAAE,MAAM,eAAe;AAAA,EAAA;AAElC;AC3CO,MAAM,WAAW;AAAA,EACtB,YAA6B,2BAAsD;AAAtD,SAAA,4BAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7B,MAAM,QAAQ,MAAoD;AAC1D,UAAA,EAAE,SAAS,QAAA,IAAY;AAEtB,WAAA;AAAA,MACL,qBAAqB,OAAO,GAAG,UAAU,cAAc,OAAO,KAAK,gBAAgB;AAAA,IACrF;AAEI,QAAA;AAEF,YAAM,KAAK,0BAA0B,mBAAmB,SAAS,OAAO;AAElE,YAAA,UAAU,sCAAsC,OAAO,GAAG,UAAU,IAAI,OAAO,KAAK,gBAAgB;AAC1G,aAAO,KAAK,OAAO;AAEnB,aAAO,EAAE,QAAQ;AAAA,aACV,OAAO;AACd,YAAM,eAAe,kCAAkC,OAAO,GAAG,UAAU,IAAI,OAAO,KAAK,gBAAgB,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAC/J,aAAA,MAAM,2BAA2B,YAAY,EAAE;AAEtD,YAAM,IAAI,UAAU,cAAc,KAAK,YAAY,IAAI;AAAA,IAAA;AAAA,EACzD;AAEJ;"}
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "dotenv/config";
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import { D as DocumentManagementService, a as PipelineManager, H as HttpFetcher, F as FileFetcher, S as SearchTool, e as ScrapeTool, f as ListLibrariesTool, c as DEFAULT_MAX_PAGES, b as DEFAULT_MAX_DEPTH, i as DEFAULT_MAX_CONCURRENCY, j as ScrapeMode, s as setLogLevel, d as LogLevel } from "./DocumentManagementService-
|
|
4
|
+
import { D as DocumentManagementService, a as PipelineManager, H as HttpFetcher, F as FileFetcher, S as SearchTool, e as ScrapeTool, f as ListLibrariesTool, c as DEFAULT_MAX_PAGES, b as DEFAULT_MAX_DEPTH, i as DEFAULT_MAX_CONCURRENCY, j as ScrapeMode, s as setLogLevel, d as LogLevel } from "./DocumentManagementService-BGW9iWNn.js";
|
|
5
5
|
import "semver";
|
|
6
|
-
import { F as FetchUrlTool, a as FindVersionTool } from "./FindVersionTool-
|
|
6
|
+
import { F as FetchUrlTool, a as FindVersionTool } from "./FindVersionTool-DhhmoGU7.js";
|
|
7
7
|
const name = "@arabold/docs-mcp-server";
|
|
8
|
-
const version = "1.12.
|
|
8
|
+
const version = "1.12.4";
|
|
9
9
|
const description = "MCP server for fetching and searching documentation";
|
|
10
10
|
const type = "module";
|
|
11
11
|
const bin = { "docs-server": "dist/server.js", "docs-cli": "dist/cli.js", "docs-web": "dist/web.js" };
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "dotenv/config";
|
|
3
3
|
import { program } from "commander";
|
|
4
|
-
import { l as logger, P as PipelineJobStatus, D as DocumentManagementService, a as PipelineManager, b as DEFAULT_MAX_DEPTH, c as DEFAULT_MAX_PAGES, L as LibraryNotFoundError, V as VersionNotFoundError, s as setLogLevel, d as LogLevel, H as HttpFetcher, F as FileFetcher, S as SearchTool, e as ScrapeTool, f as ListLibrariesTool, g as DEFAULT_PROTOCOL, h as DEFAULT_HTTP_PORT } from "./DocumentManagementService-
|
|
4
|
+
import { l as logger, P as PipelineJobStatus, D as DocumentManagementService, a as PipelineManager, b as DEFAULT_MAX_DEPTH, c as DEFAULT_MAX_PAGES, L as LibraryNotFoundError, V as VersionNotFoundError, s as setLogLevel, d as LogLevel, H as HttpFetcher, F as FileFetcher, S as SearchTool, e as ScrapeTool, f as ListLibrariesTool, g as DEFAULT_PROTOCOL, h as DEFAULT_HTTP_PORT } from "./DocumentManagementService-BGW9iWNn.js";
|
|
5
5
|
import * as http from "node:http";
|
|
6
6
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
7
7
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -13,10 +13,11 @@ import "jsdom";
|
|
|
13
13
|
import "playwright";
|
|
14
14
|
import "@joplin/turndown-plugin-gfm";
|
|
15
15
|
import "turndown";
|
|
16
|
+
import "node:util";
|
|
16
17
|
import "semver";
|
|
17
18
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
-
import { F as FetchUrlTool, a as FindVersionTool } from "./FindVersionTool-
|
|
19
|
-
import { R as RemoveTool, L as ListJobsTool } from "./RemoveTool-
|
|
19
|
+
import { F as FetchUrlTool, a as FindVersionTool } from "./FindVersionTool-DhhmoGU7.js";
|
|
20
|
+
import { R as RemoveTool, L as ListJobsTool } from "./RemoveTool-BZPTXvhj.js";
|
|
20
21
|
class CancelJobTool {
|
|
21
22
|
manager;
|
|
22
23
|
/**
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sources":["../src/tools/CancelJobTool.ts","../src/tools/GetJobInfoTool.ts","../src/mcp/services.ts","../src/mcp/utils.ts","../src/mcp/mcpServer.ts","../src/mcp/startHttpServer.ts","../src/mcp/startStdioServer.ts","../src/mcp/tools.ts","../src/mcp/index.ts","../src/server.ts"],"sourcesContent":["import type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport { PipelineJobStatus } from \"../pipeline/types\";\nimport { logger } from \"../utils/logger\";\n\n/**\n * Input parameters for the CancelJobTool.\n */\nexport interface CancelJobInput {\n /** The ID of the job to cancel. */\n jobId: string;\n}\n\n/**\n * Output result for the CancelJobTool.\n */\nexport interface CancelJobResult {\n /** A message indicating the outcome of the cancellation attempt. */\n message: string;\n /** Indicates if the cancellation request was successfully initiated or if the job was already finished/cancelled. */\n success: boolean;\n}\n\n/**\n * Tool for attempting to cancel a pipeline job.\n */\nexport class CancelJobTool {\n private manager: PipelineManager;\n\n /**\n * Creates an instance of CancelJobTool.\n * @param manager The PipelineManager instance.\n */\n constructor(manager: PipelineManager) {\n this.manager = manager;\n }\n\n /**\n * Executes the tool to attempt cancellation of a specific job.\n * @param input - The input parameters, containing the jobId.\n * @returns A promise that resolves with the outcome message.\n */\n async execute(input: CancelJobInput): Promise<CancelJobResult> {\n try {\n // Retrieve the job first to check its status before attempting cancellation\n const job = await this.manager.getJob(input.jobId);\n\n if (!job) {\n logger.warn(`[CancelJobTool] Job not found: ${input.jobId}`);\n return {\n message: `Job with ID ${input.jobId} not found.`,\n success: false,\n };\n }\n\n // Check if the job is already in a final state\n if (\n job.status === PipelineJobStatus.COMPLETED || // Use enum member\n job.status === PipelineJobStatus.FAILED || // Use enum member\n job.status === PipelineJobStatus.CANCELLED // Use enum member\n ) {\n logger.info(\n `[CancelJobTool] Job ${input.jobId} is already in a final state: ${job.status}.`,\n );\n return {\n message: `Job ${input.jobId} is already ${job.status}. No action taken.`,\n success: true, // Considered success as no cancellation needed\n };\n }\n\n // Attempt cancellation\n await this.manager.cancelJob(input.jobId);\n\n // Re-fetch the job to confirm status change (or check status directly if cancelJob returned it)\n // PipelineManager.cancelJob doesn't return status, so re-fetch is needed for confirmation.\n const updatedJob = await this.manager.getJob(input.jobId);\n const finalStatus = updatedJob?.status ?? \"UNKNOWN (job disappeared?)\";\n\n logger.info(\n `[CancelJobTool] Cancellation requested for job ${input.jobId}. Current status: ${finalStatus}`,\n );\n return {\n message: `Cancellation requested for job ${input.jobId}. Current status: ${finalStatus}.`,\n success: true,\n };\n } catch (error) {\n logger.error(`[CancelJobTool] Error cancelling job ${input.jobId}: ${error}`);\n return {\n message: `Failed to cancel job ${input.jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n success: false,\n };\n }\n }\n}\n","import type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport type { PipelineJob, PipelineJobStatus } from \"../pipeline/types\";\n\n/**\n * Input parameters for the GetJobInfoTool.\n */\nexport interface GetJobInfoInput {\n /** The ID of the job to retrieve info for. */\n jobId: string;\n}\n\n/**\n * Simplified information about a pipeline job for external use.\n */\nexport interface JobInfo {\n id: string;\n library: string;\n version: string;\n status: PipelineJobStatus;\n createdAt: string;\n startedAt: string | null;\n finishedAt: string | null;\n error: string | null;\n}\n\n/**\n * Response structure for the GetJobInfoTool.\n */\nexport interface GetJobInfoToolResponse {\n job: JobInfo | null;\n}\n\n/**\n * Tool for retrieving simplified information about a specific pipeline job.\n */\nexport class GetJobInfoTool {\n private manager: PipelineManager;\n\n /**\n * Creates an instance of GetJobInfoTool.\n * @param manager The PipelineManager instance.\n */\n constructor(manager: PipelineManager) {\n this.manager = manager;\n }\n\n /**\n * Executes the tool to retrieve simplified info for a specific job.\n * @param input - The input parameters, containing the jobId.\n * @returns A promise that resolves with the simplified job info or null if not found.\n */\n async execute(input: GetJobInfoInput): Promise<GetJobInfoToolResponse> {\n const job = await this.manager.getJob(input.jobId);\n\n if (!job) {\n // Return null in the result if job not found\n return { job: null };\n }\n\n // Transform the job into a simplified object\n const jobInfo: JobInfo = {\n id: job.id,\n library: job.library,\n version: job.version,\n status: job.status,\n createdAt: job.createdAt.toISOString(),\n startedAt: job.startedAt?.toISOString() ?? null,\n finishedAt: job.finishedAt?.toISOString() ?? null,\n error: job.error?.message ?? null,\n };\n\n return { job: jobInfo };\n }\n}\n","import { PipelineManager } from \"../pipeline/PipelineManager\";\nimport { DocumentManagementService } from \"../store/DocumentManagementService\";\nimport { logger } from \"../utils/logger\";\n\nlet docService: DocumentManagementService | undefined;\nlet pipelineManager: PipelineManager | undefined;\n\n/**\n * Initializes the shared services (DocumentManagementService and PipelineManager).\n * This should be called once at the server startup.\n */\nexport async function initializeServices(): Promise<void> {\n if (docService || pipelineManager) {\n logger.warn(\"Services already initialized.\");\n return;\n }\n\n docService = new DocumentManagementService();\n try {\n await docService.initialize();\n logger.debug(\"DocumentManagementService initialized.\");\n\n // TODO: Check if concurrency needs to be configurable\n pipelineManager = new PipelineManager(docService);\n await pipelineManager.start();\n logger.debug(\"PipelineManager initialized and started.\");\n } catch (error) {\n logger.error(`Failed to initialize services: ${error}`);\n // Attempt to shut down any services that might have been partially initialized\n await shutdownServices();\n throw error; // Re-throw the error to indicate initialization failure\n }\n}\n\n/**\n * Shuts down the shared services.\n * This should be called during server cleanup.\n */\nexport async function shutdownServices(): Promise<void> {\n if (pipelineManager) {\n await pipelineManager.stop();\n logger.info(\"PipelineManager stopped.\");\n pipelineManager = undefined;\n }\n if (docService) {\n await docService.shutdown();\n logger.info(\"DocumentManagementService shutdown.\");\n docService = undefined;\n }\n}\n\n/**\n * Gets the initialized DocumentManagementService instance.\n * @returns The DocumentManagementService instance.\n * @throws Error if services have not been initialized.\n */\nexport function getDocService(): DocumentManagementService {\n if (!docService) {\n throw new Error(\"DocumentManagementService has not been initialized.\");\n }\n return docService;\n}\n\n/**\n * Gets the initialized PipelineManager instance.\n * @returns The PipelineManager instance.\n * @throws Error if services have not been initialized.\n */\nexport function getPipelineManager(): PipelineManager {\n if (!pipelineManager) {\n throw new Error(\"PipelineManager has not been initialized.\");\n }\n return pipelineManager;\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * Creates a success response object in the format expected by the MCP server.\n * @param text The text content of the response.\n * @returns The response object.\n */\nexport function createResponse(text: string): CallToolResult {\n return {\n content: [\n {\n type: \"text\",\n text,\n },\n ],\n isError: false,\n };\n}\n\n/**\n * Creates an error response object in the format expected by the MCP server.\n * @param text The error message.\n * @returns The response object.\n */\nexport function createError(text: string): CallToolResult {\n return {\n content: [\n {\n type: \"text\",\n text,\n },\n ],\n isError: true,\n };\n}\n","import { McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { PipelineJobStatus } from \"../pipeline/types\";\nimport { type JobInfo, LibraryNotFoundError, VersionNotFoundError } from \"../tools\";\nimport { DEFAULT_MAX_DEPTH, DEFAULT_MAX_PAGES } from \"../utils/config\";\nimport { logger } from \"../utils/logger\";\nimport type { McpServerTools } from \"./tools\";\nimport { createError, createResponse } from \"./utils\";\n\n/**\n * Creates and configures an instance of the MCP server with registered tools, prompts, and resources.\n * @param tools The shared tool instances to use for server operations.\n * @returns A configured McpServer instance.\n */\nexport function createMcpServerInstance(tools: McpServerTools): McpServer {\n const server = new McpServer(\n {\n name: \"docs-mcp-server\",\n version: \"0.1.0\",\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n resources: {},\n },\n },\n );\n\n // --- Tool Definitions ---\n\n // Scrape docs tool\n server.tool(\n \"scrape_docs\",\n \"Scrape and index documentation from a URL\",\n {\n url: z.string().url().describe(\"URL of the documentation to scrape\"),\n library: z.string().describe(\"Name of the library\"),\n version: z.string().optional().describe(\"Version of the library\"),\n maxPages: z\n .number()\n .optional()\n .default(DEFAULT_MAX_PAGES)\n .describe(`Maximum number of pages to scrape (default: ${DEFAULT_MAX_PAGES})`),\n maxDepth: z\n .number()\n .optional()\n .default(DEFAULT_MAX_DEPTH)\n .describe(`Maximum navigation depth (default: ${DEFAULT_MAX_DEPTH})`),\n scope: z\n .enum([\"subpages\", \"hostname\", \"domain\"])\n .optional()\n .default(\"subpages\")\n .describe(\"Defines the crawling boundary: 'subpages', 'hostname', or 'domain'\"),\n followRedirects: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"Whether to follow HTTP redirects (3xx responses)\"),\n },\n async ({ url, library, version, maxPages, maxDepth, scope, followRedirects }) => {\n try {\n // Execute scrape tool without waiting and without progress callback\n const result = await tools.scrape.execute({\n url,\n library,\n version,\n waitForCompletion: false, // Don't wait for completion\n // onProgress: undefined, // Explicitly undefined or omitted\n options: {\n maxPages,\n maxDepth,\n scope,\n followRedirects,\n },\n });\n\n // Check the type of result\n if (\"jobId\" in result) {\n // If we got a jobId back, report that\n return createResponse(`🚀 Scraping job started with ID: ${result.jobId}.`);\n }\n // This case shouldn't happen if waitForCompletion is false, but handle defensively\n return createResponse(\n `Scraping finished immediately (unexpectedly) with ${result.pagesScraped} pages.`,\n );\n } catch (error) {\n // Handle errors during job *enqueueing* or initial setup\n return createError(\n `Failed to scrape documentation: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Search docs tool\n server.tool(\n \"search_docs\",\n \"Searches up-to-date documentation for a library. Examples:\\n\\n\" +\n '- {library: \"react\", query: \"hooks lifecycle\"} -> matches latest version of React\\n' +\n '- {library: \"react\", version: \"18.0.0\", query: \"hooks lifecycle\"} -> matches React 18.0.0 or earlier\\n' +\n '- {library: \"typescript\", version: \"5.x\", query: \"ReturnType example\"} -> any TypeScript 5.x.x version\\n' +\n '- {library: \"typescript\", version: \"5.2.x\", query: \"ReturnType example\"} -> any TypeScript 5.2.x version',\n {\n library: z.string().describe(\"Name of the library\"),\n version: z\n .string()\n .optional()\n .describe(\n \"Version of the library (supports exact versions like '18.0.0' or X-Range patterns like '5.x', '5.2.x')\",\n ),\n query: z.string().describe(\"Search query\"),\n limit: z.number().optional().default(5).describe(\"Maximum number of results\"),\n },\n async ({ library, version, query, limit }) => {\n try {\n const result = await tools.search.execute({\n library,\n version,\n query,\n limit,\n exactMatch: false, // Always false for MCP interface\n });\n\n const formattedResults = result.results.map(\n (r: { url: string; content: string }, i: number) => `\n------------------------------------------------------------\nResult ${i + 1}: ${r.url}\n\n${r.content}\\n`,\n );\n\n if (formattedResults.length === 0) {\n return createResponse(\n `No results found for '${query}' in ${library}. Try to use a different or more general query.`,\n );\n }\n return createResponse(\n `Search results for '${query}' in ${library}:\n${formattedResults.join(\"\")}`,\n );\n } catch (error) {\n if (error instanceof LibraryNotFoundError) {\n return createResponse(\n [\n `Library \"${library}\" not found.`,\n error.suggestions?.length\n ? `Did you mean: ${error.suggestions?.join(\", \")}?`\n : undefined,\n ].join(\" \"),\n );\n }\n if (error instanceof VersionNotFoundError) {\n const indexedVersions = error.availableVersions.map((v) => v.version);\n return createResponse(\n [\n `Version \"${version}\" not found.`,\n indexedVersions.length > 0\n ? `Available indexed versions for ${library}: ${indexedVersions.join(\", \")}`\n : undefined,\n ].join(\" \"),\n );\n }\n return createError(\n `Failed to search documentation: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // List libraries tool\n server.tool(\"list_libraries\", \"List all indexed libraries\", {}, async () => {\n try {\n const result = await tools.listLibraries.execute();\n if (result.libraries.length === 0) {\n return createResponse(\"No libraries indexed yet.\");\n }\n\n return createResponse(\n `Indexed libraries:\\n\\n${result.libraries.map((lib: { name: string }) => `- ${lib.name}`).join(\"\\n\")}`,\n );\n } catch (error) {\n return createError(\n `Failed to list libraries: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n });\n\n // Find version tool\n server.tool(\n \"find_version\",\n \"Find best matching version for a library\",\n {\n library: z.string().describe(\"Name of the library\"),\n targetVersion: z\n .string()\n .optional()\n .describe(\n \"Pattern to match (supports exact versions like '18.0.0' or X-Range patterns like '5.x', '5.2.x')\",\n ),\n },\n async ({ library, targetVersion }) => {\n try {\n const message = await tools.findVersion.execute({\n library,\n targetVersion,\n });\n\n if (!message) {\n return createError(\"No matching version found\");\n }\n\n return createResponse(message);\n } catch (error) {\n return createError(\n `Failed to find version: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // List jobs tool\n server.tool(\n \"list_jobs\",\n \"List pipeline jobs, optionally filtering by status.\",\n {\n status: z\n .nativeEnum(PipelineJobStatus)\n .optional()\n .describe(\"Optional status to filter jobs by.\"),\n },\n async ({ status }) => {\n try {\n const result = await tools.listJobs.execute({ status });\n // Format the simplified job list for display\n const formattedJobs = result.jobs\n .map(\n (job: JobInfo) =>\n `- ID: ${job.id}\\n Status: ${job.status}\\n Library: ${job.library}\\n Version: ${job.version}\\n Created: ${job.createdAt}${job.startedAt ? `\\n Started: ${job.startedAt}` : \"\"}${job.finishedAt ? `\\n Finished: ${job.finishedAt}` : \"\"}${job.error ? `\\n Error: ${job.error}` : \"\"}`,\n )\n .join(\"\\n\\n\");\n return createResponse(\n result.jobs.length > 0 ? `Current Jobs:\\n\\n${formattedJobs}` : \"No jobs found.\",\n );\n } catch (error) {\n return createError(\n `Failed to list jobs: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Get job info tool\n server.tool(\n \"get_job_info\",\n \"Get the simplified info for a specific pipeline job.\",\n {\n jobId: z.string().uuid().describe(\"The ID of the job to query.\"),\n },\n async ({ jobId }) => {\n try {\n const result = await tools.getJobInfo.execute({ jobId });\n if (!result.job) {\n return createError(`Job with ID ${jobId} not found.`);\n }\n const job = result.job;\n const formattedJob = `- ID: ${job.id}\\n Status: ${job.status}\\n Library: ${job.library}@${job.version}\\n Created: ${job.createdAt}${job.startedAt ? `\\n Started: ${job.startedAt}` : \"\"}${job.finishedAt ? `\\n Finished: ${job.finishedAt}` : \"\"}${job.error ? `\\n Error: ${job.error}` : \"\"}`;\n return createResponse(`Job Info:\\n\\n${formattedJob}`);\n } catch (error) {\n return createError(\n `Failed to get job info for ${jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Fetch URL tool\n server.tool(\n \"fetch_url\",\n \"Fetch a single URL and convert its content to Markdown\",\n {\n url: z.string().url().describe(\"The URL to fetch and convert to markdown\"),\n followRedirects: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"Whether to follow HTTP redirects (3xx responses)\"),\n },\n async ({ url, followRedirects }) => {\n try {\n const result = await tools.fetchUrl.execute({ url, followRedirects });\n return createResponse(result);\n } catch (error) {\n return createError(\n `Failed to fetch URL: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // Cancel job tool\n server.tool(\n \"cancel_job\",\n \"Attempt to cancel a queued or running pipeline job.\",\n {\n jobId: z.string().uuid().describe(\"The ID of the job to cancel.\"),\n },\n async ({ jobId }) => {\n try {\n const result = await tools.cancelJob.execute({ jobId });\n // Use the message and success status from the tool's result\n if (result.success) {\n return createResponse(result.message);\n }\n // If not successful according to the tool, treat it as an error in MCP\n return createError(result.message);\n } catch (error) {\n // Catch any unexpected errors during the tool execution itself\n return createError(\n `Failed to cancel job ${jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Remove docs tool\n server.tool(\n \"remove_docs\",\n \"Remove indexed documentation for a library version.\",\n {\n library: z.string().describe(\"Name of the library\"),\n version: z\n .string()\n .optional()\n .describe(\"Version of the library (optional, removes unversioned if omitted)\"),\n },\n async ({ library, version }) => {\n try {\n // Execute the remove tool logic\n const result = await tools.remove.execute({ library, version });\n // Use the message from the tool's successful execution\n return createResponse(result.message);\n } catch (error) {\n // Catch errors thrown by the RemoveTool's execute method\n return createError(\n `Failed to remove documents: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n server.prompt(\n \"docs\",\n \"Search indexed documentation\",\n {\n library: z.string().describe(\"Name of the library\"),\n version: z.string().optional().describe(\"Version of the library\"),\n query: z.string().describe(\"Search query\"),\n },\n async ({ library, version, query }) => {\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Please search ${library} ${version || \"\"} documentation for this query: ${query}`,\n },\n },\n ],\n };\n },\n );\n\n server.resource(\n \"libraries\",\n \"docs://libraries\",\n {\n description: \"List all indexed libraries\",\n },\n async (uri: URL) => {\n const result = await tools.listLibraries.execute();\n\n return {\n contents: result.libraries.map((lib: { name: string }) => ({\n uri: new URL(lib.name, uri).href,\n text: lib.name,\n })),\n };\n },\n );\n\n server.resource(\n \"versions\",\n new ResourceTemplate(\"docs://libraries/{library}/versions\", {\n list: undefined,\n }),\n {\n description: \"List all indexed versions for a library\",\n },\n async (uri: URL, { library }) => {\n const result = await tools.listLibraries.execute();\n\n const lib = result.libraries.find((l: { name: string }) => l.name === library);\n if (!lib) {\n return { contents: [] };\n }\n\n return {\n contents: lib.versions.map((v: { version: string }) => ({\n uri: new URL(v.version, uri).href,\n text: v.version,\n })),\n };\n },\n );\n\n /**\n * Resource handler for listing pipeline jobs.\n * Supports filtering by status via a query parameter (e.g., ?status=running).\n * URI: docs://jobs[?status=<status>]\n */\n server.resource(\n \"jobs\",\n \"docs://jobs\",\n {\n description: \"List pipeline jobs, optionally filtering by status.\",\n mimeType: \"application/json\",\n },\n async (uri: URL) => {\n const statusParam = uri.searchParams.get(\"status\");\n let statusFilter: PipelineJobStatus | undefined;\n\n // Validate status parameter if provided\n if (statusParam) {\n const validation = z.nativeEnum(PipelineJobStatus).safeParse(statusParam);\n if (validation.success) {\n statusFilter = validation.data;\n } else {\n // Handle invalid status - perhaps return an error or ignore?\n // For simplicity, let's ignore invalid status for now and return all jobs.\n // Alternatively, could throw an McpError or return specific error content.\n logger.warn(`Invalid status parameter received: ${statusParam}`);\n }\n }\n\n // Fetch simplified jobs using the ListJobsTool\n const result = await tools.listJobs.execute({ status: statusFilter });\n\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(result.jobs, null, 2), // Stringify the simplified jobs array\n },\n ],\n };\n },\n );\n\n /**\n * Resource handler for retrieving a specific pipeline job by its ID.\n * URI Template: docs://jobs/{jobId}\n */\n server.resource(\n \"job\", // A distinct name for this specific resource type\n new ResourceTemplate(\"docs://jobs/{jobId}\", { list: undefined }),\n {\n description: \"Get details for a specific pipeline job by ID.\",\n mimeType: \"application/json\",\n },\n async (uri: URL, { jobId }) => {\n // Validate jobId format if necessary (basic check)\n if (typeof jobId !== \"string\" || jobId.length === 0) {\n // Handle invalid jobId format - return empty or error\n logger.warn(`Invalid jobId received in URI: ${jobId}`);\n return { contents: [] }; // Return empty content for invalid ID format\n }\n\n // Fetch the simplified job info using GetJobInfoTool\n const result = await tools.getJobInfo.execute({ jobId });\n\n // result.job is either the simplified job object or null\n if (!result.job) {\n // Job not found, return empty content\n return { contents: [] };\n }\n\n // Job found, return its simplified details as JSON\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(result.job, null, 2), // Stringify the simplified job object\n },\n ],\n };\n },\n );\n\n return server;\n}\n","import * as http from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { createMcpServerInstance } from \"./mcpServer\";\nimport type { McpServerTools } from \"./tools\";\n\n/**\n * Starts the MCP server using the Streamable HTTP and SSE transports.\n * @param tools The shared tool instances.\n * @param port The port to listen on.\n * @returns The created McpServer instance.\n */\nexport async function startHttpServer(\n tools: McpServerTools,\n port: number,\n): Promise<McpServer> {\n setLogLevel(LogLevel.INFO);\n\n const server = createMcpServerInstance(tools);\n const sseTransports: Record<string, SSEServerTransport> = {};\n\n const httpServer = http.createServer(async (req, res) => {\n try {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n\n if (req.method === \"GET\" && url.pathname === \"/sse\") {\n // Handle SSE connection\n const transport = new SSEServerTransport(\"/messages\", res);\n sseTransports[transport.sessionId] = transport;\n\n res.on(\"close\", () => {\n delete sseTransports[transport.sessionId];\n transport.close();\n });\n\n await server.connect(transport);\n } else if (req.method === \"POST\" && url.pathname === \"/messages\") {\n // Handle SSE messages\n const sessionId = url.searchParams.get(\"sessionId\");\n const transport = sessionId ? sseTransports[sessionId] : undefined;\n\n if (transport) {\n let body = \"\";\n for await (const chunk of req) {\n body += chunk;\n }\n const parsedBody = JSON.parse(body);\n await transport.handlePostMessage(req, res, parsedBody);\n } else {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"No transport found for sessionId\" }));\n }\n } else if (url.pathname === \"/mcp\") {\n // Handle Streamable HTTP (stateless)\n let body = \"\";\n for await (const chunk of req) {\n body += chunk;\n }\n const parsedBody = JSON.parse(body);\n\n // In stateless mode, create a new instance of server and transport for each request\n const requestServer = createMcpServerInstance(tools);\n const requestTransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n });\n\n res.on(\"close\", () => {\n logger.info(\"Streamable HTTP request closed\");\n requestTransport.close();\n requestServer.close(); // Close the per-request server instance\n });\n\n await requestServer.connect(requestTransport);\n await requestTransport.handleRequest(req, res, parsedBody);\n } else {\n // Handle 404 Not Found\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Endpoint ${url.pathname} not found.`,\n }),\n );\n }\n } catch (error) {\n logger.error(`Error handling HTTP request: ${error}`);\n // Send an error response\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n });\n\n httpServer.listen(port, () => {\n logger.info(`🤖 Docs MCP server listening at http://127.0.0.1:${port}`);\n });\n\n // Return the server instance\n return server;\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { createMcpServerInstance } from \"./mcpServer\";\nimport type { McpServerTools } from \"./tools\";\n\n/**\n * Starts the MCP server using the Stdio transport.\n * @param tools The shared tool instances.\n * @returns The created McpServer instance.\n */\nexport async function startStdioServer(tools: McpServerTools): Promise<McpServer> {\n setLogLevel(LogLevel.ERROR);\n\n // Create a server instance using the factory and shared tools\n const server = createMcpServerInstance(tools);\n\n // Start server with Stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n logger.info(\"🤖 Docs MCP server listening on stdio\");\n\n // Return the server instance\n return server;\n}\n","import { FileFetcher, HttpFetcher } from \"../scraper/fetcher\";\nimport {\n CancelJobTool,\n FetchUrlTool,\n FindVersionTool,\n GetJobInfoTool,\n ListJobsTool,\n ListLibrariesTool,\n RemoveTool,\n ScrapeTool,\n SearchTool,\n} from \"../tools\";\nimport { getDocService, getPipelineManager } from \"./services\";\n\n/**\n * Interface for the shared tool instances.\n */\nexport interface McpServerTools {\n listLibraries: ListLibrariesTool;\n findVersion: FindVersionTool;\n scrape: ScrapeTool;\n search: SearchTool;\n listJobs: ListJobsTool;\n getJobInfo: GetJobInfoTool;\n cancelJob: CancelJobTool;\n remove: RemoveTool;\n fetchUrl: FetchUrlTool;\n}\n\n/**\n * Initializes and returns the shared tool instances.\n * This should be called after initializeServices has completed.\n * @returns An object containing all instantiated tool instances.\n */\nexport async function initializeTools(): Promise<McpServerTools> {\n const docService = getDocService();\n const pipelineManager = getPipelineManager();\n\n const tools: McpServerTools = {\n listLibraries: new ListLibrariesTool(docService),\n findVersion: new FindVersionTool(docService),\n scrape: new ScrapeTool(docService, pipelineManager),\n search: new SearchTool(docService),\n listJobs: new ListJobsTool(pipelineManager),\n getJobInfo: new GetJobInfoTool(pipelineManager),\n cancelJob: new CancelJobTool(pipelineManager),\n remove: new RemoveTool(docService),\n // FetchUrlTool now uses middleware pipeline internally\n fetchUrl: new FetchUrlTool(new HttpFetcher(), new FileFetcher()),\n };\n\n return tools;\n}\n","import \"dotenv/config\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport type { DocumentManagementService } from \"../store/DocumentManagementService\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { getDocService, getPipelineManager, initializeServices } from \"./services\"; // Import get functions\nimport { startHttpServer } from \"./startHttpServer\";\nimport { startStdioServer } from \"./startStdioServer\";\nimport { type McpServerTools, initializeTools } from \"./tools\";\n\n// Variables to hold server instances for cleanup\nlet runningServer: McpServer | null = null;\nlet runningPipelineManager: PipelineManager | null = null;\nlet runningDocService: DocumentManagementService | null = null;\n\nexport async function startServer(protocol: \"stdio\" | \"http\", port?: number) {\n try {\n // Set the default log level for the server to ERROR\n setLogLevel(LogLevel.ERROR);\n\n // Initialize shared services\n await initializeServices();\n runningDocService = getDocService(); // Get instance after initialization\n runningPipelineManager = getPipelineManager(); // Get instance after initialization\n\n // Initialize and get shared tools\n const tools: McpServerTools = await initializeTools(); // initializeTools now gets services internally\n\n let serverInstance: McpServer;\n if (protocol === \"stdio\") {\n serverInstance = await startStdioServer(tools); // startStdioServer needs to return McpServer\n } else if (protocol === \"http\") {\n if (port === undefined) {\n logger.error(\"HTTP protocol requires a port.\");\n process.exit(1);\n }\n serverInstance = await startHttpServer(tools, port); // startHttpServer needs to return McpServer\n } else {\n // This case should be caught by src/server.ts, but handle defensively\n logger.error(`Unknown protocol: ${protocol}`);\n process.exit(1);\n }\n\n // Capture the running server instance\n runningServer = serverInstance;\n\n // Handle graceful shutdown on SIGINT\n process.on(\"SIGINT\", async () => {\n logger.info(\"Received SIGINT. Shutting down gracefully...\");\n await stopServer();\n process.exit(0);\n });\n } catch (error) {\n logger.error(`❌ Fatal Error during server startup: ${error}`);\n // Attempt cleanup even if startup failed partially\n await stopServer();\n process.exit(1);\n }\n}\n\n/**\n * Stops the MCP server and related services gracefully.\n */\nexport async function stopServer() {\n logger.info(\"Shutting down MCP server and services...\");\n let hadError = false;\n try {\n if (runningPipelineManager) {\n logger.debug(\"Stopping Pipeline Manager...\");\n await runningPipelineManager.stop();\n logger.info(\"Pipeline Manager stopped.\");\n }\n } catch (e) {\n logger.error(`Error stopping Pipeline Manager: ${e}`);\n hadError = true;\n }\n try {\n if (runningDocService) {\n logger.debug(\"Shutting down Document Service...\");\n await runningDocService.shutdown();\n logger.info(\"Document Service shut down.\");\n }\n } catch (e) {\n logger.error(`Error shutting down Document Service: ${e}`);\n hadError = true;\n }\n try {\n if (runningServer) {\n logger.debug(\"Closing MCP Server connection...\");\n await runningServer.close();\n logger.info(\"MCP Server connection closed.\");\n }\n } catch (e) {\n logger.error(`Error closing MCP Server: ${e}`);\n hadError = true;\n }\n\n // Clear references\n runningPipelineManager = null;\n runningDocService = null;\n runningServer = null;\n\n if (hadError) {\n logger.warn(\"Server shutdown completed with errors.\");\n } else {\n logger.info(\"✅ Server shutdown complete.\");\n }\n}\n","#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { program } from \"commander\";\nimport { startServer, stopServer } from \"./mcp/index.js\";\nimport { DEFAULT_HTTP_PORT, DEFAULT_PROTOCOL } from \"./utils/config.js\";\nimport { logger } from \"./utils/logger\"; // Import logger for HMR hook\n\nprogram\n .option(\"--protocol <type>\", \"Protocol to use (stdio or http)\", DEFAULT_PROTOCOL)\n .option(\n \"--port <number>\",\n \"Port to listen on for http protocol\",\n `${DEFAULT_HTTP_PORT}`,\n )\n .parse(process.argv);\n\nconst options = program.opts();\n\nasync function main() {\n const protocol = options.protocol;\n // Prioritize environment variable, then CLI arg, then default\n const port = process.env.MCP_PORT\n ? Number.parseInt(process.env.MCP_PORT, 10)\n : Number.parseInt(options.port, 10);\n\n if (protocol !== \"stdio\" && protocol !== \"http\") {\n console.error('Invalid protocol specified. Use \"stdio\" or \"http\".');\n process.exit(1);\n }\n\n if (protocol === \"http\" && Number.isNaN(port)) {\n console.error(\"Port must be a number when using http protocol.\");\n process.exit(1);\n }\n\n try {\n await startServer(protocol, protocol === \"http\" ? port : undefined);\n } catch (error) {\n console.error(`Server failed to start: ${error}`);\n process.exit(1);\n }\n}\n\n// Handle HMR using Vite's API\nif (import.meta.hot) {\n import.meta.hot.on(\"vite:beforeFullReload\", async () => {\n logger.info(\"🔥 Hot reload detected. Shutting down existing MCP server...\");\n try {\n await stopServer();\n logger.info(\"✅ MCP server shut down for hot reload.\");\n } catch (error) {\n logger.error(`❌ Error stopping MCP server during HMR: ${error}`);\n // Decide if we should exit or try to continue\n }\n });\n}\n\n// Start the application\nmain();\n"],"names":["docService","pipelineManager"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../src/tools/CancelJobTool.ts","../src/tools/GetJobInfoTool.ts","../src/mcp/services.ts","../src/mcp/utils.ts","../src/mcp/mcpServer.ts","../src/mcp/startHttpServer.ts","../src/mcp/startStdioServer.ts","../src/mcp/tools.ts","../src/mcp/index.ts","../src/server.ts"],"sourcesContent":["import type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport { PipelineJobStatus } from \"../pipeline/types\";\nimport { logger } from \"../utils/logger\";\n\n/**\n * Input parameters for the CancelJobTool.\n */\nexport interface CancelJobInput {\n /** The ID of the job to cancel. */\n jobId: string;\n}\n\n/**\n * Output result for the CancelJobTool.\n */\nexport interface CancelJobResult {\n /** A message indicating the outcome of the cancellation attempt. */\n message: string;\n /** Indicates if the cancellation request was successfully initiated or if the job was already finished/cancelled. */\n success: boolean;\n}\n\n/**\n * Tool for attempting to cancel a pipeline job.\n */\nexport class CancelJobTool {\n private manager: PipelineManager;\n\n /**\n * Creates an instance of CancelJobTool.\n * @param manager The PipelineManager instance.\n */\n constructor(manager: PipelineManager) {\n this.manager = manager;\n }\n\n /**\n * Executes the tool to attempt cancellation of a specific job.\n * @param input - The input parameters, containing the jobId.\n * @returns A promise that resolves with the outcome message.\n */\n async execute(input: CancelJobInput): Promise<CancelJobResult> {\n try {\n // Retrieve the job first to check its status before attempting cancellation\n const job = await this.manager.getJob(input.jobId);\n\n if (!job) {\n logger.warn(`[CancelJobTool] Job not found: ${input.jobId}`);\n return {\n message: `Job with ID ${input.jobId} not found.`,\n success: false,\n };\n }\n\n // Check if the job is already in a final state\n if (\n job.status === PipelineJobStatus.COMPLETED || // Use enum member\n job.status === PipelineJobStatus.FAILED || // Use enum member\n job.status === PipelineJobStatus.CANCELLED // Use enum member\n ) {\n logger.info(\n `[CancelJobTool] Job ${input.jobId} is already in a final state: ${job.status}.`,\n );\n return {\n message: `Job ${input.jobId} is already ${job.status}. No action taken.`,\n success: true, // Considered success as no cancellation needed\n };\n }\n\n // Attempt cancellation\n await this.manager.cancelJob(input.jobId);\n\n // Re-fetch the job to confirm status change (or check status directly if cancelJob returned it)\n // PipelineManager.cancelJob doesn't return status, so re-fetch is needed for confirmation.\n const updatedJob = await this.manager.getJob(input.jobId);\n const finalStatus = updatedJob?.status ?? \"UNKNOWN (job disappeared?)\";\n\n logger.info(\n `[CancelJobTool] Cancellation requested for job ${input.jobId}. Current status: ${finalStatus}`,\n );\n return {\n message: `Cancellation requested for job ${input.jobId}. Current status: ${finalStatus}.`,\n success: true,\n };\n } catch (error) {\n logger.error(`[CancelJobTool] Error cancelling job ${input.jobId}: ${error}`);\n return {\n message: `Failed to cancel job ${input.jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n success: false,\n };\n }\n }\n}\n","import type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport type { PipelineJob, PipelineJobStatus } from \"../pipeline/types\";\n\n/**\n * Input parameters for the GetJobInfoTool.\n */\nexport interface GetJobInfoInput {\n /** The ID of the job to retrieve info for. */\n jobId: string;\n}\n\n/**\n * Simplified information about a pipeline job for external use.\n */\nexport interface JobInfo {\n id: string;\n library: string;\n version: string;\n status: PipelineJobStatus;\n createdAt: string;\n startedAt: string | null;\n finishedAt: string | null;\n error: string | null;\n}\n\n/**\n * Response structure for the GetJobInfoTool.\n */\nexport interface GetJobInfoToolResponse {\n job: JobInfo | null;\n}\n\n/**\n * Tool for retrieving simplified information about a specific pipeline job.\n */\nexport class GetJobInfoTool {\n private manager: PipelineManager;\n\n /**\n * Creates an instance of GetJobInfoTool.\n * @param manager The PipelineManager instance.\n */\n constructor(manager: PipelineManager) {\n this.manager = manager;\n }\n\n /**\n * Executes the tool to retrieve simplified info for a specific job.\n * @param input - The input parameters, containing the jobId.\n * @returns A promise that resolves with the simplified job info or null if not found.\n */\n async execute(input: GetJobInfoInput): Promise<GetJobInfoToolResponse> {\n const job = await this.manager.getJob(input.jobId);\n\n if (!job) {\n // Return null in the result if job not found\n return { job: null };\n }\n\n // Transform the job into a simplified object\n const jobInfo: JobInfo = {\n id: job.id,\n library: job.library,\n version: job.version,\n status: job.status,\n createdAt: job.createdAt.toISOString(),\n startedAt: job.startedAt?.toISOString() ?? null,\n finishedAt: job.finishedAt?.toISOString() ?? null,\n error: job.error?.message ?? null,\n };\n\n return { job: jobInfo };\n }\n}\n","import { PipelineManager } from \"../pipeline/PipelineManager\";\nimport { DocumentManagementService } from \"../store/DocumentManagementService\";\nimport { logger } from \"../utils/logger\";\n\nlet docService: DocumentManagementService | undefined;\nlet pipelineManager: PipelineManager | undefined;\n\n/**\n * Initializes the shared services (DocumentManagementService and PipelineManager).\n * This should be called once at the server startup.\n */\nexport async function initializeServices(): Promise<void> {\n if (docService || pipelineManager) {\n logger.warn(\"Services already initialized.\");\n return;\n }\n\n docService = new DocumentManagementService();\n try {\n await docService.initialize();\n logger.debug(\"DocumentManagementService initialized.\");\n\n // TODO: Check if concurrency needs to be configurable\n pipelineManager = new PipelineManager(docService);\n await pipelineManager.start();\n logger.debug(\"PipelineManager initialized and started.\");\n } catch (error) {\n logger.error(`Failed to initialize services: ${error}`);\n // Attempt to shut down any services that might have been partially initialized\n await shutdownServices();\n throw error; // Re-throw the error to indicate initialization failure\n }\n}\n\n/**\n * Shuts down the shared services.\n * This should be called during server cleanup.\n */\nexport async function shutdownServices(): Promise<void> {\n if (pipelineManager) {\n await pipelineManager.stop();\n logger.info(\"PipelineManager stopped.\");\n pipelineManager = undefined;\n }\n if (docService) {\n await docService.shutdown();\n logger.info(\"DocumentManagementService shutdown.\");\n docService = undefined;\n }\n}\n\n/**\n * Gets the initialized DocumentManagementService instance.\n * @returns The DocumentManagementService instance.\n * @throws Error if services have not been initialized.\n */\nexport function getDocService(): DocumentManagementService {\n if (!docService) {\n throw new Error(\"DocumentManagementService has not been initialized.\");\n }\n return docService;\n}\n\n/**\n * Gets the initialized PipelineManager instance.\n * @returns The PipelineManager instance.\n * @throws Error if services have not been initialized.\n */\nexport function getPipelineManager(): PipelineManager {\n if (!pipelineManager) {\n throw new Error(\"PipelineManager has not been initialized.\");\n }\n return pipelineManager;\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * Creates a success response object in the format expected by the MCP server.\n * @param text The text content of the response.\n * @returns The response object.\n */\nexport function createResponse(text: string): CallToolResult {\n return {\n content: [\n {\n type: \"text\",\n text,\n },\n ],\n isError: false,\n };\n}\n\n/**\n * Creates an error response object in the format expected by the MCP server.\n * @param text The error message.\n * @returns The response object.\n */\nexport function createError(text: string): CallToolResult {\n return {\n content: [\n {\n type: \"text\",\n text,\n },\n ],\n isError: true,\n };\n}\n","import { McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { PipelineJobStatus } from \"../pipeline/types\";\nimport { type JobInfo, LibraryNotFoundError, VersionNotFoundError } from \"../tools\";\nimport { DEFAULT_MAX_DEPTH, DEFAULT_MAX_PAGES } from \"../utils/config\";\nimport { logger } from \"../utils/logger\";\nimport type { McpServerTools } from \"./tools\";\nimport { createError, createResponse } from \"./utils\";\n\n/**\n * Creates and configures an instance of the MCP server with registered tools, prompts, and resources.\n * @param tools The shared tool instances to use for server operations.\n * @returns A configured McpServer instance.\n */\nexport function createMcpServerInstance(tools: McpServerTools): McpServer {\n const server = new McpServer(\n {\n name: \"docs-mcp-server\",\n version: \"0.1.0\",\n },\n {\n capabilities: {\n tools: {},\n prompts: {},\n resources: {},\n },\n },\n );\n\n // --- Tool Definitions ---\n\n // Scrape docs tool\n server.tool(\n \"scrape_docs\",\n \"Scrape and index documentation from a URL\",\n {\n url: z.string().url().describe(\"URL of the documentation to scrape\"),\n library: z.string().describe(\"Name of the library\"),\n version: z.string().optional().describe(\"Version of the library\"),\n maxPages: z\n .number()\n .optional()\n .default(DEFAULT_MAX_PAGES)\n .describe(`Maximum number of pages to scrape (default: ${DEFAULT_MAX_PAGES})`),\n maxDepth: z\n .number()\n .optional()\n .default(DEFAULT_MAX_DEPTH)\n .describe(`Maximum navigation depth (default: ${DEFAULT_MAX_DEPTH})`),\n scope: z\n .enum([\"subpages\", \"hostname\", \"domain\"])\n .optional()\n .default(\"subpages\")\n .describe(\"Defines the crawling boundary: 'subpages', 'hostname', or 'domain'\"),\n followRedirects: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"Whether to follow HTTP redirects (3xx responses)\"),\n },\n async ({ url, library, version, maxPages, maxDepth, scope, followRedirects }) => {\n try {\n // Execute scrape tool without waiting and without progress callback\n const result = await tools.scrape.execute({\n url,\n library,\n version,\n waitForCompletion: false, // Don't wait for completion\n // onProgress: undefined, // Explicitly undefined or omitted\n options: {\n maxPages,\n maxDepth,\n scope,\n followRedirects,\n },\n });\n\n // Check the type of result\n if (\"jobId\" in result) {\n // If we got a jobId back, report that\n return createResponse(`🚀 Scraping job started with ID: ${result.jobId}.`);\n }\n // This case shouldn't happen if waitForCompletion is false, but handle defensively\n return createResponse(\n `Scraping finished immediately (unexpectedly) with ${result.pagesScraped} pages.`,\n );\n } catch (error) {\n // Handle errors during job *enqueueing* or initial setup\n return createError(\n `Failed to scrape documentation: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Search docs tool\n server.tool(\n \"search_docs\",\n \"Searches up-to-date documentation for a library. Examples:\\n\\n\" +\n '- {library: \"react\", query: \"hooks lifecycle\"} -> matches latest version of React\\n' +\n '- {library: \"react\", version: \"18.0.0\", query: \"hooks lifecycle\"} -> matches React 18.0.0 or earlier\\n' +\n '- {library: \"typescript\", version: \"5.x\", query: \"ReturnType example\"} -> any TypeScript 5.x.x version\\n' +\n '- {library: \"typescript\", version: \"5.2.x\", query: \"ReturnType example\"} -> any TypeScript 5.2.x version',\n {\n library: z.string().describe(\"Name of the library\"),\n version: z\n .string()\n .optional()\n .describe(\n \"Version of the library (supports exact versions like '18.0.0' or X-Range patterns like '5.x', '5.2.x')\",\n ),\n query: z.string().describe(\"Search query\"),\n limit: z.number().optional().default(5).describe(\"Maximum number of results\"),\n },\n async ({ library, version, query, limit }) => {\n try {\n const result = await tools.search.execute({\n library,\n version,\n query,\n limit,\n exactMatch: false, // Always false for MCP interface\n });\n\n const formattedResults = result.results.map(\n (r: { url: string; content: string }, i: number) => `\n------------------------------------------------------------\nResult ${i + 1}: ${r.url}\n\n${r.content}\\n`,\n );\n\n if (formattedResults.length === 0) {\n return createResponse(\n `No results found for '${query}' in ${library}. Try to use a different or more general query.`,\n );\n }\n return createResponse(\n `Search results for '${query}' in ${library}:\n${formattedResults.join(\"\")}`,\n );\n } catch (error) {\n if (error instanceof LibraryNotFoundError) {\n return createResponse(\n [\n `Library \"${library}\" not found.`,\n error.suggestions?.length\n ? `Did you mean: ${error.suggestions?.join(\", \")}?`\n : undefined,\n ].join(\" \"),\n );\n }\n if (error instanceof VersionNotFoundError) {\n const indexedVersions = error.availableVersions.map((v) => v.version);\n return createResponse(\n [\n `Version \"${version}\" not found.`,\n indexedVersions.length > 0\n ? `Available indexed versions for ${library}: ${indexedVersions.join(\", \")}`\n : undefined,\n ].join(\" \"),\n );\n }\n return createError(\n `Failed to search documentation: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // List libraries tool\n server.tool(\"list_libraries\", \"List all indexed libraries\", {}, async () => {\n try {\n const result = await tools.listLibraries.execute();\n if (result.libraries.length === 0) {\n return createResponse(\"No libraries indexed yet.\");\n }\n\n return createResponse(\n `Indexed libraries:\\n\\n${result.libraries.map((lib: { name: string }) => `- ${lib.name}`).join(\"\\n\")}`,\n );\n } catch (error) {\n return createError(\n `Failed to list libraries: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n });\n\n // Find version tool\n server.tool(\n \"find_version\",\n \"Find best matching version for a library\",\n {\n library: z.string().describe(\"Name of the library\"),\n targetVersion: z\n .string()\n .optional()\n .describe(\n \"Pattern to match (supports exact versions like '18.0.0' or X-Range patterns like '5.x', '5.2.x')\",\n ),\n },\n async ({ library, targetVersion }) => {\n try {\n const message = await tools.findVersion.execute({\n library,\n targetVersion,\n });\n\n if (!message) {\n return createError(\"No matching version found\");\n }\n\n return createResponse(message);\n } catch (error) {\n return createError(\n `Failed to find version: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // List jobs tool\n server.tool(\n \"list_jobs\",\n \"List pipeline jobs, optionally filtering by status.\",\n {\n status: z\n .nativeEnum(PipelineJobStatus)\n .optional()\n .describe(\"Optional status to filter jobs by.\"),\n },\n async ({ status }) => {\n try {\n const result = await tools.listJobs.execute({ status });\n // Format the simplified job list for display\n const formattedJobs = result.jobs\n .map(\n (job: JobInfo) =>\n `- ID: ${job.id}\\n Status: ${job.status}\\n Library: ${job.library}\\n Version: ${job.version}\\n Created: ${job.createdAt}${job.startedAt ? `\\n Started: ${job.startedAt}` : \"\"}${job.finishedAt ? `\\n Finished: ${job.finishedAt}` : \"\"}${job.error ? `\\n Error: ${job.error}` : \"\"}`,\n )\n .join(\"\\n\\n\");\n return createResponse(\n result.jobs.length > 0 ? `Current Jobs:\\n\\n${formattedJobs}` : \"No jobs found.\",\n );\n } catch (error) {\n return createError(\n `Failed to list jobs: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Get job info tool\n server.tool(\n \"get_job_info\",\n \"Get the simplified info for a specific pipeline job.\",\n {\n jobId: z.string().uuid().describe(\"The ID of the job to query.\"),\n },\n async ({ jobId }) => {\n try {\n const result = await tools.getJobInfo.execute({ jobId });\n if (!result.job) {\n return createError(`Job with ID ${jobId} not found.`);\n }\n const job = result.job;\n const formattedJob = `- ID: ${job.id}\\n Status: ${job.status}\\n Library: ${job.library}@${job.version}\\n Created: ${job.createdAt}${job.startedAt ? `\\n Started: ${job.startedAt}` : \"\"}${job.finishedAt ? `\\n Finished: ${job.finishedAt}` : \"\"}${job.error ? `\\n Error: ${job.error}` : \"\"}`;\n return createResponse(`Job Info:\\n\\n${formattedJob}`);\n } catch (error) {\n return createError(\n `Failed to get job info for ${jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Fetch URL tool\n server.tool(\n \"fetch_url\",\n \"Fetch a single URL and convert its content to Markdown\",\n {\n url: z.string().url().describe(\"The URL to fetch and convert to markdown\"),\n followRedirects: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"Whether to follow HTTP redirects (3xx responses)\"),\n },\n async ({ url, followRedirects }) => {\n try {\n const result = await tools.fetchUrl.execute({ url, followRedirects });\n return createResponse(result);\n } catch (error) {\n return createError(\n `Failed to fetch URL: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // Cancel job tool\n server.tool(\n \"cancel_job\",\n \"Attempt to cancel a queued or running pipeline job.\",\n {\n jobId: z.string().uuid().describe(\"The ID of the job to cancel.\"),\n },\n async ({ jobId }) => {\n try {\n const result = await tools.cancelJob.execute({ jobId });\n // Use the message and success status from the tool's result\n if (result.success) {\n return createResponse(result.message);\n }\n // If not successful according to the tool, treat it as an error in MCP\n return createError(result.message);\n } catch (error) {\n // Catch any unexpected errors during the tool execution itself\n return createError(\n `Failed to cancel job ${jobId}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n // Remove docs tool\n server.tool(\n \"remove_docs\",\n \"Remove indexed documentation for a library version.\",\n {\n library: z.string().describe(\"Name of the library\"),\n version: z\n .string()\n .optional()\n .describe(\"Version of the library (optional, removes unversioned if omitted)\"),\n },\n async ({ library, version }) => {\n try {\n // Execute the remove tool logic\n const result = await tools.remove.execute({ library, version });\n // Use the message from the tool's successful execution\n return createResponse(result.message);\n } catch (error) {\n // Catch errors thrown by the RemoveTool's execute method\n return createError(\n `Failed to remove documents: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n );\n\n server.prompt(\n \"docs\",\n \"Search indexed documentation\",\n {\n library: z.string().describe(\"Name of the library\"),\n version: z.string().optional().describe(\"Version of the library\"),\n query: z.string().describe(\"Search query\"),\n },\n async ({ library, version, query }) => {\n return {\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Please search ${library} ${version || \"\"} documentation for this query: ${query}`,\n },\n },\n ],\n };\n },\n );\n\n server.resource(\n \"libraries\",\n \"docs://libraries\",\n {\n description: \"List all indexed libraries\",\n },\n async (uri: URL) => {\n const result = await tools.listLibraries.execute();\n\n return {\n contents: result.libraries.map((lib: { name: string }) => ({\n uri: new URL(lib.name, uri).href,\n text: lib.name,\n })),\n };\n },\n );\n\n server.resource(\n \"versions\",\n new ResourceTemplate(\"docs://libraries/{library}/versions\", {\n list: undefined,\n }),\n {\n description: \"List all indexed versions for a library\",\n },\n async (uri: URL, { library }) => {\n const result = await tools.listLibraries.execute();\n\n const lib = result.libraries.find((l: { name: string }) => l.name === library);\n if (!lib) {\n return { contents: [] };\n }\n\n return {\n contents: lib.versions.map((v: { version: string }) => ({\n uri: new URL(v.version, uri).href,\n text: v.version,\n })),\n };\n },\n );\n\n /**\n * Resource handler for listing pipeline jobs.\n * Supports filtering by status via a query parameter (e.g., ?status=running).\n * URI: docs://jobs[?status=<status>]\n */\n server.resource(\n \"jobs\",\n \"docs://jobs\",\n {\n description: \"List pipeline jobs, optionally filtering by status.\",\n mimeType: \"application/json\",\n },\n async (uri: URL) => {\n const statusParam = uri.searchParams.get(\"status\");\n let statusFilter: PipelineJobStatus | undefined;\n\n // Validate status parameter if provided\n if (statusParam) {\n const validation = z.nativeEnum(PipelineJobStatus).safeParse(statusParam);\n if (validation.success) {\n statusFilter = validation.data;\n } else {\n // Handle invalid status - perhaps return an error or ignore?\n // For simplicity, let's ignore invalid status for now and return all jobs.\n // Alternatively, could throw an McpError or return specific error content.\n logger.warn(`Invalid status parameter received: ${statusParam}`);\n }\n }\n\n // Fetch simplified jobs using the ListJobsTool\n const result = await tools.listJobs.execute({ status: statusFilter });\n\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(result.jobs, null, 2), // Stringify the simplified jobs array\n },\n ],\n };\n },\n );\n\n /**\n * Resource handler for retrieving a specific pipeline job by its ID.\n * URI Template: docs://jobs/{jobId}\n */\n server.resource(\n \"job\", // A distinct name for this specific resource type\n new ResourceTemplate(\"docs://jobs/{jobId}\", { list: undefined }),\n {\n description: \"Get details for a specific pipeline job by ID.\",\n mimeType: \"application/json\",\n },\n async (uri: URL, { jobId }) => {\n // Validate jobId format if necessary (basic check)\n if (typeof jobId !== \"string\" || jobId.length === 0) {\n // Handle invalid jobId format - return empty or error\n logger.warn(`Invalid jobId received in URI: ${jobId}`);\n return { contents: [] }; // Return empty content for invalid ID format\n }\n\n // Fetch the simplified job info using GetJobInfoTool\n const result = await tools.getJobInfo.execute({ jobId });\n\n // result.job is either the simplified job object or null\n if (!result.job) {\n // Job not found, return empty content\n return { contents: [] };\n }\n\n // Job found, return its simplified details as JSON\n return {\n contents: [\n {\n uri: uri.href,\n mimeType: \"application/json\",\n text: JSON.stringify(result.job, null, 2), // Stringify the simplified job object\n },\n ],\n };\n },\n );\n\n return server;\n}\n","import * as http from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { createMcpServerInstance } from \"./mcpServer\";\nimport type { McpServerTools } from \"./tools\";\n\n/**\n * Starts the MCP server using the Streamable HTTP and SSE transports.\n * @param tools The shared tool instances.\n * @param port The port to listen on.\n * @returns The created McpServer instance.\n */\nexport async function startHttpServer(\n tools: McpServerTools,\n port: number,\n): Promise<McpServer> {\n setLogLevel(LogLevel.INFO);\n\n const server = createMcpServerInstance(tools);\n const sseTransports: Record<string, SSEServerTransport> = {};\n\n const httpServer = http.createServer(async (req, res) => {\n try {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n\n if (req.method === \"GET\" && url.pathname === \"/sse\") {\n // Handle SSE connection\n const transport = new SSEServerTransport(\"/messages\", res);\n sseTransports[transport.sessionId] = transport;\n\n res.on(\"close\", () => {\n delete sseTransports[transport.sessionId];\n transport.close();\n });\n\n await server.connect(transport);\n } else if (req.method === \"POST\" && url.pathname === \"/messages\") {\n // Handle SSE messages\n const sessionId = url.searchParams.get(\"sessionId\");\n const transport = sessionId ? sseTransports[sessionId] : undefined;\n\n if (transport) {\n let body = \"\";\n for await (const chunk of req) {\n body += chunk;\n }\n const parsedBody = JSON.parse(body);\n await transport.handlePostMessage(req, res, parsedBody);\n } else {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"No transport found for sessionId\" }));\n }\n } else if (url.pathname === \"/mcp\") {\n // Handle Streamable HTTP (stateless)\n let body = \"\";\n for await (const chunk of req) {\n body += chunk;\n }\n const parsedBody = JSON.parse(body);\n\n // In stateless mode, create a new instance of server and transport for each request\n const requestServer = createMcpServerInstance(tools);\n const requestTransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n });\n\n res.on(\"close\", () => {\n logger.info(\"Streamable HTTP request closed\");\n requestTransport.close();\n requestServer.close(); // Close the per-request server instance\n });\n\n await requestServer.connect(requestTransport);\n await requestTransport.handleRequest(req, res, parsedBody);\n } else {\n // Handle 404 Not Found\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Endpoint ${url.pathname} not found.`,\n }),\n );\n }\n } catch (error) {\n logger.error(`Error handling HTTP request: ${error}`);\n // Send an error response\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n });\n\n httpServer.listen(port, () => {\n logger.info(`🤖 Docs MCP server listening at http://127.0.0.1:${port}`);\n });\n\n // Return the server instance\n return server;\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { createMcpServerInstance } from \"./mcpServer\";\nimport type { McpServerTools } from \"./tools\";\n\n/**\n * Starts the MCP server using the Stdio transport.\n * @param tools The shared tool instances.\n * @returns The created McpServer instance.\n */\nexport async function startStdioServer(tools: McpServerTools): Promise<McpServer> {\n setLogLevel(LogLevel.ERROR);\n\n // Create a server instance using the factory and shared tools\n const server = createMcpServerInstance(tools);\n\n // Start server with Stdio transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n logger.info(\"🤖 Docs MCP server listening on stdio\");\n\n // Return the server instance\n return server;\n}\n","import { FileFetcher, HttpFetcher } from \"../scraper/fetcher\";\nimport {\n CancelJobTool,\n FetchUrlTool,\n FindVersionTool,\n GetJobInfoTool,\n ListJobsTool,\n ListLibrariesTool,\n RemoveTool,\n ScrapeTool,\n SearchTool,\n} from \"../tools\";\nimport { getDocService, getPipelineManager } from \"./services\";\n\n/**\n * Interface for the shared tool instances.\n */\nexport interface McpServerTools {\n listLibraries: ListLibrariesTool;\n findVersion: FindVersionTool;\n scrape: ScrapeTool;\n search: SearchTool;\n listJobs: ListJobsTool;\n getJobInfo: GetJobInfoTool;\n cancelJob: CancelJobTool;\n remove: RemoveTool;\n fetchUrl: FetchUrlTool;\n}\n\n/**\n * Initializes and returns the shared tool instances.\n * This should be called after initializeServices has completed.\n * @returns An object containing all instantiated tool instances.\n */\nexport async function initializeTools(): Promise<McpServerTools> {\n const docService = getDocService();\n const pipelineManager = getPipelineManager();\n\n const tools: McpServerTools = {\n listLibraries: new ListLibrariesTool(docService),\n findVersion: new FindVersionTool(docService),\n scrape: new ScrapeTool(docService, pipelineManager),\n search: new SearchTool(docService),\n listJobs: new ListJobsTool(pipelineManager),\n getJobInfo: new GetJobInfoTool(pipelineManager),\n cancelJob: new CancelJobTool(pipelineManager),\n remove: new RemoveTool(docService),\n // FetchUrlTool now uses middleware pipeline internally\n fetchUrl: new FetchUrlTool(new HttpFetcher(), new FileFetcher()),\n };\n\n return tools;\n}\n","import \"dotenv/config\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { PipelineManager } from \"../pipeline/PipelineManager\";\nimport type { DocumentManagementService } from \"../store/DocumentManagementService\";\nimport { LogLevel, logger, setLogLevel } from \"../utils/logger\";\nimport { getDocService, getPipelineManager, initializeServices } from \"./services\"; // Import get functions\nimport { startHttpServer } from \"./startHttpServer\";\nimport { startStdioServer } from \"./startStdioServer\";\nimport { type McpServerTools, initializeTools } from \"./tools\";\n\n// Variables to hold server instances for cleanup\nlet runningServer: McpServer | null = null;\nlet runningPipelineManager: PipelineManager | null = null;\nlet runningDocService: DocumentManagementService | null = null;\n\nexport async function startServer(protocol: \"stdio\" | \"http\", port?: number) {\n try {\n // Set the default log level for the server to ERROR\n setLogLevel(LogLevel.ERROR);\n\n // Initialize shared services\n await initializeServices();\n runningDocService = getDocService(); // Get instance after initialization\n runningPipelineManager = getPipelineManager(); // Get instance after initialization\n\n // Initialize and get shared tools\n const tools: McpServerTools = await initializeTools(); // initializeTools now gets services internally\n\n let serverInstance: McpServer;\n if (protocol === \"stdio\") {\n serverInstance = await startStdioServer(tools); // startStdioServer needs to return McpServer\n } else if (protocol === \"http\") {\n if (port === undefined) {\n logger.error(\"HTTP protocol requires a port.\");\n process.exit(1);\n }\n serverInstance = await startHttpServer(tools, port); // startHttpServer needs to return McpServer\n } else {\n // This case should be caught by src/server.ts, but handle defensively\n logger.error(`Unknown protocol: ${protocol}`);\n process.exit(1);\n }\n\n // Capture the running server instance\n runningServer = serverInstance;\n\n // Handle graceful shutdown on SIGINT\n process.on(\"SIGINT\", async () => {\n logger.info(\"Received SIGINT. Shutting down gracefully...\");\n await stopServer();\n process.exit(0);\n });\n } catch (error) {\n logger.error(`❌ Fatal Error during server startup: ${error}`);\n // Attempt cleanup even if startup failed partially\n await stopServer();\n process.exit(1);\n }\n}\n\n/**\n * Stops the MCP server and related services gracefully.\n */\nexport async function stopServer() {\n logger.info(\"Shutting down MCP server and services...\");\n let hadError = false;\n try {\n if (runningPipelineManager) {\n logger.debug(\"Stopping Pipeline Manager...\");\n await runningPipelineManager.stop();\n logger.info(\"Pipeline Manager stopped.\");\n }\n } catch (e) {\n logger.error(`Error stopping Pipeline Manager: ${e}`);\n hadError = true;\n }\n try {\n if (runningDocService) {\n logger.debug(\"Shutting down Document Service...\");\n await runningDocService.shutdown();\n logger.info(\"Document Service shut down.\");\n }\n } catch (e) {\n logger.error(`Error shutting down Document Service: ${e}`);\n hadError = true;\n }\n try {\n if (runningServer) {\n logger.debug(\"Closing MCP Server connection...\");\n await runningServer.close();\n logger.info(\"MCP Server connection closed.\");\n }\n } catch (e) {\n logger.error(`Error closing MCP Server: ${e}`);\n hadError = true;\n }\n\n // Clear references\n runningPipelineManager = null;\n runningDocService = null;\n runningServer = null;\n\n if (hadError) {\n logger.warn(\"Server shutdown completed with errors.\");\n } else {\n logger.info(\"✅ Server shutdown complete.\");\n }\n}\n","#!/usr/bin/env node\nimport \"dotenv/config\";\nimport { program } from \"commander\";\nimport { startServer, stopServer } from \"./mcp/index.js\";\nimport { DEFAULT_HTTP_PORT, DEFAULT_PROTOCOL } from \"./utils/config.js\";\nimport { logger } from \"./utils/logger\"; // Import logger for HMR hook\n\nprogram\n .option(\"--protocol <type>\", \"Protocol to use (stdio or http)\", DEFAULT_PROTOCOL)\n .option(\n \"--port <number>\",\n \"Port to listen on for http protocol\",\n `${DEFAULT_HTTP_PORT}`,\n )\n .parse(process.argv);\n\nconst options = program.opts();\n\nasync function main() {\n const protocol = options.protocol;\n // Prioritize environment variable, then CLI arg, then default\n const port = process.env.MCP_PORT\n ? Number.parseInt(process.env.MCP_PORT, 10)\n : Number.parseInt(options.port, 10);\n\n if (protocol !== \"stdio\" && protocol !== \"http\") {\n console.error('Invalid protocol specified. Use \"stdio\" or \"http\".');\n process.exit(1);\n }\n\n if (protocol === \"http\" && Number.isNaN(port)) {\n console.error(\"Port must be a number when using http protocol.\");\n process.exit(1);\n }\n\n try {\n await startServer(protocol, protocol === \"http\" ? port : undefined);\n } catch (error) {\n console.error(`Server failed to start: ${error}`);\n process.exit(1);\n }\n}\n\n// Handle HMR using Vite's API\nif (import.meta.hot) {\n import.meta.hot.on(\"vite:beforeFullReload\", async () => {\n logger.info(\"🔥 Hot reload detected. Shutting down existing MCP server...\");\n try {\n await stopServer();\n logger.info(\"✅ MCP server shut down for hot reload.\");\n } catch (error) {\n logger.error(`❌ Error stopping MCP server during HMR: ${error}`);\n // Decide if we should exit or try to continue\n }\n });\n}\n\n// Start the application\nmain();\n"],"names":["docService","pipelineManager"],"mappings":"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"}
|
package/dist/web.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "dotenv/config";
|
|
3
3
|
import { program } from "commander";
|
|
4
|
-
import { P as PipelineJobStatus, j as ScrapeMode, l as logger,
|
|
4
|
+
import { P as PipelineJobStatus, j as ScrapeMode, l as logger, n as createJSDOM, D as DocumentManagementService, a as PipelineManager, o as getProjectRoot, e as ScrapeTool, f as ListLibrariesTool, S as SearchTool, p as DEFAULT_WEB_PORT } from "./DocumentManagementService-BGW9iWNn.js";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import formBody from "@fastify/formbody";
|
|
7
7
|
import fastifyStatic from "@fastify/static";
|
|
@@ -13,7 +13,8 @@ import "jsdom";
|
|
|
13
13
|
import "playwright";
|
|
14
14
|
import "@joplin/turndown-plugin-gfm";
|
|
15
15
|
import "turndown";
|
|
16
|
-
import
|
|
16
|
+
import "node:util";
|
|
17
|
+
import { L as ListJobsTool, R as RemoveTool } from "./RemoveTool-BZPTXvhj.js";
|
|
17
18
|
import { jsxs, jsx, Fragment } from "@kitajs/html/jsx-runtime";
|
|
18
19
|
import { unified } from "unified";
|
|
19
20
|
import remarkParse from "remark-parse";
|