Hot-Reload MCP tools - #3747
Open
aaronburtle wants to merge 23 commits into
Open
Conversation
…registry-hot-reload # Conflicts: # src/Service.Tests/Mcp/McpMetadataHelperTests.cs
aaronburtle
requested review from
Alekhya-Polavarapu,
Aniruddh25,
JerryNixon,
RubenCerna2079,
anushakolan,
rusamant,
sourabh1007,
souvikghosh04,
stuartpa and
vadeveka
as code owners
August 1, 2026 09:51
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds robust hot-reload support for MCP tools by rebuilding and atomically publishing tool-registry snapshots whenever runtime configuration/metadata refreshes, keeping tools/list and tools/call aligned with the latest successfully applied generation across both HTTP and stdio transports.
Changes:
- Introduces an immutable, versioned MCP tool-registry snapshot model with ordered refresh tied into the hot-reload pipeline.
- Serializes initial runtime initialization and file-triggered hot reloads through a shared gate, and adds coordinated shutdown draining/cancellation.
- Propagates cancellation across metadata discovery and query execution paths, and adds stdio
notifications/tools/list_changed.
Reviewed changes
Copilot reviewed 58 out of 58 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/Service/Utilities/RuntimeInitializationHelper.cs | Centralizes serialized startup init path. |
| src/Service/Utilities/RuntimeConfigLoaderShutdownService.cs | Drains loader work on host shutdown. |
| src/Service/Utilities/McpStdioHelper.cs | Runs serialized init + loader drain. |
| src/Service/Telemetry/LogLevelInitializer.cs | Adds cancellation checks on reload. |
| src/Service/Startup.cs | Uses new init helper + shutdown service. |
| src/Service/Program.cs | Registers stdio tool-list notifier services. |
| src/Service.Tests/UnitTests/SqlQueryExecutorUnitTests.cs | Adds linked cancellation unit test. |
| src/Service.Tests/UnitTests/McpStdoutWriterTests.cs | Tests nonblocking dispose with blocked stdout. |
| src/Service.Tests/UnitTests/McpStdioToolListChangedNotifierTests.cs | Adds notifier behavior/unit coverage. |
| src/Service.Tests/UnitTests/McpStdioServerRunAsyncTests.cs | Verifies notifier initialization handshake behavior. |
| src/Service.Tests/UnitTests/McpStdioServerInitializeTests.cs | Ensures listChanged advertised only when supported. |
| src/Service.Tests/UnitTests/McpStdioHelperTests.cs | Ensures stdio init order: metadata then registry. |
| src/Service.Tests/UnitTests/McpServerConfigurationTests.cs | Verifies HTTP capabilities + snapshot discovery filtering. |
| src/Service.Tests/UnitTests/ConfigFileWatcherUnitTests.cs | Adds serialization/drain/shutdown tests for loader. |
| src/Service.Tests/Mcp/McpToolRegistryTests.cs | Updates tests for snapshot/ordering/semantic comparison. |
| src/Service.Tests/Mcp/McpStdioToolRegistryHotReloadIntegrationTests.cs | Adds stdio hot-reload notification integration test. |
| src/Service.Tests/Mcp/McpMetadataHelperTests.cs | Updates metadata helper tests + new overload coverage. |
| src/Service.Tests/Mcp/McpInitialHotReloadSerializationTests.cs | Tests startup vs reload serialization correctness. |
| src/Service.Tests/Mcp/McpHttpToolRegistryHotReloadIntegrationTests.cs | Adds HTTP hot-reload integration coverage. |
| src/Service.Tests/Mcp/DynamicCustomToolTests.cs | Updates tool metadata init to explicit factory/config. |
| src/Service.Tests/Mcp/DynamicCustomToolMsSqlIntegrationTests.cs | Updates integration tests for new init signature. |
| src/Core/Services/OpenAPI/OpenApiDocumentor.cs | Adds cancellation checks on config change. |
| src/Core/Services/MetadataProviders/SqlMetadataProvider.cs | Adds cancellation-aware metadata discovery APIs. |
| src/Core/Services/MetadataProviders/MySqlMetadataProvider.cs | Propagates cancellation to schema discovery. |
| src/Core/Services/MetadataProviders/MsSqlMetadataProvider.cs | Propagates cancellation to metadata + autoentities. |
| src/Core/Services/MetadataProviders/MetadataProviderFactory.cs | Runs init with cancellation during reload. |
| src/Core/Services/MetadataProviders/ISqlMetadataProvider.cs | Adds default cancellation-aware interface method. |
| src/Core/Services/MetadataProviders/IMetadataProviderFactory.cs | Adds default cancellation-aware interface method. |
| src/Core/Services/MetadataProviders/CosmosSqlMetadataProvider.cs | Adds cancellation-aware no-op init. |
| src/Core/Services/GraphQLSchemaCreator.cs | Adds cancellation checks on config change. |
| src/Core/Resolvers/QueryExecutor.cs | Adds linked cancellation + token-aware overloads. |
| src/Core/Resolvers/PostgreSqlExecutor.cs | Adds cancellation to MI token acquisition. |
| src/Core/Resolvers/MySqlQueryExecutor.cs | Adds cancellation to MI token acquisition. |
| src/Core/Resolvers/MsSqlQueryExecutor.cs | Adds cancellation to OBO/MI token acquisition. |
| src/Core/Resolvers/IQueryExecutor.cs | Adds default cancellation-aware interface methods. |
| src/Core/Resolvers/Factories/QueryManagerFactory.cs | Adds cancellation checks on config change. |
| src/Core/Resolvers/Factories/QueryEngineFactory.cs | Adds cancellation checks on config change. |
| src/Core/Resolvers/Factories/MutationEngineFactory.cs | Adds cancellation checks on config change. |
| src/Core/Authorization/AuthorizationResolver.cs | Adds cancellation checks on config change. |
| src/Config/RuntimeConfigLoader.cs | Adds cancellation-aware ordered event signaling. |
| src/Config/HotReloadEventHandler.cs | Adds MCP registry event + docs. |
| src/Config/HotReloadEventArgs.cs | Adds CancellationToken to hot-reload args. |
| src/Config/FileSystemRuntimeConfigLoader.cs | Serializes reload + adds StopAsync drain/cancel. |
| src/Config/DabConfigEvents.cs | Adds MCP tool registry ordered event name. |
| src/Config/ConfigFileWatcher.cs | Adds stoppable watcher abstraction + lifecycle fixes. |
| src/Azure.DataApiBuilder.Mcp/Utils/McpMetadataHelper.cs | Adds overload accepting explicit metadata factory. |
| src/Azure.DataApiBuilder.Mcp/Core/McpToolRegistryRefreshService.cs | Adds refresh service + notifier integration. |
| src/Azure.DataApiBuilder.Mcp/Core/McpToolRegistryInitializer.cs | Removes startup-only hosted initializer. |
| src/Azure.DataApiBuilder.Mcp/Core/McpToolRegistry.cs | Implements immutable snapshot registry + canonical compare. |
| src/Azure.DataApiBuilder.Mcp/Core/McpStdoutWriter.cs | Makes dispose nonblocking under blocked stdout. |
| src/Azure.DataApiBuilder.Mcp/Core/McpStdioToolListChangedNotifier.cs | Implements stdio list-changed notifications. |
| src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs | Adds handshake gating + uses advertised snapshot. |
| src/Azure.DataApiBuilder.Mcp/Core/McpServiceCollectionExtensions.cs | Registers refresh service + removes config tool DI. |
| src/Azure.DataApiBuilder.Mcp/Core/McpServerConfiguration.cs | Uses advertised snapshot; disables HTTP listChanged. |
| src/Azure.DataApiBuilder.Mcp/Core/DynamicCustomTool.cs | Regenerates per snapshot + explicit metadata init. |
| src/Azure.DataApiBuilder.Mcp/Core/CustomMcpToolFactory.cs | Builds dynamic tools per generation (fail-fast). |
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.
Why make this change?
Closes #3066
DAB previously constructed the MCP tool registry only once during startup. Runtime configuration hot-reload could therefore leave MCP discovery stale when custom tools were added, removed, renamed, enabled, disabled, or given updated descriptions or stored-procedure parameters.
This change keeps MCP discovery and execution aligned with the latest successfully refreshed configuration and metadata generation.
What is this change?
tools/listandtools/callobserve either the complete previous generation or the complete new generation—never a partially rebuilt registry.IMcpToolimplementations remain available across generations.notifications/tools/list_changedsupport.HostOptions.ShutdownTimeout; synchronous disposal remains nonblocking.HttpContext.RequestAborted, so either source can stop database work.How was this tested?
notifications/tools/list_changednotification.HttpContext.RequestAbortedboth cancel the same operation.Sample Request(s)
No REST or GraphQL wire shape changes are introduced.
Start DAB in MCP stdio mode using a development-mode configuration:
Initialize the MCP session and request the initial tool list:
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"sample-client","version":"1.0.0"}}} {"jsonrpc":"2.0","method":"notifications/initialized","params":{}} {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}While DAB remains running, enable a stored-procedure entity as a custom MCP tool:
{ "entities": { "GetBook": { "source": { "object": "dbo.GetBook", "type": "stored-procedure" }, "mcp": { "custom-tool": true } } } }After the configuration reload succeeds, an initialized stdio client receives:
{"jsonrpc":"2.0","method":"notifications/tools/list_changed","params":{}}Request the tool list again to retrieve the newly published snapshot:
{"jsonrpc":"2.0","id":3,"method":"tools/list","params":{}}