Cyber Intelligence
Cloud Security10 min read

Build an Autonomous Phishing Triage Agent with Azure Logic Apps and MCP Servers

Azure Logic Apps now supports a fully autonomous agent workflow type where the LLM decides which tools to call, not your branching logic. This tutorial walks through wiring up a phishing triage agent that checks URLs against VirusTotal, reads user risk scores from Microsoft Graph, and writes a structured verdict back to Microsoft Sentinel: all without a single if/else condition in your workflow.

I
Microsoft Cloud Solution Architect
Azure Logic AppsMCPAutonomous AgentsPhishingSOARMicrosoft SentinelVirusTotalMicrosoft GraphAI Security

What We Are Building

Azure Logic Apps Standard now has an Autonomous Agent workflow type where the LLM decides which tools to call and in what sequence. Unlike a traditional Logic Apps SOAR playbook where you wire every step explicitly, the autonomous agent reads a system prompt, examines the incoming alert, and determines what evidence it needs before rendering a verdict.

This tutorial builds a phishing triage agent end to end. Here is the complete flow:

Sentinel Automation Rule (webhook trigger)
  → Logic App HTTP trigger
    → Autonomous Agent
        ├── VirusTotal MCP: URL scan + file hash lookup
        ├── Microsoft Graph MCP: user risk score + risky sign-ins
        └── Verdict: FALSE_POSITIVE | ESCALATE | AUTO_REMEDIATE
              → Sentinel incident comment
              → Analyst email (if ESCALATE or AUTO_REMEDIATE)

There is no explicit branching, no hardcoded thresholds. The agent reads the evidence from its tool calls and decides.

---

Prerequisites

Before starting, have the following ready:

  • Azure subscription with access to create Logic Apps Standard (Workflow Standard SKU). The autonomous agent workflow type is only available on Standard, not Consumption.
  • Microsoft Sentinel workspace with at least one mailbox connector ingesting phishing reports, or a simulated alert you can trigger manually.
  • VirusTotal API key: the free tier (500 requests/day) is sufficient. Get one at virustotal.com.
  • Entra ID app registration with these Microsoft Graph API permissions (application permissions, not delegated): User.Read.All, IdentityRiskyUser.Read.All, IdentityRiskEvent.Read.All
  • Microsoft Sentinel Contributor access on your account.

---

Step 1: Create the Logic App

  1. In the Azure portal, search for Logic Apps and select Add.
  2. For Plan type, choose Standard (not Consumption). The autonomous agent workflow type is only available here.
  3. Choose your subscription, resource group, and a name like phishing-triage-agent.
  4. For Region, pick the same region as your Sentinel workspace to avoid cross-region data transfer.
  5. Under Hosting, select Workflow Standard with a WS1 SKU.
  6. Enable system-assigned managed identity under the Identity tab before creating. You will use this identity to authenticate to Microsoft Graph.
  7. Click Review + Create.

Once deployed, go to the Logic App resource and select Workflows in the left menu.

---

Step 2: Create the Autonomous Agent Workflow

  1. Click Add to create a new workflow.
  2. For State type, select Autonomous Agent (a new option alongside Stateful and Stateless).
  3. Name the workflow phishing-triage.
  4. The designer opens with an Autonomous Agent trigger block. This is different from a standard trigger: instead of specifying a trigger event, you configure the agent's system prompt and available tools here.
  5. Add an HTTP Request trigger (search for "When a HTTP request is received") as the entry point.

Use this JSON schema for the request body:

{
  "type": "object",
  "properties": {
    "incidentId": { "type": "string" },
    "incidentTitle": { "type": "string" },
    "severity": { "type": "string" },
    "reportingUser": {
      "type": "object",
      "properties": {
        "email": { "type": "string" },
        "userId": { "type": "string" }
      }
    },
    "extractedUrls": {
      "type": "array",
      "items": { "type": "string" }
    },
    "extractedHashes": {
      "type": "array",
      "items": { "type": "string" }
    },
    "emailSubject": { "type": "string" },
    "senderEmail": { "type": "string" }
  }
}

This schema passes structured fields only, not raw email body text. Passing raw email body to an LLM agent is a prompt injection risk covered in the third article in this series.

---

Step 3: Write the Agent System Prompt

This is the core of the autonomous agent workflow. In the agent configuration panel, paste the following system prompt:

You are a SOC analyst triaging phishing reports for a corporate security team. You will receive a structured alert containing extracted indicators only: no raw email content.

You will receive: <ul class="list-disc pl-6 mb-4 space-y-2"> <li class="text-gray-600">incidentId: the Sentinel incident identifier</li> <li class="text-gray-600">reportingUser: email and userId of the person who reported the phishing email</li> <li class="text-gray-600">extractedUrls: array of URLs found in the reported email</li> <li class="text-gray-600">extractedHashes: array of file attachment hashes (SHA256)</li> <li class="text-gray-600">emailSubject: subject line of the reported email</li> <li class="text-gray-600">senderEmail: sender address</li> </ul>

Your job: <ol class="list-decimal pl-6 mb-4 space-y-2"> <li class="text-gray-600">Check every URL in extractedUrls using the VirusTotal URL scan tool. Do not skip any URL even if the first result is clean.</li> <li class="text-gray-600">Check every hash in extractedHashes using the VirusTotal file hash lookup tool.</li> <li class="text-gray-600">Check the reportingUser's risk score using the Microsoft Graph user risk tool.</li> <li class="text-gray-600">Check the reportingUser's recent risky sign-ins using the Microsoft Graph risky sign-ins tool.</li> <li class="text-gray-600">Based on all findings, produce exactly one verdict:</li> </ol> <ul class="list-disc pl-6 mb-4 space-y-2"> <li class="text-gray-600 ml-3">FALSE_POSITIVE: all indicators clean, user risk is none or low, no anomalous sign-ins</li> <li class="text-gray-600 ml-3">ESCALATE: any ambiguous signal (low VirusTotal detection count, medium user risk, unusual sign-in location), or if the reporting user is in a high-value role (finance, executive, IT admin)</li> <li class="text-gray-600 ml-3">AUTO_REMEDIATE: confirmed malicious indicator (VirusTotal detection count above 10/72) AND user showing active compromise signals (high risk score or risky sign-in in past 6 hours)</li> </ul>

Output format: always return this exact JSON structure, nothing else: { "verdict": "FALSE_POSITIVE" | "ESCALATE" | "AUTO_REMEDIATE", "confidence": <integer 0-100>, "reasoning": "<2-3 sentences explaining your verdict based on specific findings>", "indicators_checked": { "urls_checked": <number>, "hashes_checked": <number>, "max_vt_detection_count": <number or null>, "user_risk_score": "<none|low|medium|high>", "risky_sign_ins_past_6h": <number> }, "recommended_actions": ["<action 1>", "<action 2>"] }

Never produce a verdict without completing all tool calls. If a tool call fails, note the failure in reasoning and base your verdict on the remaining evidence.

Why this prompt structure works: each tool call is mandatory (prevents lazy short-circuiting on the first clean result), the output format is a strict schema (enables downstream validation before actions fire), and the verdict criteria are expressed as natural language heuristics rather than hardcoded thresholds. The agent can handle novel signal combinations that an explicit branching tree would miss.

---

Step 4: Connect the VirusTotal MCP Server

In the Logic Apps designer, add an MCP Server action inside the autonomous agent workflow.

Configuration:

  • MCP Server URL: https://mcp.virustotal.com/sse (VirusTotal's official MCP endpoint: verify the current URL at virustotal.com/gui/mcp as it may change during preview)
  • Authentication: API Key header. Store the key as a Logic Apps parameter (Settings > Parameters), not hardcoded. Reference it as @parameters('virusTotalApiKey').
  • Tools to expose to the agent: url_scan, file_hash_lookup, ip_address_report. Limit exposed tools to what the agent actually needs; every additional tool expands the agent's action surface.

Once saved, the agent's reasoning context automatically includes the tool descriptions published by the MCP server. The agent reads these descriptions to decide when and how to call each tool: you do not wire up specific calls manually.

---

Step 5: Connect the Microsoft Graph MCP Server

Add a second MCP Server action.

Configuration:

  • MCP Server URL: https://graph.microsoft.com/mcp (verify current endpoint in Microsoft Graph documentation)

Note: Microsoft does not yet publish a hosted Graph MCP endpoint at this URL. In practice, you deploy the open-source microsoft/msgraph-mcp server yourself (available on GitHub) and point the Logic App to your self-hosted instance. Check Microsoft's current Graph MCP documentation for the latest recommended deployment path.

  • Authentication: Managed Identity (recommended). In the Logic App's system-assigned managed identity, grant these Microsoft Graph application permissions via Entra ID admin consent: User.Read.All, IdentityRiskyUser.Read.All, IdentityRiskEvent.Read.All

Grant permissions via Azure CLI. For a Logic App's system-assigned managed identity, use the Graph API directly to assign app roles:

# Get the Logic App's system-assigned managed identity principal ID
MI_OBJECT_ID=$(az logic workflow show \
  --name phishing-triage-agent \
  --resource-group <your-rg> \
  --query "identity.principalId" -o tsv)

# Get the Microsoft Graph service principal ID in your tenant GRAPH_SP_ID=$(az ad sp show \ --id 00000003-0000-0000-c000-000000000000 \ --query id -o tsv)

# Find the app role ID for IdentityRiskyUser.Read.All # Role ID: dc5007c0-2d7d-4c42-879c-2dab87571379 az rest \ --method POST \ --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${MI_OBJECT_ID}/appRoleAssignments" \ --body "{\"principalId\": \"${MI_OBJECT_ID}\", \"resourceId\": \"${GRAPH_SP_ID}\", \"appRoleId\": \"dc5007c0-2d7d-4c42-879c-2dab87571379\"}"

Alternatively, use the Entra ID portal: go to Enterprise Applications, search for your Logic App by name, select Permissions, then Add permission, and grant the three required Graph permissions from there. The portal path is simpler and less error-prone for one-time setup.

Tools to expose: get_user_risk_score, list_risky_sign_ins, get_user_profile. Do not expose write tools like dismiss_risky_user: the agent should read and recommend, not act on identity risk directly.

---

Step 6: Test with a Live Phishing Sample

Use a known-bad URL from URLhaus (urlhaus.abuse.ch): a public phishing feed of confirmed-malicious URLs safe to use for testing.

Construct a test request payload:

{
  "incidentId": "sentinel-test-001",
  "incidentTitle": "Phishing Email Reported by User",
  "severity": "Medium",
  "reportingUser": {
    "email": "testuser@yourdomain.com",
    "userId": "<a real user ID in your test tenant>"
  },
  "extractedUrls": ["<paste a URLhaus entry here>"],
  "extractedHashes": [],
  "emailSubject": "Urgent: Your account requires verification",
  "senderEmail": "no-reply@suspicious-domain.example"
}

Trigger via the Logic App portal: open the workflow run view, click Run Trigger > With Payload, paste the JSON above.

In the run history, expand each step to see the agent's reasoning trace: which tools it called, what arguments it passed, what each MCP server returned, and how it synthesized the findings into a verdict. This trace is your audit log.

---

Step 7: Reading the Output

A typical AUTO_REMEDIATE verdict from the agent looks like this:

{
  "verdict": "AUTO_REMEDIATE",
  "confidence": 91,
  "reasoning": "The submitted URL matched 23 out of 72 VirusTotal engines as a phishing page targeting Microsoft credentials. The reporting user has a high risk score with two risky sign-ins in the past 4 hours from an IP address in a country outside their normal pattern. Taken together, these signals indicate an active credential-harvesting attempt against a potentially already-compromised account.",
  "indicators_checked": {
    "urls_checked": 1,
    "hashes_checked": 0,
    "max_vt_detection_count": 23,
    "user_risk_score": "high",
    "risky_sign_ins_past_6h": 2
  },
  "recommended_actions": [
    "Revoke all active sessions for the reporting user via Entra ID",
    "Block the sender domain in Exchange Online Protection",
    "Open a Tier 2 investigation for lateral movement from this user account"
  ]
}

After the agent step, add a Microsoft Sentinel connector action to post this as an incident comment. Map the verdict JSON fields to the comment body. For ESCALATE and AUTO_REMEDIATE verdicts, add a parallel branch that sends a notification email to your on-call queue.

Keep the recommended_actions as text in the Sentinel comment only. Do not wire up automated execution of these actions without a human approval gate: the architecture for that gate is covered in the third article in this series.

---

What to Build Next

Article 2 in this series shows how this agent compares to traditional Logic Apps SOAR playbooks, where the LLM reasoning loop is a genuine upgrade and where it is not, including a demo walkthrough of the agent's reasoning trace on an ambiguous alert. Article 3 covers the production threat model: prompt injection via phishing email content, MCP server trust boundaries, managed identity scoping, and a 12-item production readiness checklist to take to a security review board.

N

Recommended tool: Nordpass

Up to 40% commission

Get weekly security insights

Cloud security, zero trust, and identity guides — straight to your inbox.

I

Microsoft Cloud Solution Architect

Cloud Solution Architect with deep expertise in Microsoft Azure and a strong background in systems and IT infrastructure. Passionate about cloud technologies, security best practices, and helping organizations modernize their infrastructure.

Share this article

Questions & Answers

Related Articles

Need Help with Your Security?

Our team of security experts can help you implement the strategies discussed in this article.

Contact Us