Skip to content

fix: boot without a live DB and connect lazily on first query - #57

Open
mwm-pw wants to merge 2 commits into
MariaDB:mainfrom
mwm-pw:fix/non-fatal-boot-lazy-db-connect
Open

fix: boot without a live DB and connect lazily on first query#57
mwm-pw wants to merge 2 commits into
MariaDB:mainfrom
mwm-pw:fix/non-fatal-boot-lazy-db-connect

Conversation

@mwm-pw

@mwm-pw mwm-pw commented Jun 18, 2026

Copy link
Copy Markdown

Closes #58

Problem

The server calls initialize_pool() before starting the stdio transport (run_async_server), and register_tools() raises if the pool is not yet initialized. When the database sits behind a tunnel (SSH/port-forward) that isn't up at launch, the connect fails and the process exits before the transport ever comes up. The MCP client only sees Connection closed and can't recover without a manual reconnect/restart once the tunnel is established — a chicken-and-egg between "server needs DB to start" and "DB only reachable after I start working".

This affects any deployment where the DB is reached through a tunnel that is opened on demand.

Change

Make boot resilient; connect lazily:

  • register_tools() no longer requires a live pool — tools register unconditionally so the server comes up connected.
  • Startup pool init is best-effort (warms the pool when the DB is already reachable) but never fatal.
  • _execute_query establishes the pool lazily on first use, and if the DB is still unreachable returns a clear, actionable error instead of crashing.
  • Connection-level errors (2002/2003/2006/2013, or a failed acquire) reset the pool so the next query rebuilds it — a dropped tunnel self-heals.

Net: the server stays connected regardless of DB/tunnel state; queries succeed as soon as the database is reachable, with no client reconnect. Read-only enforcement in _execute_query is unchanged.

Verification

Driving the MCP stdio protocol with the DB pointed at a closed port (no tunnel):

  • initialize handshake succeeds (serverInfo returned).
  • tools/list returns all tools — registration works with no live pool.
  • tools/call returns isError: true with Database not reachable at <host>:<port> … ensure the tunnel is up, then retry., and the server stays up.

Before this change, the process exited at startup and the client saw Connection closed.

The server called initialize_pool() before starting the stdio transport,
and register_tools() raised if the pool was not yet initialized. When the
database sits behind a tunnel that is not up at launch, the connect failed
and the process exited before the transport came up — the MCP client only
saw "Connection closed", and could not recover without a manual reconnect
or restart once the tunnel was established.

Make boot resilient instead:
- register_tools() no longer requires a live pool; tools register
  unconditionally so the server comes up connected.
- startup pool init is best-effort (warms the pool when the DB is already
  reachable) but never fatal.
- _execute_query establishes the pool lazily on first use and, if the DB is
  still unreachable, returns a clear actionable error instead of crashing.
- connection-level errors (2002/2003/2006/2013, or a failed acquire) reset
  the pool so the next query rebuilds it — a dropped tunnel self-heals.

The server now stays connected regardless of DB/tunnel state; queries
succeed as soon as the database is reachable, with no client reconnect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ency

initialize_pool() checks `self.pool is None` then awaits create_safe_pool,
so two concurrent first queries both pass the check and both build a pool;
the second assignment overwrites the first and leaks its connections. Guard
the create with an asyncio.Lock and re-check under it, so only one pool is
ever built. Adds a regression test asserting a single pool across 8
concurrent initialize_pool() calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Server exits at startup when the database is unreachable; stdio client only sees "Connection closed" and can't recover

1 participant