Files
mcp-microsoft/eng/scripts/Update-AzCommandsMetadata.ps1
T
Patrick Hallisey 3fec7fdea6 Update repo to use net10.0 (#1221)
* Update projects to target net10
- Update TargetFramework in directory.build.props to net10.0
- Update framework dependency package versions to the 10.0 series
* reader.EndOfStream isn't safe in async and unnecessary when using ReadLineAsync
* Update npgsql to 10.0.1
2026-01-13 12:42:25 -08:00

214 lines
6.8 KiB
PowerShell

<#
.SYNOPSIS
Updates azmcp-commands.md with tool metadata information
.DESCRIPTION
This script executes 'azmcp tools list', extracts metadata for each tool,
and updates the azmcp-commands.md file by adding metadata information above
each tool command. Maintains the existing format, schema, and order.
.PARAMETER AzmcpPath
Path to the azmcp.exe executable. Default: ..\..\servers\Azure.Mcp.Server\src\bin\Debug\net10.0\azmcp.exe
.PARAMETER DocsPath
Path to the azmcp-commands.md file. Default: ..\..\servers\Azure.Mcp.Server\docs\azmcp-commands.md
.EXAMPLE
.\Update-AzCommandsMetadata.ps1
.EXAMPLE
.\Update-AzCommandsMetadata.ps1 -AzmcpPath "C:\path\to\azmcp.exe" -DocsPath "C:\path\to\azmcp-commands.md"
#>
[CmdletBinding()]
param(
[string]$AzmcpPath = "..\..\servers\Azure.Mcp.Server\src\bin\Debug\net10.0\azmcp.exe",
[string]$DocsPath = "..\..\servers\Azure.Mcp.Server\docs\azmcp-commands.md"
)
$ErrorActionPreference = "Stop"
function Get-MetadataLine {
param(
[string]$PropertyName,
[bool]$Value
)
$icon = if ($Value) { "✅" } else { "❌" }
# Convert to PascalCase
$pascalCase = switch ($PropertyName) {
"destructive" { "Destructive" }
"idempotent" { "Idempotent" }
"openWorld" { "OpenWorld" }
"readOnly" { "ReadOnly" }
"secret" { "Secret" }
"localRequired" { "LocalRequired" }
default { (Get-Culture).TextInfo.ToTitleCase($PropertyName) }
}
return "$icon $pascalCase"
}
function Get-ToolMetadataString {
param(
[PSCustomObject]$Metadata
)
$lines = @()
# Order: destructive, idempotent, openWorld, readOnly, secret, localRequired
if ($null -ne $Metadata.destructive) {
$lines += Get-MetadataLine "destructive" $Metadata.destructive.value
}
if ($null -ne $Metadata.idempotent) {
$lines += Get-MetadataLine "idempotent" $Metadata.idempotent.value
}
if ($null -ne $Metadata.openWorld) {
$lines += Get-MetadataLine "openWorld" $Metadata.openWorld.value
}
if ($null -ne $Metadata.readOnly) {
$lines += Get-MetadataLine "readOnly" $Metadata.readOnly.value
}
if ($null -ne $Metadata.secret) {
$lines += Get-MetadataLine "secret" $Metadata.secret.value
}
if ($null -ne $Metadata.localRequired) {
$lines += Get-MetadataLine "localRequired" $Metadata.localRequired.value
}
if ($lines.Count -gt 0) {
# Add # prefix for markdown comment
return "# " + ($lines -join " | ")
}
return $null
}
Write-Host "Starting update of azmcp-commands.md with tool metadata..." -ForegroundColor Cyan
# Validate paths
if (-not (Test-Path $AzmcpPath)) {
Write-Error "azmcp.exe not found at: $AzmcpPath"
exit 1
}
if (-not (Test-Path $DocsPath)) {
Write-Error "azmcp-commands.md not found at: $DocsPath"
exit 1
}
# Execute azmcp tools list and capture output
Write-Host "Executing 'azmcp tools list'..." -ForegroundColor Yellow
$toolsListOutput = & $AzmcpPath tools list 2>&1 | Out-String
# Parse JSON output
Write-Host "Parsing tools list output..." -ForegroundColor Yellow
try {
$toolsData = $toolsListOutput | ConvertFrom-Json
if ($toolsData.status -ne 200) {
Write-Error "Failed to get tools list. Status: $($toolsData.status), Message: $($toolsData.message)"
exit 1
}
} catch {
Write-Error "Failed to parse tools list output as JSON: $_"
exit 1
}
# Build a dictionary of command -> metadata
Write-Host "Building command metadata dictionary..." -ForegroundColor Yellow
$commandMetadata = @{}
foreach ($tool in $toolsData.results) {
if ($tool.command -and $tool.metadata) {
$commandMetadata[$tool.command] = $tool.metadata
}
}
Write-Host "Found $($commandMetadata.Count) tools with metadata" -ForegroundColor Green
# Read the docs file
Write-Host "Reading $DocsPath..." -ForegroundColor Yellow
# Split into lines for processing
$docLines = Get-Content $DocsPath
# Process the document
Write-Host "Processing document and adding metadata..." -ForegroundColor Yellow
$updatedLines = @()
$i = 0
$updatedCount = 0
$removedCount = 0
while ($i -lt $docLines.Count) {
$line = $docLines[$i]
# Check if this is a metadata line (with or without # prefix) and remove it
# We'll regenerate all metadata lines to ensure they're correct
if ($line -match '^#?\s*(✅|❌)\s+(Destructive|Idempotent|Openworld|OpenWorld|Readonly|ReadOnly|Secret|Localrequired|LocalRequired)') {
Write-Verbose "Removing existing metadata line: $line"
$removedCount++
$i++
continue
}
# Check if this line starts with "azmcp " (a command line)
if ($line -match '^azmcp\s+(.+?)(\s+\\)?$') {
# Extract the command (without the trailing backslash and parameters)
$commandLine = $line.Trim()
# Try to find the base command in our metadata dictionary
$matchedCommand = $null
$matchedMetadata = $null
foreach ($cmd in $commandMetadata.Keys) {
# Prepend "azmcp " to the command from metadata to match the format in the file
$fullCommand = "azmcp $cmd"
# Check if the line starts with this command
if ($commandLine -match "^$([regex]::Escape($fullCommand))(\s|\\|$)") {
$matchedCommand = $cmd
$matchedMetadata = $commandMetadata[$cmd]
break
}
}
if ($matchedMetadata) {
# Generate metadata string
$metadataString = Get-ToolMetadataString $matchedMetadata
if ($metadataString) {
# Add metadata line above the command
$updatedLines += $metadataString
$updatedCount++
Write-Verbose "Added metadata for: $matchedCommand"
}
}
}
# Add the current line
$updatedLines += $line
$i++
}
# Write the updated content back to the file
Write-Host "Writing updated content to $DocsPath..." -ForegroundColor Yellow
$updatedLines | Out-File -FilePath $DocsPath -Encoding utf8 -Force
# Clean up temporary output file
$tempOutputFile = "..\..\tools-list-output.json"
if (Test-Path $tempOutputFile) {
Write-Host "Cleaning up temporary output file..." -ForegroundColor Yellow
Remove-Item $tempOutputFile -Force
Write-Verbose "Deleted temporary file: $tempOutputFile"
}
Write-Host "`nUpdate complete!" -ForegroundColor Green
Write-Host " - Total commands found in metadata: $($commandMetadata.Count)" -ForegroundColor Cyan
Write-Host " - Old metadata lines removed: $removedCount" -ForegroundColor Cyan
Write-Host " - New metadata lines added: $updatedCount" -ForegroundColor Cyan
Write-Host "`nPlease review the changes in $DocsPath" -ForegroundColor Yellow