Skip to main content
Glama
zegroged

vacuous-tests-mcp

by zegroged

vacuous-tests-mcp

一个 MCP 服务器,用于找出无论代码做什么都会通过的测试。

空洞测试比缺失测试更糟糕。缺失测试是明显缺失的。空洞测试存在于测试套件中,运行显示绿色,计入总数,并被引用为行为已被覆盖的证据——而实际上它什么也没检查。这是一种无形缺失的覆盖,它恰恰能在测试本应捕获的情况下存活。

它们很容易被无意中写出,也很难通过阅读发现,因为空洞测试和真实测试往往看起来几乎一模一样。

这个案例的构建背景

一个 Rust 文件,共 6,764 行,位于一个测试套件已经定期进行人工审计的项目中。其中有两个测试:

// flagged
const SRC: &str = include_str!("lib.rs");
assert!(SRC.contains("pub sas_verified: bool,"), "the field must be exposed");
// not flagged
const SRC: &str = include_str!("lib.rs");
let prod = SRC.split_once("\n#[cfg(test)]\nmod tests {").expect("test module").0;
assert!(prod.contains("InviterSecrets::create_for_group("), "production never calls it");

两者都嵌入了文件自身的源代码。第一个直接对 SRC 进行断言——而 SRC 包含了测试本身,包括正在搜索的字符串。它通过构造即为真:删除它声称保护的生产代码,它仍然保持绿色。第二个先切掉测试模块,只对生产代码片段进行断言,因此当生产代码发生变化时它会失败。那是一个真正的门禁。

扫描该文件会报告一个发现,位于正确的行,并保留其他四个 include_str! 位置不动。扫描器跟踪绑定而不是对 include_str! 进行模式匹配,这正是区分这两种情况的关键。

Related MCP server: openhonest-umbra

规则

规则

严重级别

捕获内容

self-referential-source

高

测试嵌入了自身源代码,并断言某个字面量出现在其中。该字面量就在断言中,因此它永远不会失败。

no-assertions

高

没有任何形式的断言。只有 panic 或抛出异常才能使测试失败,因此错误但安静的行为会通过。

tautological-assertion

高

assert!(true)、assert_eq!(x, x)、expect(true).toBe(true)——无论代码如何都成立。

empty-body

高

函数体中没有可失败的内容。

skipped-test

信息

#[ignore]、it.skip、@pytest.mark.skip。因为不运行而显示绿色。

语言

语言

方法

准确性

Python

标准库中的 ast

精确

Rust

基于源代码文本的括号匹配扫描器

启发式

JavaScript / TypeScript

基于源代码文本的括号匹配扫描器

启发式

Rust 和 JS 扫描器在匹配之前会屏蔽字符串字面量和注释,因此字符串中的 { 或被注释掉的断言不会误导它们。它们被调优为宁可漏报也不误报:在这里,误报的代价高于漏报,因为第一个错误答案会让人们学会忽略输出。

将每个发现视为需要检查的问题,而不是最终结论。每个发现都指明文件和行号,因此确认只需几秒钟。

安装

尚未发布到 PyPI——从源码安装:

git clone https://github.com/zegroged/vacuous-tests-mcp
cd vacuous-tests-mcp
pip install .

这会将 vacuous-tests-mcp 命令添加到你的 PATH。

从 MCP 客户端使用

在你的客户端的 MCP 配置中添加:

{
  "mcpServers": {
    "vacuous-tests": {
      "command": "vacuous-tests-mcp"
    }
  }
}

对于 Claude Code:

claude mcp add vacuous-tests -- vacuous-tests-mcp

然后要求它扫描某些内容:

扫描 ./src 中无法失败的测试。

工具

scan_tests(path, include_skipped=True, max_findings=100) 遍历文件或目录,并报告无法失败的测试。构建和依赖目录(target、node_modules、.venv 等)会被跳过。发现结果按严重级别从高到低返回,每个结果包含路径、行号、测试名称、规则和代码片段。

list_rules() 每个规则及其描述,以便模型决定要请求什么。

explain_rule(rule) 某个规则检测什么,以及通常如何解决该发现。

服务器只读取。它不写入文件,不执行所扫描的代码,也不会查看给定路径之外的内容。

开发

pip install -e ".[dev]"
pytest

测试套件覆盖了每种语言中的每个规则,更重要的是,检查了位于空洞测试旁边的正常测试不会被报告。还有一个端到端测试,它作为子进程启动服务器,并通过真实的 MCP 握手驱动它,因此协议层得到了覆盖,而不是假设。

限制

  • Rust 和 JS/TS 检测是基于文本的,不是解析。宏生成的测试、不寻常的格式和深度嵌套的闭包可能会被遗漏。

  • no-assertions 不知道测试可能纯粹是为了证明某些东西不会 panic 而存在。这样的测试按规则是真正的阳性,但按意图是误报;使用显式断言说明这一点,它就会安静下来。

  • 只扫描上表中列出的语言。其他文件会被忽略,而不是猜测。

许可证

MIT

Available Tools

3 tools
explain_ruleA

Explain one rule: what it detects and how the finding is usually resolved.

Args: rule: A rule id as returned by list_rules or by a finding, for example self-referential-source.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

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 the full behavioral burden. It does disclose the core behavior (returns an explanation of detection and resolution), but says nothing about error handling for unknown rule ids, the structure of the returned explanation, or any side effects. Given an output schema exists, the return structure gap is partly covered, but the description alone is thin on behavioral detail.

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 purpose is front-loaded in the first sentence, and the argument documentation follows in a compact, readable block. Every sentence earns its place — the example and provenance note are exactly the information an agent needs. No filler, no redundancy.

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

Completeness4/5

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

For a single-parameter tool of low complexity with an output schema present, the description is largely sufficient: it states the tool's purpose, what the output covers, and where the argument value comes from. Minor gaps like behavior on invalid rule ids are acceptable given the simple scope and the output schema's presence.

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

Parameters4/5

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

With 0% schema description coverage, the description fully compensates for the 'rule' parameter by stating its provenance ('as returned by list_rules or by a finding') and providing a concrete example ('self-referential-source'). This adds real meaning beyond the bare string type in the schema, though it stops short of enumerating valid values or format constraints.

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 uses a specific verb+resource pair ('Explain one rule') and spells out what the explanation covers ('what it detects and how the finding is usually resolved'). The purpose is unambiguous and clearly distinct from list_rules (which lists rules) and scan_tests (which runs scans), though it never names those siblings explicitly, so differentiation relies on the reader inferring it.

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 workflow by telling the agent the rule id comes 'as returned by list_rules or by a finding', which subtly signals that explain_rule is the follow-up step to understanding a rule. However, it never explicitly states when to use this tool versus alternatives, nor any conditions where it should not be used. The guidance is implied rather than stated.

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

list_rulesA

List every rule the scanner applies, with a one-paragraph description of each.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior3/5

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

With no annotations, the description carries the full burden for behavioral disclosure. It states that the tool returns a list with one-paragraph descriptions, which is a behavioral outcome. However, it does not explicitly state that it is read-only, non-destructive, or what happens if there are no rules. For a simple list operation, this is adequate but not enriched—no mention of side effects, ordering, or potential errors.

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 sentence, front-loaded with the action and purpose. It conveys the exact scope ('every rule') and the output format ('one-paragraph description'). There is zero waste; every word earns its place.

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

Completeness4/5

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

For a simple list tool with no parameters and an output schema, the description is sufficient to convey what the agent will get. It covers the full scope ('every rule') and the format of each entry. The main missing element is an explicit statement about its read-only nature, but given the simplicity and the existence of an output schema, the description is adequately complete.

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

Parameters4/5

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

The tool has zero parameters, and the schema already reflects that (coverage 100%). The description adds no parameter info because none are needed. Per the rubric, 0 params gives a baseline of 4, and the description does not need to compensate for any missing parameter documentation. There is nothing to clarify.

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 clearly states the action 'List every rule' with a specific resource ('the scanner applies') and the nature of the content ('with a one-paragraph description of each'). It distinguishes itself from siblings: explain_rule presumably explains a single rule, and scan_tests likely performs scanning. The verb 'list' and scope 'every' make the purpose unambiguous.

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 provides no guidance on when to use this tool versus the siblings (explain_rule, scan_tests). It does not mention any conditions, prerequisites, or exclusions that would help an agent decide. The agent must infer from the name and the minimal description that this is for getting an overview, but no explicit direction is given.

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

scan_testsA

Scan a file or directory for tests that cannot fail.

Reports tests that pass regardless of the behaviour of the code they claim to cover: assertions that are true by construction, tests with no assertion at all, empty bodies, and tests that are skipped while still appearing in the suite.

Python is analysed with the ast module and is exact. Rust and JavaScript/TypeScript use a brace-matching text scanner, which is a heuristic tuned to miss cases rather than invent them. Every finding carries a file and line so it can be checked directly.

Args: path: File or directory to scan. Build and dependency directories (target, node_modules, .venv, ...) are skipped automatically. include_skipped: Include tests marked skipped or ignored. These always run green because they do not run at all, but they are usually deliberate, so they are reported at info severity. max_findings: Cap on returned findings. The summary always counts every finding, including any beyond the cap.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
max_findingsNo
include_skippedNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It does so effectively: it explains what the tool detects, how detection differs across languages (exact vs. heuristic), and that every finding includes file and line. It also discloses that include_skipped findings are reported at 'info' severity. The one gap is that it does not explicitly state the tool is read-only (no file modifications), though 'scan' strongly implies it. Overall, it is far more transparent than typical tool descriptions.

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 well-structured and front-loaded: the core purpose is stated in the first sentence, followed by detailed detection rules, then language-specific behavior, and finally parameter details. Each paragraph adds distinct value without repetition or fluff. The format is scannable and efficient for an agent.

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

Completeness5/5

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

Given the presence of an output schema, the description need not enumerate return fields, but it still provides rich context: what the tool detects, severity semantics, language-specific accuracy, and parameter behavior. An agent has all necessary information to invoke the tool correctly, choose appropriate inputs, and interpret results. It is complete for a scanning tool of this complexity.

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

Parameters5/5

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

Schema description coverage is 0%, so the description must compensate, and it does. The 'Args' section fully explains each parameter: path (file/dir, auto-skipped dirs), include_skipped (why include, severity implications), and max_findings (cap behavior, summary counts all). This goes beyond the schema by providing behavioral context, making parameter semantics extremely clear.

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 opens with a specific verb and resource: 'Scan a file or directory for tests that cannot fail.' It then enumerates concrete categories of such tests (true-by-construction assertions, no assertions, empty bodies, skipped). The purpose is unambiguous and distinct from sibling tools list_rules and explain_rule, which operate on rules rather than tests.

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

Usage Guidelines4/5

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

The description clarifies when to use the tool: it is for scanning files/directories for non-failing tests, and it explicitly notes that build/dependency directories are auto-skipped. It also distinguishes Python analysis (exact via ast) from Rust/JS (heuristic), helping agents set expectations. While it does not name alternative tools for comparison (the siblings are clearly rule-focused, not test scanners), the use case is sufficiently well-scoped. No explicit when-not-to-use guidance, but this is minor given the clear domain.

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.1.0
    • First observedexplain_rule
    • First observedlist_rules
    • First observedscan_tests

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a distinct purpose: listing available rules, explaining a specific rule, and scanning tests for vacuous assertions. There is no overlap between scan_tests and the two rule-related tools, and list_rules/explain_rule are clearly separated by verb (list vs. explain).

Naming Consistency5/5

All tools follow a consistent snake_case verb_noun pattern: list_rules, explain_rule, scan_tests. The naming is predictable and aligns perfectly with the tool's action.

Tool Count5/5

With 3 tools, the server is well-scoped for its purpose—a test scanner with rule documentation. Each tool earns its place, and the count falls squarely within the typical 3-15 range for a focused server.

Completeness5/5

The tool surface fully covers the intended workflow: discover rules, understand a rule, and run the scanner. There are no obvious gaps—the scanner's options are handled via arguments rather than requiring additional tools, and the rule lifecycle (list/explain) is complete for a read-only server.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers