Momus-MCP
The ultimate critic among the deities, pointed at your test suite.
Momus is the Greek personification of satire, mockery and blame, the one god whose entire job was to find fault, and who was thrown off Olympus for doing it too well.
- TypeScript
- MCP
- Vitest
- Jest
- PHPUnit
- pytest
- mockall
GitHub (opens in a new tab)README (opens in a new tab)Changelog (opens in a new tab)
What it does
A test suite can be green for the wrong reason. An assertion that compares a value with itself, a mock that echoes back the exact value it was just told to return, a stub for a method that no longer exists on the class it doubles: all three pass, and none of them prove that the code works. Coding agents are good at writing exactly this kind of test, because a green suite is the goal they were given, not a means to one.
Momus-MCP reads your test suite and the production code it exercises, builds a symbol graph from the real classes and interfaces, and checks every mock, spy and assertion against that graph. It never runs your code, never talks to the network, and never writes to your workspace. Findings are deterministic: the same workspace produces the same output, byte for byte, every time you audit it.
Quick start
Momus-MCP is not yet published to npm, so install it from source. Requires Node.js 20 or newer and the Claude Code CLI.
git clone https://github.com/AraneaDev/Momus-MCP.git
cd Momus-MCP
npm install
npx momus audit .
claude mcp add momus -- "$(pwd)/node_modules/.bin/momus" serveExamples
Two calls, both run for real against Momus-MCP's own source.
Listing the rule catalog:
$ npx momus rules | head -20
TAUT-001 self-comparison (error) — assertion compares an expression with itself
TAUT-002 mock-echo (error) — assertion re-asserts a stub's own configured return
TAUT-003 constant-tautology (error) — both assertion sides are compile-time constants
TAUT-004 mock-only-assertion (warning) — test exercises no production code
TAUT-005 zero-reach-stub (warning) — mock configured but never invoked or asserted
TAUT-006 unconfigured-spy-assert (warning) — toHaveBeenCalled* on a spy with no stub and no call path
DRIFT-001 missing-member (error) — stubbed member does not exist on the production target
DRIFT-002 signature-mismatch (warning) — stub call signature diverges from production (arity)
DRIFT-003 return-type-mismatch (warning) — configured value not assignable to the production return type
DRIFT-004 constructor-drift (error) — double construction omits required constructor parameters (PHP)
DRIFT-005 missing-export (error) — vi.mock factory keys reference exports that do not exist
DRIFT-006 stale-mock (warning) — mock target changed since the base ref but the mock file was not updated (git-diff mode)
MOCK-001 mock-saturation (warning) — over-mocking heuristic
MOCK-002 mock-of-self (info) — the test mocks a module it also imports as the SUT
Suppression: // @momus-ignore | // @momus-ignore:RULE | /** @momus-ignore */ | // @momus-ignore-file[:RULE]Auditing a fixture folder from a clean checkout:
$ npx momus audit packages/parser-typescript/test/fixtures 2>&1 | head -20
# Momus audit — packages/parser-typescript/test/fixtures
Audited 59 files · 0 issues (0 error · 0 warning · 0 info) · 6951ms — CLEAN:trueCapabilities
| Category | Rules | What it catches |
|---|---|---|
| Tautological assertions | TAUT-001 to TAUT-006 | Self-comparison, mock-echo, constant-tautology, mock-only assertions, zero-reach stubs, unconfigured-spy assertions |
| Mock-contract drift | DRIFT-001 to DRIFT-006 | Missing members, signature mismatches, return-type mismatches, constructor drift, missing exports, stale mocks (git-diff aware) |
| Mock hygiene | MOCK-001, MOCK-002 | Over-mocking (saturation), mocking the module under test |
The same rules run against TypeScript and JavaScript (Vitest, Jest), PHP (PHPUnit, Pest, Mockery), Python (pytest, unittest, opt-in) and Rust (mockall, opt-in).
Configuration
Momus-MCP reads .momusrc from the workspace root; npx momus init scaffolds one for you.
{
"languages": { "typescript": true, "php": false },
"testFilePatterns": ["**/*.{test,spec}.{ts,tsx,js,jsx,mjs}", "**/__tests__/**"],
"ignorePatterns": ["**/node_modules/**", "**/dist/**", "**/.git/**"],
"rules": {
"TAUT-002": { "severity": "error" }
},
"tokenBudget": { "maxIssuesPerReport": 50, "maxIssueLineTokens": 100 },
"cache": { "dir": ".momus/cache", "enabled": true }
}languages turns a parser on or off per project. ignorePatterns keeps generated and vendored code out of the audit. rules lets you tighten or loosen a specific rule's severity. tokenBudget caps how much a single report costs an agent to read, so a finding stays under 100 tokens by contract.