You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In every 2.1.x build, dab start --mcp-stdioregisters entities but never infers their database objects. The MCP handshake succeeds, tools/list returns the full tool surface, and then every tool call fails:
Database object for entity 'MyTable' has not been inferred.
read_records reports the same condition differently:
Entity 'MyTable' is not defined in the configuration.
The same config, on the same machine, in the same minute, works perfectly over REST.
{"toolName":"describe_entities","status":"error",
"error":{"type":"DataApiBuilderError",
"message":"Database object for entity 'MyTable' has not been inferred."}}
Works — identical config, identical connection string, same shell:
dab start # REST mode
curl "http://localhost:5000/api/MyTable?\$first=1"
HTTP 200, real rows, all columns.
Expected behaviour
--mcp-stdio should infer database objects for configured entities, exactly as REST mode does.
Version bracket
version
published
--mcp-stdio
REST
2.0.12 (GA)
2026-08-20
PASS
PASS
2.1.0-rc
2026-08-11
FAIL
PASS
2.1.3-rc
2026-08-25
FAIL
PASS
Same machine, same config, same database, same connection string throughout.
What we ruled out
Config shape — the minimal one-entity config above fails identically to our real 28-entity config.
Config discovery — an explicit --config with an absolute path changes nothing. Running from a directory containing no config produces no response at all, which is a different failure, so the file is definitely being found and parsed.
The MCP client — the repro above is raw JSON-RPC piped into stdin, no client involved.
Connectivity, credentials, permissions — REST serves the same entity from the same connection string; an independent SQL client sees the table and rows as the same login.
Root cause
Confirmed by reading main, not inferred from behaviour. Schema inference is reachable only through the ASP.NET Core startup path, which stdio mode skips:
1. src/Service/Program.cs — StartEngine returns before the host is ever started
IHosthost=CreateHostBuilder(args,runMcpStdio,mcpRole).Build();if(runMcpStdio){returnMcpStdioHelper.RunMcpStdioHost(host);// <-- returns here}// Normal web modehost.Run();
2. src/Service/Utilities/McpStdioHelper.cs — RunMcpStdioHost initialises tools, and only tools
So in stdio mode the tool registry knows the entity names (they come from config), while IMetadataProviderFactory is never initialised and no entity ever gets a database object. That is exactly the observed split: tools/list succeeds, every tool call fails.
This is a side effect of #3676 "Avoid starting web host in MCP stdio mode" (merged 2026-07-09, fixing #3675). That change was correct in itself — stdio mode should not bind an HTTP port — but PerformOnConfigChangeAsync did more than serve HTTP, and nothing took over its metadata-initialisation duty on the stdio path.
Suggested fix
Have RunMcpStdioHost initialise the metadata provider before entering the JSON-RPC loop — either by calling IMetadataProviderFactory.InitializeAsync() directly from DI, or by extracting the non-HTTP portion of PerformOnConfigChangeAsync (config validation + metadata init) into something both paths call. RunMcpStdioHost already resolves services from host.Services, so the plumbing is there.
Worth noting for whoever picks this up: #3430 reports that stdio blocks the initialize response until introspection finishes. Restoring inference on this path will bring that latency back, so the two probably want solving together.
--prerelease currently resolves to 2.1.3-rc, so anyone following the common dotnet tool install -g microsoft.dataapibuilder --prerelease advice lands on a build where MCP stdio cannot serve any entity. --version 2.0.12 is the working install today.
Investigated and written with Claude Code (Νύξ) 🌑 — version bracketing, the REST/stdio control and the root-cause trace were worked out together over one session. A fix is on the way as a PR.
Describe the bug
In every
2.1.xbuild,dab start --mcp-stdioregisters entities but never infers their database objects. The MCP handshake succeeds,tools/listreturns the full tool surface, and then every tool call fails:read_recordsreports the same condition differently:The same config, on the same machine, in the same minute, works perfectly over REST.
This does not reproduce on
2.0.12.Repro
dab-config.json— one entity, nothing exotic:{ "data-source": { "database-type": "mssql", "connection-string": "@env('MY_CONN')" }, "runtime": { "rest": { "enabled": true, "path": "/api" }, "graphql": { "enabled": false }, "host": { "mode": "development", "cors": { "origins": [], "allow-credentials": false }, "authentication": { "provider": "StaticWebApps" } }, "mcp": { "enabled": true, "dml-tools": { "describe-entities": true, "create-record": false, "update-record": false, "delete-record": false, "execute-entity": true } } }, "entities": { "MyTable": { "source": { "object": "dbo.MyTable", "type": "table" }, "permissions": [{ "role": "anonymous", "actions": ["read"] }] } } }(
$schemais omitted deliberately — the repro behaves the same with no$schema, with thev1.7.93URL, and with av2.1.3-rcURL, so it is not a factor.)Fails — drive the stdio server by hand, so no MCP client is involved:
{"toolName":"describe_entities","status":"error", "error":{"type":"DataApiBuilderError", "message":"Database object for entity 'MyTable' has not been inferred."}}Works — identical config, identical connection string, same shell:
HTTP 200, real rows, all columns.Expected behaviour
--mcp-stdioshould infer database objects for configured entities, exactly as REST mode does.Version bracket
--mcp-stdioSame machine, same config, same database, same connection string throughout.
What we ruled out
--configwith an absolute path changes nothing. Running from a directory containing no config produces no response at all, which is a different failure, so the file is definitely being found and parsed.initializeand the tool call makes no difference. (We checked this because of --mcp-stdio blocks initialize response until all schema introspection completes, causing MCP reconnect timeouts #3430.)Root cause
Confirmed by reading
main, not inferred from behaviour. Schema inference is reachable only through the ASP.NET Core startup path, which stdio mode skips:1.
src/Service/Program.cs—StartEnginereturns before the host is ever started2.
src/Service/Utilities/McpStdioHelper.cs—RunMcpStdioHostinitialises tools, and only toolsNo
host.StartAsync(), soStartup.Configurenever runs.3.
src/Service/Startup.cs:822—Configureis where inference is triggered4.
src/Service/Startup.cs:1431— and that is the only caller ofInitializeAsyncSo in stdio mode the tool registry knows the entity names (they come from config), while
IMetadataProviderFactoryis never initialised and no entity ever gets a database object. That is exactly the observed split:tools/listsucceeds, every tool call fails.This is a side effect of #3676 "Avoid starting web host in MCP stdio mode" (merged 2026-07-09, fixing #3675). That change was correct in itself — stdio mode should not bind an HTTP port — but
PerformOnConfigChangeAsyncdid more than serve HTTP, and nothing took over its metadata-initialisation duty on the stdio path.Suggested fix
Have
RunMcpStdioHostinitialise the metadata provider before entering the JSON-RPC loop — either by callingIMetadataProviderFactory.InitializeAsync()directly from DI, or by extracting the non-HTTP portion ofPerformOnConfigChangeAsync(config validation + metadata init) into something both paths call.RunMcpStdioHostalready resolves services fromhost.Services, so the plumbing is there.Worth noting for whoever picks this up: #3430 reports that stdio blocks the
initializeresponse until introspection finishes. Restoring inference on this path will bring that latency back, so the two probably want solving together.Environment
dotnet tool install -g microsoft.dataapibuilder --version <v>Encrypt=True;TrustServerCertificate=TrueSide note
--prereleasecurrently resolves to2.1.3-rc, so anyone following the commondotnet tool install -g microsoft.dataapibuilder --prereleaseadvice lands on a build where MCP stdio cannot serve any entity.--version 2.0.12is the working install today.Investigated and written with Claude Code (Νύξ) 🌑 — version bracketing, the REST/stdio control and the root-cause trace were worked out together over one session. A fix is on the way as a PR.