Skip to content

feat(java): add redefine_classes MCP tool for JVM hot-reload#26

Merged
debugmcpdev merged 4 commits intodebugmcp:mainfrom
Finomosec:feat/java-hot-reload
Mar 28, 2026
Merged

feat(java): add redefine_classes MCP tool for JVM hot-reload#26
debugmcpdev merged 4 commits intodebugmcp:mainfrom
Finomosec:feat/java-hot-reload

Conversation

@Finomosec
Copy link
Copy Markdown
Contributor

@Finomosec Finomosec commented Mar 26, 2026

Summary

  • Adds a new redefine_classes MCP tool that hot-swaps changed Java classes into a running JVM using JDI VirtualMachine.redefineClasses()
  • Scans a classes directory for .class files modified after a given timestamp, matches them against loaded classes, and redefines them
  • Returns redefined/skipped/failed counts and the newest file timestamp for incremental follow-up calls
  • Schema changes (new methods/fields) are reported as individual failures without blocking other classes
  • Fixes stopOnEntry not being forwarded in create_debug_session and attach_to_process, defaulting to false for attach mode so sessions report RUNNING instead of falsely reporting PAUSED

Changes

  • JdiDapServer.java: New handleRedefineClasses DAP command with directory scanning, FQCN matching, and per-class error handling
  • session-manager-operations.ts: New redefineClasses() method + RedefineClassesResult interface
  • server.ts: Tool definition + dispatch for redefine_classes; forward stopOnEntry with ?? false default in both attach code paths

Test plan

  • Attach to running JVM (STAPP on port 5009)
  • Full scan (sinceTimestamp=0): 37 classes redefined, 52 skipped (not loaded), 9 failed (schema changes)
  • Incremental scan (sinceTimestamp=newestTimestamp): 0 files scanned, 0 redefined
  • Attach no longer reports state=paused, reports state=running correctly
  • TypeScript type-check, Java compilation, full pnpm build pass

Adds a new redefine_classes tool that hot-swaps changed Java classes
into a running JVM using JDI VirtualMachine.redefineClasses(). The tool
scans a classes directory for .class files modified after a given
timestamp, matches them against loaded classes, and redefines them.
Returns redefined/skipped/failed counts and the newest file timestamp
for incremental follow-up calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Finomosec Finomosec force-pushed the feat/java-hot-reload branch from 75dc254 to 1398af4 Compare March 26, 2026 09:39
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 26, 2026

Codecov Report

❌ Patch coverage is 17.39130% with 38 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/session/session-manager-operations.ts 0.00% 38 Missing ⚠️

📢 Thoughts on this report? Let us know!

…e_debug_session

The create_debug_session attach shortcut did not forward stopOnEntry,
and the missing value caused attachToProcess to default to PAUSED state
even though the VM was not actually suspended. Now stopOnEntry is
forwarded and defaults to false for the attach shortcut, so attaching
reports RUNNING state by default.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Finomosec Finomosec force-pushed the feat/java-hot-reload branch from b21b183 to 74ee972 Compare March 26, 2026 10:24
Finomosec and others added 2 commits March 26, 2026 11:36
handleAttach did not call vm.suspend(), so stopOnEntry only affected
the MCP session state but not the actual JVM. Now the VM is suspended
after attach when stopOnEntry=true, and resumed on continue.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests cover:
- redefine_classes tool registration and input schema
- redefine_classes dispatch with correct args and sinceTimestamp default
- redefine_classes error propagation
- create_debug_session attach defaults stopOnEntry to false
- create_debug_session attach forwards stopOnEntry=true
- attach_to_process defaults stopOnEntry to false
- attach_to_process forwards stopOnEntry=true

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@debugmcpdev debugmcpdev merged commit 3c1da39 into debugmcp:main Mar 28, 2026
6 of 7 checks passed
@debugmcpdev
Copy link
Copy Markdown
Collaborator

Thanks @Finomosec — this is a great feature! Hot-swapping classes into a running JVM opens up some really interesting possibilities for interactive debugging workflows.

Merged, and we've done a small follow-up cleanup:

  • Removed the unused waitForInitialBreakpointPause method (it was never called)
  • Added unit tests for the SessionManager.redefineClasses() method to close the coverage gap Codecov flagged

Appreciate the contribution!

debugmcpdev pushed a commit that referenced this pull request Mar 28, 2026
Follow-up to PR #26 (feat/java-hot-reload):
- Remove unused waitForInitialBreakpointPause private method (never called)
- Add unit tests for SessionManager.redefineClasses() covering success,
  failures, missing proxy, empty response body, and default args

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
debugmcpdev pushed a commit that referenced this pull request Mar 28, 2026
PR #26 changed attach_to_process and create_debug_session (attach path)
to default stopOnEntry to false, but this broke attach to JVMs started
with suspend=y — the session reported RUNNING instead of PAUSED.

Revert to passing stopOnEntry as-is (undefined when not specified), which
lets the session manager preserve the original behavior: attach defaults
to PAUSED state, matching the common suspend=y workflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants