MCP server configuration
MCP Configuration
Section titled “MCP Configuration”The mcp-servers: field configures MCP (Model Context Protocol) servers that are made available to the agent via the MCP Gateway (MCPG). MCPs can be containerized stdio servers (Docker-based) or HTTP servers (remote endpoints). All MCP traffic flows through the MCP Gateway.
Docker Container MCP Servers (stdio)
Section titled “Docker Container MCP Servers (stdio)”Run containerized MCP servers. MCPG spawns these as sibling Docker containers:
mcp-servers: azure-devops: container: "node:20-slim" entrypoint: "npx" entrypoint-args: ["-y", "@azure-devops/mcp", "myorg", "-d", "core", "work-items"] env: AZURE_DEVOPS_EXT_PAT: "" allowed: - core_list_projects - wit_get_work_item - wit_create_work_itemHTTP MCP Servers (remote)
Section titled “HTTP MCP Servers (remote)”Connect to remote MCP servers accessible via HTTP:
mcp-servers: remote-ado: url: "https://mcp.dev.azure.com/myorg" headers: X-MCP-Toolsets: "repos,wit" X-MCP-Readonly: "true" allowed: - wit_get_work_item - repo_list_repos_by_projectConfiguration Properties
Section titled “Configuration Properties”Container stdio servers:
container:- Docker image to run (e.g.,"node:20-slim","ghcr.io/org/tool:latest")entrypoint:- Container entrypoint override (equivalent todocker run --entrypoint)entrypoint-args:- Arguments passed to the entrypoint (after the image indocker run)args:- Additional Docker runtime arguments (inserted before the image indocker run). Security note: dangerous flags like--privileged,--network hostwill trigger compile-time warnings.mounts:- Volume mounts in"source:dest:mode"format (e.g.,["/host/data:/app/data:ro"])
HTTP servers:
url:- HTTP endpoint URL for the remote MCP serverheaders:- HTTP headers to include in requests (e.g.,Authorization,X-MCP-Toolsets)
Common (both types):
enabled:- Whether this MCP server is active (default:true). Set tofalseto temporarily disable an entry without removing it from the front matter.allowed:- Array of tool names the agent is permitted to call from this server (required for security). See Two-Level Permission Model for how this interacts with Copilot CLI’s--allow-tool.env:- Environment variables for the MCP server process. Use""(empty string) for passthrough from the pipeline environment.
Two-Level Permission Model
Section titled “Two-Level Permission Model”MCP security operates at two distinct layers, both of which must grant permission for an agent to successfully call an MCP tool:
Layer 1: Copilot CLI Server Access (--allow-tool <server-name>)
Section titled “Layer 1: Copilot CLI Server Access (--allow-tool <server-name>)”The Copilot CLI controls which MCP servers the agent can access via --allow-tool flags. The compiler automatically generates these flags for:
- Built-in extensions —
github,safeoutputs, andazure-devops(when configured viatools.azure-devops) - User-defined MCP servers — any server in
mcp-servers:with acontainer:orurl:backing
For example, if you define an azure-devops server in mcp-servers:, the compiled pipeline includes:
copilot --allow-tool azure-devops ...This grants the agent permission to connect to the server. Without this flag, the agent cannot communicate with the server at all, regardless of the allowed: list.
When is --allow-tool automatic?
- Restricted bash mode (explicit
bash: [...]list) — the compiler emits individual--allow-toolflags for each server. - Wildcard bash mode (omitted
bash:orbash: [":*"]) — the compiler emits--allow-all-toolsinstead, which grants access to all servers and tools without individual flags.
Layer 2: MCPG Tool-Level Filtering (allowed: [...])
Section titled “Layer 2: MCPG Tool-Level Filtering (allowed: [...])”The MCP Gateway (MCPG) enforces the allowed: list for each server. Even if the agent has --allow-tool azure-devops permission, it can only call tools explicitly listed in the server’s allowed: array.
mcp-servers: azure-devops: container: "node:20-slim" entrypoint: "npx" entrypoint-args: ["-y", "@azure-devops/mcp", "myorg"] allowed: - core_list_projects # ✅ Agent can call this - wit_get_work_item # ✅ Agent can call this # wit_update_work_item ❌ Not in allowed list → MCPG blocksIf the agent attempts to call wit_update_work_item, MCPG rejects the request even though the agent has --allow-tool azure-devops.
Why Two Layers?
Section titled “Why Two Layers?”- CLI layer (
--allow-tool) — coarse-grained server access control; prevents agents from discovering or connecting to servers they shouldn’t use. - MCPG layer (
allowed:) — fine-grained tool access control; allows servers to expose many tools while agents only get a safe subset.
This defense-in-depth model ensures agents can only call the exact tools you intended, with no accidental privilege escalation.
Environment Variable Passthrough
Section titled “Environment Variable Passthrough”MCP containers may need secrets from the pipeline (e.g., ADO tokens). The env: field supports passthrough:
env: AZURE_DEVOPS_EXT_PAT: "" # Passthrough from pipeline environment STATIC_CONFIG: "some-value" # Literal value embedded in configWhen permissions.read is configured, the compiler automatically maps SC_READ_TOKEN -> AZURE_DEVOPS_EXT_PAT on the MCPG container, so agents can access ADO APIs without manual wiring.
Example: Azure DevOps MCP with Authentication
Section titled “Example: Azure DevOps MCP with Authentication”mcp-servers: azure-devops: container: "node:20-slim" entrypoint: "npx" entrypoint-args: ["-y", "@azure-devops/mcp", "myorg"] env: AZURE_DEVOPS_EXT_PAT: "" allowed: - core_list_projects - wit_get_work_itempermissions: read: my-read-arm-connectionnetwork: allowed: - "dev.azure.com" - "*.dev.azure.com"Security Notes
Section titled “Security Notes”- Two-level allow-listing: Both
--allow-tool <server>(CLI layer) andallowed:(MCPG layer) must grant permission for a tool call to succeed. See Two-Level Permission Model for details. - Containerization: Stdio MCP servers run as isolated Docker containers (per MCPG spec §3.2.1).
- Environment Isolation: MCP containers are spawned by MCPG with only the configured environment variables.
- Network Isolation: MCP containers run within the same AWF-isolated network. Users must explicitly allow external domains via
network.allowed.