diff --git a/src/Cli.Tests/ConfigureOptionsTests.cs b/src/Cli.Tests/ConfigureOptionsTests.cs
index 5824b2e054..0c8bec97ec 100644
--- a/src/Cli.Tests/ConfigureOptionsTests.cs
+++ b/src/Cli.Tests/ConfigureOptionsTests.cs
@@ -1081,6 +1081,96 @@ 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.
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);
+ }
}
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.")]