Momus-MCP
Check whether tests exercise production behaviour and mocks match production contracts.
Momus-MCP takes its name from Momus, the personification of criticism in Greek mythology.
- TypeScript
- MCP
- Vitest
- Jest
- PHPUnit
- Pest
- pytest
- mockall
GitHub (opens in a new tab)README (opens in a new tab)Changelog (opens in a new tab)
On this pageCheck test quality
Check test quality
Passing tests can provide little evidence about production behaviour. An assertion that compares a value with itself always passes. An assertion that only checks a mock's configured return value tests the setup rather than the implementation. A stub can also refer to a method that no longer exists on the production class. These problems can occur in agent-generated tests when the task focuses on achieving a passing suite.
Momus-MCP reads tests and the production code they exercise, builds a symbol graph of classes and interfaces, and checks mocks, spies and assertions against that graph. The audit does not execute your code, access the network or write to your workspace. Findings are deterministic: auditing the same workspace produces the same findings, byte for byte.
Quick start
Momus-MCP is not yet published to npm. Install it from source with 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
These examples were recorded from runs against the Momus-MCP source repository.
List the rule catalogue:
$ 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) — mocked name is not exported by the target module (vi.mock factory keys, Python patch targets)
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]Audit a fixture directory 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:trueDetection rules and language support
| Category | Rules | What is detected |
|---|---|---|
| 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 |
Thirteen of the fourteen rules apply to all four languages. Constructor drift is PHP-only; the TypeScript compiler already checks missing constructor arguments. Each language parser resolves production symbols within the relevant ecosystem for contract comparison.
| Language | Test frameworks | Supported mock APIs | Enabled |
|---|---|---|---|
| TypeScript/JavaScript | Vitest, Jest | vi.mock, vi.fn, vi.spyOn, vi.mocked, and the Jest equivalents | by default |
| PHP | PHPUnit, Pest | createMock, getMockForAbstractClass, Mockery's mock() | by default |
| Python | pytest, unittest | patch, patch.object, Mock(spec=), mocker, monkeypatch | languages.python |
| Rust | built-in test harness | mockall (#[automock], mock!, expect_*().returning()), mockito | languages.rust |
Python and Rust are opt-in. Enable the corresponding parsers to include those languages in an existing workspace audit.
Configuration
Momus-MCP reads .momusrc from the workspace root. Run npx momus init to generate a configuration:
{
"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 enables or disables each parser per project. ignorePatterns excludes generated and vendored code. rules adjusts severity per rule. tokenBudget limits report size for model consumption; the issue format keeps an individual finding under 100 tokens.