Sync eng/common directory with azure-sdk-tools for PR 10470 (#6549)
* Initialize azure sdk MCP conventions/automation * Fixes --------- Co-authored-by: Ben Broderick Phillips <bebroder@microsoft.com>
This commit is contained in:
parent
60c9a70a99
commit
1ea9610745
38
eng/common/mcp/README.md
Normal file
38
eng/common/mcp/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Azure SDK MCP Servers
|
||||
|
||||
This document details how to author, publish and use [MCP servers](https://github.com/modelcontextprotocol) for azure sdk team usage.
|
||||
|
||||
## Using the Azure SDK MCP Server
|
||||
|
||||
Run the below command to download and run the azure sdk engsys mcp server manually:
|
||||
|
||||
```
|
||||
<repo root>/eng/common/mcp/azure-sdk-mcp.ps1 -Run
|
||||
```
|
||||
|
||||
To install the mcp server for use within vscode copilot agent mode, run the following then launch vscode from the repository root.
|
||||
|
||||
```
|
||||
<repo root>/eng/common/mcp/azure-sdk-mcp.ps1 -UpdateVsCodeConfig
|
||||
```
|
||||
|
||||
*When updating the config the script will not overwrite any other server configs.*
|
||||
|
||||
The script will install the latest version of the azsdk cli executable from [tools releases](https://github.com/Azure/azure-sdk-tools/releases) and install it to `$HOME/.azure-sdk-mcp/azsdk`.
|
||||
|
||||
## Authoring an MCP server
|
||||
|
||||
MCP server code should be placed in [azure-sdk-tools/tools/mcp/dotnet](https://github.com/Azure/azure-sdk-tools/tree/main/tools/mcp/dotnet).
|
||||
|
||||
Azure SDK MCP servers should support [stdio and sse transports](https://modelcontextprotocol.io/docs/concepts/transports#server-sent-events-sse).
|
||||
|
||||
When running in copilot the default is stdio mode, but SSE is useful to support for external debugging.
|
||||
|
||||
### Developing MCP servers in C#
|
||||
|
||||
See the [C# MCP SDK](https://github.com/modelcontextprotocol/csharp-sdk)
|
||||
|
||||
Add an [SSE transport](https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples/AspNetCoreSseServer)
|
||||
|
||||
TODO: Add the azsdk-cli project to pull in MCP server dependencies from the repo
|
||||
|
||||
60
eng/common/mcp/azure-sdk-mcp.ps1
Executable file
60
eng/common/mcp/azure-sdk-mcp.ps1
Executable file
@ -0,0 +1,60 @@
|
||||
#!/bin/env pwsh
|
||||
|
||||
param(
|
||||
[string]$FileName = 'azsdk',
|
||||
[string]$Package = 'azsdk',
|
||||
[string]$Version, # Default to latest
|
||||
[string]$InstallDirectory = (Join-Path $HOME ".azure-sdk-mcp" "azsdk"),
|
||||
[string]$Repository = 'Azure/azure-sdk-tools',
|
||||
[switch]$Run,
|
||||
[switch]$UpdateVsCodeConfig,
|
||||
[switch]$Clean
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
. (Join-Path $PSScriptRoot '..' 'scripts' 'Helpers' 'AzSdkTool-Helpers.ps1')
|
||||
|
||||
if ($Clean) {
|
||||
Clear-Directory -Path $InstallDirectory
|
||||
}
|
||||
|
||||
if ($UpdateVsCodeConfig) {
|
||||
$vscodeConfigPath = $PSScriptRoot + "../../../.vscode/mcp.json"
|
||||
if (Test-Path $vscodeConfigPath) {
|
||||
$vscodeConfig = Get-Content -Raw $vscodeConfig | ConvertFrom-Json -AsHashtable
|
||||
}
|
||||
else {
|
||||
$vscodeConfig = @{}
|
||||
}
|
||||
$serverKey = "azure-sdk-mcp"
|
||||
$serverConfig = @{
|
||||
"type" = "stdio"
|
||||
"command" = "/home/ben/azs/azure-sdk-tools/eng/common/mcp/azure-sdk-mcp.ps1"
|
||||
}
|
||||
$orderedServers = [ordered]@{
|
||||
$serverKey = $serverConfig
|
||||
}
|
||||
if (-not $vscodeConfig.ContainsKey('servers')) {
|
||||
$vscodeConfig['servers'] = @{}
|
||||
}
|
||||
foreach ($key in $vscodeConfig.servers.Keys) {
|
||||
if ($key -ne $serverKey) {
|
||||
$orderedServers[$key] = $vscodeConfig.servers[$key]
|
||||
}
|
||||
}
|
||||
$vscodeConfig.servers = $orderedServers
|
||||
Write-Host "Updating vscode mcp config at $vscodeConfigPath"
|
||||
$vscodeConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $vscodeConfig -Force
|
||||
}
|
||||
|
||||
$exe = Install-Standalone-Tool `
|
||||
-Version $Version `
|
||||
-FileName $FileName `
|
||||
-Package $Package `
|
||||
-Directory $InstallDirectory `
|
||||
-Repository $Repository
|
||||
|
||||
if ($Run) {
|
||||
Start-Process -FilePath $exe -NoNewWindow -Wait
|
||||
}
|
||||
194
eng/common/scripts/Helpers/AzSdkTool-Helpers.ps1
Normal file
194
eng/common/scripts/Helpers/AzSdkTool-Helpers.ps1
Normal file
@ -0,0 +1,194 @@
|
||||
Set-StrictMode -Version 4
|
||||
|
||||
function Get-SystemArchitecture {
|
||||
$unameOutput = uname -m
|
||||
switch ($unameOutput) {
|
||||
"x86_64" { return "X86_64" }
|
||||
"aarch64" { return "ARM64" }
|
||||
"arm64" { return "ARM64" }
|
||||
default { throw "Unable to determine system architecture. uname -m returned $unameOutput." }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Package-Meta(
|
||||
[Parameter(mandatory = $true)]
|
||||
$FileName,
|
||||
[Parameter(mandatory = $true)]
|
||||
$Package
|
||||
) {
|
||||
$ErrorActionPreferenceDefault = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$AVAILABLE_BINARIES = @{
|
||||
"Windows" = @{
|
||||
"AMD64" = @{
|
||||
"system" = "Windows"
|
||||
"machine" = "AMD64"
|
||||
"file_name" = "$FileName-standalone-win-x64.zip"
|
||||
"executable" = "$Package.exe"
|
||||
}
|
||||
}
|
||||
"Linux" = @{
|
||||
"X86_64" = @{
|
||||
"system" = "Linux"
|
||||
"machine" = "X86_64"
|
||||
"file_name" = "$FileName-standalone-linux-x64.tar.gz"
|
||||
"executable" = "$Package"
|
||||
}
|
||||
"ARM64" = @{
|
||||
"system" = "Linux"
|
||||
"machine" = "ARM64"
|
||||
"file_name" = "$FileName-standalone-linux-arm64.tar.gz"
|
||||
"executable" = "$Package"
|
||||
}
|
||||
}
|
||||
"Darwin" = @{
|
||||
"X86_64" = @{
|
||||
"system" = "Darwin"
|
||||
"machine" = "X86_64"
|
||||
"file_name" = "$FileName-standalone-osx-x64.zip"
|
||||
"executable" = "$Package"
|
||||
}
|
||||
"ARM64" = @{
|
||||
"system" = "Darwin"
|
||||
"machine" = "ARM64"
|
||||
"file_name" = "$FileName-standalone-osx-arm64.zip"
|
||||
"executable" = "$Package"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($IsWindows) {
|
||||
$os = "Windows"
|
||||
# we only support x64 on windows, if that doesn't work the platform is unsupported
|
||||
$machine = "AMD64"
|
||||
}
|
||||
elseif ($IsLinux) {
|
||||
$os = "Linux"
|
||||
$machine = Get-SystemArchitecture
|
||||
}
|
||||
elseif ($IsMacOS) {
|
||||
$os = "Darwin"
|
||||
$machine = Get-SystemArchitecture
|
||||
}
|
||||
else {
|
||||
$os = "unknown"
|
||||
}
|
||||
|
||||
$ErrorActionPreference = $ErrorActionPreferenceDefault
|
||||
|
||||
return $AVAILABLE_BINARIES[$os][$machine]
|
||||
}
|
||||
|
||||
function Clear-Directory ($path) {
|
||||
if (Test-Path -Path $path) {
|
||||
Remove-Item -Path $path -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $path -Force
|
||||
}
|
||||
|
||||
function isNewVersion(
|
||||
[Parameter(mandatory = $true)]
|
||||
$Version,
|
||||
[Parameter(mandatory = $true)]
|
||||
$Directory
|
||||
) {
|
||||
$savedVersionTxt = Join-Path $Directory "downloaded_version.txt"
|
||||
if (Test-Path $savedVersionTxt) {
|
||||
$result = (Get-Content -Raw $savedVersionTxt).Trim()
|
||||
|
||||
if ($result -eq $Version) {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs a standalone version of an engsys tool.
|
||||
.PARAMETER Version
|
||||
The version of the tool to install. Requires a full version to be provided. EG "1.0.0-dev.20240617.1"
|
||||
.PARAMETER Directory
|
||||
The directory within which the exe will exist after this function invokes. Defaults to "."
|
||||
#>
|
||||
function Install-Standalone-Tool (
|
||||
[Parameter()]
|
||||
[string]$Version,
|
||||
[Parameter(mandatory = $true)]
|
||||
[string]$FileName,
|
||||
[Parameter(mandatory = $true)]
|
||||
[string]$Package,
|
||||
[Parameter()]
|
||||
[string]$Repository = "Azure/azure-sdk-tools",
|
||||
[Parameter()]
|
||||
$Directory = "."
|
||||
) {
|
||||
$ErrorActionPreference = "Stop"
|
||||
$PSNativeCommandUseErrorActionPreference = $true
|
||||
|
||||
$systemDetails = Get-Package-Meta -FileName $FileName -Package $Package
|
||||
|
||||
if (!(Test-Path $Directory) -and $Directory -ne ".") {
|
||||
New-Item -ItemType Directory -Path $Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$tag = "${Package}_${Version}"
|
||||
|
||||
if (!$Version -or $Version -eq "*") {
|
||||
Write-Host "Attempting to find latest version for package '$Package'"
|
||||
$releasesUrl = "https://api.github.com/repos/$Repository/releases"
|
||||
$releases = Invoke-RestMethod -Uri $releasesUrl
|
||||
$found = $false
|
||||
foreach ($release in $releases) {
|
||||
if ($release.tag_name -like "$Package*") {
|
||||
$tag = $release.tag_name
|
||||
$Version = $release.tag_name -replace "${Package}_", ""
|
||||
$found = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($found -eq $false) {
|
||||
throw "No release found for package '$Package'"
|
||||
}
|
||||
}
|
||||
|
||||
$downloadFolder = Resolve-Path $Directory
|
||||
$downloadUrl = "https://github.com/$Repository/releases/download/$tag/$($systemDetails.file_name)"
|
||||
$downloadFile = $downloadUrl.Split('/')[-1]
|
||||
$downloadLocation = Join-Path $downloadFolder $downloadFile
|
||||
$savedVersionTxt = Join-Path $downloadFolder "downloaded_version.txt"
|
||||
$executable_path = Join-Path $downloadFolder $systemDetails.executable
|
||||
|
||||
if (isNewVersion $version $downloadFolder) {
|
||||
Write-Host "Installing '$Package' '$Version' to '$downloadFolder' from $downloadUrl"
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $downloadLocation
|
||||
|
||||
if ($downloadFile -like "*.zip") {
|
||||
Expand-Archive -Path $downloadLocation -DestinationPath $downloadFolder -Force
|
||||
}
|
||||
elseif ($downloadFile -like "*.tar.gz") {
|
||||
tar -xzf $downloadLocation -C $downloadFolder
|
||||
}
|
||||
else {
|
||||
throw "Unsupported file format"
|
||||
}
|
||||
|
||||
# Remove the downloaded file after extraction
|
||||
Remove-Item -Path $downloadLocation -Force
|
||||
|
||||
# Record downloaded version
|
||||
Set-Content -Path $savedVersionTxt -Value $Version
|
||||
|
||||
# Set executable permissions if on macOS (Darwin)
|
||||
if ($IsMacOS) {
|
||||
chmod 755 $executable_path
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "Target version '$Version' already present in target directory '$downloadFolder'"
|
||||
}
|
||||
|
||||
return $executable_path
|
||||
}
|
||||
@ -16,18 +16,15 @@ param(
|
||||
$InstallDirectory
|
||||
)
|
||||
|
||||
. (Join-Path $PSScriptRoot test-proxy.ps1)
|
||||
. (Join-Path $PSScriptRoot '..' 'scripts' 'Helpers' 'AzSdkTool-Helpers.ps1')
|
||||
|
||||
Write-Host "Attempting to download and install version `"$Version`" into `"$InstallDirectory`""
|
||||
|
||||
Install-Standalone-TestProxy -Version $Version -Directory $InstallDirectory
|
||||
$exe = Install-Standalone-Tool `
|
||||
-Version $Version `
|
||||
-FileName "test-proxy" `
|
||||
-Package "Azure.Sdk.Tools.TestProxy" `
|
||||
-Directory $InstallDirectory
|
||||
|
||||
$PROXY_EXE = ""
|
||||
|
||||
if ($IsWindows) {
|
||||
$PROXY_EXE = Join-Path $InstallDirectory "Azure.Sdk.Tools.TestProxy.exe"
|
||||
} else {
|
||||
$PROXY_EXE = Join-Path $InstallDirectory "Azure.Sdk.Tools.TestProxy"
|
||||
}
|
||||
Write-Host "Downloaded test-proxy available at $PROXY_EXE."
|
||||
Write-Host "##vso[task.setvariable variable=PROXY_EXE]$PROXY_EXE"
|
||||
Write-Host "Downloaded test-proxy available at $exe."
|
||||
Write-Host "##vso[task.setvariable variable=PROXY_EXE]$exe"
|
||||
|
||||
@ -1,162 +0,0 @@
|
||||
Set-StrictMode -Version 4
|
||||
$AVAILABLE_TEST_PROXY_BINARIES = @{
|
||||
"Windows" = @{
|
||||
"AMD64" = @{
|
||||
"system" = "Windows"
|
||||
"machine" = "AMD64"
|
||||
"file_name" = "test-proxy-standalone-win-x64.zip"
|
||||
"executable" = "Azure.Sdk.Tools.TestProxy.exe"
|
||||
}
|
||||
}
|
||||
"Linux" = @{
|
||||
"X86_64" = @{
|
||||
"system" = "Linux"
|
||||
"machine" = "X86_64"
|
||||
"file_name" = "test-proxy-standalone-linux-x64.tar.gz"
|
||||
"executable" = "Azure.Sdk.Tools.TestProxy"
|
||||
}
|
||||
"ARM64" = @{
|
||||
"system" = "Linux"
|
||||
"machine" = "ARM64"
|
||||
"file_name" = "test-proxy-standalone-linux-arm64.tar.gz"
|
||||
"executable" = "Azure.Sdk.Tools.TestProxy"
|
||||
}
|
||||
}
|
||||
"Darwin" = @{
|
||||
"X86_64" = @{
|
||||
"system" = "Darwin"
|
||||
"machine" = "X86_64"
|
||||
"file_name" = "test-proxy-standalone-osx-x64.zip"
|
||||
"executable" = "Azure.Sdk.Tools.TestProxy"
|
||||
}
|
||||
"ARM64" = @{
|
||||
"system" = "Darwin"
|
||||
"machine" = "ARM64"
|
||||
"file_name" = "test-proxy-standalone-osx-arm64.zip"
|
||||
"executable" = "Azure.Sdk.Tools.TestProxy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-SystemArchitecture {
|
||||
$unameOutput = uname -m
|
||||
switch ($unameOutput) {
|
||||
"x86_64" { return "X86_64" }
|
||||
"aarch64" { return "ARM64" }
|
||||
"arm64" { return "ARM64" }
|
||||
default { throw "Unable to determine system architecture. uname -m returned $unameOutput." }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-Proxy-Meta () {
|
||||
$ErrorActionPreferenceDefault = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$os = "unknown"
|
||||
$machine = Get-SystemArchitecture
|
||||
|
||||
if ($IsWindows) {
|
||||
$os = "Windows"
|
||||
# we only support x64 on windows, if that doesn't work the platform is unsupported
|
||||
$machine = "AMD64"
|
||||
} elseif ($IsLinux) {
|
||||
$os = "Linux"
|
||||
} elseif ($IsMacOS) {
|
||||
$os = "Darwin"
|
||||
}
|
||||
|
||||
$ErrorActionPreference = $ErrorActionPreferenceDefault
|
||||
|
||||
return $AVAILABLE_TEST_PROXY_BINARIES[$os][$machine]
|
||||
}
|
||||
|
||||
function Get-Proxy-Url (
|
||||
[Parameter(mandatory=$true)]$Version
|
||||
) {
|
||||
$systemDetails = Get-Proxy-Meta
|
||||
|
||||
$file = $systemDetails.file_name
|
||||
$url = "https://github.com/Azure/azure-sdk-tools/releases/download/Azure.Sdk.Tools.TestProxy_$Version/$file"
|
||||
|
||||
return $url
|
||||
}
|
||||
|
||||
function Cleanup-Directory ($path) {
|
||||
if (Test-Path -Path $path) {
|
||||
Remove-Item -Path $path -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $path -Force
|
||||
}
|
||||
|
||||
function Is-Work-Necessary (
|
||||
[Parameter(mandatory=$true)]
|
||||
$Version,
|
||||
[Parameter(mandatory=$true)]
|
||||
$Directory
|
||||
) {
|
||||
$savedVersionTxt = Join-Path $Directory "downloaded_version.txt"
|
||||
if (Test-Path $savedVersionTxt) {
|
||||
$result = (Get-Content -Raw $savedVersionTxt).Trim()
|
||||
|
||||
if ($result -eq $Version) {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Installs a standalone version of the test-proxy.
|
||||
.PARAMETER Version
|
||||
The version of the proxy to install. Requires a full version to be provided. EG "1.0.0-dev.20240617.1"
|
||||
.PARAMETER Directory
|
||||
The directory within which the test-proxy exe will exist after this function invokes. Defaults to "."
|
||||
#>
|
||||
function Install-Standalone-TestProxy (
|
||||
[Parameter(mandatory=$true)]
|
||||
$Version,
|
||||
$Directory="."
|
||||
) {
|
||||
$ErrorActionPreference = "Stop"
|
||||
$systemDetails = Get-Proxy-Meta
|
||||
|
||||
if (!(Test-Path $Directory) -and $Directory -ne ".") {
|
||||
New-Item -ItemType Directory -Path $Directory -Force
|
||||
}
|
||||
|
||||
$downloadFolder = Resolve-Path $Directory
|
||||
$downloadUrl = Get-Proxy-Url $Version
|
||||
$downloadFile = $downloadUrl.Split('/')[-1]
|
||||
$downloadLocation = Join-Path $downloadFolder $downloadFile
|
||||
$savedVersionTxt = Join-Path $downloadFolder "downloaded_version.txt"
|
||||
|
||||
if (Is-Work-Necessary $version $downloadFolder) {
|
||||
Write-Host "Commencing installation of `"$Version`" to `"$downloadFolder`" from $downloadUrl."
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $downloadLocation
|
||||
|
||||
if ($downloadFile -like "*.zip") {
|
||||
Expand-Archive -Path $downloadLocation -DestinationPath $downloadFolder -Force
|
||||
} elseif ($downloadFile -like "*.tar.gz") {
|
||||
tar -xzf $downloadLocation -C $downloadFolder
|
||||
} else {
|
||||
throw "Unsupported file format"
|
||||
}
|
||||
|
||||
# Remove the downloaded file after extraction
|
||||
Remove-Item -Path $downloadLocation -Force
|
||||
|
||||
# Record downloaded version
|
||||
Set-Content -Path $savedVersionTxt -Value $Version
|
||||
|
||||
# Set executable permissions if on macOS (Darwin)
|
||||
$executable_path = Join-Path $downloadFolder $systemDetails.executable
|
||||
if ($IsMacOS) {
|
||||
chmod 755 $executable_path
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "Target version `"$Version`" already present in target directory `"$downloadFolder.`""
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user