Azure / Azure/data-api-builder

--mcp-stdio blocks initialize response until all schema introspection completes, causing MCP reconnect timeouts

Abierto
#3,430 1 comentario 3 reacciones 1 asignado Reclamado por @souvikghosh04 Ver en GitHub
bug cri mcp-server perf
Lenguaje dominante
C#
Estrellas
1.5k
Forks
370
Merge medio
3 d 22 h
PR fusionados (30 d)
9

Descripción

## Summary

When DAB starts in `--mcp-stdio` mode, it does not send the MCP `initialize` response until it has finished introspecting the schema for every registered entity. Against a remote Azure SQL Managed Instance (~160 ms round-trip per query × 2 queries per entity × 53 entities), this results in a **~17-second startup delay** before any MCP message is emitted on stdout.

This works fine on the initial connection because MCP clients wait indefinitely for first contact. However, on **reconnect**, clients typically apply a shorter timeout. Any client whose reconnect timeout is less than the schema-introspection time fails with a connection error, even though the DAB process is healthy and the database is reachable.

## Environment

- **DAB version:** Microsoft.DataApiBuilder 1.7.92
- **Database:** Azure SQL Managed Instance (remote, ~160 ms RTT)
- **Entities registered:** 53
- **MCP client:** Claude Code (desktop app)
- **OS:** Windows 11

## Steps to Reproduce

1. Register 50+ entities backed by a remote Azure SQL MI (≥ 100 ms RTT).
2. Run `dab start --config dab-config.json --mcp-stdio`.
3. Connect an MCP client (e.g. Claude Code). **First connection succeeds** after ~17 s.
4. Trigger a client reconnect (e.g. `/mcp` command in Claude Code). **Reconnect fails** — "Failed to reconnect" — because the client's reconnect timeout (< 17 s) expires before DAB emits the `initialize` response.

## Observed Behavior

DAB performs the full schema introspection synchronously before responding to the MCP `initialize` request:

```
t=0s Claude Code sends initialize
t=0s DAB starts schema introspection (53 entities × 2 queries × ~160ms = ~17s)
t=17s DAB sends initialize response ← too late for reconnect timeout
t=17s Claude Code has already given up; closes stdin
```

Wrapper log evidence:
```
[01:49:16.922Z] wrapper invoked
[01:49:16.922Z] client protocolVersion: 2025-11-25 ← initialize received immediately
[01:49:34.383Z] forwarding initialize response ← 17s later
[01:49:34.390Z] stdin EOF ← client already closed connection
```

## Expected Behavior

DAB should send the MCP `initialize` response **immediately** upon receiving the client's `initialize` request, then complete schema introspection in the background. The `tools/list` response can be delayed until introspection is done — the client will wait because the connection is already established.

Proposed flow:
```
t=0s Claude Code sends initialize
t=0s DAB sends initialize response immediately ← handshake complete
t=0s DAB starts schema introspection in background
t=17s DAB sends tools/list response (client has been waiting, connection alive)
```

## Workaround

Wrap the `dab` process in a Node.js stdio proxy that:
1. Intercepts the client's `initialize` request and replies immediately with a minimal valid response.
2. Discards DAB's own `initialize` response when it eventually arrives.
3. Passes all subsequent traffic (`tools/list`, `tools/call`, etc.) through normally.

This workaround is required to make reconnects usable against remote databases with non-trivial schema introspection times.

## Impact

- Any MCP client with a reconnect timeout shorter than the schema-introspection time cannot use reconnect commands — only a full client restart works.
- Severity increases with entity count and database RTT. On a local SQL Server instance this is unlikely to manifest; on a remote managed instance with 50+ entities it is reliably reproducible.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.