Status: unverified — needs confirmation from someone with a Linux SDK zip.
This is a code-reading deduction, not an observed failure. Sony ships per-platform SDK zips and I only had CrSDK_v2.02.00_20260610a_Win64.zip, so I could not run the Linux path. Filing it because the Windows equivalent was confirmed and shipped a silently-broken bundle.
Context
While fixing the Windows OpenCV bundling bug (#31, PR #32), the same class of defect appears to exist on Linux. On Windows this was confirmed: pack:mcp printed OpenCV libs not found — assuming static/linked, omitted all four DLLs, and produced a .mcpb whose server died instantly with STATUS_DLL_NOT_FOUND — surfacing to users as "the MCP server won't auto-start."
The Windows cause was a mismatch between the path extract.ts writes and the path opencvLibDir() reads. macOS is fine. Linux looks like it has the same mismatch.
The mismatch
opencvLibDir() in cli/src/lib/mcp-build.ts requires one of these to exist as a directory:
[['Linux', 'Release', 'x64', 'lib'], ['Linux', 'Release', 'aarch64', 'lib']]
But extract.ts writes Linux OpenCV libs with:
opencv: [{
fromRel: 'Linux',
toRel: 'Linux',
match: (f) => f.startsWith('libopencv_') && f.includes('.so'),
}]
and copyGlob is flat — readdirSync(srcDir) with no recursion, copying matched files directly into dstDir:
function copyGlob(srcDir, match, dstDir) {
if (!existsSync(srcDir)) throw new Error(`missing expected SDK directory: ${srcDir}`);
mkdirSync(dstDir, { recursive: true });
let n = 0;
for (const f of readdirSync(srcDir)) {
if (match(f)) { copyFileSync(join(srcDir, f), join(dstDir, f)); n++; }
}
return n;
}
So the only directory the extractor can ever create here is shared/opencv/Linux/, with libs sitting flat inside it. Nothing in the extract path ever creates Linux/Release/x64/lib or Linux/Release/aarch64/lib, so existsSync() fails on both candidates, opencvLibDir() returns null, and pack:mcp takes the silent "assuming static/linked" branch.
Compare: why macOS is fine
macOS works because fromRel === toRel === 'Darwin/Release/macos/bin', and opencvLibDir()'s darwin candidate is that same string. They match by construction. Windows broke precisely because the two strings disagreed. Linux disagrees in the same way.
Two possible outcomes, both bad
Depending on how the Linux SDK zip is laid out under external/opencv/Linux/:
- Libs flat in
Linux/ — they extract fine to shared/opencv/Linux/, but opencvLibDir() never finds them → OpenCV silently omitted from the .mcpb, same end result as the Windows bug.
- Libs nested (e.g.
Linux/Release/x64/lib/) — as the Windows zip nests them (Windows/x86_64/Release/bin) — then the flat copyGlob sees only subdirectory names, match() rejects all of them, and it copies zero files while returning success. OpenCV is then missing from shared/ entirely, not just from the bundle.
Case 2 would also mean crsdk build on Linux relies on OpenCV coming from somewhere else (system package?), which would mask the extraction doing nothing.
What would confirm it
On Linux, after crsdk install --zip <linux-sdk.zip>:
find shared/opencv -name 'libopencv_*' | head
ls shared/opencv/Linux/
- If libs are flat in
shared/opencv/Linux/ → case 1, opencvLibDir() needs ['Linux'] as a candidate.
- If that directory is empty → case 2,
copyGlob/fromRel needs the real nested path.
- Then
crsdk pack:mcp and check whether it prints OpenCV libs not found — assuming static/linked.
Also worth checking whether the built CameraWebApp on Linux actually has libopencv_* in its NEEDED entries (readelf -d CameraWebApp | grep NEEDED), which determines whether a missing lib is fatal at spawn as it is on Windows.
I did not blind-fix this, since the correct path depends on a layout I can't observe.
Related: the silent fallback
Underlying both this and #31: pack:mcp treats "OpenCV directory not found" as assuming static/linked and proceeds. That converts a missing-file bug into a broken artifact that only fails on the end user's machine, with no output from the dying process. Making that a hard failure (at least where OpenCV is known to be dynamically linked) would have caught the Windows bug at pack time instead of at connect time.
Happy to follow up with a PR once someone can confirm the actual Linux layout.
Context
While fixing the Windows OpenCV bundling bug (#31, PR #32), the same class of defect appears to exist on Linux. On Windows this was confirmed:
pack:mcpprintedOpenCV libs not found — assuming static/linked, omitted all four DLLs, and produced a.mcpbwhose server died instantly withSTATUS_DLL_NOT_FOUND— surfacing to users as "the MCP server won't auto-start."The Windows cause was a mismatch between the path
extract.tswrites and the pathopencvLibDir()reads. macOS is fine. Linux looks like it has the same mismatch.The mismatch
opencvLibDir()incli/src/lib/mcp-build.tsrequires one of these to exist as a directory:But
extract.tswrites Linux OpenCV libs with:and
copyGlobis flat —readdirSync(srcDir)with no recursion, copying matched files directly intodstDir:So the only directory the extractor can ever create here is
shared/opencv/Linux/, with libs sitting flat inside it. Nothing in the extract path ever createsLinux/Release/x64/liborLinux/Release/aarch64/lib, soexistsSync()fails on both candidates,opencvLibDir()returnsnull, andpack:mcptakes the silent "assuming static/linked" branch.Compare: why macOS is fine
macOS works because
fromRel === toRel === 'Darwin/Release/macos/bin', andopencvLibDir()'s darwin candidate is that same string. They match by construction. Windows broke precisely because the two strings disagreed. Linux disagrees in the same way.Two possible outcomes, both bad
Depending on how the Linux SDK zip is laid out under
external/opencv/Linux/:Linux/— they extract fine toshared/opencv/Linux/, butopencvLibDir()never finds them → OpenCV silently omitted from the.mcpb, same end result as the Windows bug.Linux/Release/x64/lib/) — as the Windows zip nests them (Windows/x86_64/Release/bin) — then the flatcopyGlobsees only subdirectory names,match()rejects all of them, and it copies zero files while returning success. OpenCV is then missing fromshared/entirely, not just from the bundle.Case 2 would also mean
crsdk buildon Linux relies on OpenCV coming from somewhere else (system package?), which would mask the extraction doing nothing.What would confirm it
On Linux, after
crsdk install --zip <linux-sdk.zip>:shared/opencv/Linux/→ case 1,opencvLibDir()needs['Linux']as a candidate.copyGlob/fromRelneeds the real nested path.crsdk pack:mcpand check whether it printsOpenCV libs not found — assuming static/linked.Also worth checking whether the built
CameraWebAppon Linux actually haslibopencv_*in itsNEEDEDentries (readelf -d CameraWebApp | grep NEEDED), which determines whether a missing lib is fatal at spawn as it is on Windows.I did not blind-fix this, since the correct path depends on a layout I can't observe.
Related: the silent fallback
Underlying both this and #31:
pack:mcptreats "OpenCV directory not found" asassuming static/linkedand proceeds. That converts a missing-file bug into a broken artifact that only fails on the end user's machine, with no output from the dying process. Making that a hard failure (at least where OpenCV is known to be dynamically linked) would have caught the Windows bug at pack time instead of at connect time.Happy to follow up with a PR once someone can confirm the actual Linux layout.