ghost-inspector-mcp
This server provides advanced analysis, diagnostic, and remediation tools for Ghost Inspector end-to-end browser tests, going beyond the native API to offer aggregations, guardrails, and detailed tool descriptions for agents. You can read, analyze, and (with opt-in gates) modify and execute tests programmatically from any AI agent.
Read & Understand
Verify credentials (
gi_whoami): Confirm API key validity, list organizations and open permission gates.Account overview (
gi_inventory): Folder→suite→test tree with per-suite test counts and failing test names; filterable.Module analysis (
gi_module_usage): Find tests importing a module, detect dead/broken modules, and find non-asserting tests.Get test definition (
gi_get_test): Fetch a test’s full definition and concurrency token.
Diagnose
Diagnose staleness (
gi_stale_tests): Separate failing tests into stale (changed after last run) vs genuine failures, and find outdated passing tests.Find vacuous tests (
gi_vacuous_tests): Identify tests that run zero steps, have no assertion, or have only a final-step assertion.Diagnose a failure (
gi_test_result): Show failing step, error, selectors, ownership, and staleness.
Propose & Apply Fixes
Propose repair (
gi_propose_repair): Generate a step rewrite proposal from a diagnosis (refuses stale).Validate test (
gi_validate_test): Run a definition on-demand without saving, with dry-run option and auto-module inlining, safe from submissions.
Mutate (Opt-In: GHOST_INSPECTOR_ALLOW_WRITES=true)
gi_update_test: Replace steps/rename with concurrency token and safety checks.gi_move_suite: Move a suite with all tests, easy to reverse.gi_create_suite: Create empty suite with name protection.gi_duplicate_test: Copy test into suite (only way to create); clears schedule by default.
Execute (Opt-In: GHOST_INSPECTOR_ALLOW_RUNS=true)
gi_run_test: Execute a saved test, with confirmation for submit steps.
Safety
The server never deletes, refuses unverified writes, prevents accidental form submissions, and provides rollback information for mutations.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ghost-inspector-mcpShow me the inventory of failing suites."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ghost-inspector-mcp
An MCP server for the Ghost Inspector API, so you can work with end-to-end browser tests from whatever agent you already use — Claude, OpenAI, OpenCode, your own automation — instead of clicking through the web UI.
Status
Fourteen tools. Nine only read, four write, and one runs a test for real. All of them are always listed — the gated ones refuse when called without their opt-in rather than hiding, so nothing has to be inferred from an absent tool.
The table is a map of the surface. Each tool's own description, which is what your agent actually reads, is where the detail and the gotchas live.
Understand an account
Tool | Access | What it does |
| read | Verifies your API key, lists the organizations it can reach with their ids, and reports which gates are open. Start here when something is misconfigured, or when an agent tells you this server cannot modify anything. |
| read | The whole account as a folder → suite tree, with per-suite counts of passing / failing / module / not-yet-run tests and the names of the failing ones. Filter by folder, or ask for failing suites only. |
| read | The reverse index of |
| read | One test's stored definition, identity and state — including the |
Find what is wrong
Tool | Access | What it does |
| read | Splits red tests into stale and genuinely broken by comparing the whole |
| read | Green tests that prove nothing, in three separate classes: runs zero steps; runs its steps but contains no assertion at all; or a shortlist whose lone final assertion may have been true before the test did anything. |
| read | Why one test is red: the failing step, its error, the selectors it was authored with rather than only the one that resolved, and which test or module actually owns the step. Leads with a staleness verdict, because a result that predates a change is not evidence. |
Fix it
Tool | Access | What it does |
| read | Turns a diagnosis into a concrete proposal: the rewritten step, which test owns it, and the token to write it. Applies nothing, and refuses on a stale diagnosis. |
| read¹ | Runs a definition through on-demand execution, which executes and discards it, and reports every step. Inlines modules first, then truncates at the first step that could submit a form. |
| write | Replaces a test's steps and/or renames it, behind four guards and a concurrency token. |
| write | Moves a suite with its tests to another folder. Reversible; returns the prior folder so the undo is one call. |
| write | Creates an empty suite, in a folder if you name one. Refuses a same-named sibling unless you insist. |
| write | Copies a test, places it in a suite and renames it in one call. The only way to get a new test — Ghost Inspector has no create endpoint — so a source test is required. Clears the copy's schedule by default. |
| run | Executes a test exactly as saved and waits for the verdict. Its own gate, separate from writes. A test that submits a form is refused unless you confirm on that call. |
¹ gi_validate_test saves nothing, but it drives a real browser against a real URL, so it is not marked read-only.
The four write tools refuse unless GHOST_INSPECTOR_ALLOW_WRITES is exactly true, and gi_run_test refuses unless GHOST_INSPECTOR_ALLOW_RUNS is. A refusal changes nothing and names the variable to set. gi_whoami reports both gates.
Not included, on purpose. Deletion of any kind. DELETE /suites/{id}/ cascades to every test in the suite with no undo, and that blast radius does not belong behind an agent; deleting a test is left out for the same reason, since there is no version history to restore from.
Creating a test from nothing is not possible. Ghost Inspector exposes no create endpoint — POST /tests/ returns the test listing, the organization- and folder-scoped variants return 404, and the vendor documents update, duplicate and delete with no create. gi_duplicate_test is the supported route: copy an existing test, place it, rename it. It is named for what it does, because calling it "create" would set the wrong expectation about needing a source.
Not built. Dating a regression back to its last green run. Old results are purged, so there is a horizon past which the API cannot answer it, and a tool that silently stops working at an unknown depth is worse than no tool.
Related MCP server: qa-ai-mcp-server-gits
What you can ask for
You talk to your agent, not to the tools. These are the questions the server is built to answer:
"Which of my failing tests are actually broken, and which just haven't run since someone edited them?" — the distinction the dashboard cannot make, and the reason a triage session usually starts here.
"Why is the checkout test red?" — the failing step, its error, and which test or module owns it.
"If I change this shared module, what breaks?" — direct importers and the full transitive reach, which is normally much larger.
"Which of my green tests aren't really testing anything?" — three separate ways a test can pass while proving nothing.
"Fix that selector." — propose a change, run it without saving to check it resolves, apply it behind the guards, then run the test to confirm. Each step is a separate tool, and the ones that change or execute anything need you to opt in first.
A note on scale. This server earns its place on accounts that have accumulated mess: hundreds of tests, shared modules with unclear ownership, a failing list nobody has triaged in months. On a small, well-tended account — a couple of dozen tests, no modules, everything green — gi_stale_tests, gi_module_usage and gi_vacuous_tests will correctly return nothing, and the server will look like it does very little. That is the honest answer for that account, not a malfunction.
Why this exists
Ghost Inspector's API is small and stable, so a 1:1 wrapper would add nothing over curl. This server is for the three things curl cannot give you:
Aggregations the API does not provide — the account as a folder → suite tree with honest counts, the reverse index of which tests import each module, and red tests split into genuinely broken versus merely out of date.
Guardrails on the write path — there is no version history for test steps and no recycle bin. Overwrites are forever.
Tool descriptions that teach the calling model how not to break things — the accumulated gotchas ship with the tool, so every agent gets them for free instead of learning them the expensive way.
Other community wrappers of this API exist. The difference here is the posture: nothing is written or executed until you opt in, no deletion at any opt-in level, and every write behind guards that cannot be turned off.
Two worked examples of that third point, because it is the whole thesis.
Marking a test Import Only — Ghost Inspector's way of saying "this is a module, other tests import its steps" — deletes its stored results. Every module is therefore permanently "never executed": no results, passing not a boolean, last-run date pinned to the 1970-01-01 epoch sentinel. The obvious implementation of stale-test detection sorts by last-run date, so it reports every module in your account as the deadest, most broken thing in it, and advises deleting exactly the steps all your live tests share. This server knows that, and ships the predicate that prevents it.
And a test whose steps are only execute calls into modules with no steps runs zero steps and passes, because nothing can fail. The dashboard shows it green while it asserts nothing, which is worse than red because nobody investigates green. Emptying one shared module does that to every test importing it, silently and all at once.
That is the smallest of three ways a test can be hollow. On a real account of a few hundred tests, gi_vacuous_tests found that the largest group by far was not this one but tests that run every step and contain no assertion at all — they can only fail if a step errors. A third group asserts only on its final step, which may well have been true before the test did anything. All of them green.
Install
Requires Node 18+. There is nothing to install ahead of time — your MCP client launches the server with:
npx -y ghost-inspector-mcp
Those two prompt for your key and store it in VS Code's own secret input rather than in a settings file.
To work on the server itself, clone and build instead:
git clone https://github.com/charliemtnez/ghost-inspector-mcp.git
cd ghost-inspector-mcp
npm install && npm run buildConfigure
Get your personal API key: Ghost Inspector → hover your name (top right) → Account Settings → API Access. Keys are per user, and regenerating one disables the previous key immediately.
Variable | Required | Purpose |
| yes | Your personal key |
| to execute a validation | Organization id — read it from |
| no (default | Set to |
| no (default | Set to |
Configuration is environment variables only. There is deliberately no .env support: this ships as a global command with no project directory of its own, and a second place to put a secret is a second place to leak it. The key is read fresh on every call, so rotating it takes effect without a restart.
Claude Code
claude mcp add ghost-inspector --scope user -- npx -y ghost-inspector-mcpClaude Desktop, Cursor, Windsurf and anything else that takes a JSON config
{
"mcpServers": {
"ghost-inspector": {
"command": "npx",
"args": ["-y", "ghost-inspector-mcp"]
}
}
}No env block: the server inherits the environment of whatever launched your client, so exporting the key in your shell profile is enough and it never has to sit in a config file. Add one only if your client cannot inherit it.
Any other MCP client
Point it at npx -y ghost-inspector-mcp over stdio, or at node <path>/dist/index.js from a clone, and pass the key through the environment.
If the tools appear but every call says the key is missing
Your client was almost certainly launched from a desktop icon, Spotlight or a launcher rather than a terminal. Those do not run a login shell, so ~/.zprofile and ~/.bash_profile are never read and your export never happened — the server starts fine and registers its tools, then finds nothing in the environment.
Either launch the client from a terminal, or have the server read the key itself at launch:
claude mcp add ghost-inspector --scope user -- \
sh -c 'GHOST_INSPECTOR_API_KEY="$(cat ~/.gi-key)" exec npx -y ghost-inspector-mcp'The same wrapper works as "command": "sh" with "args": ["-c", "..."] in a JSON config. The key stays in a 600 file that only your user can read, and never enters the client's configuration.
Handling your API key
Ghost Inspector authenticates with ?apiKey= in the query string, so the credential ends up in shell history, proxy logs and AI conversation transcripts unless you are deliberate about it.
# In a terminal you will close afterwards — the value never enters the
# command, so it never enters your history.
umask 077
read -rs 'GI?Ghost Inspector API key: '; printf '%s' "$GI" > ~/.gi-key; unset GI
# Then, in your shell profile:
export GHOST_INSPECTOR_API_KEY="$(cat ~/.gi-key)"printf rather than echo matters: a trailing newline corrupts the key inside a query parameter.
This server will never:
ask for your key through a tool call (that would put your secret in a conversation transcript)
write your key to disk
include your key in a log line, an error message or a tool response
Safety model
Nothing is written or executed unless you opt in. The mutating tools act only when GHOST_INSPECTOR_ALLOW_WRITES=true, and gi_run_test only when GHOST_INSPECTOR_ALLOW_RUNS=true. Without those, nothing can be changed or run no matter what your agent is asked to do — the check is in the handler, so it holds regardless of what the caller sends. Every tool also declares MCP annotations (readOnlyHint, destructiveHint), so a client that gates permissions on them sees the same posture the server enforces — including that gi_validate_test is not marked read-only, because driving a real browser against a real URL is a side effect even when nothing is saved.
Gated, never hidden. Every tool is listed whether or not its gate is open, and the permission check runs when the tool is called. A tool that is withheld from the listing is indistinguishable from one that does not exist, so an agent reading a short list concludes the capability is missing and tells you so — with nothing available to correct it. Here a gated call refuses, touches nothing, and names the variable to set.
Visibility is not permission. The two are separate on purpose: the listing tells the agent what this server can do, the gate decides what it may do right now.
Suite deletion is not exposed, by design. DELETE /suites/{id}/ cascades to every test in the suite, with no version history and no recycle bin. That stays a deliberate curl by someone who knows what they are doing.
Failed requests are not retried. A timeout or a dropped connection surfaces as an error instead of being attempted again. That is a decision, not an omission: execute and the write endpoints are not idempotent, and a retry that silently ran a browser test twice — or re-applied a write whose first attempt actually landed — buys convenience with exactly the kind of surprise this server exists to prevent. Read-only calls are safe to retry, so your agent can simply ask again.
Writes are guarded. Every mutating tool performs these four in order, and none can be turned off:
compare
dateUpdatedacross the wholeexecutechain against the last run — a red test whose module was edited after its last run is stale, not broken, and a fix diagnosed from that failure is diagnosed from a version that no longer exists. Imports nest up to ten levels, so the walk is bounded and detects cycles. On a real account this refused a test that had been red on the dashboard for well over a year, whose definition had been edited weeks after that last run;return the complete prior definition — on refusals too. Ghost Inspector keeps no version history of steps, so that object is your rollback;
apply the change;
re-read and diff twice over: that what was sent landed exactly, and that every field you did not send is untouched.
HTTP 200proves neither.
Writing also requires a concurrency token. You state the dateUpdated you believe is current, and the write is refused if the record has moved since. A confirmation flag can be talked past by a persuaded model; a timestamp it has to have actually read cannot be guessed. gi_get_test returns that token alongside the definition, so reading the record is the ordinary first step of an edit rather than an obstacle.
A refusal reports the current value, because that is part of diagnosing a genuine conflict, and directs you to re-read and rebuild the change rather than resend it. Replaying an edit composed against a definition that is no longer stored would overwrite whatever replaced it.
That token narrows the window rather than closing it. Ghost Inspector has no compare-and-swap, so the check is read-then-write on the client side: two writers who both read before either wrote will both pass. It catches acting on a copy you read minutes or days ago, which is the realistic case, not a genuine race.
All four guards are verified against a live account, on a disposable clone that was created, written to and deleted, leaving the account byte-identical afterwards. One behaviour that only surfaces there: Ghost Inspector normalises steps on write, filling in fields the caller omitted, so both sides are normalised before being compared. Without that, verification reports a difference on every write that landed perfectly.
Running a stored test is gated separately. gi_run_test is the one tool that executes a test exactly as saved, with nothing truncated — so in most accounts it posts to production. It needs GHOST_INSPECTOR_ALLOW_RUNS=true, which ALLOW_WRITES does not imply: an edit is recoverable from the backup the write path returns, a submitted form is not recoverable at all. On top of that, a test that submits is refused unless you confirm on that call. The check inlines modules first, since a test whose steps are only execute calls hides its submit inside one, and a chain that cannot be fully expanded counts as submitting.
Confirmation is asked for only where there is a consequence, which is the point — a flag every call needs is a flag every caller sets by reflex. Measured across a sample of real tests, roughly three quarters asked for confirmation and the rest ran without it — the ones that asked genuinely click a submit control.
Validation does not submit anything. gi_validate_test uses on-demand execution, which runs a definition and discards it, so nothing in your account changes. But it drives a real browser against a real URL, so two guards apply and neither can be turned off:
Modules are inlined before anything is inspected. A test whose steps are only
executecalls hides its submit click inside a module, and guarding the definition as written would see nothing. Measured on a real account: of eight such tests, five would have posted a live form.The run is truncated at the first step that could submit, and that step becomes an assertion on the same target — so the chain is verified, including that the submit control is reachable, without activating it. On a 30-test sample the guard fired on 25.
There is no option to make it submit; that stays a deliberate curl. Use dryRun first on anything touching production: it reports exactly what would run, inlined and guarded, without starting a browser or needing an organization id.
Development
npm ci
npm run typecheck
npm test # builds first, then runs the suite174 tests, no test dependencies — Node's own runner and assert. They are organised by what breaks if the assertion fails, not by coverage, so a failure name tells you what you broke:
File | What it pins |
| The write gate opens for an exact |
| The concurrency token reaches the caller; a module's missing verdict is not read as a failure; steps come back unexpanded so an edit targets the test that owns them |
| A copy is silenced unless the caller insists — anything short of an explicit |
| Truthy is not |
| A cycle terminates and is still reported once shared subtrees stop being re-expanded; depth does not inflate on a level that adds nobody; hitting the documented nesting limit is reported rather than passed off as a total |
| Every test lands in exactly one bucket; a module is never counted as failing; an empty suite still appears |
| The transitive radius exceeds the direct count; a cycle is a flag rather than an inflated number; a test that executes nothing is found |
| A step that never ran is not named as the failure; a resolved selector is not passed off as what the test looks for; a failing step from a module points at the module; a purged run is not reported as a test that never ran |
| A module is never called hollow however empty it looks; an assertion inherited from a module counts; a lone final assertion is shortlisted rather than condemned; an unreadable definition is skipped, not counted as empty |
| Rules that hold whatever the page contains are applied; a fragile selector is named but never rewritten, because inventing one would be a guess |
| The red pile splits with nothing lost; an unparseable date counts as changed; modules are excluded rather than evaluated |
| A submit inherited from a module is caught — guarding the definition as written was measured letting five of eight real tests post a live form; an import's condition gates every step it imports instead of being dropped |
| Allowing writes does not allow running; a submit hidden inside a module still demands confirmation; a chain that could not be fully expanded counts as submitting |
| The direction of every uncertain case in the staleness guard; Ghost Inspector's own step defaults are not reported as differences; a field that only appears after the write is still an unexpected change |
| The server starts, speaks the protocol, the write gate holds end to end, and every tool's annotations state the posture the code enforces |
server.test.js starts the real server over stdio, which is the only way to catch a registration or schema mistake. No API key is configured anywhere in the suite, so nothing reaches Ghost Inspector and the tests are safe to run against any machine.
CI runs the lot on Node 18, 20, 22 and 24 — the floor in engines plus both LTS lines and current, since npx runs on whatever Node the user already has. A second job re-runs the leak audit over the entire history rather than the working tree, because a leak scrubbed in a later commit is still in the history.
One limit worth stating. The API behaviours documented here were verified empirically against a single account on a single plan. They held every time they were checked, but a different plan could differ — if something contradicts this on your account, that is worth an issue.
Contributing
Issues and PRs welcome, but this is maintained on a best-effort basis — a tool built to solve a real problem, not a supported product. Changes are listed in CHANGELOG.md; anything security-relevant goes through SECURITY.md rather than a public issue.
No organization-specific data in code, tests, docs or examples: no ids, hostnames, folder or suite naming conventions, or test-data identities. All of that belongs in the caller's configuration. Use obvious placeholders like https://example.com and jane@example.com.
License
MIT. See LICENSE.
Ghost Inspector is a trademark of its respective owner. This project is unaffiliated.
Available Tools
5 toolsgi_inventoryGhost Inspector: account overviewARead-only
Read-only tour of the whole account: every folder, the suites inside it, and per-suite counts of passing / failing / module / not-yet-run tests, plus the names of the failing ones. Start here — no other question about this account can be answered without knowing what is in it.
Import-only tests (modules: shared steps that other tests import, the equivalent of a function) are counted in their own bucket and never as failures. Marking a test import-only deletes its stored results, so every module looks permanently unrun; folding that into a failure count invents breakage that does not exist and aims cleanup at the steps the live tests all share. Read the notes field before drawing conclusions.
Fetches roughly 440 KB from the API and returns a summary of it, so ask for the whole account rather than probing folder by folder. Totals always describe the entire account even when a filter narrows the listing.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No | Case-insensitive substring of a folder name. Omit to see every folder. | |
| failingOnly | No | List only suites with at least one failing test. Totals stay account-wide. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the readOnlyHint annotation by explaining the import-only module counting behavior, the fact that marking a test import-only deletes stored results, and the interpretation pitfall of modules appearing permanently unrun. It also discloses the ~440 KB fetch and account-wide totals, adding significant behavioral context that annotations do not cover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose in the first sentence, followed by a critical caveat and a performance/usage note. Each paragraph serves a distinct function, and no sentence is redundant or filler, achieving high information density without being bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (two optional params, no output schema), the description covers the essential return contents (counts, failing names, notes field), the behavioral caveat around import-only tests, and practical guidance on fetch size and filter semantics. This is sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already fully documents both parameters (folder and failingOnly), so the baseline is 3. The description adds meaningful nuance by clarifying that even when the 'folder' filter narrows the listing, the reported totals remain account-wide, which affects interpretation of both parameters. It also implicitly advises against using 'folder' to probe piecemeal.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb phrase ('Read-only tour of the whole account') and enumerates exactly what is included (folders, suites, per-suite counts, failing names). This clearly distinguishes it from other account-related tools like gi_whoami or gi_stale_tests.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Start here' and explains that no other question about this account can be answered without this overview, making the primary use case clear. It also advises against probing folder by folder because of the fetch size. However, it does not explicitly name alternatives or say when not to use this tool, so it falls short of the highest bar.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gi_module_usageGhost Inspector: who imports each moduleARead-only
Answers the one question the API cannot: if I edit this module, which tests break? Builds the reverse index of execute steps — for every imported test, its direct importers and its full transitive blast radius through nested chains. Run this BEFORE editing any module.
Also surfaces three things that only appear once the index exists: import-only tests nobody imports (dead, or a test that lost its caller and is silently not running); imported tests NOT flagged import-only, which run standalone and inside their importers, so an edit changes both paths; and execute steps pointing at ids that no longer exist.
🔴 It also finds vacuousTests: tests that execute no steps at all, because their definition is only execute calls and the chain bottoms out in empty modules. Those pass — nothing can fail — so the dashboard shows them green while they assert nothing, which is worse than a red test and invisible any other way. Emptying one shared module does this to every test that imports it.
This is the expensive tool. steps is absent from the test listing, so it costs one request per test in the account — a few seconds for a few hundred tests, at deliberately low concurrency because the rate limit is undisclosed. Call it once and work from the result rather than per module. A definition that cannot be read is counted in scanned.unreadable, never skipped silently, because a missing definition understates a blast radius.
| Name | Required | Description | Default |
|---|---|---|---|
| module | No | Case-insensitive substring of a module name. Narrows the listing and names every importer instead of capping the list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite having readOnlyHint and openWorldHint annotations, the description goes far beyond them by disclosing performance characteristics (one request per test at low concurrency), edge cases (import-only tests, dangling execute steps, vacuousTests), and error handling (unreadable definitions counted). It also surfaces surprising behaviors like vacuous tests passing silently, which is critical context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but densely packed with high-value information. It is front-loaded with the core purpose and then expands into important behavioral and edge-case details. The structure uses clear paragraphs and an emoji marker for emphasis, but it could potentially be tightened without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and lack of an output schema, the description thoroughly explains what the tool returns (reverse index, importer lists, blast radius), flags important edge cases, and provides operational guidance. It covers performance, error semantics, and even conditions that make the tool necessary, making it highly complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% coverage for the single optional 'module' parameter, including its case-insensitive substring matching and its effect on capping. The description itself adds minimal parameter-level detail beyond what the schema already documents, so a baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific, action-oriented question - 'if I edit this module, which tests break?' - and clearly states it builds a reverse index of execute steps. It distinguishes itself from sibling tools by targeting module import relationships and blast radius, not just inventory or stale-test detection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs to 'Run this BEFORE editing any module' and advises to 'Call it once and work from the result rather than per module.' It also warns that this is the expensive tool and explains the cost implications, giving clear usage context without needing to compare to alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gi_stale_testsGhost Inspector: stale versus genuinely brokenARead-only
Call this BEFORE diagnosing or editing any red test. Splits failures into two piles by comparing the whole execute chain's dateUpdated against each test's last run.
staleFailures are red tests whose definition or module chain changed AFTER the failing run. The failure describes a version that no longer exists — a colleague may already have fixed it and the test simply has not run again. Editing on top of one destroys their work, and Ghost Inspector keeps no version history of steps. One level deep is not enough here, because modules nest; the whole chain is walked.
genuineFailures have had no change since the failing run, so the failure still describes the current definition. Start there, oldest first.
🔴 Re-running is not free advice: many Ghost Inspector suites submit real forms against production. Confirm what a test does before triggering it.
Also reports the case nobody looks for: passing tests whose chain changed after their last run, whose green result describes the old definition and proves nothing about the current one. Import-only modules are excluded rather than evaluated, since they have no results to compare against.
Costs one request per test, a few seconds for a few hundred tests.
| Name | Required | Description | Default |
|---|---|---|---|
| includePasses | No | List the passing-but-unverified tests too. Off by default because it is the long bucket; the count is always reported. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the readOnlyHint annotation, disclosing cost ('Costs one request per test, a few seconds for a few hundred tests'), algorithmic details (walking the whole module chain), and side-effect warnings about test re-runs. It also explains exclusions and the additional report of passing-but-unverified tests.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average but each sentence earns its place, covering trigger condition, failure categorization, warnings, exclusions, and cost. It is front-loaded with the key instruction and structured logically, making it dense but efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's analytical complexity and the absence of an output schema, the description thoroughly explains the behavior, edge cases, costs, and expected results (staleFailures, genuineFailures, passing-unverified). It provides enough context for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage for the single parameter includePasses is 100%, with a clear description already. The tool description adds narrative context about passing tests but does not meaningfully enhance the parameter's meaning beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Splits failures into two piles by comparing the whole `execute` chain's `dateUpdated` against each test's last run.' The title and description distinguish it as a diagnostic classifier for stale versus genuine failures, setting it apart from sibling tools like gi_validate_test or gi_inventory.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly prescribes when to use: 'Call this BEFORE diagnosing or editing any red test.' It also gives actionable guidance on where to start ('Start there, oldest first'), and warns against unsafe re-running ('Confirm what a test does before triggering it'), covering both when-to and when-not-to.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gi_validate_testGhost Inspector: validate a definition without saving or submittingA
Runs a test definition through on-demand execution, which executes it and discards it — nothing in the account is created or changed. Use it to check that a selector chain still resolves before editing a test, and to check a definition you are authoring before saving it.
🔴 It drives a real browser against a real URL, so it is an action with real-world effects even though nothing is saved. Two guards apply and neither can be turned off. Modules are inlined first, because a test whose steps are just execute calls hides its submit inside a module and guarding the definition as written would miss it. Then the run is truncated at the first step that could submit a form, and that step is replaced by an assertion on the same target — so the whole chain is verified, including that the submit control is reachable, without ever activating it. There is no way to make this tool submit; that stays a deliberate curl.
For an existing test the suite's viewport and browser are replicated, because tests inherit those and a selector can resolve on desktop and fail on mobile. Read ranAs.configSource to see what was actually used.
A browser run takes 20-100 seconds; the tool polls until it finishes. passing: null in the raw API means not finished, never failed.
| Name | Required | Description | Default |
|---|---|---|---|
| dryRun | No | Report exactly what would run — after modules are inlined and the submit guard applied — and stop. Nothing is sent to Ghost Inspector, no browser starts, no page loads, and no organization id is needed. Use it first on anything that touches production. | |
| testId | No | Existing test to validate. Its suite's viewport and browser are replicated. | |
| browser | No | Override, e.g. "chrome". Omit to replicate the suite's. | |
| viewport | No | Override, e.g. "1280x800". Omit to replicate the suite's. | |
| definition | No | Ad-hoc definition to validate instead of an existing test. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations say readOnlyHint=false, destructiveHint=false, and openWorldHint=true, but the description adds critical context: it drives a real browser against a real URL, inlines modules, truncates at the first submit-capable step, polls for 20-100 seconds, and explains that 'passing: null' means not finished. This goes far beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Though long, every paragraph earns its place: purpose, safety guard mechanics, browser/viewport context, and timing semantics. The structure is front-loaded with the core action and then progressively adds caveats, making the length justified for a tool with non-obvious execution behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description explains key return behavior (ranAs.configSource, passing:null) and runtime expectations. For a tool with nested inputs and real-world side effects, it covers the necessary context: use cases, safety guards, timing, and how to interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds context beyond the schema for browser/viewport by explaining why replication matters ('tests inherit those and a selector can resolve on desktop and fail on mobile'). It does not add new semantics for dryRun, but the schema already covers it thoroughly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Runs a test definition through on-demand execution, which executes it and discards it.' It clearly differentiates from sibling tools by framing this as pre-save validation ('check that a selector chain still resolves before editing a test').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool: before editing a test to verify selectors, and before saving an authored definition. It also states a clear exclusion: 'There is no way to make this tool submit; that stays a deliberate curl.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gi_whoamiGhost Inspector: verify credentialsARead-only
Confirms the configured API key works and lists the organizations it can reach. Read-only and safe to call first when diagnosing setup. Returns each organization's id — export the one you want as GHOST_INSPECTOR_ORG_ID to enable on-demand validation runs.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and openWorldHint. The description reinforces this and adds behavioral context: it explains the tool confirms API key validity, lists reachable organizations, returns their IDs, and how to use the output to enable validation runs. It doesn't cover failure modes or rate limits, but key behavior is transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is exactly three sentences: function, safety/usage, and output guidance. Every sentence adds value, is front-loaded, and has no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter diagnostic tool with no output schema, the description covers what it does, when to use it, what it returns, and how to process the return value (export to GHOST_INSPECTOR_ORG_ID). It is complete enough for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and schema coverage is trivially 100%. The description adds context about the implicit API key and its use, but there are no parameter-level details to explain. Baseline for zero-parameter tools is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource: 'Confirms the configured API key works and lists the organizations it can reach.' It clearly distinguishes from sibling tools by focusing on credential verification and organization access, which is the core of 'whoami'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'safe to call first when diagnosing setup,' providing clear when-to-use context. It doesn't explicitly list alternatives or exclusions, but the positioning as a first diagnostic step implies when to prefer this over sibling tools.
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.
5 tool updates
v0.1.0- First observed
gi_inventory - First observed
gi_module_usage - First observed
gi_stale_tests - First observed
gi_validate_test - First observed
gi_whoami
TDQS
Scored across 5 tools
Each tool targets a unique aspect of the Ghost Inspector account: authentication, inventory, module dependency analysis, stale test detection, and safe on-demand validation. There is no overlap in their purposes, and the descriptions make it clear when to use each one.
All tools share the 'gi_' prefix and use snake_case, making them visually consistent. However, the naming patterns mix noun phrases (gi_inventory, gi_module_usage, gi_stale_tests) with a verb phrase (gi_validate_test) and a command-style name (gi_whoami), so the verb_noun pattern is not strictly maintained.
With exactly 5 tools, the server is well-scoped for its analysis-oriented purpose. Each tool fills a distinct need without redundancy, and the count feels neither too thin nor overwhelming.
The tools cover the full analysis lifecycle: verifying access, understanding the inventory, assessing blast radius before edits, triaging failures by staleness, and validating changes safely. There are no obvious gaps within the stated domain of read-only analysis and safe validation.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Read-only MCP server for turva.dev, an agent-readiness audit and advisory service.
MCP server for visual regression testing: triage a PR's UI diffs from your coding agent.
An MCP server that provides access to Testiny projects, test cases and test runs
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Related MCP Servers
- AlicenseBqualityCmaintenanceA production-ready MCP server that exposes Selenium 4 browser automation as MCP tools.27MIT
- AlicenseBqualityDmaintenanceMCP server for end-to-end QA automation: generates test scenarios, discovers Playwright locators, creates TypeScript test code, executes tests, and creates GitHub issues for failures.611MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for browser automation with shared authentication and built-in UI auditing.MIT
- AlicenseAqualityBmaintenanceAn MCP server that provides operational tooling over the GitHub API — issue triage, PR review monitoring, repo health audits, and team access reviews.111MIT