Skip to main content
Glama

test-inventory-mcp

An MCP server for test-inventory: AI agents ask which tests a project has, which are skipped and why, and which tests a change can affect, without running them.

It reads Playwright, Vitest, Jest, Mocha, Jasmine, Cypress, WebdriverIO, node:test and Bun test files with test-inventory and answers from their source code. The running server executes no project code, writes no files and opens no network connections. Installation through npx may download packages. Answers are passed to the MCP client; its model provider and privacy settings determine what happens to that text next.

Setup

Node.js 22.12 or newer. The client starts the server with npx and talks to it over standard input and output. The server scans the test files your test runner's config runs, with the runner --framework names or, without it, the one the project uses. Globs pick the files instead, as on test-inventory's command line.

Claude Code, in the project folder. --scope project writes .mcp.json, for everyone who works on the project:

claude mcp add --scope project test-inventory -- npx -y test-inventory-mcp@0.9 --framework playwright

Cursor, in .cursor/mcp.json:

{
  "mcpServers": {
    "test-inventory": {
      "command": "npx",
      "args": ["-y", "test-inventory-mcp@0.9", "--framework", "playwright"]
    }
  }
}

VS Code, in .vscode/mcp.json:

{
  "servers": {
    "test-inventory": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "test-inventory-mcp@0.9", "--framework", "playwright"]
    }
  }
}

Without --framework, as in a configuration shared by every project, each call scans with the runner the project uses. In a project with several runners the agent passes framework, as the tools tell it, and patterns when it wants other files than the configs run.

The project is the folder given with --root, otherwise the one Claude Code names in CLAUDE_PROJECT_DIR, otherwise the folder the client starts the server in.

Verify the setup

  1. Open your client's MCP server list and confirm that test-inventory is connected. In Claude Code use /mcp; in VS Code run MCP: List Servers from the Command Palette; in Cursor open its MCP settings.

  2. Confirm the five tools below are available, then ask: "Use test-inventory to summarize this project's tests."

  3. Check that test_summary reports the expected framework and file counts. If it reports scanErrors, ask the agent to call scan_diagnostics before trusting the counts.

Try "List tests marked fixme, with their conditions and reasons" or "Which tests may be affected by a change to pages/orders-blotter.ts?" A conditional skip is not proof a test was skipped in a run. Expected-to-fail tests run; their non-active state does not mean they are disabled. See key concepts.

Related MCP server: easy-ui-mcp

Command line

test-inventory-mcp [--framework <name>] [<glob...>] [--root <dir>]

Option

Meaning

--framework <name>

playwright, vitest, jest, mocha, jasmine, cypress, webdriverio, node or bun. Without it, the runner the project uses. A tool call can pass another.

<glob...>

The test files, relative to the project, in place of those the configs run. A tool call can pass others.

--root <dir>

The project. Tool calls can scan folders inside it, never outside.

-h, --help

Print the help.

-v, --version

Print the version.

Tools

The generated tool reference lists each argument's type, default and bounds, response fields, complete request/response examples, pagination and errors. It is checked against the running server in tests.

Tool

Answers

test_summary

Counts by state, tag and annotation, and the configs with their projects; with groupBy, the counts of each file, tag or project.

find_tests

The tests that match states, tags, grep, related, projects, only or withoutReason, with the fields you pick.

get_tests

Every key of up to 20 tests by ids, with the scan's diagnostics about them; ids it can't find come back in notFound.

scan_diagnostics

The problems the scan found, such as a file that failed to parse, by levels, codes or path.

diff_inventories

Changes between saved scans named by before and after, including renames, moves and newly declared skip states.

A typical call sequence is test_summary, find_tests, then get_tests for a few returned ids. For example, the arguments to find_tests can be:

{
  "states": ["skip", "fixme"],
  "fields": ["fullName", "state", "condition", "reason"],
  "limit": 10
}

The answer contains matching tests, their total, scanErrors, nextCursor and hint, plus the framework and its version. The records have selected keys and their id. Pass a non-null nextCursor as cursor with the same other arguments to read another page; a narrow filter returning zero tests is a valid result.

related takes the files a change touches, from the project root as git diff --name-only writes them, and keeps the tests whose dependencies include one of them, and those that reach code the scan can't follow, as test-inventory's --related does. The filter uses the actual scanned folder when directory names an internal link or an absolute path inside the project. It also keeps tests that import a changed helper elsewhere in the project, outside that scanned folder. dependencies can list hundreds of files, so it isn't among the default fields, and get_tests returns as many tests as fit in one answer, with the other ids in remaining. An id stays the same when a test moves to another line, and changes when its title, describes or file change.

Every scan tool also takes directory, a folder inside the project to scan, and framework and patterns, relative to directory, to override the command line, and expandCases, which lists each case of a .each or .for table and each pass of a loop as its own test, with the name the runner gives it, as test-inventory's --expand-cases does. Ids differ with it, so get_tests takes the same expandCases as the find_tests call the ids came from. Records have the keys of test-inventory's output format.

Unknown tool arguments are refused with an error naming the unrecognized key, so misspelled filters are not silently ignored.

Answers are JSON, sent both as structured content and as text. Lists come 50 items at a time (limit takes up to 200), and an answer stays under about 30,000 characters; passing nextCursor back as cursor gets the next page. A single oversized record is returned alone. A final page can fit more records because it needs no next-page cursor or hint. scanErrors counts the problems that may leave tests out, and hint says what to do next when there is something to say.

Compare saved inventories

diff_inventories takes before and after, paths to complete saved JSON inventories inside the project, plus limit and cursor. It returns paged changes with original records and matching evidence, the full summary, total, nextCursor, hashesComparable, warnings and hint. It does not scan or write files. Use the same framework, root, patterns, filters and expandCases setting for both scans. Hash comparisons and rename matching need the exact same core version. Incomplete scans produce warnings. Zero changes returns an empty page and a hint. Each saved file must be a regular file of at most 128 MiB. Save scans with the core CLI, without --fields or --format jsonl; see inventory diffs. If a saved file disappears or becomes unreadable while opening it, the error names the supplied file and suggests checking its existence and readability, without exposing the resolved host path. Cancellation during these operations retains the request's cancellation reason.

Troubleshooting

Symptom

Next step

The server is disconnected or tools are missing

Open the client's server logs. Check that the client can find Node.js 22.12 or newer and npx, then restart the server through the client. A client launched by a desktop app may use a different PATH from your terminal.

No files or tests were found

Check --root, directory, the framework and the config's selected files. Try explicit patterns, such as ["tests/**/*.spec.ts"]. Call scan_diagnostics for details.

Several runners were detected

Pass framework on the call, or set --framework in the server configuration. Scan each runner separately.

The answer has scanErrors

Call scan_diagnostics and resolve the errors before treating the inventory as complete.

A path is refused

Keep the scanned files and dependencies inside the configured project. For an intended shared dependency, start the server at the shared parent and use directory to select a package.

A cursor is refused

Start the query again without cursor; keep filters, directory and case expansion unchanged when requesting later pages. Files may have changed between calls.

get_tests cannot find an id

Obtain current ids from find_tests. Keep its directory, framework, patterns and expandCases settings.

A saved scan is refused

Use complete JSON inventories, not JSON Lines or --fields output. Keep both files inside the project and below the size limit.

For incorrect source analysis, use the core's troubleshooting guide. For a server bug, include the server version, client, tool arguments, expected answer and a minimal reproduction. Remove private project data before sharing it.

Security

The server reads the test files its globs match inside the project, or without globs those the configs run, and, for Vitest, the files that symbolic links among them point to, as Vitest does. It reads the configs as code, without running them. It refuses a directory or pattern that reaches outside the project, including parent-directory components in brace or extglob alternatives, and refuses scan answers whose test files, configs or dependencies resolve outside it. Saved inventories must resolve inside the project too. The scanner may read a linked file before the answer is refused; this boundary is not a filesystem sandbox. It runs no code from the project, writes no files, and opens no network connections.

Answers hold text from the project's files, such as test titles, skip reasons and comments. A client should treat it as content of that project, not as instructions. The client's handling of that text is separate from the server's local operation. To report a vulnerability, see SECURITY.md.

Versioning

Tool names, their arguments and their answers are the server's API. Before 1.0, a change that breaks them raises the minor version, so test-inventory-mcp@0.9 in the setup above gets fixes only.

License

MIT

Available Tools

5 tools
diff_inventoriesDiff inventoriesA
Read-onlyIdempotent

Compares two complete saved JSON scans inside the project, without running tests or changing files. Reports additions, removals, renames, moves, code and dependency changes, states, tags and other metadata. Uses ids first, then unique body hashes and file, suite or dependency context; ambiguous matches remain added and removed. Use the same framework, root, patterns, filters and expandCases for both saved scans. Hash comparisons and rename matching are disabled across tool versions. Follow nextCursor for more changes. For Playwright, Vitest, Jest, Mocha, Jasmine, Cypress, WebdriverIO, node:test and Bun inventories. Example: {"before":"inventories/base.json","after":"inventories/head.json"}.

Inputs: after (required), before (required), limit, cursor. Returns: hint, tool, total, changes, +8 more

find_testsFind testsA
Read-onlyIdempotent

Lists a project's tests that match filters, read from the test files without running them: each with its id, full name, file and line, state, skip reason and condition, and tags by default. Use it for questions such as which tests are skipped and why, which tests carry @smoke, where a .only was left in, or which tests a change can affect (related, the changed files); use test_summary for counts and get_tests for every key of a few ids. projects keeps the tests one of the named projects runs, after each project's grep, leaving out tests whose projects the scan cannot tell. Filters combine with AND; a list matches any of its values. fields picks other keys of the test records (id is always there). Answers are paged: follow nextCursor, or narrow the filters. Example: {"states": ["skip"], "withoutReason": true}.

Inputs: grep, only, tags, limit, +10 more. Returns: hint, tests, total, framework, +3 more

get_testsGet testsA
Read-onlyIdempotent

Returns every key of the tests with the given ids, with the scan diagnostics about them, read from the test files without running them: location, describe path, state and where it is set, condition, reason, tags, annotations, comments above the test, parameters, the projects that run it, hooks around it, timeout and retries with where each is set (the test, a describe, the file or the config), fixtures, expect() counts, steps, body hash, and the files the test runs with dependencyHash. Use it after find_tests or test_summary, for the details of up to 20 tests. Ids come from find_tests and stay the same when a test moves to another line, but change when its title, describe or file changes; ids not in the current scan are returned in notFound. Example: {"ids": ["3f9a0c1d2e4b5a69"]}. An answer that would be too long returns the first tests and the other ids in remaining.

Inputs: ids (required), patterns, directory, framework, +1 more. Returns: hint, tests, notFound, framework, +4 more

scan_diagnosticsScan diagnosticsA
Read-onlyIdempotent

Lists the problems test-inventory found while reading the test files: level error means tests may be missing from the other answers (a file that failed to parse, an import it could not follow), or that the runner fails the file or the run (a Vitest tag the config does not define, a .only that forbidOnly fails); level warning means a value is missing or approximate (a title built at run time, a config value computed at run time, a file no config runs). They are about reading the code, not test failures. Use it when another tool reports scanErrors, or to check why a test is missing or notLoaded. Answers are paged: follow nextCursor. Example: {"levels": ["error"]}.

Inputs: path, codes, limit, cursor, +5 more. Returns: hint, total, framework, nextCursor, +2 more

test_summaryTest summaryA
Read-onlyIdempotent

Counts a project's tests by state (active, skip, fixme, todo, expectedToFail, notLoaded) and by tag and annotation, from the test files, without running them. Use it first, for questions such as how many tests are skipped, or which files or tags have the most skipped tests; use find_tests to list the tests themselves. states, tags and grep count only the tests they match. groupBy "file", "tag" or "project" adds the counts of each, sorted by name and paged with limit and cursor; a test with no tag is in no tag group, and one whose projects the scan cannot tell in no project group. configs lists the config files read and their projects. Example: {"states": ["skip", "fixme"], "groupBy": "file"}.

Inputs: grep, tags, limit, cursor, +7 more. Returns: hint, total, groups, configs, +5 more

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 5 tools

    Disambiguation5/5

    The summary/find/get trio covers counts vs. filtered lists vs. full records, and the descriptions explicitly route the agent between them ("use test_summary for counts and get_tests for every key of a few ids"). scan_diagnostics and diff_inventories are clearly separate operations with no overlap.

    Naming Consistency4/5

    All names are snake_case two-token identifiers, which is predictable and readable. The only deviation is test_summary, which leads with a noun while the other four use a verb (find_, get_, scan_, diff_), a minor inconsistency in an otherwise uniform set.

    Tool Count5/5

    Five tools is well within a healthy range and each one covers a distinct, substantive capability (aggregate counts, filtered listing, full record retrieval, diagnostics, historical diff). No thin wrapper tools and nothing redundant.

    Completeness4/5

    The surface covers the read-only inventory lifecycle well: counting, listing, drilling into records, surfacing scan errors, and comparing snapshots. One workaround gap: diff_inventories requires "complete saved JSON scans" but no tool produces or exports such a snapshot, so the diff workflow depends on an out-of-band step.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Wraps existing test frameworks (Jest, Vitest, Pytest) and exposes structured, LLM-optimized results via MCP tools with progressive disclosure and diff-aware execution.
      11
      1
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI agents to run, debug, and inspect Playwright end-to-end tests, returning structured pass/fail stats, failure diagnostics with actionable fix hints, live DOM inspection, selector validation, visual diffs, and flakiness verdicts instead of raw test output.
      11
      1,816 npm
      MIT