Skip to main content
Glama
AraneaDev

Nemesis-MCP

Official
by AraneaDev

Nemesis-MCP

A mock outlives the code it stands for, and the suite goes green anyway.

Release CI Coverage License Language Last commit Conventional Commits Status

Nemesis (Νέμεσις) is the Greek goddess who deals out what is due. Her name comes from némein, to apportion, and her business is proportion: she takes back what was claimed beyond its warrant. A test double claims to stand in for something real. This tool checks whether it still has the right to.

TL;DR: Nemesis reads your test doubles and your production code, and reports every place a mock, stub or spy no longer matches the thing it replaces. It runs no tests. Nothing is executed, imported or booted, so the answer is the same every time you ask.

The failure it exists for is specific. When a signature changes, a mocked unit test keeps passing, because the mock defines the contract rather than the code does. The suite stays green while the thing it guards has moved. Agent-written tests reach that state faster than handwritten ones, because a generated mock records the shape of the code on the day it was generated and nothing ever revisits it.

Status: pre-release. Nemesis-MCP is not yet published to npm. The source is public on GitHub, so install from source, see Install. Any npm install -g or npx line in this README describes the planned published experience and does not work yet.

Contents: What it finds · Install · Quick start · Languages · Fixtures · Discovery · Suppression · Development


What it finds

Four violation types, and nothing else. The set is fixed on purpose: a checker that grows a category per bug becomes a checker nobody reads.

Type

Meaning

GHOST_METHOD

The double stubs a member that is not there any more, with a did-you-mean from edit distance. Also covers an imported target that the module no longer exports, and a module mock supplying a key the module does not have.

ARITY_MISMATCH

The double passes more arguments than the method accepts, omits required ones, passes a literal of the wrong type, names an argument matching no parameter, or supplies a replacement function whose own signature the method no longer offers.

RETURN_DRIFT

The pinned return value cannot satisfy the declared return type. Includes an object literal missing a required field or carrying a stale one, an enum case the enum no longer has, a promise handed back by a method that is not awaitable, and a fluent chain on a method that is not fluent.

VISIBILITY_BREACH

The double replaces a member it cannot legitimately replace: a private or protected method, a final method, a final class, a static reached through an instance double, an accessor spied without an access type, or a PHP constructor.

Every finding carries a confidence. definite is what syntax alone can prove and is worth failing a build over. warning is a heuristic, and the difference is deliberate: two differing named types are only a warning, because the class relating them usually lives in vendor/ or node_modules/, which are never walked. A Python method with one leading underscore is a naming convention rather than access control, so stubbing it warns; only a name-mangled __member is a definite breach. A stubbed method whose name is built at runtime, such as shouldReceive($method) inside a loop, names nothing checkable and is skipped entirely.

Where the evidence runs out, the answer is silence. A warning that is wrong most of the time teaches people to ignore the tool, which costs more than the finding was worth.

Related MCP server: open-code-review

Install

git clone https://github.com/AraneaDev/Nemesis-MCP.git
cd Nemesis-MCP
npm install
npm run build

That gives you two binaries, nemesis for the command line and nemesis-mcp for the MCP server.

Planned, not available yet: once published, this becomes npm install -g nemesis-mcp, or npx nemesis-mcp on demand. Neither works until the package ships.

Quick start

# Every double in the repository, checked against the code it stands for
node dist/cli/main.js audit

# One symbol, and the state of every double that names it
node dist/cli/main.js verify-symbol PaymentGateway

# JSON fixtures against the DTOs they are supposed to describe
node dist/cli/main.js fixtures

audit exits 0 when clean, 1 on a violation, and 2 when the scan could not complete, so it works as a pre-merge gate without further wiring. --strictness=all includes warnings, --strictness=breaking_only is the default, and --allow-partial accepts an incomplete scan knowingly rather than failing on it.

The summary says how much of the scan it actually compared:

Scanned 174 test file(s), inspected 4772 double(s).
  2772 compared, 1521 unresolved, 475 with no contract to check.

That second line matters more than the first. A double whose target cannot be resolved was counted, not checked, and a clean result over mostly-unresolved doubles means the scan found nothing because it could see nothing.

As an MCP server

{
  "mcpServers": {
    "nemesis": {
      "command": "node",
      "args": ["/absolute/path/to/Nemesis-MCP/dist/mcp/main.js"]
    }
  }
}

Three tools: nemesis_audit for a whole tree, nemesis_verify_symbol for one symbol before you change it, and nemesis_stale_fixtures for JSON and YAML fixtures against their DTOs.

The useful habit for an agent is to call nemesis_verify_symbol before editing a class and nemesis_audit after, so a rename that stranded a mock is caught in the same turn that made it rather than in review.

Supported ecosystems

Language

Frameworks

Patterns

TypeScript, JavaScript

Vitest, Jest

vi.spyOn and jest.spyOn, vi.mocked, vi.mock with a factory, manual mocks in __mocks__, mockReturnValue, mockResolvedValue, mockRejectedValue, mockImplementation, mockReturnThis, toHaveBeenCalledWith, spies on statics and on Klass.prototype, and module members reached through a namespace or default import

PHP

PHPUnit, Pest, Mockery

createMock, createStub, createConfiguredMock, createPartialMock, getMockBuilder()->onlyMethods(), getMockForAbstractClass, getMockForTrait, expects()->method(), with(), every value of willReturnOnConsecutiveCalls, willReturnCallback, Mockery::mock including the 'Foo[a,b]' partial form, shouldReceive, andReturnUsing

Python

pytest-mock, unittest.mock

mocker.patch, patch, patch.object, patch.multiple, create_autospec, Mock(spec=X), return_value=, side_effect= with a lambda, assert_called_with, and module attributes patched where they are used rather than where they are defined

Rust

mockall

MockFoo::new() and ::default() with expect_<method>(), arity from .with(...), return values from return_const(...) and returning(...), plus #[automock] and mock! { } blocks

A module is a first-class target, not only a class. patch("core.system.subprocess_runner.run") and vi.mock('../db.js', factory) both resolve to the file they name, and a name that file imports is a member of it, because that is where Python convention says to patch it.

Fixtures

nemesis fixtures compares JSON and YAML fixtures against the DTOs they describe: a missing required field, a field that no longer exists, a value of the wrong type, an enum case that was renamed, and the same questions asked again inside nested objects and arrays.

A fixture is matched to a DTO by name or by shape overlap, and an ambiguous match is left alone. Config files, lock files and anything under a config directory are never treated as fixtures.

Discovery

Zero configuration. Test files are found by the conventions each ecosystem already uses, and .gitignore is honoured, along with .nemesisignore if you add one. node_modules, vendor, dist, build and the rest are never walked. Symlinks are followed once, by real path, so a directory linked into its own tree cannot make the walk loop.

Scans are bounded: 2 MB per file, 10,000 files, 200 MB in total and 120 seconds. Hitting a bound exits 2 rather than reporting a clean result over a partial read.

Suppression

// nemesis-ignore-next-line
vi.spyOn(legacy, 'gone').mockReturnValue(true);

One line, one comment, no configuration file. A suppression that has to be found in a separate file is a suppression nobody revisits.

Development

npm run typecheck
npm run lint
npm test
npm run build

Never pipe a gate into grep or tail. A pipe reports the exit status of the last command, so a failing gate reads as a passing one. That mistake shipped a commit through a red test suite during development, twice.

Fixtures under fixtures/experiments/ are deliberately broken, one directory per drift scenario, and each one is expected to produce exactly the findings its README comment describes.

License

MIT.


Built by Tim Schipper and released as open source under Aranea Development.

Available Tools

3 tools
nemesis_auditNemesis AuditB

Scan the repository (or given paths) for contract drift between test doubles (mocks, stubs, spies) and production code.

ParametersJSON Schema
NameRequiredDescriptionDefault
langNoRestrict to these languages
pathsNoTest files or directories to inspect; defaults to standard discovery
excludeNoDirectory names to skip, e.g. a repository's own intentionally broken drift fixtures
strictnessNoSeverity filterbreaking_only

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of behavior. 'Scan' and the audit title imply read-only inspection, which is useful, but the description does not state side effects, output format, or any environmental requirements. It is not misleading, but it is thin.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one tight sentence that front-loads the action and resource before the purpose. Every word earns its place and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with four parameters, no annotations, no output schema, and closely related siblings, a single sentence is insufficient. It lacks expected output/return behavior, safety characteristics, and guidance for distinguishing it from nemesis_stale_fixtures, leaving the agent to infer important context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents lang, paths, exclude, and strictness. The phrase 'or given paths' adds slight clarity to the paths parameter, but the description otherwise adds no parameter meaning beyond the schema, matching the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('scan'), a concrete resource (repository/given paths), and the target concept (contract drift between test doubles and production code), so an agent can understand the core function. It does not explicitly contrast itself with sibling tools nemesis_verify_symbol or nemesis_stale_fixtures, so it stops short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers no guidance on when to prefer this tool over nemesis_verify_symbol or nemesis_stale_fixtures, nor any exclusions or prerequisites. The only context is that paths can be supplied, but no decision criteria are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nemesis_stale_fixturesNemesis Stale FixturesB

Check JSON/YAML fixtures against current production DTO shapes (missing/renamed/removed fields).

ParametersJSON Schema
NameRequiredDescriptionDefault
pathsNoFixture files or directories
strictnessNobreaking_only

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description must carry the full burden of behavioral disclosure. It explains what the tool checks, but does not state whether it is read-only, what it outputs, whether it requires authentication or a connection to production, or how it reports staleness. The verb 'check' implies non-mutating behavior, but this is not made explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, dense sentence that front-loads the verb and resource, then appends a clarifying parenthetical. Every word earns its place, and there is no redundant restating of the tool name or title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema and no annotations, the description leaves important gaps: what the tool returns, how strictness levels affect results, and whether it accesses live production DTO shapes. The tool is simple enough, but an agent still lacks essential information about the output format and the meaning of configuration options.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50%, and the description adds no parameter-level meaning beyond what the schema already provides. 'paths' has a schema description, but the 'strictness' enum values ('all', 'untyped_only', 'breaking_only') are unexplained, and the description does not clarify how strictness relates to the detected missing/renamed/removed fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('check') with a clear resource ('JSON/YAML fixtures') and target ('current production DTO shapes'), plus the exact concerns it covers ('missing/renamed/removed fields'). This is precise and distinguishes it from sibling tools like nemesis_audit or nemesis_verify_symbol by focusing on fixture staleness rather than general auditing or symbol verification.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The usage context is implied: use this when you need to validate fixtures against production DTO definitions. However, there is no explicit guidance about when to choose this over its siblings, no exclusions, and no mention of prerequisites such as network access to production DTO sources.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

nemesis_verify_symbolNemesis Verify SymbolA

List every test double pointing at a production symbol and whether each remains valid.

ParametersJSON Schema
NameRequiredDescriptionDefault
symbolYesQualified or short class/interface/trait name
excludeNoDirectory names to skip, e.g. a repository's own intentionally broken drift fixtures
strictnessNobreaking_only

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full responsibility for behavioral disclosure. The word 'List' suggests a read-only operation, but it does not explicitly state that it makes no changes, nor does it mention any side effects, permissions, or performance implications. It also does not describe what 'valid' means or how strictness affects results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, direct sentence that front-loads the primary action and result. No filler or redundancy. The description is highly concise and immediately comprehensible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description should provide more context about expected behavior. It does not clarify the meaning of 'valid,' the impact of 'strictness' levels, or how 'exclude' is used. While it covers the core purpose, agents may lack sufficient information to make nuanced calls.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% (symbol and exclude have descriptions, strictness does not). The description adds no parameter-specific details beyond what the schema provides; it only indirectly refers to 'symbol.' It does not explain 'exclude' or 'strictness,' which could be ambiguous for an agent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('List') on a specific resource ('test double') scoped to 'a production symbol' and adds the outcome 'whether each remains valid.' This clearly distinguishes it from siblings like nemesis_audit and nemesis_stale_fixtures by focusing on validity checking of test doubles.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies a use case (verifying test double validity) but does not explicitly state when to use this tool over its siblings or when not to use it. No alternatives are mentioned, so usage context is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.2.0
    • First observednemesis_audit
    • First observednemesis_stale_fixtures
    • First observednemesis_verify_symbol

TDQS

A3.6/5.0

Scored across 3 tools

Disambiguation4/5

nemesis_audit is a broad scan for contract drift, while nemesis_verify_symbol focuses on per-symbol test double validity and nemesis_stale_fixtures targets fixture/DTO shape mismatches. The overlap between audit and verify_symbol is minor and resolvable from context.

Naming Consistency4/5

All tools share the nemesis_ prefix and use snake_case, but the pattern is not fully uniform: nemesis_audit is verb-only, nemesis_verify_symbol is verb_noun, and nemesis_stale_fixtures is adjective_noun. The naming is still readable and predictable.

Tool Count5/5

Three tools is well-scoped for a focused contract-drift analysis server. Each tool addresses a distinct part of the domain without unnecessary bloat or obvious missing categories.

Completeness4/5

The set covers broad drift scanning, per-symbol validation, and stale fixture detection, which covers the core detection workflow. It lacks explicit remediation or detailed reporting tools, but those are not necessarily required for an analysis-focused server.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    Not graded
    maintenance
    Static analysis engine that detects schema mismatches between data producers (like MCP servers) and consumers (like client code), preventing runtime errors by validating contracts at development time.
    11
    -
  • F
    license
    A
    quality
    C
    maintenance
    AI-powered code review tool that detects AI-generated code defects invisible to traditional linters — hallucinated packages, deprecated APIs, cross-file contradictions, hidden security anti-patterns, and over-engineering. Works as a standalone CLI, GitHub Action, or MCP server. Supports TypeScript, Python, Java, Go, and Kotlin. Free for individuals, no API key required.
    4
    38
    -