docs(agents): monorepo layout + inputSchema gotcha

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.
This commit is contained in:
admin committed 2026-06-16 23:34:40 +05:00
1 parent dd6c86e17c
commit baecc24211
1 file changed
+21 -4
+21 -4
View File
@@ -2,6 +2,17 @@
Applies to every change in this repo, by any agent or human.
## Architecture
- npm workspace monorepo, three packages under `packages/`:
- `@dbmole/core` — shared Manager/registry/SSH-tunnel/MCP plumbing. `private`,
never published; each leaf bundles it via tsup (`noExternal`).
- `dbmole-mcp` — PostgreSQL + MySQL server
- `esmole-mcp` — Elasticsearch server
- Backends spread `baseConnectionShape`, add engine fields + `type`, call `.strict()`.
- Run workspace commands from the root, they fan out across packages:
`npm run typecheck` / `build` / `test:unit` / `test:int` / `coverage` / `lint`.
## Code style
- 4-space indentation
@@ -29,8 +40,8 @@ Applies to every change in this repo, by any agent or human.
- No `as unknown as X` double-casts anywhere
- No `@ts-ignore` / `@ts-expect-error` / `any` in `src/`
- In tests prefer typed fakes (see `test/unit/helpers.ts`); a single `as` cast is
a last resort, only when there is genuinely no typed way
- In tests prefer typed fakes (see `packages/dbmole-mcp/test/unit/helpers.ts`); a
single `as` cast is a last resort, only when there is genuinely no typed way
- Types must line up by construction — if they don't, fix the design, not the cast
## Testing
@@ -55,8 +66,14 @@ Applies to every change in this repo, by any agent or human.
- ESM with NodeNext resolution: relative imports need the `.js` extension
- MCP SDK v1 (`@modelcontextprotocol/sdk`): `registerTool` accepts a ZodRawShape
(plain object of zod fields) OR a full Zod object (verified on 1.29: AnySchema,
`.strict()` honored at runtime). Use a strict `z.object` where unknown-key
rejection matters (add_connection); raw shapes are fine elsewhere. Subpath
`.strict()` honored at runtime). The advertised `inputSchema` MUST expose
`.shape` — pass a ZodRawShape or a plain `z.object`/`.strict()`, NEVER a
`.superRefine`/`.refine` (ZodEffects has no `.shape`, so the SDK publishes an
empty `{ properties: {} }` and clients see no fields). Keep cross-field
refinements on a separate parse schema: `registerConnectionTools` takes
`fullSchema` (strict object, advertised) plus optional `parseSchema` (refined,
applied in the handler) — see esmole `add_connection`. Use a strict `z.object`
where unknown-key rejection matters; raw shapes are fine elsewhere. Subpath
imports (`server/mcp.js`, `server/stdio.js`, `client/index.js`, `inMemory.js`,
`types.js`)
- zod 3 (`import * as z from 'zod'`)