From a6690fc5dfd0764f1c5e04c69486bc45c092faf6 Mon Sep 17 00:00:00 2001 From: souvikghosh04 Date: Thu, 2 Apr 2026 20:47:36 +0530 Subject: [PATCH 1/3] fix: remove .enabled suffix from individual DML tool configure options (#3373) The dab configure command used option names like --runtime.mcp.dml-tools.describe-entities.enabled which implied a nested object structure ({ describe-entities: { enabled: true } }). The schema expects direct booleans ({ describe-entities: true }). Removed the .enabled suffix from 7 individual DML tool option names in ConfigureOptions.cs. Added 3 test methods (5 test cases) covering individual, bulk, and multi-tool configure scenarios. --- src/Cli.Tests/ConfigureOptionsTests.cs | 88 ++++++++++++++++++++++++++ src/Cli/Commands/ConfigureOptions.cs | 14 ++-- 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs index 5824b2e054..da52278769 100644 --- a/src/Cli.Tests/ConfigureOptionsTests.cs +++ b/src/Cli.Tests/ConfigureOptionsTests.cs @@ -1081,6 +1081,94 @@ public void TestConfigureDescriptionForMcpSettings(string descriptionValue) Assert.AreEqual(descriptionValue, runtimeConfig.Runtime.Mcp.Description); } + /// + /// Tests that running "dab configure --runtime.mcp.dml-tools.{tool} {value}" updates + /// the individual DML tool boolean in the runtime config. Each tool is a direct boolean + /// in the schema (e.g., "describe-entities": true), NOT a nested object with .enabled. + /// + [DataTestMethod] + [DataRow(true, DisplayName = "Enable individual DML tool: describe-entities")] + [DataRow(false, DisplayName = "Disable individual DML tool: describe-entities")] + public void TestConfigureIndividualDmlToolForMcpSettings(bool updatedValue) + { + // Arrange + SetupFileSystemWithInitialConfig(INITIAL_CONFIG); + + // Act: Set describe-entities via the corrected option name (no .enabled suffix) + ConfigureOptions options = new( + runtimeMcpDmlToolsDescribeEntitiesEnabled: updatedValue, + config: TEST_RUNTIME_CONFIG_FILE + ); + bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); + + // Assert + Assert.IsTrue(isSuccess); + string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); + Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); + } + + /// + /// Tests that running "dab configure --runtime.mcp.dml-tools.enabled {value}" sets all + /// DML tools at once via the bulk toggle. + /// + [DataTestMethod] + [DataRow(true, DisplayName = "Enable all DML tools at once")] + [DataRow(false, DisplayName = "Disable all DML tools at once")] + public void TestConfigureAllDmlToolsForMcpSettings(bool updatedValue) + { + // Arrange + SetupFileSystemWithInitialConfig(INITIAL_CONFIG); + + // Act: Set all tools via the bulk enabled toggle + ConfigureOptions options = new( + runtimeMcpDmlToolsEnabled: updatedValue, + config: TEST_RUNTIME_CONFIG_FILE + ); + bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); + + // Assert + Assert.IsTrue(isSuccess); + string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); + Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.CreateRecord); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.ReadRecords); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.UpdateRecord); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DeleteRecord); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.ExecuteEntity); + Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.AggregateRecords); + } + + /// + /// Tests that running "dab configure" with multiple individual DML tool options + /// correctly updates each tool independently. + /// + [TestMethod] + public void TestConfigureMultipleIndividualDmlToolsForMcpSettings() + { + // Arrange + SetupFileSystemWithInitialConfig(INITIAL_CONFIG); + + // Act: Enable describe-entities, disable create-record + ConfigureOptions options = new( + runtimeMcpDmlToolsDescribeEntitiesEnabled: true, + runtimeMcpDmlToolsCreateRecordEnabled: false, + config: TEST_RUNTIME_CONFIG_FILE + ); + bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); + + // Assert + Assert.IsTrue(isSuccess); + string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); + Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); + Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); + Assert.AreEqual(true, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); + Assert.AreEqual(false, runtimeConfig.Runtime.Mcp.DmlTools.CreateRecord); + } + /// /// Validates that `dab configure --show-effective-permissions` correctly displays /// effective permissions without modifying the config file. diff --git a/src/Cli/Commands/ConfigureOptions.cs b/src/Cli/Commands/ConfigureOptions.cs index be076d7983..970c09d052 100644 --- a/src/Cli/Commands/ConfigureOptions.cs +++ b/src/Cli/Commands/ConfigureOptions.cs @@ -212,25 +212,25 @@ public ConfigureOptions( [Option("runtime.mcp.dml-tools.enabled", Required = false, HelpText = "Enable DAB's MCP DML tools endpoint. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsEnabled { get; } - [Option("runtime.mcp.dml-tools.describe-entities.enabled", Required = false, HelpText = "Enable DAB's MCP describe entities tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.describe-entities", Required = false, HelpText = "Enable DAB's MCP describe entities tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsDescribeEntitiesEnabled { get; } - [Option("runtime.mcp.dml-tools.create-record.enabled", Required = false, HelpText = "Enable DAB's MCP create record tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.create-record", Required = false, HelpText = "Enable DAB's MCP create record tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsCreateRecordEnabled { get; } - [Option("runtime.mcp.dml-tools.read-records.enabled", Required = false, HelpText = "Enable DAB's MCP read record tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.read-records", Required = false, HelpText = "Enable DAB's MCP read record tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsReadRecordsEnabled { get; } - [Option("runtime.mcp.dml-tools.update-record.enabled", Required = false, HelpText = "Enable DAB's MCP update record tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.update-record", Required = false, HelpText = "Enable DAB's MCP update record tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsUpdateRecordEnabled { get; } - [Option("runtime.mcp.dml-tools.delete-record.enabled", Required = false, HelpText = "Enable DAB's MCP delete record tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.delete-record", Required = false, HelpText = "Enable DAB's MCP delete record tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsDeleteRecordEnabled { get; } - [Option("runtime.mcp.dml-tools.execute-entity.enabled", Required = false, HelpText = "Enable DAB's MCP execute entity tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.execute-entity", Required = false, HelpText = "Enable DAB's MCP execute entity tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsExecuteEntityEnabled { get; } - [Option("runtime.mcp.dml-tools.aggregate-records.enabled", Required = false, HelpText = "Enable DAB's MCP aggregate records tool. Default: true (boolean).")] + [Option("runtime.mcp.dml-tools.aggregate-records", Required = false, HelpText = "Enable DAB's MCP aggregate records tool. Default: true (boolean).")] public bool? RuntimeMcpDmlToolsAggregateRecordsEnabled { get; } [Option("runtime.mcp.dml-tools.aggregate-records.query-timeout", Required = false, HelpText = "Set the execution timeout in seconds for the aggregate-records MCP tool. Default: 30 (integer). Range: 1-600.")] From 4d5553a1af750dcbdf1433dee81236583cf5a69c Mon Sep 17 00:00:00 2001 From: souvikghosh04 Date: Fri, 3 Apr 2026 09:10:09 +0530 Subject: [PATCH 2/3] Copilot review fixes --- src/Cli.Tests/ConfigureOptionsTests.cs | 6 +++-- src/Cli.Tests/EndToEndTests.cs | 33 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs index da52278769..0c8bec97ec 100644 --- a/src/Cli.Tests/ConfigureOptionsTests.cs +++ b/src/Cli.Tests/ConfigureOptionsTests.cs @@ -1083,8 +1083,10 @@ public void TestConfigureDescriptionForMcpSettings(string descriptionValue) /// /// Tests that running "dab configure --runtime.mcp.dml-tools.{tool} {value}" updates - /// the individual DML tool boolean in the runtime config. Each tool is a direct boolean - /// in the schema (e.g., "describe-entities": true), NOT a nested object with .enabled. + /// the individual DML tool boolean in the runtime config. Most tools are configured as + /// direct booleans in the schema (e.g., "describe-entities": true) rather than nested + /// objects with .enabled; "aggregate-records" additionally supports an object form + /// when specifying a query-timeout. /// [DataTestMethod] [DataRow(true, DisplayName = "Enable individual DML tool: describe-entities")] diff --git a/src/Cli.Tests/EndToEndTests.cs b/src/Cli.Tests/EndToEndTests.cs index 4ae27f790f..1620e3e588 100644 --- a/src/Cli.Tests/EndToEndTests.cs +++ b/src/Cli.Tests/EndToEndTests.cs @@ -1271,4 +1271,37 @@ public void TestUpdateDatabaseType(string dbType, bool isSuccess) // Assert Assert.AreEqual(isSuccess, isError == 0); } + + /// + /// End-to-end test verifying that the corrected CLI option names for individual + /// MCP DML tools (without the .enabled suffix) are correctly parsed by + /// CommandLineParser and produce the expected config output. + /// + [DataTestMethod] + [DataRow("--runtime.mcp.dml-tools.describe-entities", "true", DisplayName = "E2E: configure describe-entities via CLI")] + [DataRow("--runtime.mcp.dml-tools.create-record", "false", DisplayName = "E2E: configure create-record via CLI")] + [DataRow("--runtime.mcp.dml-tools.read-records", "true", DisplayName = "E2E: configure read-records via CLI")] + [DataRow("--runtime.mcp.dml-tools.update-record", "true", DisplayName = "E2E: configure update-record via CLI")] + [DataRow("--runtime.mcp.dml-tools.delete-record", "false", DisplayName = "E2E: configure delete-record via CLI")] + [DataRow("--runtime.mcp.dml-tools.execute-entity", "true", DisplayName = "E2E: configure execute-entity via CLI")] + [DataRow("--runtime.mcp.dml-tools.aggregate-records", "false", DisplayName = "E2E: configure aggregate-records via CLI")] + public void TestConfigureIndividualDmlToolViaCli(string optionName, string value) + { + // Initialize the config file. + string[] initArgs = { "init", "-c", TEST_RUNTIME_CONFIG_FILE, "--host-mode", "development", "--database-type", + "mssql", "--connection-string", TEST_ENV_CONN_STRING }; + Program.Execute(initArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!); + + Assert.IsTrue(_runtimeConfigLoader!.TryLoadConfig(TEST_RUNTIME_CONFIG_FILE, out RuntimeConfig? runtimeConfig)); + Assert.IsNotNull(runtimeConfig); + + // Act: Run configure with the individual DML tool option through the full CLI parsing path. + string[] runtimeArgs = { "configure", "-c", TEST_RUNTIME_CONFIG_FILE, optionName, value }; + int exitCode = Program.Execute(runtimeArgs, _cliLogger!, _fileSystem!, _runtimeConfigLoader!); + + // Assert: Command succeeds and the config contains MCP DML tools section. + Assert.AreEqual(0, exitCode); + Assert.IsTrue(_runtimeConfigLoader!.TryLoadConfig(TEST_RUNTIME_CONFIG_FILE, out RuntimeConfig? updatedConfig)); + Assert.IsNotNull(updatedConfig?.Runtime?.Mcp?.DmlTools); + } } From 05842c7c860642c894c4550fdb4d79ac880ebfe7 Mon Sep 17 00:00:00 2001 From: souvikghosh04 Date: Tue, 7 Apr 2026 20:08:22 +0530 Subject: [PATCH 3/3] Remove constructor-based DML tool tests per reviewer feedback Keep only E2E tests that verify CLI option name parsing via Program.Execute(). --- src/Cli.Tests/ConfigureOptionsTests.cs | 90 -------------------------- 1 file changed, 90 deletions(-) diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs index 0c8bec97ec..5824b2e054 100644 --- a/src/Cli.Tests/ConfigureOptionsTests.cs +++ b/src/Cli.Tests/ConfigureOptionsTests.cs @@ -1081,96 +1081,6 @@ public void TestConfigureDescriptionForMcpSettings(string descriptionValue) Assert.AreEqual(descriptionValue, runtimeConfig.Runtime.Mcp.Description); } - /// - /// Tests that running "dab configure --runtime.mcp.dml-tools.{tool} {value}" updates - /// the individual DML tool boolean in the runtime config. Most tools are configured as - /// direct booleans in the schema (e.g., "describe-entities": true) rather than nested - /// objects with .enabled; "aggregate-records" additionally supports an object form - /// when specifying a query-timeout. - /// - [DataTestMethod] - [DataRow(true, DisplayName = "Enable individual DML tool: describe-entities")] - [DataRow(false, DisplayName = "Disable individual DML tool: describe-entities")] - public void TestConfigureIndividualDmlToolForMcpSettings(bool updatedValue) - { - // Arrange - SetupFileSystemWithInitialConfig(INITIAL_CONFIG); - - // Act: Set describe-entities via the corrected option name (no .enabled suffix) - ConfigureOptions options = new( - runtimeMcpDmlToolsDescribeEntitiesEnabled: updatedValue, - config: TEST_RUNTIME_CONFIG_FILE - ); - bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); - - // Assert - Assert.IsTrue(isSuccess); - string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); - Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); - Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); - } - - /// - /// Tests that running "dab configure --runtime.mcp.dml-tools.enabled {value}" sets all - /// DML tools at once via the bulk toggle. - /// - [DataTestMethod] - [DataRow(true, DisplayName = "Enable all DML tools at once")] - [DataRow(false, DisplayName = "Disable all DML tools at once")] - public void TestConfigureAllDmlToolsForMcpSettings(bool updatedValue) - { - // Arrange - SetupFileSystemWithInitialConfig(INITIAL_CONFIG); - - // Act: Set all tools via the bulk enabled toggle - ConfigureOptions options = new( - runtimeMcpDmlToolsEnabled: updatedValue, - config: TEST_RUNTIME_CONFIG_FILE - ); - bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); - - // Assert - Assert.IsTrue(isSuccess); - string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); - Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); - Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.CreateRecord); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.ReadRecords); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.UpdateRecord); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.DeleteRecord); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.ExecuteEntity); - Assert.AreEqual(updatedValue, runtimeConfig.Runtime.Mcp.DmlTools.AggregateRecords); - } - - /// - /// Tests that running "dab configure" with multiple individual DML tool options - /// correctly updates each tool independently. - /// - [TestMethod] - public void TestConfigureMultipleIndividualDmlToolsForMcpSettings() - { - // Arrange - SetupFileSystemWithInitialConfig(INITIAL_CONFIG); - - // Act: Enable describe-entities, disable create-record - ConfigureOptions options = new( - runtimeMcpDmlToolsDescribeEntitiesEnabled: true, - runtimeMcpDmlToolsCreateRecordEnabled: false, - config: TEST_RUNTIME_CONFIG_FILE - ); - bool isSuccess = TryConfigureSettings(options, _runtimeConfigLoader!, _fileSystem!); - - // Assert - Assert.IsTrue(isSuccess); - string updatedConfig = _fileSystem!.File.ReadAllText(TEST_RUNTIME_CONFIG_FILE); - Assert.IsTrue(RuntimeConfigLoader.TryParseConfig(updatedConfig, out RuntimeConfig? runtimeConfig)); - Assert.IsNotNull(runtimeConfig.Runtime?.Mcp?.DmlTools); - Assert.AreEqual(true, runtimeConfig.Runtime.Mcp.DmlTools.DescribeEntities); - Assert.AreEqual(false, runtimeConfig.Runtime.Mcp.DmlTools.CreateRecord); - } - /// /// Validates that `dab configure --show-effective-permissions` correctly displays /// effective permissions without modifying the config file.