Skip to content
| Marketplace
Sign in
Visual Studio Code>Debuggers>Maximo Script DebuggerNew to Visual Studio Code? Get it now.
Maximo Script Debugger

Maximo Script Debugger

Rana Ahmed

|
243 installs
| (0) | Free
VS Code debug adapter frontend for Maximo automation scripts.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Maximo Script Debugger

VS Code debug extension for Maximo automation scripts (Jython and Nashorn JS). The extension launches the Java Maximo-debugger DAP backend over stdio, and the backend attaches to a JDWP-enabled Maximo JVM.

Pre-release. This is an early pre-release that targets development/test Maximo environments. See Known Limitations and Security before using it.

Requirements

  • VS Code 1.116 or newer.
  • The MxScript extension (Rana.mxscript) — required. It is a hard dependency (VS Code installs/enables it automatically). It is the single source of truth for your Maximo connection: the debugger reuses MxScript's configured environment (host + authentication) to talk to Maximo and to auto-deploy the in-Maximo debug helper. Configure at least one Maximo environment in MxScript's Maximo Environments view, pointing at your debug target.
  • Java 17 or newer to run the debugger host process (the backend uses jdk.jdi).
    • Download a JDK from Eclipse Temurin: https://adoptium.net/temurin/releases/?version=17. Pick the JDK (not JRE) for your OS/arch, download the .zip/.tar.gz, and extract it anywhere — no installer required. Then point the extension at it with mxscriptMaximoDebugger.javaHome (the extracted folder) or mxscriptMaximoDebugger.javaPath (the bin/java inside it). Run Maximo Debugger: Validate Java Runtime to confirm.
  • A Maximo JVM started with JDWP enabled — see Enabling JDWP on Maximo.
  • A runnable Maximo debugger backend jar at server/maximo-debugger.jar (bundled), or an override path in debuggerJarPath / mxscriptMaximoDebugger.debuggerJarPath.

Maximo connection & the debug helper (auto-deployed)

The debugger gets which Maximo and how to authenticate entirely from the MxScript environment — you do not put a host/URL/API key in launch.json. The launch config adds only the JDWP transport:

{
  "type": "mxscript-maximo-debugger",
  "request": "attach",
  "name": "Debug Maximo (DEV)",
  "maximoEnvironment": "DEV",   // optional: pin to a named MxScript environment; default = active
  "jdwpPort": 7777,             // JDWP debug port (default 7777)
  "jdwpHost": "localhost"       // optional: only when JDWP is tunnelled (oc port-forward/SSH); default = env hostname
}

For Jython debugging the in-Maximo helper (driver + line-fix agent) is a hard prerequisite. On attach the extension silently deploys it to your MxScript environment over that environment's authenticated REST session (progress: "deploying debug helper…"). If the helper can't be deployed, the debugger refuses to connect (you'll get a clear error). The helper is a hot, non-persistent deploy — it is re-deployed automatically on the next attach after a Maximo restart. Nashorn-only sessions don't need the helper and skip this.

The backend jar is bundled with the published extension — there is nothing to build. (Contributors building from source: see docs/building-from-source.md.)

Sample Attach Configuration

Minimal — the Maximo host + authentication come from the MxScript environment, so you don't put host, a URL, or credentials here:

{
  "type": "mxscript-maximo-debugger",
  "request": "attach",
  "name": "Debug Maximo (DEV)",
  "maximoEnvironment": "DEV",
  "jdwpPort": 7777,
  "jythonSourceRoots": ["${workspaceFolder}/scripts/jython"],
  "nashornSourceRoots": ["${workspaceFolder}/scripts/nashorn"]
}
  • maximoEnvironment — optional; the MxScript environment to use (defaults to the active one).
  • jdwpPort — the JDWP debug port (default 7777).
  • jdwpHost — optional; only when JDWP is tunnelled to a different host than the environment (e.g. localhost via oc port-forward/SSH). Defaults to the environment hostname.
  • Jython and Nashorn are debugged together — no engine modes. A single JDWP attach drives both engines: a .py breakpoint routes to the Jython engine and a .js breakpoint routes to Nashorn. Set jythonSourceRoots and/or nashornSourceRoots for whichever languages you debug (set both to debug both). (Only one JDWP session per JVM is supported, so this one session covers everything.)
  • diveIntoJdk — optional (default true); when stepping into Java, also descend into useful JDK packages (java.util, java.time, java.math, java.text, java.io). Set false to restrict step-into to Maximo app code (psdi.* / com.ibm.tivoli.maximo.*). See Stepping into Java.

host / port are deprecated (still honored for back-compat → treated as jdwpHost / jdwpPort). Prefer maximoEnvironment + jdwpPort.

Everything else is optional and has sensible defaults — sourceMappingMode (hybrid), nashornVariableSummaryMode (safeLazy), attachTimeoutMillis, resumeOnDisconnect, etc. Override only when needed.

Enabling JDWP on Maximo (MAS 9 & Maximo 7.6)

The extension attaches to the Maximo JVM over JDWP (the standard Java debug wire protocol). You enable it by adding one JVM argument and exposing the port. This brief follows the approach in Sharptree's "remote debugging Maximo automation scripts" guidance (https://sharptree.io); adapt it to your environment.

The JVM argument is the same on both versions:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:7777
  • server=y — the JVM listens; the debugger connects in.
  • suspend=n — the JVM does not wait for a debugger at startup.
  • address=*:7777 — listen on port 7777 on all interfaces (use a specific bind address if your platform requires it).

Maximo 7.6 (traditional WebSphere):

  1. WebSphere admin console → Servers → Server Types → WebSphere application servers → <your MXServer> → Process definition → Java Virtual Machine.
  2. Add the -agentlib:jdwp=... line above to Generic JVM arguments, save, and synchronize the node.
  3. Restart the MXServer JVM.
  4. Make sure port 7777 is reachable from your workstation (host firewall / network).

MAS 9 (containerized — OpenLiberty on OpenJ9 in OpenShift/Kubernetes):

  1. Add the -agentlib:jdwp=... argument to the server's JVM options (e.g. a jvm.options entry or the JVM_ARGS/server-customization mechanism your MAS deployment uses).
  2. Roll/restart the Manage (*-manage / *-wlp-*) pod so the JVM picks up the argument.
  3. Expose port 7777 from the pod — e.g. a Service/NodePort, an OpenShift Route (TCP), or oc port-forward svc/<manage-svc> 7777:7777 for a quick local session.

The bundled in-Maximo helper also exposes a runtime enableJdwp action that can load the JDWP agent into an already-running JVM without a restart, but loading the debug agent at runtime is environment-dependent and is not a substitute for the supported boot-argument approach above.

The in-Maximo helper (auto-deployed)

Accurate Jython line + exception breakpoints need an in-Maximo helper — a DebugJSR223ScriptDriver plus a PyxLineAgent that rewrites Jython's broken _pyx line tables so JDI breakpoints land on the right line. The extension bundles these jars and deploys them for you:

  • On a Jython attach the extension uploads + activates the helper automatically (hot, no Maximo restart) over the MxScript environment's authenticated REST session, showing a "deploying debug helper…" progress notification. It's a hard prerequisite — if the deploy fails, the debugger refuses to connect with a clear error.
  • It's idempotent and self-updating: a version handshake re-uploads only when the deployed copy is older than the bundled one, and it's re-deployed automatically after a Maximo restart (the helper is a hot, non-persistent install) on the next attach.
  • Nashorn-only sessions don't need the helper and skip the deploy.

You don't run any manual command for this.

Performance

Jython debugging is agent-only and tuned for low latency. Breakpoints and stepping use real per-_pyx JDI line breakpoints — there is no slow PyFrame.setline per-line hook — so stepping doesn't flood JDWP. The Variables pane is served lazily, and on each stop the helper agent captures the frame's locals/globals in a single in-process call rather than one round-trip per variable, so it stays responsive even against remote/LAN Maximo targets. The helper self-updates on attach to enable this; if it can't be deployed, Jython breakpoints won't bind and the extension prompts you to (re)deploy it.

Stepping stays fast on large scripts — the compiled line table used to arm each step is cached per class — and fetching variables while you step quickly no longer stalls: an in-flight fetch for a stop you've already left is abandoned rather than blocking.

Nashorn Variables

Nashorn variables are displayed in VS Code's normal Variables tree. safeLazy is the default mode: locals show cheap scalar summaries immediately, while objects, arrays, Java collections, maps, custom classes, globals, closures, and implicit runtime metadata are expanded only when you open that node in the tree.

The backend owns Nashorn value inspection and emits DAP type, variablesReference, and child count metadata so the extension does not need a custom reveal button or separate variable UI.

Stepping into Java (decompiled)

From a Jython script you can Step Into a line that calls Java and the debugger descends into the actual Java method — psdi.*, com.ibm.tivoli.maximo.*, and (by default) useful JDK classes like java.util.Date — instead of stepping over it. For example, on asset.getString("assetnum") you land in psdi.mbo.Mbo.getString; on d.setTime(...) you land in java.util.Date.setTime.

  • One continuous call stack. Java frames appear above your script frames; the Jython dispatch/reflection plumbing in between is collapsed, so it reads as one script → Java stack. Step Out of the Java frames returns to the next line of your script; stepping within Java uses native JDI stepping.
  • Decompiled source, correct line. Maximo/JDK classes ship no .java, so Java frames are decompiled on demand (Vineflower) from the exact loaded bytecode fetched via the in-Maximo helper agent, and shown at the right line via the bytecode→source mapping. Results are cached per class.
  • Java variables. Locals (where the class carries debug info) and this (expandable to its fields) show in the Variables pane. Static, no-argument methods legitimately have no locals and no this.
  • JDK scope toggle. diveIntoJdk (default true) includes the useful JDK packages above; set it false for Maximo-app-only stepping. Jython's own dispatch internals (java.util.concurrent, reflection, OpenJ9/Liberty internals) are always skipped so steps land on your real target.

Requires the in-Maximo helper (auto-deployed for Jython sessions) for the decompiler's bytecode fetch. Nashorn → Java diving is not yet supported, and only the top Java frame is decompiled (deeper Java caller frames show without source for now).

Commands

  • Maximo Debugger: Open Logs
  • Maximo Debugger: Copy Sample Launch Config
  • Maximo Debugger: Copy Launch Diagnostics
  • Maximo Debugger: Validate Java Runtime
  • Maximo Debugger: Show Recent Script Executions
  • Maximo Debugger: Deploy Helper Driver + Agent
  • Maximo Debugger: Pick Debug Script (Catalog)

Settings

  • mxscriptMaximoDebugger.javaPath: Java executable used to start the backend. Defaults to java.
  • mxscriptMaximoDebugger.debuggerJarPath: Optional backend jar override.
  • mxscriptMaximoDebugger.debuggerLibPath: Optional backend dependency jar directory.
  • mxscriptMaximoDebugger.logLevel: Backend log level.
  • mxscriptMaximoDebugger.traceAdapter: Show resolved backend command and verbose diagnostics.

The attach configuration also supports per-session overrides for javaPath, javaArgs, debuggerJarPath, debuggerLibPath, and logLevel.

Use Maximo Debugger: Copy Launch Diagnostics to copy the resolved workspace roots, backend paths, and computed Java command for the current default attach configuration.

Known Limitations

This is a pre-release. Be aware of the following before relying on it:

  • Re-attach may hang the JVM's JDWP listener. On some JVMs (notably OpenJ9 with server=y libjdwp), the JDWP server-side socket can wedge after a couple of attach/detach cycles — a fresh attach then stalls or the port becomes unreachable. The extension does its best to fully resume threads and tear down its JDI event requests on disconnect, but if attaches start failing, restart the Maximo JVM (the pod/server) to clear the stuck listener. This is a JVM/JDWP behavior, not something the extension can fully work around.
  • Conditional breakpoints, hit-count breakpoints, and logpoints are experimental on Jython. They are evaluated against the in-Maximo compiled _pyx frame and can be intermittent — a condition that should pause may occasionally not, or vice versa — because the expression evaluation shares the same suspended-thread dispatch as the stop. Treat them as best-effort. Plain (unconditional) line breakpoints are reliable. Nashorn conditions are more stable than Jython.
  • Exception breakpoints are Jython-only and don't distinguish caught vs. uncaught. Toggling "Uncaught Exceptions" / "All Exceptions" pauses on exceptions raised in your script (highlights the line, shows the stack + variables, and the type/message). Because Jython wraps every Python exception in a Java PyException that its interpreter catches internally, the JDI caught/uncaught distinction doesn't map to Python — so both toggles behave the same: stop on script exceptions. Scripts that use try/except for control flow will pause on those too while enabled; untick to disable.
  • Helper redeploy after restart is automatic. The in-Maximo helper driver/agent is a hot, non-persistent deploy; it is re-deployed automatically via MxScript on the next attach after a Maximo restart.
  • One JDWP debug session at a time per Maximo JVM is the supported mode.

Security

JDWP is a remote-code-execution channel. Enable it only on development and test environments you control.

  • An open JDWP port lets anyone who can reach it run arbitrary code inside the Maximo JVM with full application privileges — there is no authentication on the debug protocol.
  • Never enable JDWP on a production Maximo, and never expose the JDWP port to the public internet or an untrusted network. Bind it to localhost or a private network and use a VPN / SSH tunnel / oc port-forward to reach it.
  • Remove the -agentlib:jdwp=... JVM argument (and any exposed port/route/service) when you are done debugging.
  • The in-Maximo helper driver + agent execute with Maximo's privileges and can rewrite loaded classes — deploy them only to environments you trust and intend to debug.

Troubleshooting

  • If attach fails before the backend starts, run Maximo Debugger: Validate Java Runtime.
  • If a Jython attach is blocked with a deploy/connection error, confirm MxScript has an environment selected for your target and that you allowed this extension access to it.
  • If breakpoints stay unverified, check jythonSourceRoots, nashornSourceRoots, and sourceMappingMode.
  • If the target does not accept JDWP attach, confirm the Maximo JVM is listening on the configured host and port.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft