Skip to content

Commit eb44439

Browse files
committed
Only enable destructive actions if explicitly set
1 parent 2959499 commit eb44439

7 files changed

Lines changed: 97 additions & 5 deletions

File tree

src/ServiceControl.AcceptanceTests/Mcp/When_mcp_server_is_enabled.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace ServiceControl.AcceptanceTests.Mcp;
1616
class When_mcp_server_is_enabled : AcceptanceTest
1717
{
1818
[SetUp]
19-
public void EnableMcp() => SetSettings = s => s.EnableMcpServer = true;
19+
public void EnableMcp() => SetSettings = s => s.EnableMcpServerWriteMode = true;
2020

2121
[Test]
2222
public async Task Should_expose_mcp_endpoint()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
namespace ServiceControl.AcceptanceTests.Mcp;
2+
3+
using System.Linq;
4+
using System.Net.Http;
5+
using System.Text.Json;
6+
using System.Threading.Tasks;
7+
using NServiceBus.AcceptanceTesting;
8+
using NUnit.Framework;
9+
using ServiceControl.AcceptanceTesting.Mcp;
10+
11+
[TestFixture]
12+
class When_mcp_server_write_mode_is_disabled : AcceptanceTest
13+
{
14+
[SetUp]
15+
public void EnableReadOnlyMcp() => SetSettings = s => s.EnableMcpServer = true;
16+
17+
[Test]
18+
public async Task Should_not_expose_write_tools()
19+
{
20+
string[] toolNames = null;
21+
22+
await Define<ScenarioContext>()
23+
.Done(async _ =>
24+
{
25+
var session = await McpAcceptanceTestSupport.InitializeAndGetSessionInfo(HttpClient);
26+
if (session == null)
27+
{
28+
return false;
29+
}
30+
31+
var response = await McpAcceptanceTestSupport.SendMcpRequest(HttpClient, session, "tools/list", new { });
32+
if (response == null || response.StatusCode != System.Net.HttpStatusCode.OK)
33+
{
34+
return false;
35+
}
36+
37+
var json = await McpAcceptanceTestSupport.ReadMcpResponseJson(response);
38+
var mcpResponse = McpAcceptanceTestSupport.DeserializeListToolsResponse(json);
39+
toolNames = mcpResponse.Result.Tools.Cast<JsonElement>()
40+
.Select(t => t.GetProperty("name").GetString())
41+
.ToArray();
42+
return true;
43+
})
44+
.Run();
45+
46+
Assert.That(toolNames, Is.Not.Null);
47+
Assert.That(toolNames, Has.Length.EqualTo(7), "Read-only mode should expose exactly 7 tools");
48+
49+
Assert.That(toolNames, Does.Contain("get_errors_summary"));
50+
Assert.That(toolNames, Does.Contain("get_failed_messages"));
51+
Assert.That(toolNames, Does.Contain("get_failed_message_by_id"));
52+
Assert.That(toolNames, Does.Contain("get_failed_message_last_attempt"));
53+
Assert.That(toolNames, Does.Contain("get_failed_messages_by_endpoint"));
54+
Assert.That(toolNames, Does.Contain("get_failure_groups"));
55+
Assert.That(toolNames, Does.Contain("get_retry_history"));
56+
57+
Assert.That(toolNames, Does.Not.Contain("retry_failed_message"));
58+
Assert.That(toolNames, Does.Not.Contain("retry_failed_messages"));
59+
Assert.That(toolNames, Does.Not.Contain("retry_failed_messages_by_queue"));
60+
Assert.That(toolNames, Does.Not.Contain("retry_all_failed_messages"));
61+
Assert.That(toolNames, Does.Not.Contain("retry_all_failed_messages_by_endpoint"));
62+
Assert.That(toolNames, Does.Not.Contain("retry_failure_group"));
63+
Assert.That(toolNames, Does.Not.Contain("archive_failed_message"));
64+
Assert.That(toolNames, Does.Not.Contain("archive_failed_messages"));
65+
Assert.That(toolNames, Does.Not.Contain("archive_failure_group"));
66+
Assert.That(toolNames, Does.Not.Contain("unarchive_failed_message"));
67+
Assert.That(toolNames, Does.Not.Contain("unarchive_failed_messages"));
68+
Assert.That(toolNames, Does.Not.Contain("unarchive_failure_group"));
69+
}
70+
}

src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,6 @@
5959
"TimeToRestartAuditIngestionAfterFailure": "00:01:00",
6060
"EnableFullTextSearchOnBodies": true,
6161
"EnableMcpServer": false,
62+
"EnableMcpServerWriteMode": false,
6263
"ShutdownTimeout": "00:00:05"
6364
}

src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public Settings(string transportType = null, string persisterType = null, Loggin
5454
ServiceControlQueueAddress = SettingsReader.Read<string>(SettingsRootNamespace, "ServiceControlQueueAddress");
5555
TimeToRestartAuditIngestionAfterFailure = GetTimeToRestartAuditIngestionAfterFailure();
5656
EnableFullTextSearchOnBodies = SettingsReader.Read(SettingsRootNamespace, "EnableFullTextSearchOnBodies", true);
57+
EnableMcpServerWriteMode = SettingsReader.Read(SettingsRootNamespace, "EnableMcpServerWriteMode", false);
5758
EnableMcpServer = SettingsReader.Read(SettingsRootNamespace, "EnableMcpServer", false);
5859
ShutdownTimeout = SettingsReader.Read(SettingsRootNamespace, "ShutdownTimeout", ShutdownTimeout);
5960

@@ -188,7 +189,14 @@ public int MaxBodySizeToStore
188189

189190
public bool EnableFullTextSearchOnBodies { get; set; }
190191

191-
public bool EnableMcpServer { get; set; }
192+
bool enableMcpServer;
193+
public bool EnableMcpServer
194+
{
195+
get => enableMcpServer || EnableMcpServerWriteMode;
196+
set => enableMcpServer = value;
197+
}
198+
199+
public bool EnableMcpServerWriteMode { get; set; }
192200

193201
// The default value is set to the maximum allowed time by the most
194202
// restrictive hosting platform, which is Linux containers. Linux

src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"NotificationsFilter": null,
3939
"AllowMessageEditing": false,
4040
"EnableMcpServer": false,
41+
"EnableMcpServerWriteMode": false,
4142
"EnableIntegratedServicePulse": false,
4243
"ServicePulseSettings": null,
4344
"MessageFilter": null,

src/ServiceControl/Infrastructure/Settings/Settings.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public Settings(
8181
DisableExternalIntegrationsPublishing = SettingsReader.Read(SettingsRootNamespace, "DisableExternalIntegrationsPublishing", false);
8282
TrackInstancesInitialValue = SettingsReader.Read(SettingsRootNamespace, "TrackInstancesInitialValue", true);
8383
ShutdownTimeout = SettingsReader.Read(SettingsRootNamespace, "ShutdownTimeout", ShutdownTimeout);
84+
EnableMcpServerWriteMode = SettingsReader.Read(SettingsRootNamespace, "EnableMcpServerWriteMode", false);
8485
EnableMcpServer = SettingsReader.Read(SettingsRootNamespace, "EnableMcpServer", false);
8586
AssemblyLoadContextResolver = static assemblyPath => new PluginAssemblyLoadContext(assemblyPath);
8687
}
@@ -114,7 +115,14 @@ public Settings(
114115

115116
public bool AllowMessageEditing { get; set; }
116117

117-
public bool EnableMcpServer { get; set; }
118+
bool enableMcpServer;
119+
public bool EnableMcpServer
120+
{
121+
get => enableMcpServer || EnableMcpServerWriteMode;
122+
set => enableMcpServer = value;
123+
}
124+
125+
public bool EnableMcpServerWriteMode { get; set; }
118126

119127
public bool EnableIntegratedServicePulse { get; set; }
120128
public ServicePulseSettings ServicePulseSettings { get; set; }

src/ServiceControl/Infrastructure/WebApi/HostApplicationBuilderExtensions.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ public static void AddServiceControlApi(this IHostApplicationBuilder builder, Se
2525
{
2626
builder.Services.AddTransient<ServiceControl.Mcp.FailedMessageTools>();
2727
builder.Services.AddTransient<ServiceControl.Mcp.FailureGroupTools>();
28-
builder.Services.AddTransient<ServiceControl.Mcp.RetryTools>();
29-
builder.Services.AddTransient<ServiceControl.Mcp.ArchiveTools>();
28+
29+
if (settings.EnableMcpServerWriteMode)
30+
{
31+
builder.Services.AddTransient<ServiceControl.Mcp.RetryTools>();
32+
builder.Services.AddTransient<ServiceControl.Mcp.ArchiveTools>();
33+
}
3034

3135
builder.Services
3236
.AddMcpServer()

0 commit comments

Comments
 (0)