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.
103 lines
4.0 KiB
Markdown
103 lines
4.0 KiB
Markdown
# dbmole-mcp
|
|
|
|
A monorepo of stdio MCP servers for databases, built on one shared connection
|
|
core. Each server exposes named connections, optional SSH tunnels, and runtime
|
|
connection management: you add, edit, and remove connections through MCP tools
|
|
without restarting the harness. Both ship as an npx package and a Docker image,
|
|
so they run anywhere your MCP client does.
|
|
|
|
## Packages
|
|
|
|
| Package | Backend | Install |
|
|
| --- | --- | --- |
|
|
| [dbmole-mcp](packages/dbmole-mcp/README.md) | PostgreSQL, MySQL | `npx -y dbmole-mcp` |
|
|
| [esmole-mcp](packages/esmole-mcp/README.md) | Elasticsearch 7.x and 8.x | `npx -y esmole-mcp` |
|
|
|
|
Each package README documents its tools, connection fields, and Docker image in
|
|
full. This page covers what the two servers share.
|
|
|
|
## Quick start
|
|
|
|
Add either server — or both — to your client's `.mcp.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"dbmole": { "command": "npx", "args": ["-y", "dbmole-mcp"] },
|
|
"esmole": { "command": "npx", "args": ["-y", "esmole-mcp"] }
|
|
}
|
|
}
|
|
```
|
|
|
|
That is enough to start a server. With no connections configured it still runs;
|
|
register one at runtime with `add_connection`, or supply connections up front
|
|
through one of the sources below.
|
|
|
|
## Shared design
|
|
|
|
Both servers inherit the same connection model from `@dbmole/core`.
|
|
|
|
**Connection sources.** Connections merge from three layers, highest priority
|
|
first. The prefix is `DBMOLE_` for dbmole and `ESMOLE_` for esmole.
|
|
|
|
| Priority | Source | How to set | Mutable at runtime |
|
|
| --- | --- | --- | --- |
|
|
| High | `<PREFIX>_CONNECTIONS` env | JSON array of connection objects | No (read-only) |
|
|
| Medium | Config file | `--config <path>` or `<PREFIX>_CONFIG`, shape `{ "connections": [...] }` | No (read-only) |
|
|
| Low | Persistent store | `~/.config/<server>/connections.json` (mode `0600`); override with `<PREFIX>_STORE` | Yes (via tools) |
|
|
|
|
Reads resolve name collisions by layer priority, and `list_connections` reports
|
|
the source layer that won. The write tools — `add_connection`,
|
|
`update_connection`, `remove_connection` — touch only the store layer; editing a
|
|
connection from the env or a config file returns an error naming its source.
|
|
|
|
**SSH tunnels.** Any connection may carry an `ssh` block to reach a host through
|
|
a bastion. Authentication accepts a password, a private key (inline or by path,
|
|
with `~` expansion), or the SSH agent at `SSH_AUTH_SOCK`.
|
|
|
|
**Readonly mode.** A `readonly: true` connection blocks writes at the server, not
|
|
by trusting the caller. dbmole pins read-only transactions; esmole enforces an
|
|
HTTP method-and-path allowlist. Treat it as defence in depth — still connect with
|
|
a least-privilege user for a hard guarantee.
|
|
|
|
**Persistent store.** The store is a plaintext JSON file written with `0600`
|
|
permissions; whoever can read it owns the credentials in it. It is re-read on
|
|
every operation, so instances sharing one store file see each other's changes at
|
|
once. For secrets you do not want the tools to persist, prefer the env or config
|
|
layer.
|
|
|
|
See each package README for the backend-specific tools, field reference, and
|
|
defaults (ports, schemes, and so on).
|
|
|
|
## Repository layout
|
|
|
|
```
|
|
packages/
|
|
core/ @dbmole/core — shared Manager, registry, SSH tunnels, MCP plumbing (private)
|
|
dbmole-mcp/ PostgreSQL and MySQL server
|
|
esmole-mcp/ Elasticsearch server
|
|
```
|
|
|
|
`@dbmole/core` is private and never published. Each leaf package bundles it at
|
|
build time, so the published artifacts have no `@dbmole/core` dependency.
|
|
|
|
## Development
|
|
|
|
The repo is an npm workspace; run these from the root to cover every package:
|
|
|
|
```bash
|
|
npm run test:unit # fast unit tests (mocked IO)
|
|
npm run test:int # integration tests (needs Docker)
|
|
npm run coverage # unit tests with coverage
|
|
npm run typecheck # tsc across all packages
|
|
npm run lint # Biome check
|
|
npm run build # bundle each package to dist/
|
|
```
|
|
|
|
See [AGENTS.md](AGENTS.md) for the contributor style contract: code style,
|
|
TypeScript discipline, testing rules, and commit conventions.
|
|
|
|
## License
|
|
|
|
[MIT](LICENSE)
|