Skip to main content
Back to Blog
Tutorial
2026-03-24

Use MCP Inspector CLI to Automate tools/list and tools/call Tests

Automate MCP tools/list and tools/call checks with the pinned Inspector CLI, typed arguments, JSON assertions, negative cases, and CI-safe evidence.

MCP Inspector CLI sending tools list and call requests to local and remote servers with automated JSON assertions

Practical MCP Inspector CLI testing turns the official Inspector from an interactive debugger into a repeatable smoke-test client. With @modelcontextprotocol/inspector@0.22.0, use --cli plus --method tools/list to capture a server's catalog, then use --method tools/call --tool-name ... --tool-arg key=value for positive and negative invocations. The CLI prints the MCP result as JSON, but your test must still assert tool names, schemas, content, structuredContent, and isError; process success alone is not a product assertion.

Place these checks inside the broader MCP server testing guide, and use the sibling official conformance suite tutorial, GitHub Actions baseline guide, and MCP schema contract guide for deeper gates. Reusable test guidance lives in /skills, including the Playwright CLI skill; the established Playwright MCP browser automation guide explains the separate browser-control use case.

Choose Inspector CLI for focused protocol probes

The official Inspector documentation presents the tool as a development utility for inspecting resources, prompts, tools, notifications, and server behavior. The tagged Inspector 0.22.0 README documents a distinct CLI mode for automation. It supports local stdio commands, remote URLs, config files, headers, and methods including tools/list and tools/call.

Inspector CLI is useful for a small number of explicit questions:

QuestionInspector commandAssertion you add
Can a client initialize and discover tools?--method tools/listRequired tools and valid schemas are present
Can a known tool accept a valid fixture?--method tools/callResult is successful and semantically correct
Does invalid product input remain actionable?Same call with negative argumentsResult has isError: true and safe diagnostic content
Does a protected endpoint reject bad credentials?Remote call with test headerCommand fails without leaking protected data
Did the tool catalog drift?Capture list JSONReviewed snapshot or contract diff explains the change

It is not the official conformance suite, a load generator, a fuzzing engine, or a guarantee that the model will choose the right tool. Use the conformance runner for its formal scenarios and Inspector for narrow reproductions and repository-owned contracts.

Version baseline and prerequisites

As of July 14, 2026, npm and the official repository identify 0.22.0 as the stable Inspector release. Its package metadata requires Node >=22.7.5. The current published MCP protocol remains 2025-11-25; the Inspector negotiates through the SDK, while your server decides which protocol version it supports.

Record these assumptions in the test artifact:

  • Inspector package 0.22.0 and committed lockfile;
  • Node version at or above the documented minimum;
  • local stdio command or remote Streamable HTTP URL;
  • server commit, SDK version, and fixture revision;
  • expected tool catalog revision;
  • authorization identity and environment, without recording the token;
  • published protocol version expected from initialization.

For repeatable repository use, install exactly one release:

npm install --save-dev --save-exact @modelcontextprotocol/inspector@0.22.0
node --version
npm exec -- mcp-inspector --cli node build/index.js --method tools/list

The third line uses the package's installed mcp-inspector binary. If you prefer the official README's on-demand form, keep the same version pin: npx @modelcontextprotocol/inspector@0.22.0 --cli .... Do not put @latest in a release gate.

Use the current tools/list syntax

For a local stdio server, place the server command and its arguments immediately after --cli, then add the Inspector operation flags. The 0.22.0 parser permits server arguments and recognizes the method flag later in the same command.

mkdir -p artifacts/mcp-inspector

npm exec -- mcp-inspector --cli   node build/index.js --fixture test/fixtures/orders.json   --method tools/list   > artifacts/mcp-inspector/tools-list.json

For a remote Streamable HTTP server, pass the endpoint URL and select http transport. Version 0.22.0 also auto-detects HTTP when a URL path ends in /mcp, but an explicit transport makes the test intent visible:

npm exec -- mcp-inspector --cli   http://127.0.0.1:3001/mcp   --transport http   --method tools/list   > artifacts/mcp-inspector/tools-list-http.json

The spelling is --transport http in CLI mode, not a guessed streamable-http flag. The wrapper maps config-file type streamable-http to the CLI's http transport value. For remote headers, the tagged README documents --header "X-API-Key: value". Use a synthetic, short-lived test credential and prevent shell tracing from printing it.

Assert the catalog instead of saving and forgetting it

The CLI serializes the method result as JSON. A catalog test should verify required tool identities, object-root input schemas, declared required fields, and intentional output schemas. Avoid exact snapshots of descriptions if editorial changes are allowed; assert only contract-bearing fields or maintain an approved normalized snapshot.

This Node script reads the captured result and reports actionable failures without adding another test framework:

import { readFile } from 'node:fs/promises';

const payload = JSON.parse(
  await readFile('artifacts/mcp-inspector/tools-list.json', 'utf8'),
);

if (!Array.isArray(payload.tools)) {
  throw new Error('tools/list result did not contain a tools array');
}

const byName = new Map(payload.tools.map((tool) => [tool.name, tool]));
const lookup = byName.get('orders.lookup');

if (!lookup) {
  throw new Error('Required tool orders.lookup is missing');
}

if (lookup.inputSchema?.type !== 'object') {
  throw new Error('orders.lookup inputSchema must have an object root');
}

if (!lookup.inputSchema.required?.includes('orderId')) {
  throw new Error('orders.lookup must require orderId');
}

if (lookup.outputSchema?.type !== 'object') {
  throw new Error('orders.lookup must publish its object output contract');
}

console.log(`Validated ${payload.tools.length} discovered tools`);

The final count is diagnostic, not a universal minimum. A server with one well-designed tool can be valid; a server with many tools can still have poor schemas. If catalog size is a team contract, store its expected value with a reason rather than presenting it as an MCP rule.

Normalize only non-contract noise

A useful catalog comparison starts from an allowlist of fields whose changes matter. Tool name, input schema, declared output schema, and required annotations may be release contracts. Human-readable descriptions may be reviewed but intentionally change more often. Preserve the raw response as evidence, then create a normalized comparison object for the gate. Do not overwrite the raw capture or sort arrays whose order has product meaning.

Schema normalization deserves care. Reordering object properties is normally presentation noise, while changing required membership, accepted types, numeric bounds, enum values, or whether additional properties are permitted can alter accepted calls. A comparison script should report those changes directly instead of reducing the whole schema to one opaque hash. If the server generates schemas from application types, test both the generated catalog and representative instances; generation can be deterministic while still expressing the wrong contract.

Tool annotations require a separate review. The published specification treats annotations as hints and says clients must not make security decisions from untrusted annotations. A changed destructive or read-only hint can affect client presentation and model planning, but it does not replace authorization or confirmation controls on the server. Catalog tests can detect the change, while security tests must prove the enforcement behavior.

Use the current tools/call syntax and typed arguments

Inspector 0.22.0 requires --tool-name for tools/call. Each --tool-arg uses key=value. The parser attempts JSON.parse on each value and falls back to a string. That means limit=2 becomes a number, includeHistory=true becomes a boolean, and status=open remains a string. Arrays and objects need valid JSON quoted for the shell.

npm exec -- mcp-inspector --cli   node build/index.js --fixture test/fixtures/orders.json   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=ORD-1001   --tool-arg includeHistory=true   --tool-arg 'fields=["status","total"]'   > artifacts/mcp-inspector/orders-lookup-success.json

npm exec -- mcp-inspector --cli   node build/index.js --fixture test/fixtures/orders.json   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=DOES-NOT-EXIST   > artifacts/mcp-inspector/orders-lookup-negative.json

Do not infer a pass from both commands exiting zero. A protocol-valid tool execution error is still a successful JSON-RPC response, so Inspector can print a result whose isError is true. Parse and assert each file according to the case.

Build positive and negative result assertions

A positive check should verify the result channel and product meaning. If the tool declares outputSchema, validate structuredContent against that schema. The MCP tools specification says servers with an output schema must provide conforming structured results, while clients should validate them. For backward compatibility, structured output should also have serialized JSON in a text content block.

A small positive/negative assertion module can keep the distinction clear:

import { readFile } from 'node:fs/promises';

async function readResult(file) {
  return JSON.parse(await readFile(file, 'utf8'));
}

const success = await readResult(
  'artifacts/mcp-inspector/orders-lookup-success.json',
);

if (success.isError === true) {
  throw new Error('Valid lookup returned a tool execution error');
}
if (success.structuredContent?.orderId !== 'ORD-1001') {
  throw new Error('Valid lookup returned the wrong fixture order');
}
if (!Array.isArray(success.content) || success.content.length === 0) {
  throw new Error('Valid lookup returned no content blocks');
}

const negative = await readResult(
  'artifacts/mcp-inspector/orders-lookup-negative.json',
);

if (negative.isError !== true) {
  throw new Error('Unknown order must be an actionable tool execution error');
}
if (!negative.content?.some((block) => block.type === 'text')) {
  throw new Error('Negative result needs a safe text explanation');
}

The expectation that an unknown order is a tool execution error is product semantics: the tool exists, the request shape is valid, and the domain lookup fails. An unknown tool name is a protocol error under the published tools specification. Test both, but do not collapse them into one generic "error test."

Negative caseExpected channelWhy
Tool name does not existJSON-RPC protocol errorClient requested an unknown protocol operation target
Call request is malformedJSON-RPC protocol errorRequest fails the CallToolRequest shape
Argument has valid JSON shape but invalid domain valueTool result with isError: trueModel can correct the argument and retry
Upstream order service is unavailableTool result with isError: trueTool executed but its dependency failed
Auth header is absent on protected endpointTransport or authorization failureRequest is not authorized to reach tool execution
Successful call returns wrong orderSuccessful transport but failed product assertionProtocol success does not imply semantic correctness

Build fixtures that expose semantic mistakes

Choose fixture values that make the wrong branch obvious. A successful lookup should use an identifier with distinctive status, totals, and history so an assertion can detect accidental fallback to the first record. A missing identifier should be absent by construction, not merely unlikely to exist. For tenant tests, place records with similar identifiers in two synthetic tenants and prove that the test principal receives only the authorized record.

Keep expected protocol errors separate from domain failures in the fixture manifest. An unknown tool tests dispatch before product code runs. A missing required argument tests schema handling. A well-shaped request for a closed account tests product policy. A simulated dependency outage tests execution failure and safe error content. These cases may all be described as negative tests in a dashboard, but their expected envelopes and remediation owners differ.

Assertions should reject accidental data disclosure as well as wrong status. Error text must not contain fixture secrets, authorization headers, stack traces, or another tenant's values. This is a security recommendation and product policy layered on top of the protocol's error channels; Inspector captures the response, while your assertion module defines which content is safe for the application.

Test omitted fields and defaults deliberately

Run one call without an optional argument and another with the explicit value. Inspector sends only the --tool-arg pairs you provide. The 0.22.0 README advises Inspector implementations to omit empty optional fields, preserve explicit defaults when supplied by a form, include required fields, and defer deep validation to the server.

JSON Schema's default keyword is an annotation; validation does not automatically insert the value. Therefore, your server contract must state whether omitted input is normalized to a default, passed downstream as absent, or rejected by product policy. Inspector can demonstrate the observed behavior, but it does not define that behavior.

# Omitted includeHistory: tests the server's omission policy.
npm exec -- mcp-inspector --cli node build/index.js   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=ORD-1001   > artifacts/mcp-inspector/orders-default-omitted.json

# Explicit false: tests a concrete boolean, not the string "false".
npm exec -- mcp-inspector --cli node build/index.js   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=ORD-1001   --tool-arg includeHistory=false   > artifacts/mcp-inspector/orders-default-explicit.json

Compare normalized results or server audit records. Do not require byte-identical output when timestamps or trace IDs are intentionally dynamic; remove those fields before comparing.

Test local stdio and remote HTTP without mixing claims

Local stdio testing launches the command provided to Inspector. It validates the built entry point, environment, stdio framing, and tool behavior in one process tree. Remote HTTP testing validates a deployed endpoint, HTTP transport, headers, and its configured backing services. Passing one does not prove the other.

SurfaceStrengthCommon blind spot
Local stdioFast, isolated, easy fixture injectionDoes not exercise HTTP Origin, auth, proxy, or deployment config
Local Streamable HTTPExercises HTTP lifecycle with disposable dataMay omit production gateway behavior
Staging Streamable HTTPExercises routing, authorization, and managed dependenciesHarder to keep data deterministic
Production read-only smokeConfirms a narrow live pathMust not become a destructive conformance or regression suite

When using a bearer token, prefer a masked environment secret and a short-lived test principal. A header passed on a command line can be visible to local process inspection. On shared runners, use repository-approved secret handling and never upload command traces containing the header.

Put Inspector smoke tests in CI

Create a repository script that runs catalog capture, positive calls, negative calls, and assertion modules under set -euo pipefail. Upload JSON and sanitized server logs even on failure. Pin Inspector in devDependencies; the CI command should use the local binary rather than downloading code at runtime.

An example script sequence is:

set -euo pipefail
rm -rf artifacts/mcp-inspector
mkdir -p artifacts/mcp-inspector

npm exec -- mcp-inspector --cli node build/index.js   --method tools/list   > artifacts/mcp-inspector/tools-list.json
node test/contracts/assert-tools-list.mjs

npm exec -- mcp-inspector --cli node build/index.js   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=ORD-1001   > artifacts/mcp-inspector/orders-lookup-success.json

npm exec -- mcp-inspector --cli node build/index.js   --method tools/call   --tool-name orders.lookup   --tool-arg orderId=DOES-NOT-EXIST   > artifacts/mcp-inspector/orders-lookup-negative.json

node test/contracts/assert-tool-results.mjs

Run this job when tool registration, schemas, handlers, SDK versions, transport configuration, or fixture data changes. Keep the official conformance suite as a separate named job so reviewers can tell an Inspector product-contract failure from a formal scenario failure.

Read the artifacts as one test transaction

Catalog and call captures should identify the same server build, fixture revision, identity, and transport. Otherwise a catalog from one process can be paired with a call from another configuration and produce a misleading conclusion. Write a small manifest beside the JSON files containing nonsecret commit, package, fixture, endpoint mode, and test-principal identifiers. This manifest is a team evidence format, not Inspector output or an MCP requirement.

Preserve stderr separately from stdout for local stdio runs. Inspector needs machine-readable JSON on its captured output, while server diagnostics help explain startup and handler failures. Redact diagnostics before artifact upload and retain the unmodified raw files only in an access-controlled location if policy permits. For HTTP tests, include sanitized server-side correlation identifiers so a reviewer can connect a tool result to the intended request without storing credentials.

Review the collection before release: the listed schema should match the call assumptions, positive output should satisfy declared and product contracts, negative output should use the intended error channel, and no artifact should expose sensitive values. A single green assertion script cannot compensate for captures produced from inconsistent configurations.

Troubleshooting exact CLI failures

"Method is required." Add --method tools/list or --method tools/call. CLI mode does not infer the operation from --tool-name.

"Tool name is required." A tools/call command needs --tool-name. Confirm the spelling against captured tools/list output; names are case-sensitive by specification guidance.

A number arrives as a string. Make the value valid JSON. limit=2 parses as number two; limit='02' is not valid JSON and remains a string. Inspect the captured server arguments when debugging.

An object argument is split by the shell. Quote the entire key=JSON pair, such as --tool-arg 'options={"limit":2}'. Validate the command in the same shell used by CI.

A remote /mcp URL uses the wrong transport. Pass --transport http explicitly. Use sse only for an SSE endpoint and stdio only with a local command.

The command exits zero but the negative case is wrong. Inspect isError and content. A tool execution error travels inside a successful JSON-RPC result; write a semantic assertion rather than relying only on the process code.

Captured JSON contains unexpected text. Ensure a stdio server writes only MCP messages to stdout and sends logs to stderr. For remote mode, check whether wrapper scripts print banners before launching the server.

Limitations and safe claims

Inspector CLI invokes one operation at a time. It does not generate a complete conformance verdict, prove concurrency safety, explore every schema boundary, or assess whether a language model chooses tools safely. Its output reflects one fixture, identity, transport, and server version.

The CLI parser helps encode basic JSON values, but it is not a replacement for server-side JSON Schema validation. The official Inspector guidance explicitly defers deep validation to the server. Treat catalog and call assertions as repository-owned tests whose thresholds and expected semantics require product review.

Automation checklist

  • Pin @modelcontextprotocol/inspector@0.22.0 and commit the lockfile.
  • Use Node >=22.7.5; record the actual CI patch version.
  • Use --cli --method tools/list for catalog capture.
  • Use --method tools/call --tool-name plus repeated --tool-arg pairs for calls.
  • Quote JSON arrays and objects for the shell.
  • Assert JSON content, structuredContent, and isError, not only exit code.
  • Test unknown tool, domain-invalid input, dependency failure, and unauthorized access separately.
  • Keep stdio and Streamable HTTP evidence labeled by transport.
  • Use synthetic data and short-lived test credentials.
  • Run formal conformance, security, and load tests as separate gates.

Frequently asked questions

What is the exact command to list MCP tools with Inspector 0.22.0?

For local stdio, use npm exec -- mcp-inspector --cli node build/index.js --method tools/list. For a remote MCP endpoint, use the URL as the target and add --transport http --method tools/list.

How do I call a tool from Inspector CLI?

Use --method tools/call --tool-name NAME, followed by one or more --tool-arg key=value options. Version 0.22.0 parses valid JSON values, so booleans, numbers, arrays, and objects retain their JSON types when quoted correctly for the shell.

Does Inspector validate a tool's inputSchema?

The Inspector exposes schemas and performs basic argument handling, but its official guidance defers deep validation to the server. Add a JSON Schema validator in your contract tests and verify the server reports invalid domain input through the correct error channel.

Why did a tool error produce exit code zero?

A tool execution error is a valid MCP result with isError: true. The Inspector successfully completed the protocol request and printed that result. Parse the JSON and assert isError plus diagnostic content for the negative case.

Should I snapshot the entire tools/list response?

Only if every field is intentionally stable. Normalized contract assertions are often better: required names, schema dialect, required fields, output schemas, and security annotations. Review description or ordering changes separately if they are not compatibility contracts.

Can Inspector replace the official conformance suite?

No. Inspector is excellent for smoke tests and reproductions, while the conformance runner executes its maintained protocol scenarios and baseline logic. Use both, with clearly different job names and claims.

Is MCP Inspector safe to expose on a shared network?

The official Inspector warns that its UI proxy can launch local processes and should not be exposed to untrusted networks. CLI mode still executes the target command or connects to a supplied URL. Run it in an isolated environment, restrict credentials and egress, and do not disable security controls for convenience.

Conclusion

Inspector CLI becomes a useful automation tool when the syntax and assertion boundary are explicit. Pin 0.22.0, capture tools/list, invoke tools/call with correctly typed arguments, and inspect the JSON result channel. That creates fast, readable smoke tests while leaving conformance, schema depth, security, and product behavior to their appropriate test layers.