Deploying your server¶
Agora Workbench servers are deployed as Docker containers. The repository provides a shared base image and deployment tooling for both local development and Azure Container Apps.
Install the deployment CLI from PyPI:
The deployment CLI itself is available in the base package. The generated
code-execution base image installs agora-workbench[azure,catalog-vector] to
preserve the full Azure and hybrid-catalog runtime. For a direct Python
installation used to run an Azure-backed server, install the azure extra (and
catalog-vector as well when using vector catalog search).
Local development with Docker¶
1. Build the base image¶
The base image includes the Agora Workbench runtime and common dependencies. First, scaffold the deployment files:
Then build the base image:
The base image installs agora-workbench from PyPI, so it builds from your own
project root — nothing is read from the build context. Pin a specific release
with --build-arg AGORA_WORKBENCH_VERSION=0.3.3.
Building against a workbench checkout
If you are developing against a clone of this repository rather than the published package, build from the repository root and select the source checkout explicitly:
docker build -f src/agora_workbench/deployment/templates/docker/base.Dockerfile \
--build-arg AGORA_WORKBENCH_SOURCE=local -t mcp-server-base:local .
deployment/azure/deploy-network.sh honours the same choice via the
AGORA_WORKBENCH_SOURCE environment variable.
2. Create your server's Dockerfile¶
Extend the base image with your domain-specific server:
FROM mcp-server-base:local
# Copy domain tools package
COPY chemistry_tools/ /app/chemistry_tools/
# Copy server module
COPY server/ /app/server/
# Install domain tools into the execution environment
RUN pip install --no-deps /app/chemistry_tools/
EXPOSE 8000
CMD ["python", "-m", "server.chemistry_server"]
3. Run with Docker Compose¶
# docker-compose.yml
services:
chemistry:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
- HOST=0.0.0.0
- PORT=8000
This non-loopback container bind requires production authentication. If a local
development container deliberately uses no-op authentication behind a
loopback-only port mapping, it must also set
AGORA_ALLOW_UNAUTHENTICATED_REMOTE=1.
Warming the environment¶
For faster cold starts, warm the Python environment at build time:
This pre-builds the conda/uv/pip environment so it's ready when the container starts.
Activity UI¶
The deployment CLI can scaffold the standalone monitoring service without requiring a source checkout:
agora-workbench-deploy init --target activity-ui
docker network create agora-activity
docker compose -f deployment/activity_ui/docker-compose.yml up -d --build
Open http://127.0.0.1:8030. See Monitoring your servers for server wiring and security guidance.
Azure Container Apps deployment¶
Run agora-workbench-deploy init --target azure to scaffold the Bicep templates and deploy scripts.
Prerequisites¶
- Azure CLI (
az) authenticated - A container registry (ACR) for pushing images
- Environment variables in
docker/.env.server
Deploy steps¶
cd deployment/azure/
# Configure your deployment
cp ../docker/.env.server.example ../docker/.env.server
# Edit .env.server with your Azure resource details
# Build and push
az acr build --registry <your-acr> --image myserver:latest ..
# Deploy via Bicep
az deployment group create \
--resource-group <your-rg> \
--template-file main.bicep \
--parameters containerImage=<your-acr>.azurecr.io/myserver:latest
Environment variables for deployment¶
| Variable | Description |
|---|---|
HOST |
Bind address (default: 127.0.0.1) |
PORT |
Listen port (default: 8000) |
ENTRA_CLIENT_ID |
Entra ID app registration client ID |
ENTRA_TENANT_ID |
Azure AD tenant ID |
AZURE_CLIENT_ID |
Managed identity client ID |
CODE_OUTPUT_TRUNCATION_THRESHOLD |
Output truncation limit |
PARALLEL_EXECUTE_MAX_CONCURRENCY |
Max parallel executions |
Production considerations¶
Health checks¶
Every server exposes /health for liveness/readiness probes:
# Container Apps health probe
healthProbes:
- type: liveness
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
Resource limits¶
Set execution timeouts and concurrency limits appropriate for your workload:
config = ServerConfig(
...,
max_timeout=300, # 5 min max per execution
default_timeout=120, # 2 min default
parallel_max_concurrency=4, # max 4 concurrent executions
output_truncation_threshold=50_000,
)
Scaling¶
MCP servers maintain session state and must be available to receive tool calls at any time, so scale-to-zero is not appropriate. Configure a fixed replica count based on your expected concurrency. Each replica runs its own Python environment and session pool independently.
Multi-server deployment¶
For deployments with multiple domain servers plus a router, deploy each as a separate Container App and configure the router's upstream URLs to point to the internal endpoints:
# Each domain server
UPSTREAM_CHEMISTRY_URL=https://chemistry-server.internal.azurecontainerapps.io
UPSTREAM_GIS_URL=https://gis-server.internal.azurecontainerapps.io
See Server networks for the router/gateway configuration.