From a840e88b08071951947c821a5354b93209fa7864 Mon Sep 17 00:00:00 2001 From: Aaron Burtle Date: Thu, 27 Aug 2026 19:37:50 -0700 Subject: [PATCH 1/3] fix white space in comma separated lists --- .../BuiltInTools/ReadRecordsTool.cs | 2 +- .../Mcp/ReadRecordsToolMsSqlIntegrationTests.cs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs index 8da3c4856a..26a4e1451f 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs @@ -201,7 +201,7 @@ public async Task ExecuteAsync( if (!string.IsNullOrWhiteSpace(select)) { // Update the context to specify which fields will be returned from the entity. - IEnumerable fieldsReturnedForFind = select.Split(",").ToList(); + IEnumerable fieldsReturnedForFind = select.Split(',').Select(field => field.Trim()).ToList(); context.UpdateReturnFields(fieldsReturnedForFind); } diff --git a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs index 26e07b359c..3d919d565e 100644 --- a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs +++ b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs @@ -61,6 +61,23 @@ public async Task ReadRecords_WithSelect_ReturnsSelectedFields() Assert.IsTrue(firstRecord.TryGetProperty("title", out _), "Expected 'title' field in result."); } + /// + /// Reads records with whitespace after a comma in the select clause. + /// + [TestMethod] + public async Task ReadRecords_WithWhitespaceAfterSelectComma_ReturnsSelectedFields() + { + CallToolResult result = await ExecuteReadAsync("Book", select: "id, title"); + + AssertSuccess(result, "ReadRecords with whitespace after a select comma should succeed."); + + JsonElement root = ParseResultRoot(result); + JsonElement records = GetRecordsArray(root); + JsonElement firstRecord = records[0]; + Assert.IsTrue(firstRecord.TryGetProperty("id", out _), "Expected 'id' field in result."); + Assert.IsTrue(firstRecord.TryGetProperty("title", out _), "Expected 'title' field in result."); + } + /// /// Reads records with an OData filter expression and verifies filtered results are returned. /// From 3fb708109ea434e7741bac70f74738a534ab543f Mon Sep 17 00:00:00 2001 From: Aaron Burtle Date: Tue, 1 Sep 2026 15:57:40 -0700 Subject: [PATCH 2/3] validate empty read_records select fields --- .../BuiltInTools/ReadRecordsTool.cs | 7 ++++++- .../Mcp/ReadRecordsToolMsSqlIntegrationTests.cs | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs index 26a4e1451f..bd33dd8433 100644 --- a/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs +++ b/src/Azure.DataApiBuilder.Mcp/BuiltInTools/ReadRecordsTool.cs @@ -201,7 +201,12 @@ public async Task ExecuteAsync( if (!string.IsNullOrWhiteSpace(select)) { // Update the context to specify which fields will be returned from the entity. - IEnumerable fieldsReturnedForFind = select.Split(',').Select(field => field.Trim()).ToList(); + List fieldsReturnedForFind = select.Split(',').Select(field => field.Trim()).ToList(); + if (fieldsReturnedForFind.Any(string.IsNullOrEmpty)) + { + return McpResponseBuilder.BuildErrorResult(toolName, "InvalidArguments", "The 'select' argument cannot contain empty field names.", logger); + } + context.UpdateReturnFields(fieldsReturnedForFind); } diff --git a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs index 3d919d565e..519e2529ec 100644 --- a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs +++ b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs @@ -78,6 +78,20 @@ public async Task ReadRecords_WithWhitespaceAfterSelectComma_ReturnsSelectedFiel Assert.IsTrue(firstRecord.TryGetProperty("title", out _), "Expected 'title' field in result."); } + /// + /// Rejects empty field names in the select clause with a clear error. + /// + [DataTestMethod] + [DataRow("id,title,")] + [DataRow("id,,title")] + public async Task ReadRecords_WithEmptySelectField_ReturnsInvalidArguments(string select) + { + CallToolResult result = await ExecuteReadAsync("Book", select: select); + + AssertError(result, "The 'select' argument cannot contain empty field names."); + Assert.AreEqual("InvalidArguments", ParseResultRoot(result).GetProperty("error").GetProperty("type").GetString()); + } + /// /// Reads records with an OData filter expression and verifies filtered results are returned. /// From 95bf97b88cdcf424170c22d5294bf8691e6924b8 Mon Sep 17 00:00:00 2001 From: Aaron Burtle Date: Tue, 1 Sep 2026 18:42:23 -0700 Subject: [PATCH 3/3] fix read_records error assertion --- .../Mcp/ReadRecordsToolMsSqlIntegrationTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs index 519e2529ec..2c009e772e 100644 --- a/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs +++ b/src/Service.Tests/Mcp/ReadRecordsToolMsSqlIntegrationTests.cs @@ -88,8 +88,10 @@ public async Task ReadRecords_WithEmptySelectField_ReturnsInvalidArguments(strin { CallToolResult result = await ExecuteReadAsync("Book", select: select); - AssertError(result, "The 'select' argument cannot contain empty field names."); - Assert.AreEqual("InvalidArguments", ParseResultRoot(result).GetProperty("error").GetProperty("type").GetString()); + AssertError(result); + JsonElement error = ParseResultRoot(result).GetProperty("error"); + Assert.AreEqual("InvalidArguments", error.GetProperty("type").GetString()); + Assert.AreEqual("The 'select' argument cannot contain empty field names.", error.GetProperty("message").GetString()); } ///