Run Logic Apps Standard as an MCP server in a Docker container on Azure Container Apps — then call it from another Logic App using the built-in MCP client connector inside an agent loop.
This post connects two earlier pieces:
-
MCP server setup: Logic Apps ❤️ MCP — Expose Arithmetic Tools — enabling the
/api/mcpendpoint and testing the tools - Running on ACA: Logic Apps Standard on ACA — we take the same MCP server principles and host it as a Docker container on Azure Container Apps
If you haven't read those, here's what's already running before this post starts.
What's already deployed
Seven arithmetic workflows — add, sub, mul, div, mod, pow, sqrt — each an HTTP trigger workflow that takes inputs and returns a result. They're baked into a Docker image and running as a single container on ACA.
Running locally first
Before pushing to ACA you can run the same image locally. docker-compose up starts the Logic Apps runtime on port 7074 backed by Azurite for blob and queue storage. The MCP endpoint is immediately available at:
http://localhost:7074/api/mcp
No auth is needed locally — the "type": "anonymous" setting in host.json covers both local dev and the ACA demo deployment. This is the right place to verify tool schemas, test workflow logic, and confirm the runtime discovers all seven tools before you deploy anything to the cloud.
One block in host.json enables the MCP endpoint:
"workflow": {
"McpServerEndpoints": {
"enable": true,
"authentication": { "type": "anonymous" }
}
}
The runtime exposes each workflow as an MCP tool automatically. No extra code, no separate service — the container itself is the MCP server, reachable at:
https://la-arithmeticmcp.<env>.westeurope.azurecontainerapps.io/api/mcp
All seven tools are immediately discoverable:
Consuming it from another Logic App
A second Logic App — BODMASAgent — receives a math expression via HTTP and uses an Agent action (Azure OpenAI) to solve it. The agent has one tool available: the MCP server connector pointing at the endpoint above.
When you add the MCP server action inside the Agent loop and connect it to the endpoint, the designer auto-discovers all tools and lets you pick which ones the agent can call:
POST (2 + 3) * 4^2 / 2 and the agent works through BODMAS order on its own, calling one tool per step:
✅ Step 1: (2 + 3) = 5 → wf_arithmetic_add
✅ Step 2: 4² = 16 → wf_arithmetic_pow
✅ Step 3: 5 × 16 = 80 → wf_arithmetic_mul
✅ Step 4: 80 ÷ 2 = 40 → wf_arithmetic_div
✅ Final Answer: 40
No orchestration code in the consuming Logic App. The agent decides the order and arguments; each tool call triggers a real workflow run on the server container and returns the result.
Securing the MCP endpoint on ACA
The host.json above sets "type": "anonymous" — fine for local dev and demos, but for production you want the endpoint protected.
ACA doesn't have App Service Easy Auth built in, but it has its own ingress-level authentication that works the same way: the ACA runtime validates the Azure AD Bearer token before the request reaches the container. The Logic App MCP endpoint stays anonymous internally; ACA acts as the auth gateway.
Setup — two steps:
- Create an Azure AD app registration (
la-arithmeticmcp-auth) and create a service principal for it in the tenant:
az ad sp create --id <app-id>
- Enable ACA auth via ARM REST — do not use
az containerapp auth update, it has a known CLI bug that silently strips the first and last character ofexcludedPathsvalues, producing invalid config:
az rest --method PUT \
--url "https://management.azure.com/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.App/containerApps/la-arithmeticmcp/authConfigs/current?api-version=2024-03-01" \
--body '{
"properties": {
"globalValidation": {
"unauthenticatedClientAction": "Return401",
"excludedPaths": ["/runtime/webhooks/workflow/scaleUnits/*"]
},
"platform": { "enabled": true },
"identityProviders": {
"azureActiveDirectory": {
"registration": {
"clientId": "<app-id>",
"openIdIssuer": "https://sts.windows.net/<tenant-id>/"
},
"validation": {
"allowedAudiences": ["api://<app-id>"]
}
}
}
}
}'
The excludedPaths entry for scaleUnits/* is required. ACA enforces Bearer token validation on all paths by default — including /runtime/webhooks/*. The scaleUnits subtree hosts SAS-authenticated payload fetch URLs (run inputs/outputs) that the Logic Apps runtime generates per run action. Excluding it lets those requests pass through on SAS params alone.
Do not set
WORKFLOWAPP_AAD_CLIENTIDorWORKFLOWAPP_AAD_TENANTIDon the container. These env vars activate DirectApi Azure AD token validation inside the Logic Apps runtime. Any client in EasyAuth mode sends a Bearer token on every request — including to the SAS-authenticatedscaleUnitsURLs. When both a Bearer token and SAS params are present on the same request, the runtime rejects withDirectApiRequestHasMoreThanOneAuthorization. ACA validates the Bearer token; the runtime validates the SAS params. They operate independently — don't configure them to overlap.
Getting a token (client credentials):
curl -X POST "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=<app-id>" \
--data-urlencode "client_secret=<secret>" \
--data-urlencode "scope=api://<app-id>/.default"
Result:
# No token
HTTP 401 ← blocked by ACA ingress
# Valid Bearer token → initialize session
HTTP 200 {"protocolVersion":"2025-06-18","serverInfo":{"name":"Logic Apps Remote MCP Server",...}}
# Session established → tools/list
HTTP 200 {"tools":[{"name":"wf_arithmetic_div",...},{"name":"wf_arithmetic_add",...}]}
What ACA auth actually protects:
| Path | Auth |
|---|---|
/api/mcp |
✅ Bearer token required |
/runtime/webhooks/workflow/api/management/* |
✅ Bearer token required |
/runtime/webhooks/workflow/scaleUnits/* |
❌ Excluded — SAS params only |
The MCP client (Postman, Logic App connector, or any client) just needs to include Authorization: Bearer <token> on every request.
Validating with VS Code Copilot
VS Code Copilot can talk to any HTTP MCP server directly from the IDE. Add the secured endpoint to .vscode/mcp.json in your workspace:
{
"servers": {
"la-arithmeticmcp": {
"type": "http",
"url": "https://la-arithmeticmcp.<env>.westeurope.azurecontainerapps.io/api/mcp",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}
On workspace open, Copilot sends initialize → tools/list and populates its tool list from the response. The screenshot below shows the result — all 7 arithmetic tools returned from the live ACA endpoint, confirming that the Bearer token clears ACA ingress and the MCP session handshake completes successfully end to end.
Further reading — how MCP session handling works under the hood
The built-in MCP client connector handles session initialization, tool discovery, and JSON-RPC framing automatically. If you're building a custom client or want to understand what's happening behind the scenes — how initialize establishes a session, how tools/list returns the catalog, and how tools/call invokes a tool — this post walks through it manually:
Consume an MCP Endpoint from Azure Logic Apps with an Agent Loop






Top comments (0)