Add IoT Hub device list command#3074
Open
Iris20050110 wants to merge 1 commit into
Open
Conversation
Adds the `azmcp iothub device list` command to list device identities in an Azure IoT Hub device registry. Returns device metadata without authentication keys, supports --max-count (default 100, maximum 100) with a truncated flag when more devices exist, and returns a validation error when --max-count is less than 1. Includes the Azure.Mcp.Tools.IoTHub project (device list command, options, models, services, unit and live tests) and wires it into the server registration, command docs, e2e prompts, CHANGELOG, and consolidated-tools.json.
Iris20050110
requested review from
KarishmaGhiya,
g2vinay,
hallipr,
jairmyree,
tmeschter,
vukelich and
xirzec
July 16, 2026 20:47
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new Azure IoT Hub toolset and wires it into Azure MCP Server so users can run azmcp iothub device list to list device identities (metadata-only) from an IoT Hub device registry.
Changes:
- Introduces
Azure.Mcp.Tools.IoTHubwith a device-list command, models, and services for IoT Hub device registry listing. - Adds unit + live test projects and live-test infrastructure (Bicep + post-deploy script) for the IoT Hub toolset.
- Registers the new area/tool and updates server docs, e2e prompts, consolidated tool mapping, and changelog.
Invoking Livetests
Copilot submitted PRs are not trustworthy by default. Users with write access to the repo need to validate the contents of this PR before leaving a comment with the text /azp run mcp - pullrequest - live. This will trigger the necessary livetest workflows to complete required validation.
Reviewed changes
Copilot reviewed 36 out of 37 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/Azure.Mcp.Tools.IoTHub/tests/test-resources.bicep | Adds Bicep template to provision an IoT Hub for live tests. |
| tools/Azure.Mcp.Tools.IoTHub/tests/test-resources-post.ps1 | Adds post-deploy script to create test devices. |
| tools/Azure.Mcp.Tools.IoTHub/tests/Azure.Mcp.Tools.IoTHub.UnitTests/Device/IoTHubDeviceListCommandTests.cs | Adds unit tests for the device list command behavior. |
| tools/Azure.Mcp.Tools.IoTHub/tests/Azure.Mcp.Tools.IoTHub.UnitTests/Azure.Mcp.Tools.IoTHub.UnitTests.csproj | Adds unit test project for the IoT Hub toolset. |
| tools/Azure.Mcp.Tools.IoTHub/tests/Azure.Mcp.Tools.IoTHub.LiveTests/IoTHubCommandTests.cs | Adds live test coverage for iothub_device_list. |
| tools/Azure.Mcp.Tools.IoTHub/tests/Azure.Mcp.Tools.IoTHub.LiveTests/Azure.Mcp.Tools.IoTHub.LiveTests.csproj | Adds live test project for IoT Hub toolset. |
| tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubService.cs | Implements ARM-side IoT Hub discovery and key retrieval helpers. |
| tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubDeviceService.cs | Implements data-plane device registry listing via IoT Hub REST + SAS auth. |
| tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubService.cs | Adds IoT Hub service contract (hub lookup + keys). |
| tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubDeviceService.cs | Adds device registry service contract (list devices). |
| tools/Azure.Mcp.Tools.IoTHub/src/Options/IoTHubOptionDefinitions.cs | Defines CLI options for IoT Hub commands (name, max-count). |
| tools/Azure.Mcp.Tools.IoTHub/src/Options/Device/IoTHubDeviceListOptions.cs | Adds options POCO for the device list command. |
| tools/Azure.Mcp.Tools.IoTHub/src/Models/IoTHubKey.cs | Adds model to represent IoT Hub SAS policies/keys (internal plumbing). |
| tools/Azure.Mcp.Tools.IoTHub/src/Models/IoTHubDescription.cs | Adds model for IoT Hub metadata returned from ARM query. |
| tools/Azure.Mcp.Tools.IoTHub/src/Models/DeviceListResult.cs | Adds response model (devices + truncated flag). |
| tools/Azure.Mcp.Tools.IoTHub/src/Models/DeviceIdentity.cs | Adds device identity DTO (intentionally excluding auth keys). |
| tools/Azure.Mcp.Tools.IoTHub/src/IoTHubSetup.cs | Registers IoT Hub services + commands into the area system. |
| tools/Azure.Mcp.Tools.IoTHub/src/GlobalUsings.cs | Adds global usings for the new toolset. |
| tools/Azure.Mcp.Tools.IoTHub/src/Commands/IoTHubJsonContext.cs | Adds STJ source-gen context for IoT Hub models (AOT-safe). |
| tools/Azure.Mcp.Tools.IoTHub/src/Commands/Device/IoTHubDeviceListCommand.cs | Adds azmcp iothub device list command implementation. |
| tools/Azure.Mcp.Tools.IoTHub/src/Commands/BaseIoTHubCommand.cs | Adds IoT Hub command base to share common subscription/resource-group options. |
| tools/Azure.Mcp.Tools.IoTHub/src/Azure.Mcp.Tools.IoTHub.csproj | Adds new toolset project and dependencies. |
| tools/Azure.Mcp.Tools.IoTHub/src/AssemblyInfo.cs | Adds InternalsVisibleTo for new test projects. |
| servers/Azure.Mcp.Server/src/Program.cs | Registers the new IoT Hub area and adjusts console logging behavior. |
| servers/Azure.Mcp.Server/README.md | Adds IoT Hub to the supported services list. |
| servers/Azure.Mcp.Server/docs/e2eTestPrompts.md | Adds e2e prompts for IoT Hub device list tool. |
| servers/Azure.Mcp.Server/docs/azmcp-commands.md | Documents the new azmcp iothub device list command. |
| servers/Azure.Mcp.Server/CHANGELOG.md | Adds changelog entry for the new IoT Hub command. |
| package.json | Adds root Node dependency on @azure/mcp. |
| package-lock.json | Locks root Node dependency graph for @azure/mcp. |
| dotnet-tools.json | Adds a dotnet tool manifest with the azmcp tool. |
| Directory.Packages.props | Adds IoTHub ARM SDK package version and bumps OTel exporter version. |
| core/Azure.Mcp.Core/src/Services/Http/HttpClientService.cs | Redirects debug output to stderr to avoid corrupting stdout JSON. |
| core/Azure.Mcp.Core/src/Areas/Server/Resources/consolidated-tools.json | Adds consolidated mapping entry for the new IoT Hub device list tool. |
| .vscode/settings.json | Adds VS Code MCP sampling config for a local IoT Hub-only server profile. |
| .vscode/mcp.json | Adds a local MCP server config to run Azure.Mcp.Server filtered to iothub. |
| .github/CODEOWNERS | Adds CODEOWNERS entries for the new IoT Hub toolset. |
Comment on lines
+19
to
+33
| public class IoTHubDeviceService( | ||
| IIoTHubService ioTHubService, | ||
| IAzureTokenCredentialProvider credentialProvider, | ||
| IHttpClientService httpClientService, | ||
| ITenantService tenantService, | ||
| ICacheService cacheService, | ||
| ILogger<IoTHubDeviceService> logger) | ||
| : BaseAzureService(tenantService), IIoTHubDeviceService | ||
| { | ||
| private readonly IIoTHubService _ioTHubService = ioTHubService ?? throw new ArgumentNullException(nameof(ioTHubService)); | ||
| private readonly IAzureTokenCredentialProvider _credentialProvider = credentialProvider ?? throw new ArgumentNullException(nameof(credentialProvider)); | ||
| private readonly IHttpClientService _httpClientService = httpClientService ?? throw new ArgumentNullException(nameof(httpClientService)); | ||
| private readonly ITenantService _tenantService = tenantService ?? throw new ArgumentNullException(nameof(tenantService)); | ||
| private readonly ICacheService _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService)); | ||
| private readonly ILogger<IoTHubDeviceService> _logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
Comment on lines
+7
to
+13
| using Azure.Mcp.Core.Options; | ||
| using Azure.Mcp.Core.Services.Azure; | ||
| using Azure.Mcp.Core.Services.Azure.Authentication; | ||
| using Azure.Mcp.Core.Services.Azure.Tenant; | ||
| using Azure.Mcp.Core.Services.Caching; | ||
| using Azure.Mcp.Core.Services.Http; | ||
| using Azure.Mcp.Tools.IoTHub.Commands; |
Comment on lines
+4
to
+23
| using System.Text.Json; | ||
| using Azure.Mcp.Core.Options; | ||
| using Azure.Mcp.Core.Services.Azure; | ||
| using Azure.Mcp.Core.Services.Azure.Subscription; | ||
| using Azure.Mcp.Core.Services.Azure.Tenant; | ||
| using Azure.Mcp.Tools.IoTHub.Models; | ||
| using Azure.ResourceManager.IotHub; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Azure.Mcp.Tools.IoTHub.Services; | ||
|
|
||
| public class IoTHubService( | ||
| ISubscriptionService subscriptionService, | ||
| ITenantService tenantService, | ||
| ILogger<IoTHubService> logger) | ||
| : BaseAzureResourceService(subscriptionService, tenantService), IIoTHubService | ||
| { | ||
| private readonly ISubscriptionService _subscriptionService = subscriptionService; | ||
| private readonly ILogger<IoTHubService> _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
|
|
Comment on lines
+4
to
+17
| using System.CommandLine; | ||
| using System.Net; | ||
| using Azure.Mcp.Core.Commands; | ||
| using Azure.Mcp.Core.Commands.Subscription; | ||
| using Azure.Mcp.Core.Extensions; | ||
| using Azure.Mcp.Core.Models.Command; | ||
| using Azure.Mcp.Core.Models.Option; | ||
| using Azure.Mcp.Core.Options; | ||
| using Azure.Mcp.Tools.IoTHub.Options; | ||
| using Azure.Mcp.Tools.IoTHub.Options.Device; | ||
| using Azure.Mcp.Tools.IoTHub.Services; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Mcp.Core.Models.Option; | ||
|
|
Comment on lines
+25
to
+30
| public override string Description => "List devices in an IoT Hub device registry. Returns each device identity metadata without authentication keys. " + | ||
| "This is the preferred command for listing devices, including when the user asks for a small, specific number of devices (e.g. 'list 2 devices'); set --max-count to the requested number. " + | ||
| "Use --max-count to set the page size (default 100, maximum 100). Values greater than 100 are capped at 100, so one call returns at most 100 devices. " + | ||
| "For natural-language user requests to list all devices, the rest of the devices, more than 100 devices, or any large device set, use the 'iothub query run' command (MCP tool iothub_query_run) with a compact projection instead of this list command, but still return only one page and do not loop for additional pages. " + | ||
| "For normal list/show responses, present a compact summary with deviceId, status, connectionState, and any user-requested tags or fields. Do not include full raw JSON unless the user explicitly asks for raw device identity metadata. " + | ||
| "Hub names/IDs are case-sensitive and must match exactly."; |
| public sealed class IoTHubDeviceListCommand(IIoTHubDeviceService service, ILogger<IoTHubDeviceListCommand> logger) | ||
| : BaseIoTHubCommand<IoTHubDeviceListOptions> | ||
| { | ||
| public override string Id => "iothub-device-list"; |
Comment on lines
+218
to
+224
| Assert.Contains("more than 100 devices", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("iothub query run", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("iothub_query_run", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("compact projection", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("compact summary", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("return only one page", _command.Description, StringComparison.Ordinal); | ||
| Assert.Contains("do not loop", _command.Description, StringComparison.Ordinal); |
Comment on lines
+11
to
+13
| # Create test devices for device registry tests | ||
| $testDevices = @('test-device-1', 'test-device-2', 'test-device-3') | ||
|
|
Comment on lines
+2
to
+6
| "chat.mcp.serverSampling": { | ||
| "mcp-pr/.vscode/mcp.json: iris-local-mcp": { | ||
| "allowedDuringChat": true | ||
| } | ||
| } |
Author
|
@microsoft-github-policy-service agree company="Microsoft" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the
azmcp iothub device listcommand to list device identities in an Azure IoT Hub device registry. Returns device metadata without authentication keys, supports --max-count (default 100, maximum 100) with a truncated flag when more devices exist, and returns a validation error when --max-count is less than 1.Includes the Azure.Mcp.Tools.IoTHub project (device list command, options, models, services, unit and live tests) and wires it into the server registration, command docs, e2e prompts, CHANGELOG, and consolidated-tools.json.
What does this PR do?
[Provide a clear, concise description of the changes][Add additional context, screenshots, or information that helps reviewers]GitHub issue number?
[Link to the GitHub issue this PR addresses]Pre-merge Checklist
servers/Azure.Mcp.Server/README.mdand/orservers/Fabric.Mcp.Server/README.mddocumentationREADME.mdchanges running the script./eng/scripts/Process-PackageReadMe.ps1. See Package READMEToolDescriptionEvaluatorand obtained a score of0.4or more and a top 3 ranking for all related test promptsconsolidated-tools.jsonbreaking-changelabelservers/Azure.Mcp.Server/docs/azmcp-commands.md./eng/scripts/Update-AzCommandsMetadata.ps1to update tool metadata inazmcp-commands.md(required for CI)servers/Azure.Mcp.Server/docs/e2eTestPrompts.mdcrypto mining, spam, data exfiltration, etc.)/azp run mcp - pullrequest - liveto run Live Test Pipeline