fix: boot without a live DB and connect lazily on first query - #57
Open
mwm-pw wants to merge 2 commits into
Open
fix: boot without a live DB and connect lazily on first query#57mwm-pw wants to merge 2 commits into
mwm-pw wants to merge 2 commits into
Conversation
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>
mwm-pw
force-pushed
the
fix/non-fatal-boot-lazy-db-connect
branch
from
June 18, 2026 17:00
f9806fc to
94ef7ad
Compare
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #58
Problem
The server calls
initialize_pool()before starting the stdio transport (run_async_server), andregister_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 seesConnection closedand 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._execute_queryestablishes the pool lazily on first use, and if the DB is still unreachable returns a clear, actionable error instead of crashing.2002/2003/2006/2013, or a failedacquire) 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_queryis unchanged.Verification
Driving the MCP stdio protocol with the DB pointed at a closed port (no tunnel):
initializehandshake succeeds (serverInforeturned).tools/listreturns all tools — registration works with no live pool.tools/callreturnsisError: truewithDatabase 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.