Skip to content

Fixed nested value envelope in MCP stored procedure responses - #3868

Open
Vaishali123t wants to merge 4 commits into
Azure:mainfrom
Vaishali123t:Vaishali123t/fix/mcp-response-double-values
Open

Vaishali123t wants to merge 4 commits into
Azure:mainfrom
Vaishali123t:Vaishali123t/fix/mcp-response-double-values

Conversation

@Vaishali123t

@Vaishali123t Vaishali123t commented Oct 20, 2026 •

Copy link
Copy Markdown

Unwrap DAB’s { "value": [...] } response in built-in and custom MCP tools, and add regression tests for both paths.

Why make this change?

  • Fixes Double value in MCP response #3848 — MCP stored-procedure responses contain a duplicate value wrapper, making returned rows harder to consume.
  • The SQL engine’s SqlResponseHelpers.OkResponse() already wraps result rows in { "value": [...] }. Both MCP adapters then placed that complete engine response inside their own value field, producing the nested shape shown in the issue.

What is this change?

  • Unwrap the engine’s outer response envelope in both affected paths: built-in execute_entity and dynamic custom MCP tools. Preserve the rows themselves—including any legitimate array-valued column named value.
  • Before, for one returned row:
    {
    "entity": "GetBook",
    "value": {
    "value": [{ "id": 1 }]
    },
    "status": "success"
    }

After:
{
"entity": "GetBook",
"value": [{ "id": 1 }],
"status": "success"
}

  • Regression tests for both tools use SqlResponseHelpers.OkResponse() and verify empty results, multiple rows, and a row with an array-valued value column remain unchanged after unwrapping the outer envelope.

How was this tested?

  • Integration Tests
  • Unit Tests

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 "FullyQualifiedNameAzure.DataApiBuilder.Service.Tests.Mcp.ExecuteEntityToolTests|FullyQualifiedNameAzure.DataApiBuilder.Service.Tests.Mcp.DynamicCustomToolTests" --verbosity quiet

Result: 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:

  • execute_entity: single-row, empty and multirow results.
  • Dynamic custom tools: single-row, empty and multirow results.
  • REST stored-procedure response: retained its existing single value envelope.

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.

Unwrap DAB’s { "value": [...] } response in built-in and custom MCP tools, and add regression tests for both paths.
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Vaishali123t

Copy link
Copy Markdown
Author

Vaishali123t please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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
Vaishali123t marked this pull request as draft October 20, 2026 15:24
@Vaishali123t

Vaishali123t commented Oct 20, 2026 •

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Vaishali123t
Vaishali123t marked this pull request as ready for review October 20, 2026 15:55
@gmohit21

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).

@gmohit21

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Double value in MCP response

4 participants