docbrain-mcp 1.5.10 → 1.5.11

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.
Files changed (3) hide show
  1. package/install.js +22 -5
  2. package/package.json +3 -3
  3. package/run.js +41 -2
package/install.js CHANGED
@@ -40,14 +40,31 @@ function download(url) {
40
40
  reject(new Error(`Download failed: HTTP ${res.statusCode}`));
41
41
  return;
42
42
  }
43
- const file = fs.createWriteStream(dest);
43
+ // Download to a scratch path and rename into place. rename() is atomic
44
+ // within a filesystem, so a download that is interrupted — or two that
45
+ // race, now that run.js can trigger one on first use — can never leave a
46
+ // half-written file at `dest`. A truncated binary is the worst outcome
47
+ // available here: it exists, so nothing re-downloads it, and it fails at
48
+ // exec with an error that says nothing about the real cause.
49
+ const tmp = `${dest}.tmp-${process.pid}`;
50
+ const file = fs.createWriteStream(tmp);
44
51
  res.pipe(file);
45
52
  file.on("finish", () => {
46
- file.close();
47
- fs.chmodSync(dest, 0o755);
48
- resolve();
53
+ file.close(() => {
54
+ try {
55
+ fs.chmodSync(tmp, 0o755);
56
+ fs.renameSync(tmp, dest);
57
+ resolve();
58
+ } catch (err) {
59
+ try { fs.unlinkSync(tmp); } catch {}
60
+ reject(err);
61
+ }
62
+ });
63
+ });
64
+ file.on("error", (err) => {
65
+ try { fs.unlinkSync(tmp); } catch {}
66
+ reject(err);
49
67
  });
50
- file.on("error", reject);
51
68
  })
52
69
  .on("error", reject);
53
70
  });
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "docbrain-mcp",
3
- "version": "1.5.10",
4
- "description": "DocBrain MCP server — query your documentation from Claude Code, Cursor, and any MCP-compatible editor",
3
+ "version": "1.5.11",
4
+ "description": "DocBrain MCP server \u2014 query your documentation from Claude Code, Cursor, and any MCP-compatible editor",
5
5
  "homepage": "https://github.com/docbrain-ai/docbrain",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/docbrain-ai/docbrain.git"
9
9
  },
10
- "license": "BSL-1.1",
10
+ "license": "MIT",
11
11
  "bin": {
12
12
  "docbrain-mcp": "run.js"
13
13
  },
package/run.js CHANGED
@@ -1,11 +1,47 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
4
- const { spawn } = require("child_process");
4
+ const { spawn, execFileSync } = require("child_process");
5
+ const fs = require("fs");
5
6
  const path = require("path");
6
7
 
7
8
  const binary = path.join(__dirname, "bin", "docbrain-mcp");
8
9
 
10
+ // npm 12 turned lifecycle scripts off by default, so the postinstall hook that
11
+ // fetches this binary may never have run — and `npx -y docbrain-mcp@latest`,
12
+ // which is how the MCP setup instructions tell people to launch this, goes
13
+ // through exactly that path. Fetching on first use covers it.
14
+ //
15
+ // Deliberately synchronous, before the spawn below. This runs once, at startup,
16
+ // before any MCP traffic exists to delay; doing it asynchronously would mean
17
+ // wiring the signal forwarding and exit plumbing around a pending download for
18
+ // no benefit.
19
+ //
20
+ // Note that stderr is used for the progress line, never stdout: stdout is the
21
+ // MCP stdio transport, and a stray byte there corrupts the protocol stream.
22
+ function ensureBinary() {
23
+ if (fs.existsSync(binary)) return;
24
+
25
+ console.error("DocBrain MCP binary not found — downloading it now (one-time).");
26
+ try {
27
+ execFileSync(process.execPath, [path.join(__dirname, "install.js")], {
28
+ stdio: ["ignore", "ignore", "inherit"],
29
+ });
30
+ } catch {
31
+ console.error("");
32
+ console.error(`Could not place the binary at: ${binary}`);
33
+ console.error(
34
+ "If that path is not writable, run this once as the user that installed the package,"
35
+ );
36
+ console.error(
37
+ "or download the binary manually from https://github.com/docbrain-ai/docbrain/releases"
38
+ );
39
+ process.exit(1);
40
+ }
41
+ }
42
+
43
+ ensureBinary();
44
+
9
45
  const child = spawn(binary, process.argv.slice(2), {
10
46
  stdio: "inherit",
11
47
  env: process.env,
@@ -25,7 +61,10 @@ child.on("exit", (code, signal) => {
25
61
  });
26
62
 
27
63
  child.on("error", (err) => {
64
+ // ensureBinary already guaranteed the file exists, so this is no longer a
65
+ // missing-binary case — it is a permissions or exec-format problem, and
66
+ // suggesting a reinstall would send the user down the wrong path.
28
67
  console.error(`Failed to run DocBrain MCP server: ${err.message}`);
29
- console.error("Try reinstalling: npx -y docbrain-mcp@latest");
68
+ console.error(`Binary: ${binary}`);
30
69
  process.exit(1);
31
70
  });