OpenAPI Contract Verification with AI
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:
- Passive verification (
verify_traffic_against_openapi) — validate the API calls already recorded by MockServer against an OpenAPI spec - Active contract testing (
run_contract_test) — send example requests derived from an OpenAPI spec to a running service and check the responses conform - 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
- Set up MockServer as a forwarding proxy (using
create_forward_expectation) - Run your application's tests or trigger API calls through MockServer
- Call
verify_traffic_against_openapiwith the OpenAPI spec - 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
- The tool parses the OpenAPI spec and enumerates all operations
- 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
- Each request is sent to the specified base URL
- 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
- The tool parses the OpenAPI spec and builds a valid example request for each operation (reusing the same logic as
run_contract_test) - 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
- Each mutated request is sent to the service
- 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
controlPlaneJWTAuthenticationRequiredconfiguration 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