Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@
# ServiceLabel: %tools-Grafana
# ServiceOwners: @weng5e @xiangyan99

# PRLabel: %tools-IoTHub
/tools/Azure.Mcp.Tools.IoTHub/ @prerakpradhan @jichang1 @microsoft/azure-mcp

# ServiceLabel: %tools-IoTHub
# ServiceOwners: @prerakpradhan @jichang1 @microsoft/azure-mcp

# PRLabel: %tools-KeyVault
/tools/Azure.Mcp.Tools.KeyVault/ @vcolin7 @JonathanCrd @microsoft/azure-mcp

Expand Down
16 changes: 16 additions & 0 deletions .vscode/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"servers": {
"iris-local-mcp": {
"type": "stdio",
"command": "dotnet",
"args": [
"servers/Azure.Mcp.Server/src/bin/Release/net9.0/azmcp.dll",
"server",
"start",
"--namespace",
"iothub"
]
}
},
"inputs": []
}
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"chat.mcp.serverSampling": {
"mcp-pr/.vscode/mcp.json: iris-local-mcp": {
"allowedDuringChat": true
}
}
Comment thread
Copilot marked this conversation as resolved.
}
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<PackageVersion Include="Azure.ResourceManager.ContainerService" Version="1.2.5" />
<PackageVersion Include="Azure.ResourceManager.EventGrid" Version="1.2.0-beta.2" />
<PackageVersion Include="Azure.ResourceManager.EventHubs" Version="1.2.1" />
<PackageVersion Include="Azure.ResourceManager.IotHub" Version="1.2.0-beta.2" />
<PackageVersion Include="Azure.ResourceManager.CognitiveServices" Version="1.5.1" />
<PackageVersion Include="Microsoft.CognitiveServices.Speech" Version="1.46.0" />
<PackageVersion Include="Azure.ResourceManager.MySql" Version="1.1.2" />
Expand Down Expand Up @@ -86,7 +87,7 @@
<PackageVersion Include="System.Net.ServerSentEvents" Version="10.0.0-rc.1.25451.107" />
<PackageVersion Include="System.Numerics.Tensors" Version="9.0.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.9" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.3.0" />
<PackageVersion Include="Microsoft.Extensions.Azure" Version="1.11.0" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.9" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,39 @@
"keyvault_secret_create"
]
},
{
"name": "query_azure_iothub_devices",
"description": "List devices and retrieve device identity metadata from the Azure IoT Hub device registry.",
"toolMetadata": {
"destructive": {
"value": false,
"description": "This tool performs only read operations without deleting or modifying existing resources."
},
"idempotent": {
"value": true,
"description": "Running this operation multiple times with the same arguments produces the same result without additional effects."
},
"openWorld": {
"value": false,
"description": "This tool's domain of interaction is closed and well-defined, limited to a specific set of entities."
},
"readOnly": {
"value": true,
"description": "This tool only performs read operations without modifying any state or data."
},
"secret": {
"value": false,
"description": "This tool does not handle sensitive or secret information."
},
"localRequired": {
"value": false,
"description": "This tool is available in both local and remote server modes."
}
},
"mappedToolList": [
"iothub_device_list"
]
},
{
"name": "import_azure_key_vault_certificates",
"description": "Import external certificates into Azure Key Vault",
Expand Down
4 changes: 2 additions & 2 deletions core/Azure.Mcp.Core/src/Services/Http/HttpClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ private HttpClient CreateClientInternal()
#if DEBUG
// If a TEST_PROXY_URL is configured, insert RecordingRedirectHandler as the last delegating handler
var testProxyUrl = Environment.GetEnvironmentVariable("TEST_PROXY_URL");
Console.WriteLine("Using test proxy URL: " + testProxyUrl);
HttpMessageHandler pipeline = handler;
if (!string.IsNullOrWhiteSpace(testProxyUrl) && Uri.TryCreate(testProxyUrl, UriKind.Absolute, out var proxyUri))
{
Console.WriteLine("Inserting RecordingRedirectHandler for test proxy.");
// Write to stderr so stdout stays reserved for command/JSON-RPC output.
Console.Error.WriteLine("Inserting RecordingRedirectHandler for test proxy: " + testProxyUrl);
// RecordingRedirectHandler should be the last delegating handler before the transport
pipeline = new RecordingRedirectHandler(proxyUri)
{
Expand Down
13 changes: 13 additions & 0 deletions dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"azure.mcp": {
"version": "2.0.4",
"commands": [
"azmcp"
],
"rollForward": false
}
}
}
156 changes: 156 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@azure/mcp": "^3.0.0-beta.19"
}
}
2 changes: 2 additions & 0 deletions servers/Azure.Mcp.Server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The Azure MCP Server updates automatically by default whenever a new release com

### Features Added

- Added `azmcp iothub device list` to list device identities in an Azure IoT Hub device registry. The command returns device metadata without authentication keys, applies a default page size of 100 and a maximum of 100 to `--max-count`, returns a validation error when `--max-count` is less than 1, and flags `truncated` (with an explanatory message) when the hub contains more devices than were returned.

### Breaking Changes

### Bugs Fixed
Expand Down
1 change: 1 addition & 0 deletions servers/Azure.Mcp.Server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ The Azure MCP Server provides tools for interacting with **40+ Azure service are
- 🐘 **Azure Database for PostgreSQL** - PostgreSQL database management
- 📊 **Azure Event Grid** - Event routing and management
- ⚡ **Azure Functions** - Function App management
- 🌐 **Azure IoT Hub** - IoT device management and messaging
- 🔑 **Azure Key Vault** - Secrets, keys, and certificates
- ☸️ **Azure Kubernetes Service (AKS)** - Container orchestration
- 📦 **Azure Load Testing** - Performance testing
Expand Down
14 changes: 14 additions & 0 deletions servers/Azure.Mcp.Server/docs/azmcp-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,20 @@ azmcp loadtesting testrun update --subscription <subscription> \
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp grafana list --subscription <subscription>
```
### Azure IoT Hub Operations

#### Device Registry Operations

```bash
# List devices in an IoT Hub
# Returns one page of device identities. --max-count sets the page size (default 100, maximum 100).
# When the hub has more devices than were returned, the response sets truncated=true with an explanatory message.
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp iothub device list --subscription <subscription> \
--resource-group <resource-group> \
--name <iothub-name> \
[--max-count <max-count>]
```

### Azure Marketplace Operations

Expand Down
9 changes: 9 additions & 0 deletions servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,15 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
| functionapp_get | Show me my Azure function apps |
| functionapp_get | What function apps do I have? |

## Azure IoT Hub

| Tool Name | Test Prompt |
|:----------|:----------|
| iothub_device_list | List all devices in IoT Hub <iothub-name> |
| iothub_device_list | Show me the devices in IoT Hub <iothub-name> in resource group <resource-group> |
| iothub_device_list | List the first 10 devices in IoT Hub <iothub-name> |
| iothub_device_list | What devices are registered in IoT Hub <iothub-name>? |

## Azure Key Vault

| Tool Name | Test Prompt |
Expand Down
5 changes: 4 additions & 1 deletion servers/Azure.Mcp.Server/src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ private static async Task<int> Main(string[] args)
services.AddLogging(builder =>
{
builder.ConfigureOpenTelemetryLogger();
builder.AddConsole();
// Send console logs to stderr so stdout carries only the command's JSON
// response. Keeps CLI output parseable and avoids corrupting stdio MCP output.
builder.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);
builder.SetMinimumLevel(LogLevel.Information);
});

Expand Down Expand Up @@ -97,6 +99,7 @@ private static IAreaSetup[] RegisterAreas()
new Azure.Mcp.Tools.Foundry.FoundrySetup(),
new Azure.Mcp.Tools.FunctionApp.FunctionAppSetup(),
new Azure.Mcp.Tools.Grafana.GrafanaSetup(),
new Azure.Mcp.Tools.IoTHub.IoTHubSetup(),
new Azure.Mcp.Tools.KeyVault.KeyVaultSetup(),
new Azure.Mcp.Tools.Kusto.KustoSetup(),
new Azure.Mcp.Tools.LoadTesting.LoadTestingSetup(),
Expand Down
7 changes: 7 additions & 0 deletions tools/Azure.Mcp.Tools.IoTHub/src/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Azure.Mcp.Tools.IoTHub.UnitTests")]
[assembly: InternalsVisibleTo("Azure.Mcp.Tools.IoTHub.LiveTests")]
20 changes: 20 additions & 0 deletions tools/Azure.Mcp.Tools.IoTHub/src/Azure.Mcp.Tools.IoTHub.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="**\Resources\*.txt" />
<EmbeddedResource Include="**\Resources\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\core\Azure.Mcp.Core\src\Azure.Mcp.Core.csproj" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<PackageReference Include="Azure.ResourceManager" />
<PackageReference Include="Azure.ResourceManager.IotHub" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="ModelContextProtocol" />
<PackageReference Include="System.CommandLine" />
</ItemGroup>
</Project>
Loading