dbmole reported a hardcoded SERVER_VERSION of 0.1.0 while the package was
already published as 0.1.1: the constant had drifted because a bump has to
touch two places. Both servers now read the version from package.json
(resolveJsonModule + a JSON import attribute), so a release updates one
place and the reported version can no longer fall behind.
Add a dbmole guard test that add_connection publishes a non-empty
inputSchema with the expected required fields, mirroring esmole, so a future
`.superRefine` on the schema cannot silently empty it.
add_connection advertised an empty `{ properties: {} }` while the server
validated strictly, so clients could not see field types or the required
`type` literal and sent port/verifyTls as strings.
Cause: the connection schema was wrapped in `.superRefine`, producing a
ZodEffects with no `.shape`. The MCP SDK's normalizeObjectSchema returns
undefined for it and falls back to EMPTY_OBJECT_JSON_SCHEMA. update_connection
passed a raw shape, so it serialized fine - hence the asymmetry.
Split the schema: a strict z.object (connectionObjectSchema) is advertised as
the wire schema, and the refined connectionConfigSchema is passed as a new
optional parseSchema applied in the handler. Strict unknown-key rejection and
the apiKey-or-user+password check are both preserved. fullSchema is now typed
as a ZodObject so a ZodEffects can no longer be passed by mistake.
Build from repo root so @dbmole/core resolves; tsup bundles core into
dist while undici/MCP SDK/zod/ssh2 ship as pruned node_modules.
Mark ssh2 external in tsup: it is pulled in transitively by the bundled
core and ships an optional native crypto addon (pure-JS fallback). Inlining
would force esbuild to resolve a .node binary that need not exist on the
target; node-gyp also cannot reliably build it on alpine. Externalizing lets
ssh2 resolve from node_modules at runtime.
npm nests undici under packages/esmole-mcp/node_modules, so the runtime
stage copies both the root and the per-package node_modules.