Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Deploy Azure MCP Server as a self-hosted remote server over HTTPS on Azure Container Apps. This article uses the on-behalf-of (OBO) authentication model, which lets the server call Azure services by using the identity of the signed-in user rather than the server's own managed identity. Agents in Microsoft Foundry and Microsoft Copilot Studio can connect to the deployed server and invoke Azure MCP tools that operate with the user's own permissions and access.
How the OBO flow works
The on-behalf-of flow is distinct from the managed identity approach used in other Azure MCP Server templates:
- Managed identity approach: The server authenticates to downstream Azure services by using its own managed identity. All users share the permissions granted to that identity. For a Microsoft Foundry example that uses this model, see Deploy a remote Azure MCP Server and connect using Microsoft Foundry.
- OBO approach: When a user authenticates with the server, the server exchanges the user's token for a new token scoped to a downstream Azure service. The server calls Azure services on behalf of the user, so each user's own Azure permissions determine what they can do.
The template provisions two Microsoft Entra app registrations to enable this flow:
- Server app registration: Exposed to clients as the OAuth 2.0 resource. When a user's token arrives, the server uses a federated identity credential (backed by a managed identity) to perform the OBO token exchange to access downstream APIs like Azure Resource Manager and Azure Storage.
- Client app registration: Used by external clients (Foundry agents, Copilot Studio custom connectors) to authenticate against the server. The client app is pre-authorized on the server app so users don't need to consent separately.
Prerequisites
- Azure subscription with Owner or User Access Administrator permissions
- Azure Developer CLI (azd) installed
- Azure CLI installed
- The list of Azure MCP Server tool namespaces you want to enable. See azmcp-commands.md. The template in this article enables the
storagenamespace by default.
Deploy the Azure MCP Server
This article shows how to use the azmcp-obo-aca azd template to deploy the Azure MCP Server to Azure Container Apps with OBO authentication. Deploy the server:
Initialize the
azmcp-obo-templatetemplate by using theazd initcommand.azd init -t azmcp-obo-templateWhen prompted, enter an environment name.
Run the template by using the
azd upcommand.azd upazdprompts you for the following values:- Subscription: Select the subscription for the provisioned resources.
- Resource group: Create or select a resource group to hold the resources.
azd uses the template files to provision the following resources and configurations:
- Azure Container App: Runs the Azure MCP Server with the
storagenamespace enabled. - User-assigned managed identity: Provides a client credential for the server app registration through a federated identity credential. The server uses this identity to perform the OBO token exchange.
- Entra app registration (server): The OAuth 2.0 resource exposed to clients. Has the
Mcp.Tools.ReadWritescope, and carries Azure Resource Manager and Azure Storage API permissions for the OBO exchange. - Entra app registration (client): Used by clients such as Foundry agents and Power Apps custom connectors to authenticate with the server. Pre-authorized on the server app to eliminate the need for user consent.
- Application Insights: Provides telemetry and monitoring.
Retrieve deployment outputs
After the deployment finishes, use the azd env get-values command to get the azd environment variables.
azd env get-values
Example output:
AZURE_RESOURCE_GROUP="<your-resource-group-name>"
AZURE_SUBSCRIPTION_ID="<your-subscription-id>"
AZURE_TENANT_ID="<your-tenant-id>"
CONTAINER_APP_NAME="<your-container-app-name>"
CONTAINER_APP_URL="https://<your-container-app-name>.<region>.azurecontainerapps.io"
ENTRA_APP_CLIENT_CLIENT_ID="<client-app-registration-id>"
ENTRA_APP_SERVER_CLIENT_ID="<server-app-registration-id>"
Keep this output available. You need these values in the sections that follow.
Grant admin consent and add the API scope
After deployment, complete two required configuration steps before clients can connect.
Add the API scope to the client app registration
The client app registration needs permission to call the server app's Mcp.Tools.ReadWrite scope.
- In the Azure portal, search for the client app registration by using the
ENTRA_APP_CLIENT_CLIENT_IDvalue. - Go to API permissions → Add a permission → My APIs tab.
- Select the server app registration and add the
Mcp.Tools.ReadWritescope. - Select Grant admin consent to apply the permission to all users.
Note
If the server app registration doesn't appear under My APIs, the app might still be propagating. Wait a few minutes and refresh, or see the Troubleshooting section.
Grant admin consent for downstream API permissions
The server app registration has Azure Resource Manager and Azure Storage API permissions configured, but these permissions require admin consent before the OBO token exchange can succeed.
- In the Azure portal, search for the server app registration by using the
ENTRA_APP_SERVER_CLIENT_IDvalue. - Go to API permissions.
- Select Grant admin consent for <your tenant> and confirm.
Note
If the Grant admin consent button is unavailable, your account lacks sufficient permissions. This template requires an Azure subscription with Owner or User Access Administrator access.
Alternatively, use the Azure CLI:
az ad app permission admin-consent --id <ENTRA_APP_SERVER_CLIENT_ID>
Connect to the server
After deploying and completing the post-deployment configuration, you can connect clients to the server. Select the option that fits your scenario.
The template includes a .NET console app in the client/ folder that you can use to verify the deployment locally. The app authenticates interactively through the browser by using the client app registration, connects to the MCP server, lists the available tools, and optionally calls the storage_account_get tool.
Prerequisites: .NET 10 SDK
In the
client/folder, openappsettings.jsonand set the following values by using theazd env get-valuesoutput:{ "McpServer": { "Url": "<CONTAINER_APP_URL>" }, "EntraClientClientId": "<ENTRA_APP_CLIENT_CLIENT_ID>", "SubscriptionId": "<AZURE_SUBSCRIPTION_ID>" }Tip
You can also create an
appsettings.Development.jsonfile with your local values and set theDOTNET_ENVIRONMENTenvironment variable toDevelopmentto load it without modifying the committed file.From the
client/folder, run the app:dotnet runThe app opens a browser window for you to sign in. After sign-in, it connects to the MCP server and prints the list of available tools.
To also call the
storage_account_gettool and list storage accounts in your subscription, pass the--list-accountsflag:dotnet run -- --list-accounts true
If you encounter authentication errors such as MsalUiRequiredException, see the Troubleshooting section.
Add more Azure tools
The template enables the storage namespace by default. To enable additional tool namespaces:
Identify the API permissions required for the tools you want. See the API permissions reference.
Add the permissions to the server app registration by using the Azure CLI:
az ad app permission add \ --id <ENTRA_APP_SERVER_CLIENT_ID> \ --api <downstream-api-id> \ --api-permissions <permission-id>=ScopeGrant admin consent for the new permissions:
az ad app permission admin-consent --id <ENTRA_APP_SERVER_CLIENT_ID>Update the Container App environment variables to pass the additional namespace flags to the server startup command.
Clean up resources
Run azd down to delete the Azure resources created by this template.
azd down
Note
azd down doesn't delete the Entra app registrations. After running azd down, manually delete them in the Azure portal by searching for the ENTRA_APP_CLIENT_CLIENT_ID and ENTRA_APP_SERVER_CLIENT_ID values.
Troubleshooting
The following sections provide details on common errors you might encounter and how to resolve them.
IDW10502: MsalUiRequiredException
{"status":500,"message":"IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user..."}
The server's OBO token exchange failed because admin consent isn't granted for the downstream API permissions on the server app registration. In the Azure portal, find the server app registration (using ENTRA_APP_SERVER_CLIENT_ID) → API permissions → Grant admin consent.
OBO token exchange failures
Check the Entra sign-in logs for details. In the Azure portal, go to Microsoft Entra ID → Monitoring → Sign-in logs → User sign-ins (non-interactive). Look for entries where the application matches your server app registration and the resource matches the downstream Azure API.
Container App errors
Open the Azure portal, go to your Container App → Monitoring → Log stream to view real-time application logs. Application Insights telemetry is available under Investigate → Search or via Log Analytics queries on the requests and traces tables.
ServiceManagementReference error on redeploy
{"error":{"code":"BadRequest","message":"ServiceManagementReference field is required for Update..."}}
This error occurs when running azd up on an existing deployment that was originally created without a serviceManagementReference value. Add the parameter to infra/main.parameters.json:
{
"parameters": {
"serviceManagementReference": {
"value": "<your-guid>"
}
}
}
Note
For a list of other known issues, see KnownIssues.md in the template repository.