{"_id":"@ahmedshaikh/mutant-mcp","name":"@ahmedshaikh/mutant-mcp","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ahmedshaikh/mutant-mcp","version":"0.1.0","type":"module","description":"Mutation test-gap finder as an MCP server — systematically mutate your changed code and report the SURVIVORS: lines a test executes but no assertion actually checks. Answers 'would my suite even notice if this broke?'","bin":{"mutant":"dist/server.js"},"engines":{"node":">=22"},"scripts":{"serve":"tsx src/server.ts","build":"tsc","test":"node --import tsx --test --test-force-exit test/*.test.ts","prepublishOnly":"npm run build"},"dependencies":{"@modelcontextprotocol/sdk":"^1.0.0","zod":"^3.23.8"},"devDependencies":{"@types/node":"^24.0.0","tsx":"^4.7.0","typescript":"^5.4.0"},"license":"MIT","author":{"name":"ahmedshaikh"},"keywords":["mcp","model-context-protocol","claude","agent","ai","mutation-testing","test-quality","coverage","test-gaps"],"repository":{"type":"git","url":"git+https://github.com/RaziStuff/mutant-mcp.git"},"homepage":"https://github.com/RaziStuff/mutant-mcp#readme","bugs":{"url":"https://github.com/RaziStuff/mutant-mcp/issues"},"publishConfig":{"access":"public"},"gitHead":"bc1adbaa3debe046da90f67dd8e8fadfaa0efff6","_id":"@ahmedshaikh/mutant-mcp@0.1.0","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-TRLdD70a+MLmmSMLKTP62NdIb2Gq9pMBqtBZGoyCD1Efdz43evcTl4OLtr2wU9se/HRBChF57hF6NsrxC7FG1A==","shasum":"bd35c7ea5a5f2e2f57711b432c4c20bf0fea8c31","tarball":"https://registry.npmjs.org/@ahmedshaikh/mutant-mcp/-/mutant-mcp-0.1.0.tgz","fileCount":10,"unpackedSize":30781,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGPxsVizaa5wev8kIIh/y3d+thYYQdFE0w0UUCkqMebYAiB2CUdRmlqpzgCyBpMa8YGwjZE40pzZ7ukHr7/SUh0YRQ=="}]},"_npmUser":{"name":"ahmedshaikh","email":"ahmed@shaikh1.com"},"directories":{},"maintainers":[{"name":"ahmedshaikh","email":"ahmed@shaikh1.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mutant-mcp_0.1.0_1783378856690_0.8277658997015636"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-06T23:00:56.517Z","0.1.0":"2026-07-06T23:00:56.836Z","modified":"2026-07-06T23:00:57.074Z"},"maintainers":[{"name":"ahmedshaikh","email":"ahmed@shaikh1.com"}],"description":"Mutation test-gap finder as an MCP server — systematically mutate your changed code and report the SURVIVORS: lines a test executes but no assertion actually checks. Answers 'would my suite even notice if this broke?'","homepage":"https://github.com/RaziStuff/mutant-mcp#readme","keywords":["mcp","model-context-protocol","claude","agent","ai","mutation-testing","test-quality","coverage","test-gaps"],"repository":{"type":"git","url":"git+https://github.com/RaziStuff/mutant-mcp.git"},"author":{"name":"ahmedshaikh"},"bugs":{"url":"https://github.com/RaziStuff/mutant-mcp/issues"},"license":"MIT","readme":"# mutant-mcp\n\n**Mutation test-gap finder as an MCP server — \"would my suite even notice if this broke?\"**\n\nA green suite tells you the tests *pass*. It doesn't tell you the tests would *catch a\nbug*. mutant systematically breaks your changed code — one small mutation at a time —\nreruns the suite, and reports the **survivors**: lines a test executes but no assertion\nactually checks. Those are your real test gaps.\n\n```\nfind_gaps\n→ 32 mutations · 28 run on covered lines · killed 17 · survived 11 · caught 61%\n\n  SURVIVED — a test executes these lines but nothing catches the change (real gaps):\n    shard/receipt.py:131  [Lt->LtE@1]  0 <= lo < hi <= layer_count → 0 <= lo <= hi <= layer_count\n    shard/receipt.py:141  [NotEq->Eq]  lo != cursor → lo == cursor\n    …\n  → add/extend an assertion that would fail under each change above\n```\n\n(That first survivor is a real one, found live on [`leyten/shard`](https://github.com/leyten/shard):\nweakening `lo < hi` to `lo <= hi` lets a zero-length receipt block into a paid tiling, and\nthe whole suite stayed green.)\n\n## How it works\n\n1. **Green + coverage pre-pass.** Runs the suite once under `coverage.py`. If it isn't\n   green, mutation testing is meaningless — mutant aborts and says so. The pass also\n   records which lines each test executes.\n2. **Mutate.** For each changed `.py` file, generates surgical single-node mutations via\n   the `ast` module: comparison flips (`<`↔`<=`, `==`↔`!=`, including each position of a\n   *chained* compare like `0 <= lo < hi`), off-by-one boundary swaps, arithmetic\n   (`+`↔`-`, `*`↔`/`), `and`↔`or`, `return X → return None`, and constant tweaks. Every\n   mutation is re-parsed before use, so a mutant never fails to compile.\n3. **Split by coverage.** Mutations on lines no test executes survive trivially — they're\n   reported as \"uncovered\" *for free*, without a run. Only mutations on covered lines get\n   the expensive per-mutant suite run.\n4. **Run & classify.** Each covered mutant is applied in place, the suite runs, the file\n   is restored: suite fails → **KILLED** (good), suite passes → **SURVIVED** (a gap).\n\nFiles are mutated in place and restored from an in-memory snapshot in a `finally`, so an\ninterrupted run never leaves a mutated tree — but don't run `find_gaps` concurrently with\nedits to the same files.\n\n## Tools\n\n| tool | purpose |\n| --- | --- |\n| `find_gaps` | mutate changed (or named) files, run the suite per mutant, report survivors |\n| `list_mutations` | dry run: preview the mutations that would be generated, no test runs |\n\n`find_gaps` defaults to the files changed vs `HEAD`; pass `files=[...]` to target specific\nmodules, `base=<ref>` to change the diff base, `cmd=...` to set the test command, and\n`max_mutants` to bound the per-mutant runs (default 30).\n\n## Install\n\n```jsonc\n// .mcp.json\n{\n  \"mcpServers\": {\n    \"mutant\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@ahmedshaikh/mutant-mcp\"]\n    }\n  }\n}\n```\n\nNeeds `coverage.py` in the interpreter under test (`pip install coverage`). Interpreter\nauto-detected (`python3`/`python`, override with `MUTANT_PYTHON`); project root defaults to\nthe server cwd (`MUTANT_ROOT` or per-call `cwd`).\n\n## Notes & limits\n\n- **Python only in v1.** JS/TS mutation needs a real parser to avoid garbage mutants;\n  deferred rather than done badly.\n- **Cost is O(covered mutations × suite time).** Scope `cmd` to the relevant tests and use\n  `max_mutants` on big changes. A narrow `cmd` also *narrows what \"caught\" means* — a\n  survivor may just mean \"this line is covered by a different test file you didn't run.\"\n- Mutations on unexecuted lines are reported as uncovered, not run — they mark code your\n  tests never reach at all (a different, coarser kind of gap).\n- Requires a green baseline; a red suite aborts the run.\n\n## Development\n\n```\nnpm install\nnpm test        # node:test; needs python3 + coverage.py (set MUTANT_PYTHON to override)\nnpm run build\n```\n\nMIT\n","readmeFilename":"README.md","_rev":"1-6aaee7fa4a4a9ac02d8731923af78079"}