Example: Building an IT Investigation Broker
Use MuleSoft Vibes to build an IT Investigation agent that triages incoming support tickets, escalates critical issues, resolves common problems through cross-platform investigation, and handles licensing requests.
In each phase, you interact with MuleSoft Vibes as it builds your agent network project. Here’s how it works.
Phase 1: Input Functional Requirements
In this first phase, you define the functionality of the IT Investigation agent, which is to triage, investigate, and resolve support tickets. The agent reads incoming ticket descriptions (received via an A2A message with a Jira ticket ID), classifies severity (High, Low, or too vague to classify) using an LLM’s judgment, and then takes the correct action. If the ticket is too vague, the agent first asks the user for clarification.
High-severity tickets are immediately routed for escalation using an Escalation MCP tool. Low-severity tickets require multi-agent investigation, using a Help Center agent and a License Procurement agent.
This investigation path results in one of three deterministic outcomes: "Help Given," "License Given," or "Unresolved," the latter of which requires escalation to a human. Crucially, the severity classification and cross-platform investigation are open-ended, but the routing based on that classification and the final resolution must be deterministic.
Phase 2: Asset Registration
In this phase, you work with MuleSoft Vibes to identify and register the necessary external tools and LLMs to support the agent’s requirements. Since the investigation and resolution actions require four external assets, you select two A2A agents: the Help Center Agent for searching the knowledge base and the License Procurement Agent for checking software licenses.
You also select two MCP tools: the Escalation MCP Server for handling high-severity cases and the Jira MCP Server for updating ticket status.
For the LLMs, you select OpenAI GPT-5.4 for reasoning and orchestration tasks, such as cross-platform triage. You register Gemini 2.5 Flash for fast, one-shot summaries and response message generation.
Phase 3: Define the Broker (Agent Script)
In this phase, MuleSoft Vibes establishes the logical workflow for the IT Investigation agent by defining a series of interconnected nodes. The graph begins with an A2A trigger node (ticketTrigger) that receives the incoming ticket and Jira ID. This immediately flows into a generator node (classifySeverity), which uses LLM reasoning to classify the ticket as High or Low, and produces a structured output.
The deterministic severityRouter node then directs the process into two paths based on the classification output:
-
High: An executor node calls the Escalation MCP tool.
-
Low: An orchestrator node coordinates agents and tools to investigate, producing a structured outcome (for example,
help_given). A second router then directs the flow based on this outcome, with all paths concluding via an Echo node.
Phase 4: Asset Assignment to Graph
In this phase, MuleSoft Vibes assigns the registered assets to the specific nodes in the graph while adhering to the principle of least privilege.
This table shows which assets and LLMs MuleSoft Vibes mapped to which nodes.
| Node | Type | Assets | LLM | Total Assets | Notes |
|---|---|---|---|---|---|
|
generator |
(none) |
Gemini 2.5 Flash (default) |
0 |
Pure LLM classification (needs deep reasoning to classify ambiguous tickets). Constraint: Can only read the ticket and classify, has no actions. |
|
orchestrator |
Help Center A2A, License Procurement A2A, Jira MCP |
OpenAI GPT 5.4 |
3 |
Coordinates multi-agent investigation (needs deep reasoning). Constraint: Can investigate and update tickets, but cannot escalate. |
|
generator |
— |
Gemini 2.5 Flash (default) |
— |
One-shot summary generation. |
|
generator |
— |
Gemini 2.5 Flash (default) |
— |
One-shot summary generation. |
|
executor |
Escalation MCP |
— |
1 |
Deterministic action call (no LLM). Constraint: Can only escalate, not investigate or resolve. |
|
executor |
Escalation MCP |
— |
1 |
Deterministic escalation for unresolved tickets (no LLM). Constraint: Can only escalate unresolved tickets after investigation has been exhausted. |
|
echo |
— |
— |
— |
Deterministic response formatting (no LLM). |
Phase 5: Instruction Refinement
In this phase, MuleSoft Vibes writes and validates (with you) the precise natural language instructions for the LLM-powered nodes. The instructions for the classifySeverity node clearly define what constitutes High and Low severity, such as classifying a system outage as High severity.
The crossPlatformTriage node instructions outline the required investigation steps: searching the Help Center, checking the License Procurement agent, and updating the Jira ticket.
Furthermore, these instructions define the two structured resolution outcomes the node produces: help_given or license_given. MuleSoft Vibes runs a rigorous contradiction test to make sure that no node’s instructions accidentally override the deterministic routing logic defined in the graph. MuleSoft Vibes verifies all instructions against the overall graph structure and cross-node checks.
Phase 6: Final Topology Review
In this final phase, MuleSoft Vibes provides a comprehensive validation of the fully defined and instructed agent topology before deployment. The review confirms the crucial separation of concerns, ensuring LLM reasoning is used only for classification, with all subsequent routing being deterministic.
The complete separation of the three severity paths - escalation, investigation, and asking for more info - is fully validated. The topology confirms that all possible paths terminate correctly at an echo response node to communicate the outcome to the original caller. Key operational parameters are also finalized, including maximum loop limits (5 for orchestration, 3 for classification) to prevent infinite loops. An edge case is defined, specifying that if the orchestration node cannot determine a resolution, the outcome defaults to help_given.
IT Agent Project Reference
These are the project files for the IT agent.
Project structure
it-help-network/
agent-network.yaml
brokers/
it-help-investigation.agent
exchange.json
agent-network.yaml
agentNetwork: 2.0.0
info:
label: "IT Help Investigation Agent Network"
version: v1
registry:
agents:
helpCenterAgent:
info:
label: Help Center Agent
metadata:
platform: Other
interfaces:
a2a_v03:
card:
name: Help Center Agent
description: Searches the IT knowledge base for answers to common issues. Returns relevant articles with step-by-step instructions.
url: ${helpCenterAgent.url}
protocolVersion: 0.3.0
version: 1.0.0
capabilities:
pushNotifications: false
defaultInputModes:
- application/json
- text/plain
defaultOutputModes:
- application/json
- text/plain
skills:
- id: knowledge-search
name: Knowledge Base Search
description: Search for IT help articles and known solutions.
tags:
- knowledge-base
- it-support
examples:
- How do I reset my VPN password?
- My email is not syncing
- How do I set up two-factor authentication?
inputModes:
- application/json
- text/plain
outputModes:
- application/json
- text/plain
licenseProcurementAgent:
info:
label: License Procurement Agent
metadata:
platform: Other
interfaces:
a2a_v03:
card:
name: License Procurement Agent
description: Checks software license availability and provisions licenses for employees.
url: ${licenseProcurementAgent.url}
protocolVersion: 0.3.0
version: 1.0.0
capabilities:
pushNotifications: false
defaultInputModes:
- application/json
- text/plain
defaultOutputModes:
- application/json
- text/plain
skills:
- id: license-check
name: License Check and Provision
description: Check license availability and provision for a user.
tags:
- licensing
- provisioning
examples:
- Provision a Figma license for jane.doe@company.com
- Check if we have available GitHub Enterprise seats
- I need access to Jira
inputModes:
- application/json
- text/plain
outputModes:
- application/json
- text/plain
mcps:
escalationMcp:
info:
label: Escalation MCP Server
metadata:
transport:
kind: streamableHttp
path: /mcp
jiraMcp:
info:
label: Jira MCP Server
metadata:
transport:
kind: streamableHttp
path: /mcp
llms:
openAiMini:
info:
label: GPT Mini
metadata:
platform: OpenAI
context:
connections:
help_center_agent_connection:
kind: a2a
ref:
name: helpCenterAgent
url: ${helpCenterAgent.url}
license_procurement_agent_connection:
kind: a2a
ref:
name: licenseProcurementAgent
url: ${licenseProcurementAgent.url}
authentication:
kind: oauth2-client-credentials
clientId: ${licenseProcurementAgent.clientId}
clientSecret: ${licenseProcurementAgent.clientSecret}
token:
url: ${licenseProcurementAgent.tokenUrl}
escalation_mcp_connection:
kind: mcp
ref:
name: escalationMcp
url: ${escalationMcp.url}
authentication:
kind: apiKey
apiKey: ${escalationMcp.apiKey}
jira_mcp_connection:
kind: mcp
ref:
name: jiraMcp
url: ${jiraMcp.url}
authentication:
kind: oauth2-obo
flow: oauth2-token-exchange
clientId: ${jiraMcp.clientId}
clientSecret: ${jiraMcp.clientSecret}
tokenEndpoint: ${jiraMcp.tokenUrl}
openai_mini_connection:
kind: llm
ref:
name: openAiMini
url: https://api.openai.com/v1
authentication:
kind: apiKey
apiKey: ${openai.apiKey}
brokers:
it_help_investigation:
kind: AgentScript
implementation: ./brokers/it-help-investigation.agent
interfaces:
a2a:
card:
name: IT Help Desk Broker
description: Triages IT support tickets, escalates critical issues, and resolves common problems through cross-platform investigation.
version: 1.0.0
capabilities:
streaming: false
pushNotifications: true
defaultInputModes:
- text/plain
defaultOutputModes:
- text/plain
skills:
- id: ticket-triage
name: IT Ticket Triage
description: Classifies and resolves IT support tickets.
tags:
- it-support
- help-desk
it-help-investigation.agent file:
# @dialect: AGENTFABRIC=1.0
system:
instructions: "You are an IT Help Desk agent. You triage incoming support tickets, classify their severity, and either escalate, investigate, or request more information."
config:
agent_name: "it-help-investigation"
default_llm: @llm.openai_mini
llm:
openai_mini:
target: "llm://openai_mini_connection"
kind: "OpenAI"
model: "gpt-5-mini"
# -- ACTION DEFINITIONS -------------------------------------------------------
actions:
help_center_agent:
target: "a2a://help_center_agent_connection"
kind: "a2a:send_message"
license_procurement_agent:
target: "a2a://license_procurement_agent_connection"
kind: "a2a:send_message"
escalate:
target: "mcp://escalation_mcp_connection"
kind: "mcp:tool"
tool_name: "escalate"
updateIssue:
target: "mcp://jira_mcp_connection"
kind: "mcp:tool"
tool_name: "updateIssue"
# -- TRIGGER -------------------------------------------------------------------
trigger ticketTrigger:
kind: "a2a"
target: "brokers://it_help_investigation/a2a"
on_message: ->
transition to @generator.classifySeverity
# -- SEVERITY CLASSIFICATION ---------------------------------------------------
generator classifySeverity:
description: "Classifies the severity of the support ticket."
label: "Classify Severity"
llm: @llm.openai_mini
system:
instructions: |
Classify the severity of the incoming IT support ticket and extract the Jira ticket ID.
Classify as HIGH:
- System outages affecting multiple users (e.g. "VPN is down for the entire office", "Nobody in Building 3 can connect")
- Security incidents involving unauthorized access or suspicious activity (e.g. "unauthorized login attempts from an IP in another country")
- Any blocking issue impacting a team, building, or department
Classify as LOW:
- Password resets or connectivity help (e.g. "I forgot my VPN password")
- Software license or access requests (e.g. "rate limited on my Figma MCP server", "I need access to Tableau")
- Single-user issues with a clear description
The ticket_id must always be a string value.
If no Jira ticket ID is provided in the input, default ticket_id to "JIRA001".
prompt: ->
| {!@request.payload.message.parts[0].text}
outputs:
properties:
ticket_id:
type: "string"
description: "The Jira ticket ID extracted from the input (e.g. '001' from 'Jira ticket ID 001')"
severity:
type: "string"
description: "The severity level"
enum:
- "high"
- "low"
reason:
type: "string"
description: "Brief explanation of the classification"
on_exit: ->
transition to @router.severityRouter
# -- SEVERITY ROUTING ----------------------------------------------------------
router severityRouter:
description: "Routes based on the classified severity."
routes:
- target: @executor.escalateTicket
when: @generator.classifySeverity.output.severity == "high"
label: "High"
otherwise:
target: @orchestrator.crossPlatformTriage
# -- HIGH: ESCALATION ---------------------------------------------------------
executor escalateTicket:
description: "Escalates the ticket using the Escalation MCP tool."
do: ->
run @actions.escalate
on_exit: ->
transition to @echo.escalationResponse
echo escalationResponse:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED"
message: a2a.message({messageId: uuid(), parts: [a2a.textPart("Ticket " + @generator.classifySeverity.output.ticket_id + " has been escalated to the on-call team due to high severity: " + @generator.classifySeverity.output.reason)]})
# -- LOW: CROSS-PLATFORM TRIAGE -----------------------------------------------
orchestrator crossPlatformTriage:
description: "Investigates the ticket using Help Center and License Procurement agents."
label: "Cross-Platform Triage"
llm: @llm.openai_mini
system:
instructions: |
Investigate this low-severity IT support ticket.
Step 1: Search the Help Center agent for relevant articles or known solutions.
Step 2: If the issue involves software licensing, check with the License Procurement agent.
Step 3: Update the Jira ticket with your findings and resolution.
If you found an answer from the Help Center, set resolution to "help_given".
If you resolved a licensing issue, set resolution to "license_given".
If you could not find a solution or the issue requires human intervention, set resolution to "unresolved".
Always update the Jira ticket with resolution notes.
reasoning:
instructions: ->
| {!@request.payload.message.parts[0].text}
actions:
search_help: @actions.help_center_agent
check_license: @actions.license_procurement_agent
update_ticket: @actions.updateIssue
with http_headers = {"Authorization": @request.headers["Authorization"]}
outputs:
properties:
resolution:
type: "string"
description: "The resolution type"
enum:
- "help_given"
- "license_given"
- "unresolved"
summary:
type: "string"
description: "Summary of the resolution and actions taken"
on_exit: ->
transition to @router.resolutionRouter
# -- RESOLUTION ROUTING --------------------------------------------------------
router resolutionRouter:
description: "Routes based on the resolution type from triage."
routes:
- target: @generator.licenseSummary
when: @orchestrator.crossPlatformTriage.output.resolution == "license_given"
label: "License Given"
- target: @executor.escalateUnresolved
when: @orchestrator.crossPlatformTriage.output.resolution == "unresolved"
label: "Unresolved"
otherwise:
target: @generator.helpSummary
# -- HELP GIVEN PATH ----------------------------------------------------------
generator helpSummary:
description: "Generates a summary of the help resolution."
system:
instructions: "You generate clear, friendly summaries of IT help desk resolutions."
prompt: ->
| Generate a resolution summary for the user. Original request: {!@request.payload.message.parts[0].text}. Resolution and actions taken: {!@orchestrator.crossPlatformTriage.output.summary}
on_exit: ->
transition to @echo.helpResponse
echo helpResponse:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED"
message: a2a.message({messageId: uuid(), parts: [a2a.textPart(@generator.helpSummary.output)]})
# -- LICENSE GIVEN PATH --------------------------------------------------------
generator licenseSummary:
description: "Generates a summary of the license provisioning."
system:
instructions: "You generate clear, friendly summaries of license provisioning actions."
prompt: ->
| Generate a license provisioning summary for the user. Original request: {!@request.payload.message.parts[0].text}. Resolution and actions taken: {!@orchestrator.crossPlatformTriage.output.summary}
on_exit: ->
transition to @echo.licenseResponse
echo licenseResponse:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED"
message: a2a.message({messageId: uuid(), parts: [a2a.textPart(@generator.licenseSummary.output)]})
# -- UNRESOLVED PATH -----------------------------------------------------------
executor escalateUnresolved:
description: "Escalates an unresolved low-severity ticket to a human agent."
do: ->
run @actions.escalate
on_exit: ->
transition to @echo.unresolvedResponse
echo unresolvedResponse:
kind: "a2a:status_update_event"
state: "TASK_STATE_COMPLETED"
message: a2a.message({messageId: uuid(), parts: [a2a.textPart("Ticket " + @generator.classifySeverity.output.ticket_id + " could not be resolved automatically and has been escalated to a human agent. Summary: " + @orchestrator.crossPlatformTriage.output.summary)]})
exchange.json
{
"main": "agent-network.yaml",
"name": "IT Help Investigation Agent Network",
"classifier": "agentic-network",
"groupId": "${organizationId}",
"assetId": "it-help-investigation-network",
"version": "1.0.0",
"descriptorVersion": "1.0.0",
"apiVersion": "v1.0",
"description": "Triages IT support tickets, escalates critical issues, and resolves common problems through cross-platform investigation with Help Center and License Procurement agents.",
"tags": [],
"dependencies": [],
"metadata": {
"variables": {
"helpCenterAgent": {
"url": {
"description": "Help Center Agent A2A URL",
"default": "",
"secret": false
}
},
"licenseProcurementAgent": {
"url": {
"description": "License Procurement Agent A2A URL",
"default": "",
"secret": false
},
"tokenUrl": {
"description": "OAuth2 token endpoint for the License Procurement agent (client credentials grant)",
"default": "",
"secret": false
},
"clientId": {
"description": "OAuth2 client ID the broker presents to the License Procurement agent",
"default": "",
"secret": false
},
"clientSecret": {
"description": "OAuth2 client secret -- inject at deploy time via --property, never commit a default value",
"default": "",
"secret": true
}
},
"escalationMcp": {
"url": {
"description": "Escalation MCP Server URL",
"default": "",
"secret": false
},
"apiKey": {
"description": "API key for the Escalation MCP server -- inject at deploy time, never commit a default value",
"default": "",
"secret": true
}
},
"jiraMcp": {
"url": {
"description": "Jira MCP Server URL (called on-behalf-of the inbound user)",
"default": "",
"secret": false
},
"tokenUrl": {
"description": "OAuth2 token endpoint Jira accepts for the OBO token exchange",
"default": "",
"secret": false
},
"clientId": {
"description": "OAuth2 client ID the broker uses to perform the OBO exchange with Jira",
"default": "",
"secret": false
},
"clientSecret": {
"description": "OAuth2 client secret for the Jira OBO exchange -- inject at deploy time, never commit a default value",
"default": "",
"secret": true
}
},
"openai": {
"apiKey": {
"description": "OpenAI API key -- inject at deploy time, never commit a default value",
"default": "",
"secret": true
}
}
}
}
}



