@arabold/docs-mcp-server 1.25.2 → 1.25.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/index.js +77 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -254,6 +254,7 @@ You can index documentation from your local filesystem by using a `file://` URL
|
|
|
254
254
|
-e OPENAI_API_KEY="your-key" \
|
|
255
255
|
-v /absolute/path/to/docs:/docs:ro \
|
|
256
256
|
-v docs-mcp-data:/data \
|
|
257
|
+
-p 6280:6280 \
|
|
257
258
|
ghcr.io/arabold/docs-mcp-server:latest \
|
|
258
259
|
scrape mylib file:///docs/my-library
|
|
259
260
|
```
|
|
@@ -498,7 +499,11 @@ DOCS_MCP_TELEMETRY=false npx @arabold/docs-mcp-server@latest
|
|
|
498
499
|
**Option 3: Docker**
|
|
499
500
|
|
|
500
501
|
```bash
|
|
501
|
-
docker run
|
|
502
|
+
docker run \
|
|
503
|
+
-e DOCS_MCP_TELEMETRY=false \
|
|
504
|
+
-v docs-mcp-data:/data \
|
|
505
|
+
-p 6280:6280 \
|
|
506
|
+
ghcr.io/arabold/docs-mcp-server:latest
|
|
502
507
|
```
|
|
503
508
|
|
|
504
509
|
For more details about our telemetry practices, see the [Telemetry Guide](docs/telemetry.md).
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { PostHog } from "posthog-node";
|
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import fs, { existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import path from "node:path";
|
|
12
|
+
import { fileURLToPath, URL as URL$1 } from "node:url";
|
|
12
13
|
import envPaths from "env-paths";
|
|
13
14
|
import { Option, Command } from "commander";
|
|
14
15
|
import formBody from "@fastify/formbody";
|
|
@@ -22,7 +23,6 @@ import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
|
|
|
22
23
|
import { v4 } from "uuid";
|
|
23
24
|
import { VirtualConsole, JSDOM } from "jsdom";
|
|
24
25
|
import mime from "mime";
|
|
25
|
-
import { fileURLToPath, URL as URL$1 } from "node:url";
|
|
26
26
|
import psl from "psl";
|
|
27
27
|
import fs$1 from "node:fs/promises";
|
|
28
28
|
import axios from "axios";
|
|
@@ -539,6 +539,49 @@ class PostHogClient {
|
|
|
539
539
|
return this.enabled && !!this.client;
|
|
540
540
|
}
|
|
541
541
|
}
|
|
542
|
+
let projectRoot = null;
|
|
543
|
+
function getProjectRoot() {
|
|
544
|
+
if (projectRoot) {
|
|
545
|
+
return projectRoot;
|
|
546
|
+
}
|
|
547
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
548
|
+
let currentDir = path.dirname(currentFilePath);
|
|
549
|
+
while (true) {
|
|
550
|
+
const packageJsonPath = path.join(currentDir, "package.json");
|
|
551
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
552
|
+
projectRoot = currentDir;
|
|
553
|
+
return currentDir;
|
|
554
|
+
}
|
|
555
|
+
const parentDir = path.dirname(currentDir);
|
|
556
|
+
if (parentDir === currentDir) {
|
|
557
|
+
throw new Error("Could not find project root containing package.json.");
|
|
558
|
+
}
|
|
559
|
+
currentDir = parentDir;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function resolveStorePath(storePath) {
|
|
563
|
+
let dbDir;
|
|
564
|
+
if (storePath) {
|
|
565
|
+
dbDir = storePath;
|
|
566
|
+
} else {
|
|
567
|
+
const projectRoot2 = getProjectRoot();
|
|
568
|
+
const oldDbDir = path.join(projectRoot2, ".store");
|
|
569
|
+
const oldDbPath = path.join(oldDbDir, "documents.db");
|
|
570
|
+
const oldDbExists = fs.existsSync(oldDbPath);
|
|
571
|
+
if (oldDbExists) {
|
|
572
|
+
dbDir = oldDbDir;
|
|
573
|
+
} else {
|
|
574
|
+
const standardPaths = envPaths("docs-mcp-server", { suffix: "" });
|
|
575
|
+
dbDir = standardPaths.data;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
580
|
+
} catch (error) {
|
|
581
|
+
console.warn(`⚠️ Failed to create database directory ${dbDir}: ${error}`);
|
|
582
|
+
}
|
|
583
|
+
return dbDir;
|
|
584
|
+
}
|
|
542
585
|
class TelemetryConfig {
|
|
543
586
|
static instance;
|
|
544
587
|
enabled = true;
|
|
@@ -560,7 +603,7 @@ class TelemetryConfig {
|
|
|
560
603
|
}
|
|
561
604
|
function generateInstallationId(storePath) {
|
|
562
605
|
try {
|
|
563
|
-
const dataDir = storePath
|
|
606
|
+
const dataDir = resolveStorePath(storePath);
|
|
564
607
|
const installationIdPath = path.join(dataDir, "installation.id");
|
|
565
608
|
if (fs.existsSync(installationIdPath)) {
|
|
566
609
|
const existingId = fs.readFileSync(installationIdPath, "utf8").trim();
|
|
@@ -709,7 +752,7 @@ function extractProtocol(urlOrPath) {
|
|
|
709
752
|
}
|
|
710
753
|
}
|
|
711
754
|
const name = "@arabold/docs-mcp-server";
|
|
712
|
-
const version = "1.25.
|
|
755
|
+
const version = "1.25.2";
|
|
713
756
|
const description = "MCP server for fetching and searching documentation";
|
|
714
757
|
const type = "module";
|
|
715
758
|
const bin = { "docs-mcp-server": "dist/index.js" };
|
|
@@ -1582,26 +1625,6 @@ class MimeTypeUtils {
|
|
|
1582
1625
|
return mimeToLanguage[mimeType] || "";
|
|
1583
1626
|
}
|
|
1584
1627
|
}
|
|
1585
|
-
let projectRoot = null;
|
|
1586
|
-
function getProjectRoot() {
|
|
1587
|
-
if (projectRoot) {
|
|
1588
|
-
return projectRoot;
|
|
1589
|
-
}
|
|
1590
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
1591
|
-
let currentDir = path.dirname(currentFilePath);
|
|
1592
|
-
while (true) {
|
|
1593
|
-
const packageJsonPath = path.join(currentDir, "package.json");
|
|
1594
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
1595
|
-
projectRoot = currentDir;
|
|
1596
|
-
return projectRoot;
|
|
1597
|
-
}
|
|
1598
|
-
const parentDir = path.dirname(currentDir);
|
|
1599
|
-
if (parentDir === currentDir) {
|
|
1600
|
-
throw new Error("Could not find project root containing package.json.");
|
|
1601
|
-
}
|
|
1602
|
-
currentDir = parentDir;
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
1628
|
const fullTrim = (str) => {
|
|
1606
1629
|
return str.replace(/^[\s\r\n\t]+|[\s\r\n\t]+$/g, "");
|
|
1607
1630
|
};
|
|
@@ -7390,14 +7413,6 @@ function parseHeaders(headerOptions) {
|
|
|
7390
7413
|
}
|
|
7391
7414
|
return headers;
|
|
7392
7415
|
}
|
|
7393
|
-
const CLI_DEFAULTS = {
|
|
7394
|
-
PROTOCOL: DEFAULT_PROTOCOL,
|
|
7395
|
-
HTTP_PORT: DEFAULT_HTTP_PORT,
|
|
7396
|
-
WEB_PORT: DEFAULT_WEB_PORT,
|
|
7397
|
-
HOST: DEFAULT_HOST,
|
|
7398
|
-
MAX_CONCURRENCY: DEFAULT_MAX_CONCURRENCY,
|
|
7399
|
-
TELEMETRY: true
|
|
7400
|
-
};
|
|
7401
7416
|
function parseAuthConfig(options) {
|
|
7402
7417
|
if (!options.authEnabled) {
|
|
7403
7418
|
return void 0;
|
|
@@ -12540,34 +12555,10 @@ class DocumentManagementService {
|
|
|
12540
12555
|
normalizeVersion(version2) {
|
|
12541
12556
|
return (version2 ?? "").toLowerCase();
|
|
12542
12557
|
}
|
|
12543
|
-
constructor(embeddingConfig, pipelineConfig
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
dbDir = storePath;
|
|
12548
|
-
dbPath = path.join(dbDir, "documents.db");
|
|
12549
|
-
logger.debug(`Using database directory from storePath parameter: ${dbDir}`);
|
|
12550
|
-
} else {
|
|
12551
|
-
const projectRoot2 = getProjectRoot();
|
|
12552
|
-
const oldDbDir = path.join(projectRoot2, ".store");
|
|
12553
|
-
const oldDbPath = path.join(oldDbDir, "documents.db");
|
|
12554
|
-
const oldDbExists = fs.existsSync(oldDbPath);
|
|
12555
|
-
if (oldDbExists) {
|
|
12556
|
-
dbPath = oldDbPath;
|
|
12557
|
-
dbDir = oldDbDir;
|
|
12558
|
-
logger.debug(`Using legacy database path: ${dbPath}`);
|
|
12559
|
-
} else {
|
|
12560
|
-
const standardPaths = envPaths("docs-mcp-server", { suffix: "" });
|
|
12561
|
-
dbDir = standardPaths.data;
|
|
12562
|
-
dbPath = path.join(dbDir, "documents.db");
|
|
12563
|
-
logger.debug(`Using standard database directory: ${dbDir}`);
|
|
12564
|
-
}
|
|
12565
|
-
}
|
|
12566
|
-
try {
|
|
12567
|
-
fs.mkdirSync(dbDir, { recursive: true });
|
|
12568
|
-
} catch (error) {
|
|
12569
|
-
logger.error(`⚠️ Failed to create database directory ${dbDir}: ${error}`);
|
|
12570
|
-
}
|
|
12558
|
+
constructor(storePath, embeddingConfig, pipelineConfig) {
|
|
12559
|
+
const dbDir = storePath;
|
|
12560
|
+
const dbPath = path.join(dbDir, "documents.db");
|
|
12561
|
+
logger.debug(`Using database directory: ${dbDir}`);
|
|
12571
12562
|
this.store = new DocumentStore(dbPath, embeddingConfig);
|
|
12572
12563
|
this.documentRetriever = new DocumentRetrieverService(this.store);
|
|
12573
12564
|
this.pipelines = PipelineFactory$1.createStandardPipelines(pipelineConfig);
|
|
@@ -12922,16 +12913,19 @@ async function createDocumentManagement(options = {}) {
|
|
|
12922
12913
|
await client.initialize();
|
|
12923
12914
|
return client;
|
|
12924
12915
|
}
|
|
12916
|
+
if (!options.storePath) {
|
|
12917
|
+
throw new Error("storePath is required when not using a remote server");
|
|
12918
|
+
}
|
|
12925
12919
|
const service = new DocumentManagementService(
|
|
12920
|
+
options.storePath,
|
|
12926
12921
|
options.embeddingConfig,
|
|
12927
|
-
void 0
|
|
12928
|
-
options.storePath
|
|
12922
|
+
void 0
|
|
12929
12923
|
);
|
|
12930
12924
|
await service.initialize();
|
|
12931
12925
|
return service;
|
|
12932
12926
|
}
|
|
12933
|
-
async function createLocalDocumentManagement(
|
|
12934
|
-
const service = new DocumentManagementService(embeddingConfig, void 0
|
|
12927
|
+
async function createLocalDocumentManagement(storePath, embeddingConfig) {
|
|
12928
|
+
const service = new DocumentManagementService(storePath, embeddingConfig, void 0);
|
|
12935
12929
|
await service.initialize();
|
|
12936
12930
|
return service;
|
|
12937
12931
|
}
|
|
@@ -12939,7 +12933,7 @@ function createDefaultAction(program) {
|
|
|
12939
12933
|
return program.addOption(
|
|
12940
12934
|
new Option("--protocol <protocol>", "Protocol for MCP server").env("DOCS_MCP_PROTOCOL").default("auto").choices(["auto", "stdio", "http"])
|
|
12941
12935
|
).addOption(
|
|
12942
|
-
new Option("--port <number>", "Port for the server").env("DOCS_MCP_PORT").env("PORT").default(
|
|
12936
|
+
new Option("--port <number>", "Port for the server").env("DOCS_MCP_PORT").env("PORT").default(DEFAULT_HTTP_PORT.toString()).argParser((v) => {
|
|
12943
12937
|
const n = Number(v);
|
|
12944
12938
|
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
12945
12939
|
throw new Error("Port must be an integer between 1 and 65535");
|
|
@@ -12947,7 +12941,7 @@ function createDefaultAction(program) {
|
|
|
12947
12941
|
return String(n);
|
|
12948
12942
|
})
|
|
12949
12943
|
).addOption(
|
|
12950
|
-
new Option("--host <host>", "Host to bind the server to").env("DOCS_MCP_HOST").env("HOST").default(
|
|
12944
|
+
new Option("--host <host>", "Host to bind the server to").env("DOCS_MCP_HOST").env("HOST").default(DEFAULT_HOST).argParser(validateHost)
|
|
12951
12945
|
).addOption(
|
|
12952
12946
|
new Option(
|
|
12953
12947
|
"--embedding-model <model>",
|
|
@@ -13004,12 +12998,12 @@ function createDefaultAction(program) {
|
|
|
13004
12998
|
validateAuthConfig(authConfig);
|
|
13005
12999
|
warnHttpUsage(authConfig, port);
|
|
13006
13000
|
}
|
|
13007
|
-
const globalOptions = program.
|
|
13001
|
+
const globalOptions = program.opts();
|
|
13008
13002
|
ensurePlaywrightBrowsersInstalled();
|
|
13009
13003
|
const embeddingConfig = resolveEmbeddingContext(options.embeddingModel);
|
|
13010
13004
|
const docService = await createLocalDocumentManagement(
|
|
13011
|
-
|
|
13012
|
-
|
|
13005
|
+
globalOptions.storePath,
|
|
13006
|
+
embeddingConfig
|
|
13013
13007
|
);
|
|
13014
13008
|
const pipelineOptions = {
|
|
13015
13009
|
recoverJobs: options.resume || false,
|
|
@@ -13160,9 +13154,9 @@ function createListCommand(program) {
|
|
|
13160
13154
|
}
|
|
13161
13155
|
function createMcpCommand(program) {
|
|
13162
13156
|
return program.command("mcp").description("Start MCP server only").addOption(
|
|
13163
|
-
new Option("--protocol <protocol>", "Protocol for MCP server").env("DOCS_MCP_PROTOCOL").default(
|
|
13157
|
+
new Option("--protocol <protocol>", "Protocol for MCP server").env("DOCS_MCP_PROTOCOL").default(DEFAULT_PROTOCOL).choices(["auto", "stdio", "http"])
|
|
13164
13158
|
).addOption(
|
|
13165
|
-
new Option("--port <number>", "Port for the MCP server").env("DOCS_MCP_PORT").env("PORT").default(
|
|
13159
|
+
new Option("--port <number>", "Port for the MCP server").env("DOCS_MCP_PORT").env("PORT").default(DEFAULT_HTTP_PORT.toString()).argParser((v) => {
|
|
13166
13160
|
const n = Number(v);
|
|
13167
13161
|
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
13168
13162
|
throw new Error("Port must be an integer between 1 and 65535");
|
|
@@ -13170,7 +13164,7 @@ function createMcpCommand(program) {
|
|
|
13170
13164
|
return String(n);
|
|
13171
13165
|
})
|
|
13172
13166
|
).addOption(
|
|
13173
|
-
new Option("--host <host>", "Host to bind the MCP server to").env("DOCS_MCP_HOST").env("HOST").default(
|
|
13167
|
+
new Option("--host <host>", "Host to bind the MCP server to").env("DOCS_MCP_HOST").env("HOST").default(DEFAULT_HOST).argParser(validateHost)
|
|
13174
13168
|
).addOption(
|
|
13175
13169
|
new Option(
|
|
13176
13170
|
"--embedding-model <model>",
|
|
@@ -13530,7 +13524,7 @@ function createSearchCommand(program) {
|
|
|
13530
13524
|
}
|
|
13531
13525
|
function createWebCommand(program) {
|
|
13532
13526
|
return program.command("web").description("Start web interface only").addOption(
|
|
13533
|
-
new Option("--port <number>", "Port for the web interface").env("DOCS_MCP_WEB_PORT").env("DOCS_MCP_PORT").env("PORT").default(
|
|
13527
|
+
new Option("--port <number>", "Port for the web interface").env("DOCS_MCP_WEB_PORT").env("DOCS_MCP_PORT").env("PORT").default(DEFAULT_WEB_PORT.toString()).argParser((v) => {
|
|
13534
13528
|
const n = Number(v);
|
|
13535
13529
|
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
13536
13530
|
throw new Error("Port must be an integer between 1 and 65535");
|
|
@@ -13538,7 +13532,7 @@ function createWebCommand(program) {
|
|
|
13538
13532
|
return String(n);
|
|
13539
13533
|
})
|
|
13540
13534
|
).addOption(
|
|
13541
|
-
new Option("--host <host>", "Host to bind the web interface to").env("DOCS_MCP_HOST").env("HOST").default(
|
|
13535
|
+
new Option("--host <host>", "Host to bind the web interface to").env("DOCS_MCP_HOST").env("HOST").default(DEFAULT_HOST).argParser(validateHost)
|
|
13542
13536
|
).addOption(
|
|
13543
13537
|
new Option(
|
|
13544
13538
|
"--embedding-model <model>",
|
|
@@ -13620,7 +13614,7 @@ function createWorkerCommand(program) {
|
|
|
13620
13614
|
return String(n);
|
|
13621
13615
|
})
|
|
13622
13616
|
).addOption(
|
|
13623
|
-
new Option("--host <host>", "Host to bind the worker API to").env("DOCS_MCP_HOST").env("HOST").default(
|
|
13617
|
+
new Option("--host <host>", "Host to bind the worker API to").env("DOCS_MCP_HOST").env("HOST").default(DEFAULT_HOST).argParser(validateHost)
|
|
13624
13618
|
).addOption(
|
|
13625
13619
|
new Option(
|
|
13626
13620
|
"--embedding-model <model>",
|
|
@@ -13640,11 +13634,15 @@ function createWorkerCommand(program) {
|
|
|
13640
13634
|
logger.info(`🚀 Starting external pipeline worker on port ${port}`);
|
|
13641
13635
|
ensurePlaywrightBrowsersInstalled();
|
|
13642
13636
|
const embeddingConfig = resolveEmbeddingContext(cmdOptions.embeddingModel);
|
|
13643
|
-
const
|
|
13637
|
+
const globalOptions = program.parent?.opts() || {};
|
|
13638
|
+
const docService = await createLocalDocumentManagement(
|
|
13639
|
+
globalOptions.storePath,
|
|
13640
|
+
embeddingConfig
|
|
13641
|
+
);
|
|
13644
13642
|
const pipelineOptions = {
|
|
13645
13643
|
recoverJobs: cmdOptions.resume,
|
|
13646
13644
|
// Use the resume option
|
|
13647
|
-
concurrency:
|
|
13645
|
+
concurrency: DEFAULT_MAX_CONCURRENCY
|
|
13648
13646
|
};
|
|
13649
13647
|
const pipeline = await createPipelineWithCallbacks(docService, pipelineOptions);
|
|
13650
13648
|
const config = createAppServerConfig({
|
|
@@ -13692,10 +13690,12 @@ function createCliProgram() {
|
|
|
13692
13690
|
).enablePositionalOptions().allowExcessArguments(false).showHelpAfterError(true);
|
|
13693
13691
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
13694
13692
|
const globalOptions = thisCommand.opts();
|
|
13693
|
+
const resolvedStorePath = resolveStorePath(globalOptions.storePath);
|
|
13694
|
+
globalOptions.storePath = resolvedStorePath;
|
|
13695
13695
|
setupLogging(globalOptions);
|
|
13696
13696
|
initTelemetry({
|
|
13697
13697
|
enabled: globalOptions.telemetry ?? true,
|
|
13698
|
-
storePath:
|
|
13698
|
+
storePath: resolvedStorePath
|
|
13699
13699
|
});
|
|
13700
13700
|
if (shouldEnableTelemetry()) {
|
|
13701
13701
|
if (analytics.isEnabled()) {
|