Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

Commit 5dea2ef

Browse files
authored
Add azure-storage-share-file-list command (#793)
* Initial command * Add tests * Add documentation * Fix StorageCommandTests name * Fix property name * Fix CSpell * Fix OAuth for uploading to File Share * Change when file intent is enabled * Remove file upload in resource deployment * Add intent when using Managed Identity * Change MI role * Enhance live test * Use correct parameter * PR feedback * Remove bad, failing test * Update test code to match new naming * Cleanup azmcp-commands
1 parent 5ca3874 commit 5dea2ef

24 files changed

+516
-12
lines changed

.vscode/cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
"testproxy",
159159
"testrg",
160160
"testserver",
161+
"testshare",
161162
"testsub",
162163
"testfilesystem",
163164
"toplevel",

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The Azure MCP Server updates automatically by default whenever a new release com
88

99
- Added support for providing the `--content-type` and `--tags` properties to the `azmcp-appconfig-kv-set` command. [[#459](https://github.com/Azure/azure-mcp/pull/459)]
1010
- Added `filter-path` and `recursive` capabilities to `azmcp-storage-datalake-file-system-list-paths`. [[#770](https://github.com/Azure/azure-mcp/issues/770)]
11-
11+
- Added support for listing files and directories in Azure File Shares via the `azmcp-storage-share-file-list` command. This command recursively lists all items in a specified file share directory with metadata including size, last modified date, and content type. [[#793](https://github.com/Azure/azure-mcp/pull/793)]
1212

1313
- Added support for Azure Virtual Desktop with new commands:
1414
- `azmcp-virtualdesktop-hostpool-list` - List all host pools in a subscription

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<PackageVersion Include="Azure.Storage.Blobs" Version="12.24.0" />
3535
<PackageVersion Include="Azure.Storage.Blobs.Batch" Version="12.21.0" />
3636
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.22.0" />
37+
<PackageVersion Include="Azure.Storage.Files.Shares" Version="12.22.0" />
3738
<PackageVersion Include="Azure.ResourceManager.Datadog" Version="1.0.0-beta.6" />
3839
<PackageVersion Include="Azure.ResourceManager.CosmosDB" Version="1.4.0-beta.13" />
3940
<PackageVersion Include="Azure.ResourceManager.OperationalInsights" Version="1.3.1" />

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ The Azure MCP Server supercharges your agents with Azure context. Here are some
7575
* "Show me the tables in my Storage account"
7676
* "Get details about my Storage container"
7777
* "List paths in my Data Lake file system"
78+
* "List files and directories in my File Share"
7879

7980
## 🛠️ Currently Supported Tools
8081

@@ -221,6 +222,7 @@ The Azure MCP Server supercharges your agents with Azure context. Here are some
221222
* List and query Storage tables
222223
* List paths in Data Lake file systems
223224
* Get container properties and metadata
225+
* List files and directories in File Shares
224226

225227
### 📋 Azure Subscription
226228

areas/storage/src/AzureMcp.Storage/AzureMcp.Storage.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<PackageReference Include="Azure.Storage.Blobs" />
1818
<PackageReference Include="Azure.Storage.Blobs.Batch" />
1919
<PackageReference Include="Azure.Storage.Files.DataLake" />
20+
<PackageReference Include="Azure.Storage.Files.Shares" />
2021
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
2122
<PackageReference Include="ModelContextProtocol" />
2223
<PackageReference Include="System.CommandLine" />
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using AzureMcp.Core.Commands;
6+
using AzureMcp.Storage.Commands;
7+
using AzureMcp.Storage.Options;
8+
using AzureMcp.Storage.Options.Share;
9+
10+
namespace AzureMcp.Storage.Commands.Share;
11+
12+
public abstract class BaseShareCommand<
13+
[DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] TOptions>
14+
: BaseStorageCommand<TOptions> where TOptions : BaseShareOptions, new()
15+
{
16+
protected readonly Option<string> _shareOption = StorageOptionDefinitions.Share;
17+
18+
protected override void RegisterOptions(Command command)
19+
{
20+
base.RegisterOptions(command);
21+
command.AddOption(_shareOption);
22+
}
23+
24+
protected override TOptions BindOptions(ParseResult parseResult)
25+
{
26+
var options = base.BindOptions(parseResult);
27+
options.Share = parseResult.GetValueForOption(_shareOption);
28+
return options;
29+
}
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using AzureMcp.Core.Commands;
6+
using AzureMcp.Storage.Options;
7+
using AzureMcp.Storage.Options.Share.File;
8+
9+
namespace AzureMcp.Storage.Commands.Share.File;
10+
11+
public abstract class BaseFileCommand<
12+
[DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] TOptions>
13+
: BaseShareCommand<TOptions> where TOptions : BaseFileOptions, new()
14+
{
15+
protected readonly Option<string> _directoryPathOption = StorageOptionDefinitions.DirectoryPath;
16+
17+
protected override void RegisterOptions(Command command)
18+
{
19+
base.RegisterOptions(command);
20+
command.AddOption(_directoryPathOption);
21+
}
22+
23+
protected override TOptions BindOptions(ParseResult parseResult)
24+
{
25+
var options = base.BindOptions(parseResult);
26+
options.DirectoryPath = parseResult.GetValueForOption(_directoryPathOption);
27+
return options;
28+
}
29+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using AzureMcp.Core.Commands;
5+
using AzureMcp.Core.Services.Telemetry;
6+
using AzureMcp.Storage.Models;
7+
using AzureMcp.Storage.Options;
8+
using AzureMcp.Storage.Options.Share.File;
9+
using AzureMcp.Storage.Services;
10+
using Microsoft.Extensions.Logging;
11+
12+
namespace AzureMcp.Storage.Commands.Share.File;
13+
14+
public sealed class FileListCommand(ILogger<FileListCommand> logger) : BaseFileCommand<FileListOptions>()
15+
{
16+
private const string CommandTitle = "List Storage Share Files and Directories";
17+
private readonly ILogger<FileListCommand> _logger = logger;
18+
19+
public override string Name => "list";
20+
21+
public override string Description =>
22+
$"""
23+
Lists files and directories within a file share directory. This tool recursively lists all items in a specified file share directory,
24+
including files, subdirectories, and their properties. Files and directories may be filtered by a prefix. Returns file listing as JSON.
25+
""";
26+
27+
public override string Title => CommandTitle;
28+
29+
public override ToolMetadata Metadata => new() { Destructive = false, ReadOnly = true };
30+
31+
protected override void RegisterOptions(Command command)
32+
{
33+
base.RegisterOptions(command);
34+
command.AddOption(StorageOptionDefinitions.Prefix);
35+
}
36+
37+
protected override FileListOptions BindOptions(ParseResult parseResult)
38+
{
39+
var options = base.BindOptions(parseResult);
40+
options.Prefix = parseResult.GetValueForOption(StorageOptionDefinitions.Prefix);
41+
return options;
42+
}
43+
44+
public override async Task<CommandResponse> ExecuteAsync(CommandContext context, ParseResult parseResult)
45+
{
46+
var options = BindOptions(parseResult);
47+
48+
try
49+
{
50+
if (!Validate(parseResult.CommandResult, context.Response).IsValid)
51+
{
52+
return context.Response;
53+
}
54+
55+
context.Activity?.WithSubscriptionTag(options);
56+
57+
var storageService = context.GetService<IStorageService>();
58+
var filesAndDirectories = await storageService.ListFilesAndDirectories(
59+
options.Account!,
60+
options.Share!,
61+
options.DirectoryPath!,
62+
options.Prefix,
63+
options.Subscription!,
64+
options.Tenant,
65+
options.RetryPolicy);
66+
67+
context.Response.Results = filesAndDirectories?.Count > 0
68+
? ResponseResult.Create(new FileListCommandResult(filesAndDirectories), StorageJsonContext.Default.FileListCommandResult)
69+
: null;
70+
}
71+
catch (Exception ex)
72+
{
73+
_logger.LogError(ex, "Error listing storage share files and directories. Account: {Account}, Share: {Share}, Directory: {Directory}, Prefix: {Prefix}.", options.Account, options.Share, options.DirectoryPath, options.Prefix);
74+
HandleException(context, ex);
75+
}
76+
77+
return context.Response;
78+
}
79+
80+
internal record FileListCommandResult(List<FileShareItemInfo> Files);
81+
}

areas/storage/src/AzureMcp.Storage/Commands/StorageJsonContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using AzureMcp.Storage.Commands.Blob.Container;
99
using AzureMcp.Storage.Commands.DataLake.Directory;
1010
using AzureMcp.Storage.Commands.DataLake.FileSystem;
11+
using AzureMcp.Storage.Commands.Share.File;
1112
using AzureMcp.Storage.Commands.Table;
1213

1314
namespace AzureMcp.Storage.Commands;
@@ -20,6 +21,7 @@ namespace AzureMcp.Storage.Commands;
2021
[JsonSerializable(typeof(ContainerDetailsCommand.ContainerDetailsCommandResult))]
2122
[JsonSerializable(typeof(FileSystemListPathsCommand.FileSystemListPathsCommandResult))]
2223
[JsonSerializable(typeof(DirectoryCreateCommand.DirectoryCreateCommandResult))]
24+
[JsonSerializable(typeof(FileListCommand.FileListCommandResult))]
2325
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
2426
internal sealed partial class StorageJsonContext : JsonSerializerContext
2527
{
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Text.Json.Serialization;
5+
6+
namespace AzureMcp.Storage.Models;
7+
8+
public record FileShareItemInfo(
9+
[property: JsonPropertyName("name")] string Name,
10+
[property: JsonPropertyName("isDirectory")] bool IsDirectory,
11+
[property: JsonPropertyName("size")] long? Size,
12+
[property: JsonPropertyName("lastModified")] DateTimeOffset? LastModified,
13+
[property: JsonPropertyName("etag")] string? ETag);

0 commit comments

Comments
 (0)