Repository navigation
Fixed nested value envelope in MCP stored procedure responses - #3868
Open
Vaishali123t wants to merge 4 commits into
Open
Vaishali123t wants to merge 4 commits into
Vaishali123t wants to merge 4 commits into
Conversation
Unwrap DAB’s { "value": [...] } response in built-in and custom MCP tools, and add regression tests for both paths.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Author
|
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The focused fix covers both execution paths with regression tests and no blocking issues identified; tests were not executed.
No open issues 🎉
What changed in this PR
Fixes nested value envelopes in DAB’s built-in and custom MCP stored procedure responses.
Changes:
- Centralizes envelope unwrapping and array normalization.
- Applies the shared helper to both execution paths.
- Adds regression tests and tightens SQL Server integration assertions.
| File | Description |
|---|---|
| src/Service.Tests/Mcp/ExecuteEntityToolTests.cs | Tests built-in envelope unwrapping. |
| src/Service.Tests/Mcp/ExecuteEntityToolMsSqlIntegrationTests.cs | Requires a direct result array. |
| src/Service.Tests/Mcp/DynamicCustomToolTests.cs | Tests custom-tool envelope unwrapping. |
| src/Service.Tests/Mcp/DynamicCustomToolMsSqlIntegrationTests.cs | Requires a direct result array. |
| src/Azure.DataApiBuilder.Mcp/Utils/McpResponseBuilder.cs | Adds shared result normalization. |
| src/Azure.DataApiBuilder.Mcp/Core/DynamicCustomTool.cs | Uses shared normalization. |
| src/Azure.DataApiBuilder.Mcp/BuiltInTools/ExecuteEntityTool.cs | Uses shared normalization. |
Review effort: Balanced
Vaishali123t
marked this pull request as draft
October 20, 2026 15:24
Author
|
@microsoft-github-policy-service agree |
Vaishali123t
marked this pull request as ready for review
October 20, 2026 15:55
Mohit G (gmohit21)
approved these changes
Oct 27, 2026
Member
|
/azp run |
|
Azure Pipelines: Successfully started running 6 pipeline(s). |
Member
|
/azp run |
|
Azure Pipelines: Successfully started running 6 pipeline(s). |
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.
Unwrap DAB’s { "value": [...] } response in built-in and custom MCP tools, and add regression tests for both paths.
Why make this change?
What is this change?
{
"entity": "GetBook",
"value": {
"value": [{ "id": 1 }]
},
"status": "success"
}
After:
{
"entity": "GetBook",
"value": [{ "id": 1 }],
"status": "success"
}
How was this tested?
Build
powershell
dotnet build src\Azure.DataApiBuilder.Mcp\Azure.DataApiBuilder.Mcp.csproj --no-restore --verbosity quiet
Result: passed with zero warnings and zero errors.
Focused unit tests
powershell
dotnet test src\Service.Tests\Azure.DataApiBuilder.Service.Tests.csproj --no-build --no-restore --filter "FullyQualifiedName
Azure.DataApiBuilder.Service.Tests.Mcp.ExecuteEntityToolTests|FullyQualifiedNameAzure.DataApiBuilder.Service.Tests.Mcp.DynamicCustomToolTests" --verbosity quietResult: 106 passed, 0 failed, 0 skipped.
The six new regression cases were also run against the original adapter
implementation: all six failed before the fix and passed with the fix.
They verify empty results, multiple rows, and preservation of a legitimate
array-valued column named value through both tools.
SQL-backed integration tests
The following classes were run separately against an isolated local
SQL Server 2022 database:
powershell
dotnet test src\Service.Tests\Azure.DataApiBuilder.Service.Tests.csproj --no-build --no-restore --filter "FullyQualifiedName~ExecuteEntityToolMsSqlIntegrationTests" --verbosity quiet
dotnet test src\Service.Tests\Azure.DataApiBuilder.Service.Tests.csproj --no-build --no-restore --filter "FullyQualifiedName~DynamicCustomToolMsSqlIntegrationTests" --verbosity quiet
Results: 8/8 built-in-tool tests and 16/16 custom-tool tests passed.
Environment qualification: the unmodified shared fixture requires newer
SQL vector/native JSON types unavailable on this local SQL Server 2022
instance. A reviewer-only setup configured the isolated database and used
nvarchar(max) for those unrelated fixture columns. The stored procedures,
PR implementation, and PR test assertions were unchanged. These results
are not an unmodified full-suite or CI pass.
Additional reviewer-only HTTP validation
Seven additional checks passed through DAB's in-process HTTP test server
against the real SQL database:
These checks used a temporary review harness, not tests included in this PR.
No full cross-database suite or CI pass is claimed.
Sample Request(s)
Using the repository's MSSQL test configuration, after initializing an MCP
session, send these tools/call requests to /mcp with the negotiated
protocol version, session header, and appropriate authentication.
Built-in tool:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_entity",
"arguments": {
"entity": "GetBook",
"parameters": { "id": 1 }
}
}
}
Equivalent custom tool:
json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_book",
"arguments": { "id": 1 }
}
}
For both tools, the decoded JSON inside MCP result.content[0].text
contains a single value array holding the actual book rows. The first
row has id: 1; the engine's additional value envelope is absent.
A nonexistent ID returns "value": [].
REST compatibility control:
http
GET /api/GetBook?id=1
The REST response retains its established {"value":[...]} envelope.
No CLI behavior changes are introduced.