Thank you for your interest in contributing to mcp-debugger! We welcome contributions from the community and are grateful for your support.
- Code of Conduct
- Getting Started
- Development Workflow
- Dev-Loop Gate
- Code Style
- Testing
- Commit Messages
- Pull Request Process
- Project Structure
- Questions
This project adheres to the Contributor Covenant Code of Conduct. All contributors are expected to follow it. Please be respectful and professional in all interactions.
- Node.js 22+
- pnpm 12 (required —
workspace:*protocol needs pnpm, not npm). The exact version is pinned via thepackageManagerfield inpackage.json; pnpm 10+ switches to it on its own, or runcorepack enableto have corepack do it. Project-level pnpm settings (overrides,allowBuilds) live inpnpm-workspace.yaml— pnpm 11+ no longer reads apnpmfield inpackage.json. Never commit a regeneratedpnpm-lock.yaml— a different pnpm version rewrites it destructively (dropping the securityoverridesblock); ifpnpm installmodifies it, rungit checkout pnpm-lock.yamlbefore committing. - Python 3.7+ (for debugging Python code)
- Go 1.18+ and Delve (for debugging Go code, optional)
- Rust toolchain (for debugging Rust code, optional — CodeLLDB auto-downloads during install)
- JDK 21+ (for debugging Java code, optional — JDI bridge compiles on first use; compile target code with
javac -gfor variable inspection) - Docker (optional, for containerized development)
- Git
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/mcp-debugger.git cd mcp-debugger - Add upstream remote:
git remote add upstream https://github.com/debugmcp/mcp-debugger.git
- Install dependencies:
pnpm install
- Build the project:
npm run build
-
Sync with upstream:
git fetch upstream git checkout main git merge upstream/main
-
Create a feature branch:
git checkout -b feature/your-feature-name # or git checkout -b fix/your-bug-fix -
Make your changes following our code style guidelines
-
Build and test — run the Dev-Loop Gate below. It is the exact set of checks
.husky/pre-pushand CI enforce, so passing it locally means nothing downstream surprises you. -
Commit your changes using conventional commits (see below)
-
Push to your fork:
git push origin feature/your-feature-name
-
Create a Pull Request from your fork to our
mainbranch
This is the canonical description of the checks that gate a push. .husky/pre-push runs all five
steps in this order; CI's Lint Code job runs steps 1 and 3, and its Build and Test job
covers steps 4 and 5 via pnpm run build:ci and pnpm run test:ci-coverage. Other docs should
link here rather than restate it.
Lint Code also runs four PR-blocking checks that pre-push does not, so a clean local gate is
not a guarantee: pnpm run check:all-personal-paths, pnpm run check:docs (relative links that
no longer resolve, and counts that fell behind the code), pnpm run changelog:check, and a
"Require a changelog fragment" step on pull requests — a user-visible change needs a fragment
(test-only changes are exempt automatically; label a genuine no-op PR no-changelog). Running
those four before you push saves a CI round-trip.
-
Lint —
pnpm run lint. ESLint oversrc/**/*.ts,packages/*/src/**/*.ts,scripts/**/*.{js,mjs,cjs}, andtools/**/*.{js,mjs,cjs}(the dev-proxy supervisor lives undertools/, and it starts, stops and proxies the backend — it is production tooling, not a probe script).pnpm run lint:fixruns the same globs with--fix. Experimental probes belong inscripts/experiments/, whicheslint.config.jsignores. -
A committed
tests/typecheck-baseline.json— pre-push refuses to go further while that file is modified but uncommitted. The ratchet validates your working tree locally but the pushed commit in CI, so an uncommitted baseline passes here and fails there. -
Type-check —
pnpm run typecheck:all, which istypecheck(the shipped sources, viatsconfig.typecheck.json) plustypecheck:tests(the per-file ratchet over the test trees).src/andpackages/*/srcmust be strict-clean. The tests carry a recorded per-file error backlog that may only shrink, and the ratchet fails in both directions:- a count went up — you introduced type errors; fix them;
- a count went down, or a test file was removed — that is progress, but the baseline is now
stale: run
pnpm run typecheck:tests:updateand committests/typecheck-baseline.jsonin the same PR.
pnpm run typecheck:tests:rawprints unfilteredtscoutput fortsconfig.spec.jsonwhen you need to see the diagnostics themselves. -
Clean build —
npm run clean && npm run build, so no stale artifact can mask a compile error. -
Tests —
npm run test:unit && npm run test:integration. Deliberately not the full suite: the heavye2eproject (smoke, Docker, npx) runs in CI. (A tags-only push runs the reducednpm run test:ci-no-pythoninstead.)
The pre-commit hook is much lighter and runs none of the above: it runs the personal-paths
check, blocks accidentally staged build artifacts (.js/.d.ts/.js.map under src/ or
packages/*/src/) and .tgz tarballs, and runs an optional docstar check if docstar is installed.
No tests, no build.
IMPORTANT: Never commit personal information to the repository. This includes:
- Personal file paths (e.g.,
C:\path\to\or/path/to/) - Personal email addresses (project emails like
admin@debugmcp.ioare okay) - Cloud storage paths with personal folders
- Any other personally identifiable information
We have a pre-commit hook that automatically checks for personal information patterns. If detected, your commit will be blocked with instructions on how to fix it.
When documenting or writing examples, always use generic paths like:
/path/to/projectC:\path\to\project~/workspace/project
You can manually run the privacy check:
# Check staged files (what pre-commit does)
npm run check:personal-paths
# Check all files in the repository
npm run check:all-personal-pathsWe use ESLint to maintain consistent code style. There is no Prettier setup in this repo —
eslint.config.js is the only style tool of record.
# Run ESLint (src/**, packages/*/src/**, scripts/**, tools/**)
npm run lint
# Fix auto-fixable issues over the same globs
npm run lint:fix- Use TypeScript for all new code
- Follow the existing code structure and patterns
- Write self-documenting code with clear variable names
- Add JSDoc comments for public APIs
- Keep functions small and focused
- Use dependency injection patterns (see existing code)
We recommend configuring your editor to:
- Apply ESLint auto-fixes on save
- Show ESLint warnings/errors inline
- Use the project's TypeScript version
Example VS Code settings:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.tsdk": "node_modules/typescript/lib"
}The project includes a comprehensive test suite. Please ensure all tests pass before submitting a pull request. If you're adding a new feature, please include tests for it.
The project uses Vitest as its test runner:
# Run all tests
npm test
# Run specific test suites
npm run test:unit # Unit tests only
npm run test:integration # Integration tests only
npm run test:e2e # End-to-end tests only
# Run tests with coverage
npm run test:coverage
# Run a specific test file (SessionManager specs live under tests/core/unit/session/)
npx vitest run tests/core/unit/session/session-manager-state.test.tsBefore pushing, run the full Dev-Loop Gate — npm test alone is not what CI
and the pre-push hook check.
Our tests follow a three-tiered approach:
- Unit Tests: Test individual components in isolation.
- Focus: Session management, debugger provider implementations, utility functions.
- Integration Tests: Test interactions between components.
- Focus: Complete debugging workflow tests, DAP message sequencing.
- End-to-End (E2E) Tests: Test the full system with actual
debugpyservers.- Focus: Full debugging scenarios from MCP request to
debugpyinteraction and back.
- Focus: Full debugging scenarios from MCP request to
- Write tests for all new features and bug fixes
- Aim for >90% code coverage
- Use descriptive test names that explain what is being tested
- Follow the AAA pattern: Arrange, Act, Assert
- Mock external dependencies appropriately
We follow the Conventional Commits specification:
<type>(<scope>): <subject>
<body>
<footer>
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, semicolons, etc.)refactor: Code refactoring without changing functionalityperf: Performance improvementstest: Adding or modifying testsbuild: Build system or dependency changesci: CI/CD configuration changeschore: Other changes that don't modify src or test files
feat(debugger): add support for conditional breakpoints
Added ability to set breakpoints with conditions that are evaluated
at runtime. This allows for more precise debugging workflows.
Closes #123fix(session): handle disconnect during stepping
Fixed race condition where disconnect during step operations
could leave the session in an invalid state.By contributing to this project, you certify the Developer Certificate of Origin (DCO) v1.1: that you wrote the contribution or otherwise have the right to submit it under the project's MIT license, and that you understand the contribution is public and a record of it is maintained indefinitely.
Sign off each commit to make this certification explicit:
git commit -s -m "feat(scope): your change"which appends a Signed-off-by: Your Name <you@example.com> trailer. If you forget, git commit --amend -s fixes the latest commit. We do not currently enforce sign-off in CI, but including it is expected for non-trivial contributions.
-
Before submitting:
- Ensure all tests pass
- Update documentation if needed
- Add tests for new functionality
- Run linting and fix any issues
- Add a changelog fragment if the change is user-visible — a new file at
changelog.d/<issue-number>.<category>.mdholding the entry text. Do not editCHANGELOG.mddirectly; fragments are collated into it at release time. Seechangelog.d/README.md. CI requires one for changes undersrc/,packages/, ortools/(test-only changes are exempt; apply theno-changeloglabel for a PR that genuinely needs no entry).
-
PR Guidelines:
- Use the PR template
- Link related issues
- Keep PRs focused on a single concern
- Write clear descriptions
- Add screenshots/demos for UI changes
- Client and harness integrations (Claude Code, Codex, pi, ...) ship as documentation or
inside the published
@debugmcp/mcp-debuggerpackage (its manifest keys and the shippedskills/directory), never as per-harness directories or manifest keys at the repository root — the rootpackage.jsonis private and never reaches users
-
Review Process:
- PRs require at least one review from @debugmcp
- Address all review comments
- Keep discussions professional and constructive
- Be patient - reviews may take a few days
-
After Approval:
- Squash commits if requested
- Ensure CI passes
- Maintainer will merge using "Squash and merge"
mcp-debugger/
├── packages/ # 18 monorepo workspace packages
│ ├── shared/ # Shared interfaces, types, adapter policies, utilities
│ ├── adapter-python/ # Python debug adapter (debugpy)
│ ├── adapter-ruby/ # Ruby debug adapter (rdbg/debug gem)
│ ├── adapter-javascript/# JavaScript/Node.js adapter (js-debug)
│ ├── adapter-rust/ # Rust adapter (CodeLLDB)
│ ├── adapter-go/ # Go adapter (Delve)
│ ├── adapter-java/ # Java adapter (JDI bridge)
│ ├── adapter-dotnet/ # .NET/C# adapter (netcoredbg)
│ ├── adapter-cpp/ # C/C++ adapter (CodeLLDB)
│ ├── adapter-cobol/ # COBOL adapter (GnuCOBOL + CodeLLDB behind a DAP shim)
│ ├── codelldb-common/ # Shared CodeLLDB infrastructure (Rust, C/C++ + COBOL adapters)
│ ├── codelldb-win32-x64/ # Prebuilt CodeLLDB binaries, one package per
│ ├── codelldb-linux-x64/ # platform, published with os/cpu fields so an
│ ├── codelldb-linux-arm64/ # install pulls only the matching payload
│ ├── codelldb-darwin-x64/
│ ├── codelldb-darwin-arm64/
│ ├── adapter-mock/ # Mock adapter for testing
│ └── mcp-debugger/ # Self-contained CLI bundle (npx distribution)
├── src/ # Core server source code
│ ├── adapters/ # Adapter loading, registry, and per-session leases
│ ├── cli/ # Reusable CLI wiring (commands, setup, error handlers)
│ ├── container/ # Dependency injection
│ ├── dap-core/ # Pure DAP state/handler core
│ ├── errors/ # Debug error types
│ ├── factories/ # ProxyManager and SessionStore factories
│ ├── implementations/ # Concrete filesystem/process/network implementations
│ ├── interfaces/ # Interfaces for the injected dependencies
│ ├── proxy/ # DAP proxy components
│ ├── server/ # MCP tool layer: tool schemas, validation, dispatch, handlers/ (one module per tool family), resource and prompt handlers
│ ├── session/ # Session management (core -> data -> operations -> session-manager) plus the per-operation slices launch/ attach/ breakpoints/ execution/ inspection/ jvm/ mirror/
│ └── utils/ # Utility functions
├── tests/ # Test files
│ ├── unit/ # Unit tests
│ ├── core/unit/ # Core unit tests (server, session, adapters, factories, utils)
│ ├── adapters/ # Adapter-specific tests
│ ├── integration/ # Integration tests
│ ├── e2e/ # End-to-end tests
│ └── test-utils/ # Shared test utilities
├── examples/ # Example scripts
├── docs/ # Documentation
└── .github/ # GitHub templates and workflows
- Session Manager: Manages debugging session lifecycle
- DAP Proxy: Handles communication with debug adapters via DAP protocol
- Adapter Registry: Dynamically loads and manages language-specific adapters
- Adapter Policies: Language-specific behavior via policy pattern
- MCP Tools: Implements the 28 MCP protocol tools
To see mcp-debugger in action:
-
Build the project:
npm run build
-
Run with a demo script:
# Start the server in STDIO mode (the default subcommand) node dist/index.js stdio # Or start in Streamable HTTP mode for remote/web clients node dist/index.js http -p 3001
The
ssesubcommand still exists but is deprecated; usehttpinstead. -
Example debugging session:
- Create a debug session
- Set a breakpoint at line 10
- Start debugging swap_vars.py
- Step through and inspect variables
- See the bug and fix it!
- General questions: Open a Discussion
- Bug reports: Open an Issue
- Direct contact: admin@debugmcp.io
Thank you for contributing to mcp-debugger! 🙏