Skip to main content
July 28, 2026 MCP shipped its 2026-07-28 revision: the initialize handshake is gone, requests are self-contained, and the protocol becomes request/response. We adopted it alongside the TypeScript SDK v2 that implements it. The upgrade ships in DBHub 1.0.0 — 2026-07-28 clients get the new protocol on the same /mcp endpoint that keeps serving 2025-era clients. This post shows each change with before/after code, and what we evaluated but did not build.

1. The stateless core

DBHub’s HTTP transport has always been stateless — no session affinity, safe behind a round-robin load balancer. The 2025-era protocol assumed a session, so we faked statelessness: a fresh transport and server instance per request, session management disabled by hand. Before:
After (SDK v2’s createMcpHandler — one factory, both protocol eras):
On 2026-07-28, each request carries protocol version, client identity, and capabilities in _meta — no initialize exchange, no Mcp-Session-Id. The per-request model we hand-rolled is now the native serving model; 2025-era clients are handled by the SDK’s built-in stateless fallback. stdio got the same treatment: server.connect(new StdioServerTransport()) became serveStdio(createServer). Result: ~25 lines of session-faking deleted. Running N replicas behind any load balancer is now spec-guaranteed instead of workaround-dependent.

2. Cacheable tools/list

DBHub’s tool list is fixed per configuration, yet every 2025-era client re-fetches it each session — the protocol had no way to say “this doesn’t change.” The 2026-07-28 revision adds ttlMs / cacheScope fields on cacheable results. Our entire change: Before:
After:
On the wire:
Result: clients skip re-fetching the tool list for five minutes at a time. Not “forever” because DBHub hot-reloads its TOML config and the tool list can change at runtime — the TTL bounds staleness.

3. Header-based routing

2026-07-28 clients send Mcp-Method and Mcp-Name headers on every Streamable HTTP request, so a gateway in front of DBHub can tell a write-capable execute_sql call from a search_objects call without parsing JSON bodies. Our change was one CORS line (the headers come from the SDK): Before:
After:
Result: an nginx front can throttle tool execution with no MCP awareness:

4. Evaluated and skipped: MRTR write confirmation

Multi-round-trip requests (MRTR) replace server-initiated elicitation: a tool returns resultType: "input_required" and the client retries with answers — which finally works over stateless HTTP. The obvious application for a database tool: a confirmation prompt before writes. We designed it and didn’t ship it:
  1. Confirmation is the host’s job. DBHub already annotates write-capable tools with destructiveHint: true, and hosts like Claude Code gate destructive calls behind their own approval UI. A server-side prompt double-confirms.
  2. The fallback is weak. Clients without elicitation degrade to a confirm: true argument, which models learn to set preemptively.
  3. It required new config. Every design added TOML knobs on top of the existing readonly boolean, creating conflicting semantics.
The evaluation did trigger a cleanup that needed no new config. Read-only enforcement used to re-interpret the readonly boolean in four places. It now flows through one pipeline: every statement is classified (read | dml | ddl | admin | unknown, dialect-aware), and the config compiles into a class→verdict policy. Before (one of four scattered interpretations):
After (all four sites consume one policy):
The verdict set can grow a confirm member later — when elicitation-capable clients are the norm, MRTR write confirmation slots into the two gate sites without touching config. Until then, readonly = true/false remains the entire configuration vocabulary.

5. Compatibility

  • 2025-era clients are unaffected. Same /mcp endpoint, same initialize handshake, served by the SDK’s stateless fallback. stdio clients see no difference.
  • One caveat for hand-rolled HTTP clients: the legacy path now answers with spec-standard SSE framing (event: message / data: {...}) instead of plain JSON bodies. MCP clients already accept both; a raw curl script needs to read the data: line.
  • No config migration. No TOML key is added or changed.

Takeaway

For DBHub, adoption was mostly deletion — the spec absorbed our workaround — plus two small opt-ins (cache hints, CORS headers). Everything here ships in DBHub 1.0.0. The source is at github.com/bytebase/dbhub; the adoption is a readable series of commits on main.