--- title: OpenAPI Contract Verification with AI description: AI assistants can verify recorded traffic against an OpenAPI spec, run active contract tests, and execute resiliency tests via MockServer MCP tools. shortTitle: Contract Verification layout: page pageOrder: 3.5 section: 'AI Integration' subsection: true sitemap: priority: 0.8 changefreq: 'monthly' lastmod: 2026-05-22T00:00:00+00:00 ---

MockServer's MCP integration provides two powerful tools for verifying that HTTP traffic conforms to an OpenAPI specification. These tools enable both passive verification of already-recorded traffic and active contract testing of a running service.

## Overview

There are three verification workflows:

1. Passive verification (`verify_traffic_against_openapi`) — validate the API calls already recorded by MockServer against an OpenAPI spec
2. Active contract testing (`run_contract_test`) — send example requests derived from an OpenAPI spec to a running service and check the responses conform
3. Resiliency testing (`run_resiliency_test`) — send deliberately malformed and boundary-case requests to a running service and verify it rejects them gracefully

All tools produce structured per-operation results with pass/fail status and detailed validation errors, making them ideal for AI-assisted development workflows where an agent needs machine-enforceable conformance guardrails.

## Passive Verification: Recorded Traffic

After capturing traffic through MockServer (e.g. via a forwarding proxy), use `verify_traffic_against_openapi` to check that every recorded request-response pair conforms to a given OpenAPI specification.

### Workflow

1. Set up MockServer as a forwarding proxy (using `create_forward_expectation`)
2. Run your application's tests or trigger API calls through MockServer
3. Call `verify_traffic_against_openapi` with the OpenAPI spec
4. Review the per-pair conformance report

Example prompt:

> "Verify that the traffic recorded by MockServer conforms to our API specification at /specs/api.yaml"

The AI assistant will use the `verify_traffic_against_openapi` tool:

    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "tools/call",
      "params": {
        "name": "verify_traffic_against_openapi",
        "arguments": {
          "specUrlOrPayload": "/specs/api.yaml"
        }
      }
    }

Example response (conformant):

    {
      "jsonrpc": "2.0",
      "id": 1,
      "result": {
        "content": [
          {
            "type": "text",
            "text": "{\"status\":\"conformant\",\"totalPairs\":3,\"passed\":3,\"failed\":0,\"results\":[...]}"
          }
        ],
        "isError": false
      }
    }

Example response (non-conformant):

    {
      "status": "non_conformant",
      "totalPairs": 3,
      "passed": 2,
      "failed": 1,
      "results": [
        {
          "method": "GET",
          "path": "/api/users",
          "matchedOperation": "GET /api/users",
          "passed": true
        },
        {
          "method": "POST",
          "path": "/api/users",
          "matchedOperation": "POST /api/users",
          "passed": false,
          "responseErrors": [
            "response body validation error: ..."
          ]
        }
      ]
    }

### Filtering

Use the optional `method` and `path` parameters to verify only a subset of the recorded traffic:

    {
      "name": "verify_traffic_against_openapi",
      "arguments": {
        "specUrlOrPayload": "/specs/api.yaml",
        "method": "POST",
        "path": "/api/orders"
      }
    }

## Active Contract Testing: Running Service

Use `run_contract_test` to actively test a running service by sending example requests derived from an OpenAPI spec and validating the responses.

### How it works

1. The tool parses the OpenAPI spec and enumerates all operations
2. For each operation, it builds a representative example request:
   - Path parameters are resolved from spec examples, schema defaults, or generated values
   - Required query parameters and headers are included
   - Request bodies are generated from spec examples or schema-derived values
3. Each request is sent to the specified base URL
4. Each response is validated against the spec (status code, response body schema, required headers)

Example prompt:

> "Run contract tests against my service at localhost:3000 using our OpenAPI spec"

    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "tools/call",
      "params": {
        "name": "run_contract_test",
        "arguments": {
          "specUrlOrPayload": "/specs/api.yaml",
          "baseUrl": "http://localhost:3000"
        }
      }
    }

Example response:

    {
      "status": "all_passed",
      "totalOperations": 4,
      "passed": 4,
      "failed": 0,
      "results": [
        {
          "operationId": "listUsers",
          "method": "GET",
          "path": "/api/users",
          "statusCode": 200,
          "passed": true
        },
        {
          "operationId": "createUser",
          "method": "POST",
          "path": "/api/users",
          "statusCode": 201,
          "passed": true
        }
      ]
    }

### Filtering by Operation

Use the optional `operationId` parameter to test only a specific operation:

    {
      "name": "run_contract_test",
      "arguments": {
        "specUrlOrPayload": "/specs/api.yaml",
        "baseUrl": "http://localhost:3000",
        "operationId": "createUser"
      }
    }

## Resiliency Testing: Error Handling Verification

Use `run_resiliency_test` to verify that a running service handles malformed input gracefully. The tool derives a bounded mutation catalogue from each operation in an OpenAPI spec, sends each mutated request to the service, and classifies the outcome.

### How it works

1. The tool parses the OpenAPI spec and builds a valid example request for each operation (reusing the same logic as `run_contract_test`)
2. For each operation, it generates a catalogue of mutations that actually apply:
   - Omit required path or query parameter
   - Omit required request body field
   - Type violation — string where the schema requires integer/boolean, etc.
   - Numeric boundary violation — minimum−1, maximum+1 (only when the schema defines bounds)
   - String length violation — minLength−1, maxLength+1 (only when the schema defines length constraints)
   - Oversized string field — a 10,000-character string for string fields without an explicit maxLength
   - Malformed JSON body — unparseable JSON
3. Each mutated request is sent to the service
4. Each response is classified:
   - HANDLED — the service returned a 4xx response (it rejected the bad input cleanly)
   - UNEXPECTED — the service returned 5xx, 2xx, or a connection error (it failed to handle the bad input)

Example prompt:

> "Run a resiliency test against my service at localhost:3000 using our OpenAPI spec to check that it rejects bad input properly"

    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "tools/call",
      "params": {
        "name": "run_resiliency_test",
        "arguments": {
          "specUrlOrPayload": "/specs/api.yaml",
          "baseUrl": "http://localhost:3000"
        }
      }
    }

Example response (all handled):

    {
      "status": "all_handled",
      "totalMutations": 12,
      "handled": 12,
      "unexpected": 0,
      "operationSummaries": [
        {
          "operationId": "createUser",
          "method": "POST",
          "path": "/api/users",
          "handled": 12,
          "unexpected": 0
        }
      ],
      "results": [
        {
          "operationId": "createUser",
          "method": "POST",
          "path": "/api/users",
          "mutationType": "OMIT_REQUIRED_BODY_FIELD",
          "mutationDescription": "omit required body field 'name'",
          "statusCode": 400,
          "classification": "HANDLED"
        }
      ]
    }

Example response (failures detected):

    {
      "status": "failures_detected",
      "totalMutations": 12,
      "handled": 8,
      "unexpected": 4,
      "operationSummaries": [
        {
          "operationId": "createUser",
          "method": "POST",
          "path": "/api/users",
          "handled": 8,
          "unexpected": 4
        }
      ],
      "results": [
        {
          "operationId": "createUser",
          "method": "POST",
          "path": "/api/users",
          "mutationType": "TYPE_VIOLATION",
          "mutationDescription": "type violation on field 'age' (expected integer)",
          "statusCode": 500,
          "classification": "UNEXPECTED"
        }
      ]
    }

### Filtering by Operation

Use the optional `operationId` parameter to test only a specific operation:

    {
      "name": "run_resiliency_test",
      "arguments": {
        "specUrlOrPayload": "/specs/api.yaml",
        "baseUrl": "http://localhost:3000",
        "operationId": "createUser"
      }
    }

## Use Cases

### Verifying code you just wrote

After implementing a new API endpoint, ask your AI assistant to run a contract test against your local server. The assistant will derive example requests from the spec and verify your implementation returns conforming responses.

### Continuous conformance checking

After a test run that routes traffic through MockServer, verify that all recorded request-response pairs conform to the spec. This catches both request-side issues (your code sending malformed requests) and response-side issues (the service returning non-conforming responses).

### Spec-first development

Write your OpenAPI spec first, then use `run_contract_test` as a guardrail while implementing. The AI assistant can run the contract test after each change, telling you exactly which operations still fail and what the validation errors are.

### Verifying error handling

After implementing an API endpoint, use `run_resiliency_test` to verify that your service rejects bad input with appropriate 4xx responses rather than crashing with 5xx or silently accepting invalid data. The tool generates boundary-case and malformed inputs automatically from the spec, so you do not need to write negative test cases by hand.

## Security Considerations

The `run_contract_test` and `run_resiliency_test` tools send HTTP requests to the `baseUrl` provided by the caller. This is intentional — they are designed to test arbitrary services — but it means an MCP client can direct MockServer to make outbound requests to any reachable host.

When MockServer is exposed beyond localhost, secure the MCP control plane to prevent unauthorized use:

- Enable control plane JWT authentication via the `controlPlaneJWTAuthenticationRequired` configuration property so that only authenticated clients can invoke MCP tools.
- Enable mutual TLS (mTLS) on the control plane so that only clients presenting a trusted certificate can connect.
- Restrict network access to the MockServer control plane port using firewall rules or network policies.

All outbound requests made by these tools are logged at INFO level, including the target URL, so that unexpected external traffic is visible in the MockServer log.

## Related Pages

- MCP Tools Reference — full parameter documentation for both tools
- MCP Setup — how to connect your AI assistant to MockServer
- Debugging with AI — using AI assistants to analyse captured traffic
- AI Traffic Inspection — inspect and record LLM/MCP traffic for debugging and deterministic replay