Scan Mule applications for migration complexity assessment
Project description
mule-discovery
Scan Mule applications for migration complexity assessment.
Parses Mule 4 (and 3) XML source files, POM dependencies, DataWeave scripts, and API specifications to produce a structured migration readiness report with complexity scoring.
Estate Analysis
The output produced by mule-discover (JSON or YAML) can be fed into the estate-analyzer agent skill to generate pre-sales migration reports. The estate-analyzer processes discovery output across your entire Mule application estate to produce complexity summaries, connector frequency analysis, PoC candidate recommendations, and migration sizing reports.
Quick Start (uv)
No install required — just run from the project directory:
cd mule-discovery
# Discover all Mule apps under a directory
uv run mule-discover /path/to/apps --output-dir ./inventory
# JSON output instead of YAML
uv run mule-discover /path/to/apps --json --output-dir ./inventory
uv run reads pyproject.toml, resolves dependencies into an ephemeral environment, and runs the command. Nothing is installed globally.
Installation
From PyPI with uv (recommended)
Install as a global CLI tool — uv puts the entry points on your PATH:
uv tool install mule-discovery
# Then run directly from anywhere
mule-discover /path/to/apps --output-dir ./inventory
Upgrade or remove later with:
uv tool upgrade mule-discovery
uv tool uninstall mule-discovery
For Anypoint Platform integration (policy scanning), install with the extra:
uv tool install "mule-discovery[anypoint]"
From PyPI with pip
pip install mule-discovery
# Then run directly
mule-discover /path/to/apps --output-dir ./inventory
For Anypoint Platform integration (policy scanning):
pip install mule-discovery[anypoint]
From source (development)
uv sync --extra dev
Requires Python 3.10+.
CLI Tools
mule-discover
Recursively find all Mule applications under a directory and produce migration complexity reports for each.
# Discover all apps, write YAML inventories (default) to ./inventory
uv run mule-discover /path/to/apps --output-dir ./inventory
# JSON output
uv run mule-discover /path/to/apps --json --output-dir ./inventory
# Suppress progress output
uv run mule-discover /path/to/apps -o ./inventory -q
# Custom complexity thresholds
uv run mule-discover /path/to/apps --flow-low 8 --flow-medium 18 --flow-high 30
# Resolve parent POMs and external flow-refs against a customer's shared frameworks
uv run mule-discover /path/to/apps --common-libs /path/to/common_libs_home -o ./inventory
--common-libs
Customers often ship their Mule apps alongside a separate "common libs" / shared frameworks directory containing parent POMs (which the apps inherit dependencies from) and shared Mule projects defining flows that the apps reference via flow-ref. Without this directory, the discovery tool only sees what's local to each app and reports an empty connector list and unresolved flow-refs.
When you pass --common-libs PATH, the tool will:
- Resolve parent POM chains. Each app's
<parent>coordinates are looked up in the directory; if found, the parent's<dependencies>are merged into the app's connector inventory (withsource_fileindicating which parent contributed each connector). Multi-level chains are walked. - Resolve external flow-refs. Every
flow-refwhose target is not defined inside the app is checked against an index of<flow>and<sub-flow>definitions found anywhere under the common-libs directory. Resolved refs include the library name, source file, and line number; unresolved ones are reported separately so they can be flagged for follow-up. - Pull in only what's referenced. The common-libs directory may be large; the tool does not blanket-include everything from it. Only parent POMs the apps actually inherit from and flows the apps actually reference are surfaced.
Expected directory layout (one Mule project per top-level subdirectory):
common_libs_home/
├── hvcp-mule4-common-framework-handler/
│ ├── pom.xml
│ └── src/main/mule/*.xml
├── hvcp-mule4-common-messaging-framework/
│ └── ...
└── shared-parent-poms/
└── pom.xml
The discovery output gains two new fields under the per-app inventory:
resolved_parent_poms: list of parent POMs in the inheritance chain, each withgroupId,artifactId,version,resolved(boolean),source_file, and thedependenciesdeclared there.external_flow_refs:{"resolved": [...], "unresolved": [...]}. Each resolved ref shows the library and source file/line of the matching definition.
Connector discovery without a parent POM
When an app's pom.xml declares no dependencies (typical when everything is inherited from a parent POM that isn't on disk), the tool falls back to deriving connectors from the xmlns: declarations in the Mule XML files themselves. These entries are tagged with notes: "derived from XML namespaces - parent POM not resolved" and source_file: "(xml-namespaces)" so the source of each connector remains traceable. Pass --common-libs to replace this fallback with proper parent-POM resolution where possible.
Each per-app report includes:
- Flow inventory with complexity levels (LOW / MEDIUM / HIGH / VERY_HIGH)
- DataWeave transformation analysis and classification
- HTTP listener and scheduled job detection
- Connector inventory with migration weights
- API specification detection (OpenAPI, WSDL)
- External dependency and out-of-scope item tracking
- AWS service usage (SQS, S3, DynamoDB)
- SOAP/WSDL service detection
- HTTP request-config inventory and connector authentication metadata (
request_configs,connector_auth) - Overall migration score (0–100) with recommendation (SIMPLE / MODERATE / COMPLEX / VERY_COMPLEX)
mule-scan-policies
Scan Anypoint Platform for API policies on deployed applications. Requires the anypoint extra.
pip install -e ".[anypoint]"
export ANYPOINT_CLIENT_ID=...
export ANYPOINT_CLIENT_SECRET=...
export ANYPOINT_ORG_ID=...
export ANYPOINT_ENV_ID=...
uv run mule-scan-policies
uv run mule-scan-policies --format json
mule-download-policies
Download custom policies from Anypoint Exchange. Requires the anypoint extra.
export ANYPOINT_CLIENT_ID=...
export ANYPOINT_CLIENT_SECRET=...
export ANYPOINT_ORG_ID=...
uv run mule-download-policies --output-dir ./custom_policies
Complexity Scoring
Each application receives a migration score from 0 to 100 (higher = simpler migration):
| Score Range | Recommendation | Meaning |
|---|---|---|
| 75–100 | SMALL | Straightforward migration |
| 50–74 | MEDIUM | Some complexity, manageable |
| 25–49 | LARGE | Significant effort required |
| 0–24 | XLARGE | Major rework needed |
Deductions are applied across eight dimensions:
| Dimension | Max Deduction |
|---|---|
| Flow complexity | 30 pts |
| Transform complexity | 15 pts |
| Risk / out-of-scope items | 20 pts |
| Connector migration weight | 20 pts |
| WSDL / SOAP services | 10 pts |
| Scale (flow + component count) | 20 pts |
| Pattern complexity (scatter-gather, choices, batch, parallel-foreach, retries) | 15 pts |
| DataWeave volume | 15 pts |
Flow Complexity Thresholds
Flows are classified by component count (configurable via CLI flags):
| Components | Complexity |
|---|---|
| ≤ 6 | LOW |
| 7–14 | MEDIUM |
| 15–25 | HIGH |
| > 25 | VERY_HIGH |
DataWeave Classification
DataWeave transformations are classified by line count and function usage:
| Classification | Criteria |
|---|---|
| simple_mapping | ≤ 5 lines, no complex functions |
| field_level_logic | 6–20 lines, or uses routine functions (map, filter, pluck, etc.) |
| business_logic | > 20 lines, or uses complex functions (reduce, groupBy, flatMap, etc.) |
Package Structure
src/mule_discovery/
├── __init__.py # Main discover_mule_app() orchestrator
├── constants.py # XML namespaces, element classifications, connector weights
├── xml_helpers.py # XML utility functions
├── models/ # Data models (dataclasses)
│ ├── result.py # DiscoveryResult (top-level container)
│ ├── flows.py # FlowInfo, BatchInfo, ChoiceInfo, ScatterGatherInfo, ...
│ ├── connectors.py # ConnectorInfo, SpringDependency
│ ├── dataweave.py # DataWeaveInfo
│ ├── listeners.py # HttpListenerInfo, ScheduledJobInfo
│ ├── dependencies.py # ExternalDependencyInfo, SourceFiles, OutOfScopeItem
│ ├── schemas.py # ApiSpecInfo (OpenAPI, WSDL)
│ └── scoring.py # ComplexityThresholds, ScoreResult
├── parsers/ # File IO → models
│ ├── file_discovery.py # find_mule_apps(), find_mule_xml_files()
│ ├── mule_xml.py # Mule XML parsing (flows, listeners, jobs)
│ ├── pom.py # POM parsing (app name, version, connectors, parent-POM chain resolution)
│ ├── common_libs.py # Indexing of customer-supplied common-libs (flows + parent POMs)
│ ├── http_auth.py # HTTP auth config extraction
│ ├── dataweave.py # DataWeave script parsing
│ ├── soap.py # SOAP/WSDL service detection
│ ├── aws.py # AWS service detection (SQS, S3, DynamoDB)
│ ├── openapi.py # OpenAPI spec detection
│ └── wsdl.py # WSDL parsing utilities
├── analysis/ # Models → models (pure functions)
│ ├── classification.py # Flow type and source category constants
│ ├── complexity.py # Flow and DataWeave complexity assignment
│ ├── patterns.py # Pattern detection (async, scatter-gather, choice, ...)
│ ├── scoring.py # Migration score calculation (0–100)
│ └── dependencies.py # External dependency and out-of-scope extraction
├── output/ # Models → formatted strings
│ ├── yaml_output.py # YAML
│ ├── json_output.py # JSON
│ └── text_output.py # Human-readable text summary
├── anypoint/ # Anypoint Platform integration (optional)
│ ├── policies.py # Policy scanning
│ └── exchange.py # Custom policy download
└── cli/ # CLI entry points (thin wrappers)
├── discover.py # mule-discover
├── scan_policies.py # mule-scan-policies
└── download_policies.py # mule-download-policies
Design Principles
- No function does both IO and computation. Parsers read files → return models. Analysis takes models → returns models. Output takes models → returns strings.
- All data models are plain dataclasses with typed fields — no methods with side effects.
- All analysis functions are standalone — no class methods, no inheritance.
- Each output format is a separate module.
Testing
make test
Or directly:
uv run --extra dev python -m pytest
Coverage is enforced at 70% (branch coverage) via pyproject.toml.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mule_discovery-1.3.0.tar.gz.
File metadata
- Download URL: mule_discovery-1.3.0.tar.gz
- Upload date:
- Size: 115.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6de9a3a1aa59e2fa4ff388ae00fcaa1f73fed918894984d527d11bd01f960b8e
|
|
| MD5 |
982a5ebca467d8a8f5f401671a49177e
|
|
| BLAKE2b-256 |
130d9b9c837abc16725a1703d58de87396dd1de68e08c7cc47e33e74c859e734
|
File details
Details for the file mule_discovery-1.3.0-py3-none-any.whl.
File metadata
- Download URL: mule_discovery-1.3.0-py3-none-any.whl
- Upload date:
- Size: 57.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b5db8498a590a84e8c3cc17be5b8c580e95eba5192d88a036e78a4a9d76beba
|
|
| MD5 |
89f43036cddaec06332fe9677eec2552
|
|
| BLAKE2b-256 |
3b74a90ef33d616df2dac6f825089c596618b1a01410c642406e511cd246e951
|