Skip to content

Commit 1c7ffc4

Browse files
author
Shreya Sangwa
committed
Add initial Azure ManagedCleanroom toolset with first commands: collaborations list and collaboration create
1 parent b475bd9 commit 1c7ffc4

26 files changed

Lines changed: 983 additions & 2 deletions

.github/CODEOWNERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@
281281
# ServiceLabel: %tools-ManagedLustre
282282
# ServiceOwners: @rebecca-makar @wolfgang-desalvador
283283

284+
# PRLabel: %tools-ManagedCleanroom
285+
/tools/Azure.Mcp.Tools.ManagedCleanroom/ @microsoft/azure-mcp @ashank @yavohra @vaidmishra
286+
287+
# ServiceLabel: %tools-ManagedCleanroom
288+
# ServiceOwners: @microsoft/azure-mcp @ashank @yavohra @vaidmishra
289+
284290
# PRLabel: %tools-Marketplace
285291
/tools/Azure.Mcp.Tools.Marketplace/ @meirloichter @shaharsandak @obit91 @microsoft/azure-mcp
286292

Directory.Packages.props

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.4" />
1212
<PackageVersion Include="Azure.AI.OpenAI" Version="2.8.0-beta.1" />
1313
<PackageVersion Include="Azure.Bicep.Types" Version="0.6.50" />
14-
<PackageVersion Include="Azure.Core" Version="1.55.0" />
14+
<PackageVersion Include="Azure.Core" Version="1.57.0" />
1515
<PackageVersion Include="Azure.Data.AppConfiguration" Version="1.6.1" />
1616
<PackageVersion Include="Azure.Data.Tables" Version="12.11.0" />
1717
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
@@ -22,6 +22,7 @@
2222
<PackageVersion Include="Azure.Monitor.Ingestion" Version="1.2.0" />
2323
<PackageVersion Include="Azure.Monitor.Query.Logs" Version="1.0.0" />
2424
<PackageVersion Include="Azure.ResourceManager" Version="1.14.0" />
25+
<PackageVersion Include="Azure.ResourceManager.CleanRoom" Version="1.0.0-alpha.20260603.1" />
2526
<PackageVersion Include="Azure.ResourceManager.ApplicationInsights" Version="1.1.0-beta.1" />
2627
<PackageVersion Include="Azure.ResourceManager.AppContainers" Version="1.4.1" />
2728
<PackageVersion Include="Azure.ResourceManager.AppService" Version="1.4.1" />
@@ -93,7 +94,7 @@
9394
<PackageVersion Include="Npgsql" Version="10.0.1" />
9495
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
9596
<PackageVersion Include="Yarp.ReverseProxy" Version="2.3.0" />
96-
<PackageVersion Include="System.ClientModel" Version="1.11.0" />
97+
<PackageVersion Include="System.ClientModel" Version="1.13.0" />
9798
<PackageVersion Include="System.CommandLine" Version="2.0.6" />
9899
<PackageVersion Include="System.Formats.Asn1" Version="10.0.6" />
99100
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />

Microsoft.Mcp.slnx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,13 @@
309309
<Folder Name="/tools/Azure.Mcp.Tools.LoadTesting/tests/">
310310
<Project Path="tools/Azure.Mcp.Tools.LoadTesting/tests/Azure.Mcp.Tools.LoadTesting.Tests/Azure.Mcp.Tools.LoadTesting.Tests.csproj" />
311311
</Folder>
312+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/" />
313+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/src/">
314+
<Project Path="tools/Azure.Mcp.Tools.ManagedCleanroom/src/Azure.Mcp.Tools.ManagedCleanroom.csproj" />
315+
</Folder>
316+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/tests/">
317+
<Project Path="tools/Azure.Mcp.Tools.ManagedCleanroom/tests/Azure.Mcp.Tools.ManagedCleanroom.Tests/Azure.Mcp.Tools.ManagedCleanroom.Tests.csproj" />
318+
</Folder>
312319
<Folder Name="/tools/Azure.Mcp.Tools.ManagedLustre/" />
313320
<Folder Name="/tools/Azure.Mcp.Tools.ManagedLustre/src/">
314321
<Project Path="tools/Azure.Mcp.Tools.ManagedLustre/src/Azure.Mcp.Tools.ManagedLustre.csproj" />

servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@
158158
<Folder Name="/tools/Azure.Mcp.Tools.ConfidentialLedger/tests/">
159159
<Project Path="../../tools/Azure.Mcp.Tools.ConfidentialLedger/tests/Azure.Mcp.Tools.ConfidentialLedger.Tests/Azure.Mcp.Tools.ConfidentialLedger.Tests.csproj" />
160160
</Folder>
161+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/" />
162+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/src/">
163+
<Project Path="../../tools/Azure.Mcp.Tools.ManagedCleanroom/src/Azure.Mcp.Tools.ManagedCleanroom.csproj" />
164+
</Folder>
165+
<Folder Name="/tools/Azure.Mcp.Tools.ManagedCleanroom/tests/">
166+
<Project Path="../../tools/Azure.Mcp.Tools.ManagedCleanroom/tests/Azure.Mcp.Tools.ManagedCleanroom.Tests/Azure.Mcp.Tools.ManagedCleanroom.Tests.csproj" />
167+
</Folder>
161168
<Folder Name="/tools/Azure.Mcp.Tools.ContainerApps/" />
162169
<Folder Name="/tools/Azure.Mcp.Tools.ContainerApps/src/">
163170
<Project Path="../../tools/Azure.Mcp.Tools.ContainerApps/src/Azure.Mcp.Tools.ContainerApps.csproj" />
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
changes:
2+
- section: "New Features"
3+
description: "Added Azure Managed Cleanroom toolset with two commands for interacting with Azure Cleanroom: `managedcleanroom collaborations list` and `managedcleanroom collaboration create`."

servers/Azure.Mcp.Server/src/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ private static IAreaSetup[] RegisterAreas()
213213
new Azure.Mcp.Tools.KeyVault.KeyVaultSetup(),
214214
new Azure.Mcp.Tools.Kusto.KustoSetup(),
215215
new Azure.Mcp.Tools.LoadTesting.LoadTestingSetup(),
216+
new Azure.Mcp.Tools.ManagedCleanroom.ManagedCleanroomSetup(),
216217
new Azure.Mcp.Tools.Marketplace.MarketplaceSetup(),
217218
new Azure.Mcp.Tools.Quota.QuotaSetup(),
218219
new Azure.Mcp.Tools.Monitor.MonitorSetup(),
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Azure Managed Cleanroom MCP Toolset - Architecture
2+
3+
## Overview
4+
5+
`Azure.Mcp.Tools.ManagedCleanroom` currently implements two commands under the `azmcp managedcleanroom` namespace:
6+
7+
- `collaborations list` (data plane)
8+
- `collaboration create` (control plane)
9+
10+
## Implemented Command Surfaces
11+
12+
| Surface | Command | Tool Name | Purpose |
13+
|---------|---------|-----------|---------|
14+
| Data plane (Analytics Frontend) | `collaborations list` | `managedcleanroom_collaborations_list` | Lists collaborations the caller can access from the configured endpoint. |
15+
| Control plane (ARM) | `collaboration create` | `managedcleanroom_collaboration_create` | Creates an ARM collaboration resource in the specified resource group and subscription. |
16+
17+
## Project Structure (Current Scope)
18+
19+
```
20+
Azure.Mcp.Tools.ManagedCleanroom/
21+
├── src/
22+
│ ├── ManagedCleanroomSetup.cs
23+
│ ├── Commands/
24+
│ │ ├── ManagedCleanroomJsonContext.cs
25+
│ │ ├── Collaboration/CollaborationCreateCommand.cs
26+
│ │ └── Collaborations/CollaborationsListCommand.cs
27+
│ ├── Options/
28+
│ │ ├── ManagedCleanroomOptionDescriptions.cs
29+
│ │ ├── Collaboration/CollaborationCreateOptions.cs
30+
│ │ └── Collaborations/CollaborationsListOptions.cs
31+
│ └── Services/
32+
│ ├── IManagedCleanroomService.cs
33+
│ └── ManagedCleanroomService.cs
34+
└── tests/
35+
└── Azure.Mcp.Tools.ManagedCleanroom.Tests/
36+
├── Collaboration/CollaborationCreateCommandTests.cs
37+
└── Collaborations/CollaborationsListCommandTests.cs
38+
```
39+
40+
## Notes
41+
42+
- Commands not listed above are intentionally out of scope for this branch.
43+
- The setup registers only the two commands above so tool discovery is restricted to this initial implementation slice.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
[assembly: InternalsVisibleTo("Azure.Mcp.Tools.ManagedCleanroom.Tests")]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<IsAotCompatible>true</IsAotCompatible>
4+
<AzureSupportedClouds>AzureCloud</AzureSupportedClouds>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<ProjectReference Include="..\..\..\core\Azure.Mcp.Core\src\Azure.Mcp.Core.csproj" />
8+
</ItemGroup>
9+
<ItemGroup>
10+
<PackageReference Include="Azure.Core" />
11+
<PackageReference Include="Azure.Identity" />
12+
<PackageReference Include="Azure.ResourceManager.Resources" />
13+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
14+
<PackageReference Include="ModelContextProtocol" />
15+
<PackageReference Include="System.CommandLine" />
16+
</ItemGroup>
17+
</Project>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Net;
5+
using Azure.Mcp.Core.Commands.Subscription;
6+
using Azure.Mcp.Core.Services.Azure.Subscription;
7+
using Azure.Mcp.Tools.ManagedCleanroom.Options.Collaboration;
8+
using Azure.Mcp.Tools.ManagedCleanroom.Services;
9+
using Microsoft.Extensions.Logging;
10+
using Microsoft.Mcp.Core.Commands;
11+
using Microsoft.Mcp.Core.Models.Command;
12+
13+
namespace Azure.Mcp.Tools.ManagedCleanroom.Commands.Collaboration;
14+
15+
[CommandMetadata(
16+
Id = "e247b9e0-2d87-43a7-8e5d-57eea22237a3",
17+
Name = "create",
18+
Title = "Create Cleanroom Collaboration",
19+
Description = """
20+
Creates an Azure Cleanroom collaboration ARM resource in the specified resource group and location.
21+
Polls provisioningState every 30 seconds until the resource reaches a terminal state (expected ~25 minutes).
22+
Returns the final ARM resource properties and a summary message with the outcome and elapsed time.
23+
Required options:
24+
- --name: unique collaboration name within the resource group
25+
- --location: Azure region for the ARM resource (e.g., 'eastus')
26+
- --resource-group: resource group to create the collaboration in
27+
- --subscription: Azure subscription
28+
""",
29+
Destructive = false,
30+
Idempotent = true,
31+
OpenWorld = false,
32+
ReadOnly = false,
33+
Secret = false,
34+
LocalRequired = false)]
35+
public sealed class CollaborationCreateCommand(
36+
ILogger<CollaborationCreateCommand> logger,
37+
IManagedCleanroomService service,
38+
ISubscriptionResolver subscriptionResolver)
39+
: SubscriptionCommand<CollaborationCreateOptions, CollaborationCreateCommand.CollaborationCreateCommandResult>(subscriptionResolver)
40+
{
41+
private readonly ILogger<CollaborationCreateCommand> _logger = logger;
42+
private readonly IManagedCleanroomService _service = service;
43+
44+
public override async Task<CommandResponse> ExecuteAsync(
45+
CommandContext context, CollaborationCreateOptions options, CancellationToken cancellationToken)
46+
{
47+
try
48+
{
49+
var result = await _service.CreateCollaborationArmResourceAsync(
50+
options.Name,
51+
options.ResourceGroup,
52+
options.Subscription!,
53+
options.Location,
54+
options.ResourceLocation,
55+
options.Collaborators,
56+
options.Tenant,
57+
options.RetryPolicy,
58+
cancellationToken).ConfigureAwait(false);
59+
60+
context.Response.Message = result.Message;
61+
context.Response.Results = ResponseResult.Create(
62+
result.Properties,
63+
ManagedCleanroomJsonContext.Default.JsonElement);
64+
}
65+
catch (Exception ex)
66+
{
67+
_logger.LogError(ex,
68+
"Error creating cleanroom collaboration. Name: {Name}, ResourceGroup: {ResourceGroup}, Subscription: {Subscription}",
69+
options.Name, options.ResourceGroup, options.Subscription);
70+
HandleException(context, ex);
71+
}
72+
73+
return context.Response;
74+
}
75+
76+
protected override string GetErrorMessage(Exception ex) => ex switch
77+
{
78+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Conflict =>
79+
"A collaboration with this name already exists in the resource group.",
80+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
81+
$"Authorization failed creating the collaboration. Details: {reqEx.Message}",
82+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
83+
"Resource group not found. Verify the resource group exists and you have access.",
84+
RequestFailedException reqEx => reqEx.Message,
85+
_ => base.GetErrorMessage(ex)
86+
};
87+
88+
protected override HttpStatusCode GetStatusCode(Exception ex) => ex switch
89+
{
90+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Conflict =>
91+
HttpStatusCode.Conflict,
92+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
93+
HttpStatusCode.Forbidden,
94+
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
95+
HttpStatusCode.NotFound,
96+
RequestFailedException reqEx => (HttpStatusCode)reqEx.Status,
97+
_ => base.GetStatusCode(ex)
98+
};
99+
100+
public record CollaborationCreateCommandResult;
101+
}

0 commit comments

Comments
 (0)