MuleSoft Agent Broker V1 to V2 Converter
Converts an Agent Network V1 project (schema 1.0.0) into V2 (schema 2.0.0) by producing a brand-new project folder. The conversion is intentionally simple: every V1 broker becomes a V2 broker backed by an Agent Script .agent file with exactly one orchestrator node. Routing, classification, and conditional logic that V1 stuffed into a single LLM prompt remain inside that orchestrator's system.instructions — the upgrade does not break the prompt apart into multiple nodes.
Preserve the user's wording. Do not improvise or "improve" the source instructions. Treat the V1 file as the source of truth and only change what V2 actually requires.
If the user wants a richer multi-node graph (split deterministic routing into router nodes, move side-effects into executor nodes, separate cheap summary work into generator nodes), point them at build-agent-broker-project as the natural next step.
When to use
- Convert / upgrade / migrate / port an Agent Network or Agent Broker from V1 to V2.
- The user mentions
schemaVersion: 1.0.0and wantsagentNetwork: 2.0.0. - Working folder contains a V1
agent-network.yamlandexchange.json.
For general V2 questions (without converting), point at the builder skill instead.
References
references/v1-example.md— canonical V1 input (customer-onboarding-v1).references/v2-example.md— canonical V2 output for that input. When in doubt about formatting, mirror this.references/v2-template.agent— the orchestrator template to fill in for Step 3c.
Workflow
- Validate input — Step 1.
- Choose output location — Step 2.
- Read source files in full — V1
agent-network.yaml+exchange.jsonend-to-end. - Translate — Step 3 (sub-steps 3a/3b/3c).
- Write output folder with suffix
_v2_conversion— Step 4. - Report the new path and what was converted — Step 5.
Step 1: Validate input
Verify the working folder is actually a V1 Agent Network project. Do not run the conversion against the wrong folder.
- Determine working folder. If unclear, ask.
- Confirm both files exist:
agent-network.yaml(or.yml) andexchange.json. - Read the YAML — must have
schemaVersion: 1.0.0at top level. (V2 usesagentNetwork: 2.0.0.) - Read
exchange.json— must have"classifier": "agent-network". (V2 uses"agentic-network".)
If any check fails, stop and ask the user to point you at the correct folder:
I don't see a V1 Agent Network project in this folder. Looking for
agent-network.yamlwithschemaVersion: 1.0.0andexchange.jsonwith"classifier": "agent-network". What folder should I convert?
Step 2: Choose output location
The new folder name is <original>_v2_conversion. Use AskUserQuestion to offer:
- Same parent directory as source (default).
- Specific path the user provides.
Don't silently overwrite. If the target exists, ask whether to overwrite or pick a different name.
Step 3: Translate
The conversion has three outputs derived from the same V1 source.
3a. Build the V2 agent-network.yaml
V2 has these top-level sections: agentNetwork, info, registry, context, brokers. Map V1 → V2:
| V1 location | V2 location | Notes |
|---|---|---|
schemaVersion: 1.0.0 |
agentNetwork: 2.0.0 |
Required string. |
label (top level) |
info.label |
Required. |
| (none in V1) | info.version |
Required. Use 1.0.0. |
brokers.<id>.card.description |
info.description |
If present, lift the broker's description into info. |
agents.<id> |
registry.agents.<id> |
See Agent translation. |
mcpServers.<id> |
registry.mcps.<id> |
V1 says mcpServers, V2 says mcps. |
llmProviders.<id> |
registry.llms.<id> |
Move card-less LLM info under metadata. |
connections.<id> |
context.connections.<id> |
See Connection translation. |
brokers.<id> |
brokers.<id> + ./brokers/<id>.agent |
See Broker translation. |
Agent translation (agents → registry.agents)
For each V1 agent:
- Lift
labelintoinfo.label. - Keep
metadata.platformas-is. Dropmetadata.protocol— GA replaces it withmetadata.interfaces. - Build
metadata.interfaces.a2a_v03.card— V1 agents were A2A v0.3-based, so the conservative conversion places them in thea2a_v03(back-compat) branch. The card retainsurl: ${<refName>.url},protocolVersion: 0.3.0,version: 1.0.0,capabilities.pushNotifications: false, modes =[application/json, text/plain]. Defaults fornameanddescriptioncome from the agent's V1label. - The broker itself emits A2A v1.0 — keep
brokers.<id>.interfaces.a2a(NOTa2a_v03). - One
skillsentry per agent.id=<agentName>-<verb>(e.g.workday-create-record); copy purpose intonameanddescription.
Don't invent capabilities V1 didn't claim. If V1 doesn't say pushNotifications: true, leave it false.
MCP translation (mcpServers → registry.mcps)
For each V1 MCP server:
- Lift
labelintoinfo.label. Add a shortinfo.descriptionif you can derive one safely from the V1 broker's instructions. - Keep
metadata.transportexactly as-is. - Add
metadata.toolsarray. For each tool the V1 broker calls (look atbrokers.tools[*].mcp.allowedfor the canonical name), add an entry withname,description, and a minimalinputSchema(type: object, pluspropertiesfor arguments you can confidently infer from the broker's instructions). If you can't determine the schema, leavepropertiesempty rather than fabricate.
LLM translation (llmProviders → registry.llms)
For each V1 LLM provider:
- Lift
labelintoinfo.labelanddescriptionintoinfo.description. - Keep
metadata.platform. - Add
metadata.modelsas a list. Include the model V1 actually uses (spec.llm.configuration.model) plus one obvious sibling. Don't pad speculatively.
Connection translation (connections → context.connections)
V1's flat connections object has each connection with kind, ref.name, spec.url, optional spec.configuration for auth. V2 keeps the idea but URL moves up out of spec.
# V1
WorkdayAgentTestConnection:
kind: agent
ref:
name: WorkdayAgentTest
spec:
url: https://...
becomes
# V2
workdayAgentConnection:
kind: a2a # V1 'agent' becomes V2 'a2a'
ref:
name: workdayAgent
url: ${workdayAgent.url}
Mapping rules:
kind: agent(V1) →kind: a2a(V2).kind: mcpandkind: llmstay.- For LLM connections, move auth into a top-level
authenticationblock:kind: apiKey,apiKey: ${<llmName>.apiKey}. Don't keep V1'sspec.configurationshape. - Replace hardcoded URLs with
${<refName>.url}variables. The actual URL value goes intoexchange.json. - Connection identifiers and ref names should be camelCase in V2 (e.g.
workdayAgentConnection,workdayAgent). Rename V1's PascalCase consistently.
Broker translation
V1 puts the broker's A2A card and the orchestrator's prompt (spec.instructions) in one block. V2 splits them:
- A2A card stays in
agent-network.yamlunderbrokers.<broker-id>.interfaces.a2a.card. - Orchestrator prompt moves into
./brokers/<broker-id>.agent.
V2 broker entry (GA, A2A v1.0 — broker IS the endpoint, so its card omits url and protocolVersion):
brokers:
<broker-id>:
kind: AgentScript
implementation: ./brokers/<broker-id>.agent
interfaces:
a2a:
card:
name: <copied from V1 card.name>
description: <copied from V1 card.description>
version: 1.0.0
capabilities:
streaming: false
pushNotifications: <copied from V1 card.capabilities.pushNotifications, default false>
defaultInputModes: [application/json, text/plain]
defaultOutputModes: [application/json, text/plain]
skills:
- id: <copied, lowercased / kebab-cased>
name: <copied>
description: <copied>
tags: <copied>
examples: <copied if present>
inputModes: [application/json, text/plain]
outputModes: [application/json, text/plain]
Use a kebab-case broker id derived from V1 (e.g. CustomerOnboardingBrokerTest → customer-onboarding).
3b. Build the V2 exchange.json
Take V1's exchange.json and:
- Change
"classifier": "agent-network"→"classifier": "agentic-network". - Update
name,assetId,versionto reflect the V2 conversion (e.g.-v2suffix). - Add a
descriptionfield. - For every connection that points to an external URL in V1, add
metadata.variables.<refName>.urlwith the URL asdefault. This is what makes the${<refName>.url}references resolve. - Preserve any existing variables (e.g.
gemini.apiKey). - Mark API keys
"secret": true. Mark URLs"secret": false.
3c. Build the Agent Script <broker-id>.agent
Use references/v2-template.agent as the structural skeleton and fill in the placeholders. Critical naming and content rules:
Action naming:
- For each V1 linked agent, create one
a2a:send_messageaction. Convert the agent name to snake_case (e.g.WorkdayAgentTest→workday_agent). - For each V1 MCP tool listed in
brokers.tools[*].mcp.allowed, create onemcp:toolaction. Pick a snake_case action id reflecting the tool's purpose (e.g.SlackMcpServer.send_status_update→send_slack_status_update). Always preserve the originaltool_nameexactly. - Don't add
inputs:to MCP actions. V1 has no tool input schemas. The V2 runtime auto-discovers a tool's arguments. Inferringinputs:from the orchestrator's prose is fabrication and produces a wrong schema. - The only time you'd add
inputs:is to fix or default an argument value viawithlater (e.g. pinning achannel_id). The conversion shouldn't introduce that.
Reasoning action aliases:
- Inside
reasoning.actions, use short readable aliases (e.g.workday,salesforce,slack_update) rather than reusing the action id verbatim. Makes orchestrator instructions more human-readable.
Prompt preservation:
- Copy
spec.instructionsfrom V1 verbatim into the orchestrator'ssystem.instructions. - Mechanical edits only:
- Replace dotted MCP tool names with the new V2 action alias if the prompt names a tool.
- Tighten obvious typos only if they'd confuse (e.g.
"this a long running task"→"this is a long running task"). When in doubt, leave the user's wording alone.
- Don't split the prompt into multiple nodes. Don't add routers, executors, or generators. The whole orchestration runs inside one orchestrator — that's the explicit constraint.
Step 4: Write output
<chosen_path>/<original_folder_name>_v2_conversion/
├── agent-network.yaml
├── exchange.json
└── brokers/
└── <broker-id>.agent
Use mkdir -p for directories and Write for files. Skip .mvn, .vscode, .cursor, target/ and other IDE folders — they aren't part of the project spec. If the destination exists, ask before overwriting.
After writing, list the created files.
Step 5: Report
Tell the user:
- Full path to the new folder.
- Broker name and orchestrator node id.
- One-line note: this is a simple V1→V2 translation with one orchestrator node; for a richer multi-node graph (router/generator/executor split), use
build-agent-broker-project.
Common mistakes to avoid
- Don't keep
schemaVersion: 1.0.0— V2 usesagentNetwork: 2.0.0. - Don't keep V1's
agent-networkclassifier — V2 usesagentic-network. - Don't invent extra nodes (router, generator, executor). The user wants a single orchestrator.
- Don't rewrite the user's prompt to "improve" it.
- Don't hardcode URLs — parameterize via
${<name>.url}and put the value inexchange.json. - Don't forget
info.version(required in V2, absent in V1). - Don't put auth blocks inside the registry — auth lives on
context.connections.<name>.authentication. - Don't add
inputs:to MCP actions during V1→V2 conversion. V1 has no schemas, so anyinputs:block is guessed from prose. - Don't emit
metadata.protocolor flatmetadata.cardon registry agents — GA usesmetadata.interfaces.<branch>.card. Place V1-converted agents undera2a_v03(back-compat); the broker itself usesa2a(v1.0). - Don't emit
kind: "a2a:response"with a nestedtask: a2a.task({...})in echo nodes — GA useskind: "a2a:status_update_event"(state + message) orkind: "a2a:artifact_update_event"(artifact + append/lastChunk). State values areTASK_STATE_*constants. - Don't emit
# @dialect: AGENTFABRIC=0.1-BETA— use# @dialect: AGENTFABRIC=0.1for GA.