These tests exercise a running gateway, the Python examples, and registered HTTP tools. They cover modern discovery/direct calls, protocol errors, authorization, private catalogs, and incremental streaming with cancellation. For upgrade requirements and request examples, see MCP 2026-07-28 migration.
Run the commands below from the repository root. Prerequisites are .NET 8 SDK or later, Node 22.18 or later, PowerShell 7.4 or later for the examples, Docker Desktop with Kubernetes, and kubectl. Install portal dependencies with npm --prefix portal ci.
The deployment regression checks require only PowerShell 7.4 or later. They mock all Azure calls and cover namespace consistency, secret creation and reuse, failure handling, temporary-file cleanup, and ARM template settings. They do not require Azure credentials or a cluster.
pwsh -File deployment/e2e/test-deployment.ps1
Pass -BashPath bash, or the full path to Git Bash on Windows, to also syntax-check the embedded Bicep deployment script. Regenerate the ARM JSON with az bicep build --file deployment/infra/azure-deployment.bicep after changing Bicep or the cloud manifest. These offline checks do not replace a deployment test.
The local overlay uses namespace mcp-modern-e2e, a shared Redis store, and two gateway and two Tools replicas. It does not replace a deployment in the default adapter namespace. Always specify the Kubernetes context.
dotnet test dotnet/Microsoft.McpGateway.sln --configuration Debug
npm --prefix portal test
npm --prefix portal run build
docker run -d --name mcp-modern-e2e-registry -p 127.0.0.1:5000:5000 registry:2.8
e2e. For subsequent runs, choose a new tag, update both image entries in the overlay, and set MCP_IMAGE_TAG to the fixture tag so a stale local image cannot mask a change. $tag = 'e2e'
$fixtures = @{
'mcp-example' = 'sample-servers/mcp-example'
'mcp-proxy' = 'sample-servers/mcp-proxy'
'weather-tool' = 'sample-servers/tool-example'
'mcp-stream-fixture' = 'deployment/e2e/stream-server'
}
foreach ($fixture in $fixtures.GetEnumerator()) {
docker build -f "$($fixture.Value)/Dockerfile" $fixture.Value -t "localhost:5000/$($fixture.Key):$tag"
if ($LASTEXITCODE -ne 0) { throw "Build failed: $($fixture.Key)" }
docker push "localhost:5000/$($fixture.Key):$tag"
if ($LASTEXITCODE -ne 0) { throw "Push failed: $($fixture.Key)" }
}
$publishRoot = Join-Path ([IO.Path]::GetTempPath()) ([Guid]::NewGuid().ToString('N'))
dotnet publish dotnet/Microsoft.McpGateway.Service/src/Microsoft.McpGateway.Service.csproj -c Release /p:PublishProfile=localhost_5000.pubxml /p:PublishImageTag=$tag /p:PublishDir="$publishRoot/service/"
dotnet publish dotnet/Microsoft.McpGateway.Tools/src/Microsoft.McpGateway.Tools.csproj -c Release /p:PublishProfile=localhost_5000.pubxml /p:PublishImageTag=$tag /p:PublishDir="$publishRoot/tools/"
docker pull "localhost:5000/microsoft-mcpgateway-service:$tag"
docker pull "localhost:5000/microsoft-mcpgateway-tools:$tag"
kubectl --context docker-desktop apply --dry-run=client -k deployment/e2e/local
kubectl --context docker-desktop apply -k deployment/e2e/local
kubectl --context docker-desktop -n mcp-modern-e2e rollout status deployment/redis --timeout=180s
kubectl --context docker-desktop -n mcp-modern-e2e rollout status deployment/mcpgateway --timeout=180s
kubectl --context docker-desktop -n mcp-modern-e2e rollout status statefulset/toolgateway --timeout=180s
kubectl --context docker-desktop -n mcp-modern-e2e port-forward --address 127.0.0.1 service/mcpgateway-service 18000:8000
$env:MCP_IMAGE_TAG = $tag
node deployment/e2e/test-mcp.mjs setup
foreach ($name in @('e2e-example', 'e2e-proxy', 'e2e-stream', 'e2e-weather')) {
kubectl --context docker-desktop -n mcp-modern-e2e rollout status "statefulset/$name" --timeout=240s
}
node deployment/e2e/test-mcp.mjs verify
http://localhost:18000/portal/. Use development identity e2e-owner with role mcp.admin to inspect the fixtures, connect to an adapter, and run a tool. Synthetic development identities are for local tests only.The test-only network policy permits just e2e-proxy to call e2e-example on port 8000. Record running pod imageID values when comparing builds. To clean up, delete only the dedicated namespace and registry after confirming they contain no work you need:
kubectl --context docker-desktop delete namespace mcp-modern-e2e
docker rm -f mcp-modern-e2e-registry
Use a dedicated test subscription/resource group or another explicitly isolated environment. Deploy using the Azure guide with exact gateway and fixture image tags. Validate regional quota, permissions, policy, cost, and TLS before running the tests.
AcrPull and the gateway’s Cosmos data-plane role. If policy blocks public Cosmos access, enable its private endpoint rather than opening the firewall.-GatewayImage and -ToolGatewayImage. Keep cloud Entra authentication enabled. Use two gateway and Tools replicas for the replica-independent routing test when the cluster has sufficient capacity. $env:MCP_BASE_URL = 'https://<gateway-hostname>/'
$env:MCP_NAMESPACE = 'adapter'
$env:MCP_IMAGE_TAG = '<fixture-image-tag>'
$token = az account get-access-token --tenant '<tenant-id>' --scope 'api://<client-id>/access' --output json | ConvertFrom-Json
if ($LASTEXITCODE -ne 0) { throw 'Token acquisition failed.' }
$env:MCP_E2E_TOKEN = $token.accessToken
Never print or commit tokens. For a short-lived test certificate, set NODE_EXTRA_CA_CERTS to its public PEM certificate; do not disable TLS verification. Production deployments need a trusted certificate.
node deployment/e2e/test-mcp.mjs setup, apply the fixture-only network policy using the cloud test context and namespace, and wait for the fixture rollouts. Then run node deployment/e2e/test-mcp.mjs verify against the public endpoint. Cloud verification includes unauthenticated 401; synthetic cross-caller checks run only locally.MCP_E2E_TOKEN when finished and remove only the dedicated test resources and app registration. Stopping AKS does not stop Application Gateway, registry, or storage charges.Application Gateway can consume the X-Accel-Buffering hint. The local suite checks that the gateway supplies it; cloud verification checks prompt event delivery, a 30-second quiet interval, and downstream cancellation through the public ingress.
| Environment variable | Default | Purpose |
|---|---|---|
MCP_BASE_URL |
http://localhost:18000 |
Gateway endpoint |
MCP_NAMESPACE |
mcp-modern-e2e |
Namespace of the test fixture backends |
MCP_IMAGE_TAG |
e2e |
Tag used to register fixture images |
MCP_E2E_TOKEN |
Unset | Entra bearer token for HTTPS cloud tests; not logged |
NODE_EXTRA_CA_CERTS |
Unset | Optional public certificate trust for an isolated TLS test |
Setup can be repeated, but it refuses to silently use a fixture with a different image tag. Use a separate namespace/deployment when changing fixture versions.
The basic FastMCP example does not implement subscriptions/listen. The test fixture uses the official Python SDK to acknowledge a subscription immediately, send an event after a quiet interval, and report cancellation counters. It is not a production gateway feature.
To test the handler directly, run the fixture container with its source mounted read-only at /app and execute python -m unittest test_main -v.