Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 4 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
# Build the runtime image
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS runtime
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/runtime:10.0.0-rc.1-azurelinux3.0-distroless AS runtime

# Add build argument for publish directory
ARG PUBLISH_DIR

# Error out if PUBLISH_DIR is not set
RUN if [ -z "$PUBLISH_DIR" ]; then \
echo "ERROR: PUBLISH_DIR build argument is required" && exit 1; \
fi

RUN apk add --no-cache libc6-compat
ARG TARGETOS
ARG TARGETARCH

# Copy the contents of the publish directory to '/azuremcpserver' and set it as the working directory
RUN mkdir -p /azuremcpserver
COPY ${PUBLISH_DIR} /azuremcpserver/
COPY ${PUBLISH_DIR}/${TARGETOS}-${TARGETARCH}/dist/ /azuremcpserver/
WORKDIR /azuremcpserver
Comment on lines +9 to 10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be easier to support by templating PUBLISH_DIR with os and arch outside of the docker build call... we should also just assume PUBLISH_DIR is a path to binary root. Also, we'll need to support other servers:

Suggested change
COPY ${PUBLISH_DIR}/${TARGETOS}-${TARGETARCH}/dist/ /azuremcpserver/
WORKDIR /azuremcpserver
COPY ${PUBLISH_DIR} /mcpserver/
WORKDIR /mcpserver

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, to support multiple servers, we need to start passing the CLI name in. This is a little difficult as ENTRYPOINT doesn't have access to build variables and doesn't evaluate environment variables, se we can't do something simple like:

ENTRYPOINT ["./${CLI_NAME}", "server", "start"]

or even

ENV CLI=${CLI_NAME}
ENTRYPOINT ["./$CLI", "server", "start"]

If we use the exec form, but invoke the shell, we can still wire up additional docker run args:

ENV CLI=${CLI_NAME}
ENTRYPOINT ["sh", "-c", "./$CLI server start $@"]

I'm not sure how this compares to the shell form:

ENV CLI=${CLI_NAME}
ENTRYPOINT "./$CLI" server start $0

Copy link
Member

@hallipr hallipr Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the shell-via-exec form, I was able to pass additional command line parameters through a docker run call:

> docker run azure-sdk/template-mcp:0.0.12-alpha.12345 --version
0.0.12-alpha.12345+3af3798511a7cf2441b662c2473941070331c5de


# List the contents of the current directory
RUN ls -la

# Ensure the main binary exists and is executable
RUN if [ ! -f "azmcp" ]; then \
echo "ERROR: azmcp executable does not exist" && exit 1; \
fi \
&& chmod +x azmcp \
&& test -x azmcp

ENTRYPOINT ["./azmcp", "server", "start"]
88 changes: 77 additions & 11 deletions eng/scripts/Build-Docker.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,105 @@ param(
[Parameter(Mandatory=$true)]
[string] $ServerName,
[switch] $Trimmed,
[switch] $DebugBuild
[switch] $DebugBuild,
[Parameter(Mandatory=$true, ParameterSetName='SpecificPlatform')]
[ValidateSet('windows','linux','macOS')]
[string] $OperatingSystem,
[Parameter(Mandatory=$true, ParameterSetName='SpecificPlatform')]
[ValidateSet('x64','arm64')]
[string] $Architecture,
[Parameter(ParameterSetName='AllPlatforms')]
[switch] $AllPlatforms
)

function Get-DockerOS([string]$dotnetName) {
switch ($dotnetName) {
'linux' { return 'linux' }
'macOS' { return 'linux' }
'windows' { return 'win' }
default { return $dotnetName }
}
}

function Get-DockerArchitecture([string]$dotnetName) {
switch ($dotnetName) {
'x64' { return 'amd64' }
default { return $dotnetName }
}
}

. "$PSScriptRoot/../common/scripts/common.ps1"
$root = $RepoRoot.Path.Replace('\', '/')
$distPath = "$root/.work"
$dockerFile = "$root/Dockerfile"
$properties = & "$PSScriptRoot/Get-ProjectProperties.ps1" -ProjectName "$ServerName.csproj"
$dockerImageName = $properties.DockerImageName
$buildDirectory = $([System.IO.Path]::Combine($distPath, "build", $ServerName))

if(!$Version) {
$Version = $properties.Version
}

# Will fix this when we update Dockerfile to multi-platform
$os = "linux"
$arch = "x64"
$SingleFile = $Trimmed
$tag = "$dockerImageName`:$Version$VersionSuffix";

& "$root/eng/scripts/Build-Code.ps1" -ServerName $ServerName -VersionSuffix $VersionSuffix -SelfContained -Trimmed:$Trimmed -SingleFile:$SingleFile -DebugBuild:$DebugBuild -OperatingSystem $os -Architecture $arch
if ($AllPlatforms) {
& "$root/eng/scripts/Build-Code.ps1" -ServerName $ServerName -VersionSuffix $VersionSuffix -SelfContained -Trimmed:$Trimmed -SingleFile:$SingleFile -DebugBuild:$DebugBuild -AllPlatforms

$operatingSystems = @('linux','windows')
$architectures = @('x64','arm64')

} elseif ($OperatingSystem -and $Architecture) {
if ($OperatingSystem -eq 'macOS') {
$OperatingSystem = 'linux'
}

& "$root/eng/scripts/Build-Code.ps1" -ServerName $ServerName -VersionSuffix $VersionSuffix -SelfContained -Trimmed:$Trimmed -SingleFile:$SingleFile -DebugBuild:$DebugBuild -OperatingSystem $OperatingSystem -Architecture $Architecture

$operatingSystems = @($OperatingSystem)
$architectures = @($Architecture)
} else {
Write-Error "Either specify both OperatingSystem and Architecture, or use the AllPlatforms switch."
exit 1
}

if ($LastExitCode -ne 0) {
exit $LastExitCode
}

[string]$publishDirectory = $([System.IO.Path]::Combine($distPath, "build", $ServerName, "$os-$arch", "dist"))
$relativeDirectory = $(Resolve-Path $publishDirectory -Relative).Replace('\', '/')
# Move x64 folder to amd64 to match Docker naming conventions
foreach ($os in $operatingSystems) {

}
Comment on lines +77 to +79
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed anymore?

Suggested change
foreach ($os in $operatingSystems) {
}


[string[]]$identifiers = @()
foreach($os in $operatingSystems) {
$dockerOS = Get-DockerOS $os

Write-Host "Building Docker image ($tag). PATH: [$relativeDirectory]. Absolute: [$publishDirectory]."
foreach($arch in $architectures) {
$dockerArchitecture = Get-DockerArchitecture $arch

if (!(Test-Path $publishDirectory)) {
Write-Error "Build output directory does not exist: $publishDirectory"
if ($arch -eq 'x64') {
$x64Folder = "$buildDirectory/$dockerOS-x64"
$destination = "$buildDirectory/$dockerOS-amd64"
Write-Host "Moving $x64Folder to $destination" -ForegroundColor Yellow
Move-Item -Path $x64Folder -Destination $destination -Force
}

$identifiers += "$dockerOS/$dockerArchitecture"
}
}

# The COPY command needs to be within the scope of the "working directory". Usually where the ./Dockerfile is. We need a relative path.
$relativeDirectory = $(Resolve-Path $buildDirectory -Relative).Replace('\', '/')

if (!(Test-Path $buildDirectory)) {
Write-Error "Build output directory does not exist: $buildDirectory"
return
}

& docker build --build-arg PUBLISH_DIR="$relativeDirectory" --file $dockerFile --tag $tag .
[string]$platformString = [string]::Join(',', $identifiers)

Write-Host "Building Docker image ($tag). PATH: [$relativeDirectory]. Absolute: [$buildDirectory]. Platforms: [$platformString]"

& docker build --platform $platformString --build-arg PUBLISH_DIR="$relativeDirectory" --file $dockerFile --tag $tag .
Loading