@fanduzi/deltascope-mcp 0.16.3 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,9 +14,9 @@ The launched `deltascope-mcp` server exposes a unified `audit_sql` surface for:
14
14
 
15
15
  - MySQL offline audit
16
16
  - TiDB offline audit
17
- - PostgreSQL offline audit on PG-capable release binaries
17
+ - PostgreSQL offline audit on the main PG-capable release binaries across the supported macOS and Linux platforms
18
18
 
19
- Connection-backed metadata-aware audit remains limited to MySQL/TiDB-compatible instances. PostgreSQL requests must stay offline-only on the MCP surface.
19
+ Connection-backed metadata-aware audit supports MySQL/TiDB-compatible instances and PostgreSQL on the main PG-capable release binaries across the supported macOS and Linux platforms.
20
20
 
21
21
  ## Version Contract
22
22
 
@@ -37,6 +37,12 @@ const archiveName = resolveArchiveName({
37
37
  arch: platform.arch,
38
38
  });
39
39
  const checksumsURL = resolveChecksumsURL({ version });
40
+ const preferredChecksumsURL = resolveChecksumsURL({
41
+ version,
42
+ os: platform.os,
43
+ arch: platform.arch,
44
+ });
45
+ const checksumsURLs = [...new Set([preferredChecksumsURL, checksumsURL])];
40
46
 
41
47
  function log(message) {
42
48
  process.stderr.write(`[deltascope-mcp-launcher] ${message}\n`);
@@ -54,11 +60,16 @@ const binaryPath = await ensureExecutable({
54
60
  (async () => {
55
61
  log(`cache miss; downloading ${archiveURL}`);
56
62
  log(`cache target ${destinationPath}`);
57
- log(`verifying archive against ${checksumsURL}`);
63
+ log(
64
+ checksumsURLs.length > 1
65
+ ? `verifying archive against ${checksumsURLs[0]} (fallback ${checksumsURLs[1]})`
66
+ : `verifying archive against ${checksumsURLs[0]}`,
67
+ );
58
68
  try {
59
69
  const result = await downloadAndExtractBinary({
60
70
  archiveURL,
61
- checksumsURL,
71
+ checksumsURL: preferredChecksumsURL,
72
+ checksumsURLs,
62
73
  archiveName,
63
74
  destinationPath,
64
75
  });
package/lib/download.js CHANGED
@@ -44,6 +44,7 @@ function parseChecksums(text) {
44
44
  export async function downloadAndExtractBinary({
45
45
  archiveURL,
46
46
  checksumsURL,
47
+ checksumsURLs = [],
47
48
  archiveName,
48
49
  destinationPath,
49
50
  fetchImpl = globalThis.fetch
@@ -52,33 +53,51 @@ export async function downloadAndExtractBinary({
52
53
  throw new Error("fetch implementation is required");
53
54
  }
54
55
 
55
- const [archiveResponse, checksumsResponse] = await Promise.all([
56
- fetchImpl(archiveURL),
57
- fetchImpl(checksumsURL)
58
- ]);
56
+ const requestedChecksumsURLs = [
57
+ ...checksumsURLs,
58
+ ...(checksumsURL ? [checksumsURL] : [])
59
+ ].filter(Boolean);
60
+ const uniqueChecksumsURLs = [...new Set(requestedChecksumsURLs)];
61
+ if (uniqueChecksumsURLs.length === 0) {
62
+ throw new Error("at least one checksums URL is required");
63
+ }
64
+
65
+ const archiveResponse = await fetchImpl(archiveURL);
59
66
 
60
67
  if (!archiveResponse.ok) {
61
68
  throw new Error(`failed to download ${archiveURL}`);
62
69
  }
63
- if (!checksumsResponse.ok) {
64
- throw new Error(`failed to download ${checksumsURL}`);
65
- }
66
70
 
67
71
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "deltascope-mcp-archive-"));
68
72
  const archivePath = path.join(tempDir, "archive.tar.gz");
69
73
  const extractDir = path.join(tempDir, "extract");
70
74
  const archiveBuffer = Buffer.from(await archiveResponse.arrayBuffer());
71
- const checksums = parseChecksums(await checksumsResponse.text());
72
- const expectedChecksum = checksums.get(archiveName);
73
75
  const actualChecksum = sha256(archiveBuffer);
74
76
 
75
- try {
76
- if (!expectedChecksum) {
77
- throw new Error(`missing checksum for ${archiveName}`);
78
- }
79
- if (actualChecksum !== expectedChecksum) {
80
- throw new Error(`checksum mismatch for ${archiveName}`);
77
+ const resolveExpectedChecksum = async () => {
78
+ let lastError = new Error(`missing checksum for ${archiveName}`);
79
+ for (const candidateURL of uniqueChecksumsURLs) {
80
+ const checksumsResponse = await fetchImpl(candidateURL);
81
+ if (!checksumsResponse.ok) {
82
+ lastError = new Error(`failed to download ${candidateURL}`);
83
+ continue;
84
+ }
85
+ const checksums = parseChecksums(await checksumsResponse.text());
86
+ const expectedChecksum = checksums.get(archiveName);
87
+ if (!expectedChecksum) {
88
+ lastError = new Error(`missing checksum for ${archiveName}`);
89
+ continue;
90
+ }
91
+ if (actualChecksum !== expectedChecksum) {
92
+ throw new Error(`checksum mismatch for ${archiveName}`);
93
+ }
94
+ return expectedChecksum;
81
95
  }
96
+ throw lastError;
97
+ };
98
+
99
+ try {
100
+ const expectedChecksum = await resolveExpectedChecksum();
82
101
  await fs.mkdir(extractDir, { recursive: true });
83
102
  await fs.writeFile(archivePath, archiveBuffer);
84
103
  await runTar(["-xzf", archivePath, "-C", extractDir]);
package/lib/releases.js CHANGED
@@ -43,8 +43,11 @@ export function resolveArchiveName({ version, os, arch }) {
43
43
  return `deltascope_${version.replace(/^v/, "")}_${os}_${arch}.tar.gz`;
44
44
  }
45
45
 
46
- export function resolveChecksumsName({ version }) {
46
+ export function resolveChecksumsName({ version, os = "", arch = "" }) {
47
47
  const rawVersion = version.replace(/^v/, "");
48
+ if (os && arch) {
49
+ return `deltascope_${rawVersion}_${os}_${arch}_checksums.txt`;
50
+ }
48
51
  return `deltascope_${rawVersion}_checksums.txt`;
49
52
  }
50
53
 
@@ -61,6 +64,6 @@ export function resolveArchiveURL({
61
64
  return `https://github.com/${repo}/releases/download/${version}/${resolveArchiveName({ version, os, arch })}`;
62
65
  }
63
66
 
64
- export function resolveChecksumsURL({ repo = "Fanduzi/DeltaScope", version }) {
65
- return `https://github.com/${repo}/releases/download/${version}/${resolveChecksumsName({ version })}`;
67
+ export function resolveChecksumsURL({ repo = "Fanduzi/DeltaScope", version, os = "", arch = "" }) {
68
+ return `https://github.com/${repo}/releases/download/${version}/${resolveChecksumsName({ version, os, arch })}`;
66
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanduzi/deltascope-mcp",
3
- "version": "0.16.3",
3
+ "version": "0.18.0",
4
4
  "description": "Launcher package for the DeltaScope MCP stdio server",
5
5
  "type": "module",
6
6
  "repository": {