Process identity, the raw config and its path, tier, discovery switches, a programmatic mode override, and the logger. See LoadDynamicPackagesOptions.
The DynamicPackagesReport: Loaded, Skipped (with a reason), NotFound,
Failed, plus the resolved mode and where it came from.
Order of operations. Mode is resolved first (MJ_DYNAMIC_PACKAGES env var → options.mode
→ dynamicPackages.policy → 'load'). Candidates are then discovered generic-to-specific —
the host's codeGeneration.packages, then dynamicPackages.<tier>[], then the mj-app.json
beside the config — and merged by package name (mergeCandidates). Under mode 'none'
every candidate is reported as skipped and nothing is imported. Otherwise each candidate is
filtered (Enabled === false, then Processes / ExcludeProcesses via MatchesProcess),
served from the per-process cache when an earlier call already loaded it (module returned,
startup export not re-run), or imported through importFromHost with an on-disk
workspace fallback for manifest entries.
Why order matters. @RegisterClass resolves by load-order priority — the last registration
for a key wins — so importing generic-to-specific is what makes an Open App's server subclass
beat its generated one, and the app you are standing in beat an installed copy.
When to call it. After the host's class-registration manifest has been imported (so app
registrations land last) and before any database provider exists (a StartupExport may rely on
nothing but the ClassFactory).
Failure model. Throws only when processId is missing. A package that no anchor can resolve
is NotFound (expected before npm install, or for an unbuilt workspace member); one that
resolves but throws while loading is Failed with its own error, logged on the warn path and
never masked by a resolution message. Boot never crashes because of an app package.
const { config, configFilePath } = DiscoverMJConfig();
const report = await LoadDynamicPackages({ processId: 'mcp', config, configFilePath });
for (const failed of report.Failed) {
console.error(`app package ${failed.Entry.PackageName} failed to load`, failed.Error);
}
Loads every dynamic package that applies to
options.processIdand returns a report of what happened to each entry. This is the one call a host makes; everything else in the package is a primitive it composes.