prepublishOnly only typechecked and bundled, so a compiling but failing
change could reach npm. Insert `vitest run` (unit only, no Docker) before
the bundle step in both packages, gating publish on a green unit suite.
Assert add_connection advertises fullSchema as its inputSchema (never the
refined schema) and applies an optional parseSchema in the handler: a
refinement rejection surfaces as an error and skips registry.add, while a
passing config persists. Locks the wire/parse split at the core level.
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 an Architecture section: the three-package workspace, core being
private and bundled, and the root-level workspace commands. New sessions
had no map of the repo.
Rewrite the MCP SDK note to warn that the advertised inputSchema must
expose .shape: a .superRefine/.refine (ZodEffects) serializes to an empty
{ properties: {} }. Document the fullSchema/parseSchema split so the
add_connection bug fixed this cycle cannot recur. Fix the stale
test/unit/helpers.ts path to its per-package location.
The root README described only dbmole and never mentioned esmole, even
though the repo now ships both servers. Rework it into a monorepo landing
page: a package table, a shared `.mcp.json` quick start, and the connection
model both servers inherit from @dbmole/core.
Move the dbmole-specific reference into packages/dbmole-mcp/README.md so the
package has its own doc on npm, mirroring esmole. Fix the stale Docker build
command there: the Dockerfile moved under packages/dbmole-mcp, so the build
now needs -f and the repo root as context. This also resolves esmole's
README link to ../dbmole-mcp/README.md, which pointed at a missing file.
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.
Run the MCP server from src via tsx so the in-repo client always
uses current source. Avoids the stale/ missing dist trap from bare
`npx dbmole-mcp` resolving the local package in this folder.