Skip to content

MCP tests

An MCP test connects to your MCP server on a schedule the way an agent would, and fails when the server stops identifying itself, stops advertising a tool, or a tool call stops returning a result you accept. An agent creates one through the create_api_test MCP tool with type MCP; in the app, pick type MCP server in the test editor.

Each attempt is one short MCP session, in the order an agent would run it: the server identifies itself (the handshake), the test reads the tools the server advertises (tools/list), and the test calls one tool (tools/call). Check depth sets how far into that session a healthy server has to get. The tiers are cumulative; each checks everything the one before it checks, and the test sends only what its tier needs.

TierApp labelWhat is sentPasses when
HANDSHAKEHandshakeThe handshakeThe server identifies itself.
TOOLS_LISTTools listThe handshake, then tools/listThe server lists every tool you expect.
TOOL_CALLTool callThe handshake, tools/list, then one tools/callThe tool you name returns a result you accept.

How the handshake works depends on the protocol generation: the current, stateless revision answers server/discover, older revisions answer initialize, the oldest over a GET event stream. The test identifies itself as fixter-monitoring. See MCP protocol revisions.

Every tier also checks Max latency when it is set, and a pinned protocol revision. To check that a server keeps accepting several revisions, create one pinned Handshake test per revision; see Watching several revisions.

Protocol revision defaults to Newest supported: the test runs against the newest revision the server speaks and moves with it when the server changes, and a move is not a failure. Pick a dated revision instead to pin the test; it then fails when the server stops accepting that revision. You do not have to know what your server speaks: once the URL looks complete, the editor detects it (after a short pause in typing, at once on paste or when you leave the field), sets the picker to Newest supported and shows currently <revision> beside it. The revisions, detection and pinning are on MCP protocol revisions.

FieldMCP parameterApp labelTierWhat it takes
URLmcpUrlURLAllAn absolute http:// or https:// URL with a host, reachable from the public internet. Any other URL is never sent: the run fails with malformed target URL, so the test cannot be saved. Takes request variables.
CredentialmcpCredentialIdCredentialAllNone, or a saved credential. See Credentials.
Check depthmcpTierCheck depthAllHANDSHAKE, TOOLS_LIST or TOOL_CALL. Required. See The three tiers.
Protocol revisionmcpProtocolRevisionProtocol revisionAllA dated revision to pin, or NEWEST_SUPPORTED. Optional; omitted, it is NEWEST_SUPPORTED. See Protocol revision.
Expected toolsexpectedToolsExpected toolsTOOLS_LISTTool names the server must advertise. Required for this tier.
Tool nametoolNameTool nameTOOL_CALLThe tool to call. Required.
Tool argumentstoolArgumentsJsonTool arguments (JSON)TOOL_CALLThe arguments, as a JSON object. Required: a tool that takes none needs {}. Takes request variables.
Result validationmcpResultValidationTier, mcpResultValidationSampleResult validation, Result sampleTOOL_CALLThe same five tiers as an HTTP body. Optional; None checks nothing.
Max latencymcpMaxLatencyMillisMax latency (ms)AllOptional; left empty, speed is not checked.

An MCP test has no method and no request headers. Request variables such as {{uuid}} apply to the URL and the tool arguments only, not to the tool name or the expected tools. Values are minted once per attempt, so a retry gets fresh ones.

The result validation reads the tool result’s structuredContent as JSON when the result has it, and otherwise the text of its text content items, joined. The tiers then apply exactly as they do to an HTTP response body: see Body validation. A result marked isError: true fails the test whatever the result validation says.

Max latency is compared with the attempt’s total time across the session’s requests.

An MCP test follows 301, 302, 303, 307 and 308 redirects, up to five, and never from https to http. Past five, or on a downgrade, it stops following and takes the redirect response itself as the server’s answer. Every hop must be a public address.

Every request of a run carries:

  • User-Agent: FixterMonitoring/1.0 (+https://fixter.dev).
  • A traceparent header with the run’s trace id, the same on every attempt of the run. See Runs, states and uptime.
  • The credential’s headers, and its query parameters merged into the URL, when the test has a credential. See Credentials.

A run checks every assertion its tier includes and lists every failure; none stops the others.

AssertionFails whenThe run says
mcp.initializeThe server did not identify itself (every tier).MCP server did not identify itself
mcp.tools.containsAn expected tool is not advertised, one failure per tool (TOOLS_LIST).Tool <name> is missing
mcp.tool.isErrorThe tool call returned an error result (TOOL_CALL).Tool <toolName> returned an error
mcp.protocol.revisionThe test is pinned and the server stops accepting that revision.Server no longer speaks protocol <pin>
maxLatencyMillisThe attempt took longer than Max latency (every tier).Took <actual> ms, limit <limit> ms

A failed result validation reads as it does for an HTTP body, for example Response body is missing expected fields; the sentences say “Response body” for a tool result too.

When nothing at the URL identified itself as an MCP server on any revision, the run fails mcp.initialize with the message the target did not identify itself as an MCP server.

Once the server has identified itself, a JSON-RPC error in reply to tools/list leaves no tool names, so every expected tool reads as missing. In a Tool call test it also reads as Tool <toolName> returned an error, even though the tool was never called. A JSON-RPC error in reply to tools/call reads the same. A plain error status with no JSON-RPC reply fails the run with MCP server rejected <method>, for example MCP server rejected tools/list.

Two tests on an orders MCP server, which assumes a Bearer token credential named Orders MCP token already exists. The first checks that two tools are advertised; the second calls one of them. In the app, Expected tools is shown only for Tools list, so the two checks are two tests.

FieldFirst testSecond test
NameOrders MCP toolsOrders MCP search
TypeMCP serverMCP server
URLhttps://mcp.example.com/mcphttps://mcp.example.com/mcp
CredentialOrders MCP tokenOrders MCP token
Protocol revisionNewest supportedNewest supported
Check depthTools listTool call
Expected toolssearch_orders, get_order
Tool namesearch_orders
Max latency20002000
Result validationContains fields

The second test’s Tool arguments (JSON):

{"query": "{{uuid}}"}

Its Result sample:

{"results": []}

Each attempt searches for a fresh {{uuid}}, so the call never depends on data left by an earlier run. The sample asks for a results array; an empty sample array accepts any array, so {"results": [], "total": 0} passes.

If the server drops get_order, the first test fails with Tool get_order is missing. If the search tool starts returning an error result, the second fails with Tool search_orders returned an error. A session that took 2400 ms fails either test with Took 2400 ms, limit 2000 ms.

An agent can fold both checks into one test: create_api_test with tier TOOL_CALL also accepts expectedTools, and the run then checks the names as well as the call.

Create API test runs the test once before saving it, and saves it only if that run passes.