mcptest docs GitHub

mcptest mock

mcptest mock spawns a stdio MCP server whose catalog and responses come from a declarative manifest instead of a running backend. Point a client, an agent, or an mcptest suite at it to develop and test against a fake server before the real one exists, or to keep tests deterministic and offline.

It speaks one-line-per-message JSON-RPC over stdio. It is the server you reach for in a suite's command::

servers:
  mock:
    command: ["mcptest", "mock", "--tools-from", "fixtures/catalog.yaml"]

Command shape

mcptest mock (--tools-from <PATH> | --preset <NAME>) [--fault <KIND>] [--log-level <LEVEL>]

The mock runs until its stdin closes (the client disconnects).

Manifest format

mock_server:
  name: weather-fixture          # advertised on initialize; defaults to mcptest-mock
  tools:
    - name: get_weather
      description: "Get the weather for a city."
      input_schema:              # JSON Schema; alias inputSchema also accepted
        type: object
        required: [city]
        properties:
          city: { type: string }
      response:                  # canned tools/call result; ${args.<name>} interpolated
        content:
          - type: text
            text: "It is 72 F and sunny in ${args.city}."
  resources:
    - uri: "file:///workspace/README.md"
      name: readme               # optional
      mime_type: text/plain      # optional; alias mimeType
      text: "# Project\nHello."  # returned by resources/read
  prompts:
    - name: bug_triage
      description: "Triage a bug report."   # optional
      text: "Classify the report by severity and component."

Every block is optional. A manifest with only tools: is the common case; add resources: and prompts: when you want to test those primitives too.

Methods served

MethodBehavior
initializeReturns server info and a capabilities block advertising only the primitives the manifest declares (tools, plus resources/prompts when present).
notifications/initialized, pingAcknowledged; keep the connection healthy.
tools/listLists the manifest's tools (name, description, inputSchema).
tools/callValidates arguments against the tool's input_schema (-32602 on a missing required field), then returns the tool's response with ${args.<name>} interpolated. A tool without a response gets a generic { "content": [{ "type": "text", "text": "mock <name>" }] }.
resources/listLists the manifest's resources (uri, name, mimeType).
resources/readReturns { "contents": [{ uri, mimeType?, text }] } for the matching uri; -32602 for an unknown uri.
prompts/listLists the manifest's prompts (name, description).
prompts/getReturns { "messages": [{ "role": "user", "content": { "type": "text", "text": <text> } }] } for the matching name; -32602 for an unknown prompt.
anything else-32601 Method not found, matching the MCP spec.

This is exactly the surface a suite's tool, resource, and prompt tests exercise (see the resources and prompts blocks).

Using it in a suite or in CI

Because it is just a stdio server, any suite can target it deterministically and key-free:

servers:
  mock:
    command: ["mcptest", "mock", "--tools-from", "fixtures/weather.yaml"]
tools:
  - name: weather call returns a temperature
    server: mock
    tool: get_weather
    args: { city: Denver }
    expect:
      - target: result.content[0].text
        matcher: { icontains: "72 F" }

A fault run drives the connect/timeout paths:

mcptest mock --tools-from fixtures/weather.yaml --fault slow:2000   # every call waits 2s
mcptest mock --tools-from fixtures/weather.yaml --fault hang        # calls never return

Built-in presets

--preset <NAME> serves a bundled catalog so you do not have to hand-author one. The only preset today is evil.

mcptest mock --preset evil

The evil preset is a deliberately misbehaving server for hardening a client or agent against a hostile MCP server. It models, in one catalog, the attack classes a real malicious server uses:

Use it as the server under test in a suite to assert that your client refuses the injected instructions, prefers the legitimate tool over the shadow, and rejects or sanitizes the malformed result. Combine with --fault to also exercise the unresponsive-server path against the same hostile catalog.

What this is not

This is a declarative mock, not a record/replay engine. It serves responses from a manifest you write; it does not capture or replay a real server's traffic. For that, use a cassette: record an MCP server's JSON-RPC exchanges and replay them with a cassette: server source. The richer record/replay surface (request-hash matching, OAuth simulation, and .well-known/mcp.json publishing) is still.

References