You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Control-plane role-based authorization (off by default). With controlPlaneAuthorizationEnabled
and a controlPlaneScopeMapping (e.g. platform-admins=admin,qa-team=mutate,viewers=read), an
authenticated principal's scopes/groups are mapped to one of three hierarchical roles
(admin ⊇ mutate ⊇ read): reads require read, every mutating operation requires mutate, and a
principal lacking the role gets 403 Forbidden (recorded in the audit log). Fail-closed — use together
with control-plane OIDC authentication. Covers all HttpState.handle operations plus the Netty-serviced /mockserver/configuration, /openapi.yaml and /llm/optimisationReport reads/writes. Not yet covered:
the lifecycle endpoints (/bind, /stop, /status) and per-tool MCP authorization. See docs/code/tls-and-security.md.
JWT control-plane validation rejects HMAC algorithms.JWTValidator verifies against a public-key
JWK set, so it now accepts only asymmetric algorithms (RS*/ES*/PS*/EdDSA) and rejects HMAC
(HS256/384/512), closing an algorithm-confusion forgery vector. Switch to an asymmetric key if you
relied on HMAC.
SCIM bearer-token enforcement now fails closed. When enforcement is enabled but no expected token is
configured, requests are rejected instead of accepting any token, and the comparison is constant-time.
Opt-in secret redaction in the event log and dashboard (redactSecretsInLog, default off). Masks
sensitive header values (Authorization, Cookie, x-api-key, …) and configured JSON body fields in
retrieved/exported logs and the dashboard event view. Matching and verification still see the original
values, so behaviour is unchanged.
Dashboard dompurify pinned to 3.4.11 via an npm overrides entry, clearing all 16 open
Dependabot DOMPurify advisories (mXSS / DOM-clobbering / prototype-pollution).
Added
AI, LLM & agent protocols (LLM / MCP / A2A)
LLM and MCP mock builders in every client. Idiomatic LLM-mocking (completions, tool calls, streaming
physics, usage, embeddings, multi-turn conversations, provider failover) and MCP-server-mocking (tools,
resources, prompts over JSON-RPC 2.0) builders are now available in all eight clients (Java, Node, Python,
Ruby, Go, Rust, .NET, PHP), all producing the same wire JSON.
LLM optimisation export. Proxy your agent's LLM calls through MockServer, then export a one-click
optimisation brief (Markdown) or structured JSON bundle (LlmOptimisationReport) from captured traffic.
Nine deterministic signals detect repeated system prompts, low cache-hit rates, unused tool schema,
model overspend, large resent context, deterministic tool calls, oversized tool results, output-token
bloat and duplicate calls — each with token counts, estimated USD saving, and structured fix guidance
(copy-paste config snippet or example expectation where applicable). An in-product verdict (A–F grade
and "$X recoverable" headline computed via per-call MAX attribution so the total is always ≤ actual spend)
and two new session KPIs (cache-hit rate and one-shot rate) appear in the dashboard and the
Markdown brief. New LLM Optimise dashboard screen (with verdict banner, "Copy verdict" button, and
updated hero cards), GET /mockserver/llm/optimisationReport endpoint, and export_optimisation_report
MCP tool. Export-only and deterministic; secrets are redacted. The Anthropic codec now maps the top-level system field so cache and repeated-prompt signals fire on Anthropic traffic.
More embedding providers and rerank mocking.httpLlmResponse embeddings now cover Gemini, Ollama and
Bedrock (Titan / Cohere-on-Bedrock) in addition to OpenAI/Azure, all deterministic and L2-normalised. A new
rerank action mocks Cohere and Voyage rerank endpoints in the provider-correct envelope.
MockServer's MCP control plane gains prompts/list, prompts/get and sampling/createMessage over
HTTP/1.1, HTTP/2 and HTTP/3, configured via a new McpPromptRegistry.
A2A mock builder: streaming and push notifications (opt-in). withStreaming() generates an SSE stream
of task status/artifact events; withPushNotifications(webhookUrl) POSTs each completed task to a webhook.
Strict structured-output enforcement (enforceOutputSchema, opt-in). A mocked completion whose body
doesn't conform to its outputSchema fails loudly (502 + diagnostic header) instead of returning the
non-conforming body — modelling a real provider's strict json_schema mode. Checked before streaming begins.
Provider-correct LLM chaos error bodies. Error injection emits each provider's real error shape
(Anthropic overloaded_error, OpenAI server_error/rate_limit_exceeded, Gemini, Ollama) so SDK
retry/backoff can be tested realistically. An optional errorKind (OVERLOAD / RATE_LIMIT / SERVER_ERROR) emits the provider's distinct body and natural HTTP status without picking the code yourself.
Multimodal request recognition. Conversation decoders recognise image content parts (OpenAI image_url,
Anthropic image, Gemini inline_data) and audio parts (OpenAI input_audio), so a request matcher can
assert on image/audio presence; ParsedMessage exposes hasImage()/hasAudio() etc. A new response-side toolChoice field (auto/none/required/named) drives finish_reason. Request recognition only —
MockServer does not store the bytes.
Cached / reasoning token usage fields.Usage gains optional cachedInputTokens, cacheCreationTokens and reasoningTokens, decoded from each provider's usage shape and emitted on GenAI
telemetry spans, so cost dashboards can split cached-input and reasoning spend.
LLM model/pricing catalog refresh — current Claude (Opus 4.5–4.8, Sonnet 4.5/4.6, Haiku 4.5, Fable 5),
OpenAI (gpt-4.1, o3/o4) and Gemini 2.5 families, with most-specific-prefix matching. gpt-5* entries are
flagged placeholders — confirm against the provider price list.
Approximate token-count utility and opt-in usage inference (llmInferUsageEnabled, default off). A
mocked completion that omits usage can be auto-populated with estimated token counts (documented as an
estimate, not a real BPE tokenizer); existing responses are unchanged.
AMQP 0.9.1 (RabbitMQ) broker mocking in the AsyncAPI module, alongside the existing Kafka and MQTT
support (configure via asyncAmqpUri).
Agent framework recipes (docs): a new ai_agent_frameworks.html page with recipes for pointing
LlamaIndex and the OpenAI Agents SDK at MockServer to mock LLM provider calls.
One-call mock OIDC / OAuth2 provider.PUT /mockserver/oidc (or mockOpenIdProvider()) stands up a
complete IdP — discovery, JWKS, token, authorize, userinfo, introspection, revocation, logout — with the
full OAuth2 authorization-code flow (PKCE S256/plain), client-credentials, refresh-token, and the device
authorization grant (RFC 8628). Tokens are minted at request time (correct nonce/at_hash, id_token
split from access_token); signing is configurable (RS/ES 256/384/512). Optional token-endpoint client
authentication (enforceClientAuthentication) and opaque access tokens with working /introspect.
Verified OIDC bearer authentication for the control plane (controlPlaneOidcAuthenticationRequired,
off by default). Verifies the Authorization: Bearer token against an external IdP's JWK set (direct or
discovered), asserting issuer, audience, exp/nbf and required scopes, and records the verified sub
as the audit principal. Combinable with mTLS and JWT control-plane auth.
One-call mock SAML 2.0 IdP.PUT /mockserver/saml stands up a mock IdP (metadata + SP-initiated POST
SSO) returning an XML-DSig-signed assertion with configurable subject/attributes. Configurable signing
algorithm (RS/ES 256/384/512), Single Logout, and negative-test flags (expiredAssertion, wrongAudience, tamperedSignature) to exercise an SP's rejection paths. Typed mockSamlProvider(...) Java API; inbound
parsing is XXE-hardened.
One-call mock SCIM 2.0 provider.PUT /mockserver/scim (or mockScimProvider(...)) generates an
in-memory SCIM provider: CRUD over Users/Groups, discovery documents, application/scim+json shapes,
single-attribute filtering (eq/co/sw/pr), PatchOp, pagination, an optional bearer-token gate and
configurable base path/seed data.
Load injection, chaos & SRE
API-driven load generation via Load Scenarios (loadGenerationEnabled, off by default). A named,
registry-based control plane (PUT/GET/DELETE /mockserver/loadScenario, /start, /stop) drives outbound
traffic at a target: load a scenario by name, then trigger one or many to run concurrently, each with
its own startDelayMillis. A scenario is a list of request steps (template-rendered per iteration with an iteration context) with per-step think-time and a profile of ordered stages — closed-model VU
stages, open-model arrival-rate (iterations/sec) stages with LINEAR/EXPONENTIAL/QUADRATIC ramp curves,
and pauses — composing step/spike/soak/stress shapes. Scenarios can be preloaded at startup
(loadScenarioInitializationJsonPath). Bounded by hard caps on VUs, rate, stages and concurrent scenarios.
Full registry API and runnable examples in all eight clients.
First-class load-injection metrics (Prometheus + OTEL). A load run exposes a dedicated mock_server_load_* family — request duration histogram (with trace_id exemplars), iterations, bytes,
throttles, errors-by-kind, and live active_vus/inflight gauges — labelled by scenario, run_id, step, route, method, status_class (with auto-templatized low-cardinality routes and
opt-in custom labels). Zero-cost when metrics are off; mock_server_forward_* is unchanged.
SLO resilience verdicts (sloTrackingEnabled, off by default). A windowed sample store records latency
and error per forwarded round-trip; PUT /mockserver/verifySLO evaluates latency-percentile and error-rate
objectives and returns a structured verdict (200 PASS / 406 FAIL / 400 malformed). Pairs with chaos:
drive faults, then assert the system stayed within objectives.
Connection-lifecycle fault injection and preemption simulation. The per-host TCP chaos profile gains
mid-response RST, jittered slow-close and HTTP/2 GOAWAY faults. A new PUT/GET/DELETE /mockserver/preemption
simulates a Kubernetes rolling-update / spot-reclaim drain — cordoning new exchanges, reporting in-flight
count, and auto-uncordoning after a TTL — without stopping the JVM.
Saved chaos profile library. Save/apply/list/delete chaos experiments by name
(/mockserver/chaosExperiment/profiles/{name}, /apply/{name}). Profiles persist in the StateBackend,
so they survive a reset and replicate across a cluster. The dashboard Chaos panel gains a Saved Profiles list.
Scheduled chaos experiment start. A chaos experiment can carry startDelayMillis (fixed delay) and/or cronSchedule (5-field cron, JVM time zone, minute granularity); it sits in a scheduled status until the
scheduled time. No scheduling fields = immediate start (unchanged).
General-purpose rate limiting (rateLimit expectation clause, off by default). A protocol-agnostic
clause returns a deterministic 429 with Retry-After and X-RateLimit-* headers once a matched
expectation exceeds its rate, via fixed_window or token_bucket algorithms, with an optional named shared
counter — so a test can exercise client backoff without a chaos profile.
Retry/backoff recovery primitive (recoverAfter on httpResponse, opt-in). Returns a failure response
(default 503) for the first failTimes matches and then the success response, so a test can deterministically
exercise client retry/backoff. An optional idempotencyHeader scopes the counter per request-header value.
Stream-level error injection (HTTP/2 / HTTP/3). httpError().withStreamError(...) resets a matched
request stream with a given error code (HTTP/2 RST_STREAM, HTTP/3 RESET_STREAM) without affecting other
multiplexed streams; HTTP/1.1 falls back to dropping the connection. Also on the Node, Python and Ruby clients.
Conditional breakpoints. Breakpoint matchers accept skipCount (pause only after N matching hits) and,
on the RESPONSE phase, responseStatusCodeMin/Max and responseBodyContains so a breakpoint can pause
only on, e.g., 5xx responses or a body containing a particular message.
Request matching & response generation
Per-expectation hit-count response branching (SWITCH response mode + optional switchAfter). With an
index-aligned httpResponses list, an expectation serves the first response for its first N matches then
advances — ideal for "succeed, then start failing" on a single endpoint without a full scenario.
Generate a schema-valid response body from an inline JSON Schema (generateFromSchema). Synthesises a
schema-valid body at response time, reusing the OpenAPI example engine; fires only when the response has no
explicit body.
Regex path capture groups exposed to templates via request.pathGroups (numbered) and request.namedPathGroups, usable from Mustache, Velocity and JavaScript.
Request-driven (template) response delay — a delay may carry a template+templateType rendered
against the request, so e.g. larger payloads respond slower.
Conditional (if-then-else) request matcher (conditionalRequestDefinition with if/then/else).
Accept-header content-negotiation matching — an opt-in accept:<media-type> header-matcher directive
matches per RFC 7231 (q-weights, wildcards, specificity).
Conditional and chainable response modifiers — a forward/override modifier may carry a condition
(status code / range / header presence) and/or an ordered modifiers chain where each sees the previous output.
Deterministic fuzzy body matcher (FuzzyBody) — matches when the request body is similar enough to an
expected string by Jaro-Winkler ratio at or above a configurable threshold (a non-LLM similarity match).
Case-sensitive matching opt-in (matchExactCase, default off). When enabled, method, path and regex
string-body matching become case-sensitive; header/cookie/query matching always stays case-insensitive.
Match and verify by negotiated protocol (HTTP/1.1, HTTP/2, HTTP/3). withProtocol(...) on an
expectation or verify(...) matches/asserts on the protocol a request arrived over; the new HTTP_3 value
(experimental) is server-trusted via the h3 ALPN identifier, and protocol now round-trips through
recorded requests.
HTTP response trailers — httpResponse().withTrailers(...) emits protocol-appropriate trailing headers
(chunked + Trailer on HTTP/1.1, a trailing HEADERS frame on HTTP/2/3). gRPC responses are unaffected.
Expectation namespacing / multi-tenancy — an optional namespace field plus a configurable match header
(matchNamespaceHeader, default X-MockServer-Namespace) lets teams share one instance without colliding;
scoped clear/retrieve and Java clearByNamespace/retrieveActiveExpectations(...).
multipart/form-data request-body matching (MultipartBody) — match individual parts by field
name/value, filename and content-type; OpenAPI multipart bodies build field matchers from the schema.
Declarative capture rules and scenario-state templates. A capture rule extracts a value from the
matched request (jsonPath/xpath/header/query/cookie/pathParameter) into scenario state; templates can read
and write scenario state via a scenario helper — enabling auth→resource→confirm journeys.
New response-template helpers — crypto (md5/sha1/sha256/sha512/hmacSha256), regex
(matches/replaceAll/group), html, csv, xpath (XXE-hardened) and yaml, plus jsonPath/xPath
request-body extraction now in the Velocity and JavaScript engines (previously Mustache only).
Proxying, forwarding & recording
Upstream forward retry policy and per-upstream circuit breaker (opt-in, off by default). Retry
re-issues idempotent (GET/HEAD/OPTIONS/PUT/DELETE/TRACE) calls on a connection error or 502/503/504 with
linear back-off; the circuit breaker trips open (fail-fast 503) after N consecutive failures to a host:port, then half-opens. Open upstreams export mock_server_upstream_circuit_open when metrics are on.
Upstream connection pooling (forwardConnectionPoolEnabled, default true). Idle HTTP/1.1 keep-alive
upstream connections are pooled and reused, eliminating per-request TCP/TLS handshakes and the ephemeral-port
exhaustion that caused request errors under sustained forward load (a k6 baseline of 21%/68% errors at
750/1500 rps dropped to ~0%). Safe by default: the forward client runs on its own event-loop group (no
self-deadlock in synchronous local callbacks) and a channel is only pooled when its codec is genuinely
quiescent. Only plain HTTP/1.1 keep-alive is pooled — HTTP/2, HTTP/3, binary, streaming, tunnelled and Connection: close connections always use a fresh connection. Set to false to restore the old behaviour.
One-command record round-trip.GET/PUT /mockserver/retrieve?type=RECORDED_EXPECTATIONS&format=... now
accepts forwardUnmatchedTo=<upstream>, arming record-and-forward of unmatched requests and returning the
recorded expectations (in any supported language/JSON) in one call — removing the multi-step proxy setup.
The upstream is SSRF-validated before any state is mutated.
JSON Patch / JSON Merge Patch on forwarded responses. A response modifier may carry an inline jsonPatch
(RFC 6902) and/or jsonMergePatch (RFC 7386) applied to a forwarded/proxied JSON response body, so one field
of a real upstream response can be changed without replacing the whole body. jsonPatch runs first; a
non-JSON body or failed patch leaves the body unchanged.
Redact secrets in recorded traffic.redactSecretsInRecordedExpectations (off by default) masks
sensitive request headers when recorded expectations are retrieved, generated as code, or persisted; HAR and
Postman imports redact sensitive headers and common secret body fields by default. Redaction preserves times/timeToLive/priority/id so recordings still replay.
Smart deduplication and templatization of recorded traffic. Collapse many recorded requests that differ
only by an id segment (/users/123, /users/456) into one /users/{id} expectation and drop exact
duplicates. With templatizeRecordedValues (opt-in), volatile query/header/JSON-body values (UUIDs, ids,
dates, JWTs, opaque tokens) are also generalized into matchers, while stable values are kept verbatim.
Baseline traffic drift comparison.PUT /mockserver/baseline/compare diffs current recorded
interactions against a saved baseline and returns a structured added/removed/changed report (value-insensitive
JSON-shape comparison), usable from CI.
Verification
Timeout-aware verification (Java client). verify(..., Duration timeout) polls until the verification
passes or times out (for async / fire-and-forget code), and verifyNever(..., Duration window) asserts a
condition stays unmet for the whole window. Implemented client-side; existing snapshot verify(...) is unchanged.
Soft/collecting verification and verify-by-disposition.verifyAll(...) runs every supplied
verification and throws one error listing all mismatches instead of failing on the first. Verification.withDisposition(FORWARDED | MOCKED) narrows a count to requests that were forwarded vs matched
a mock.
Response verification: status-code range / operator matching — a response template may match by class
range (statusCodeRange: "2XX") or operator (">= 400"); verification-only, never written to the wire.
Field-level closest-match diff for failures. When detailedVerificationFailures is enabled (default),
a failed sequence verification — and response verification — now appends a per-step "closest match diff"
naming the fields that differ. Response reason-phrase matching honours matchExactCase, and response cookies
use the same sub-set/notted semantics as the request side. Diagnostic only; pass/fail is unchanged.
OpenAPI & contract testing
Opt-in OpenAPI request validation during mock matching (validateRequestsAgainstOpenApiSpec, off by
default). A request matched by a spec-backed expectation is validated against that spec before the action is
dispatched; a violation is rejected with 400 and an OPENAPI_REQUEST_VALIDATION_FAILED event. Previously
validation only ran on the proxy/forward path.
OpenAPI contract testing endpoint (PUT /mockserver/contractTest). Runs a spec as contract tests against
a live service: builds a representative request per operation, sends it (with the same SSRF protection as
forwarding), validates the response, and returns a pass/fail-per-operation report. Optional operationId
restricts the run.
Enforce OpenAPI response validation for mocks (enforceResponseValidationForMocks, off by default). When
enabled alongside response validation, a mock response that fails validation is replaced with a 502,
matching the proxy-path enforcement; default stays advisory-only.
Pact provider-state preconditions and v3 import. Pact providerState(s) round-trip on import/verify/export
and map onto a MockServer scenario, so an imported interaction only matches once its state is active. PUT /mockserver/import?format=pact (or /pact/import) imports Pact v3 consumer contracts as expectations.
Deterministic OpenAPI example generation — an optional reproducibility seed and per-field value overrides
via a reserved __generationOptions__ entry in the operations map.
Auth in generated Postman & Bruno collections — the collection generator now emits collection-level auth
(bearer / API key / basic from securitySchemes, else a placeholder JWT bearer) with blank placeholder
credentials, so the collections still work against an unauthenticated MockServer.
gRPC & GraphQL
GraphQL and AsyncAPI spec import.PUT /mockserver/graphql imports SDL / introspection and generates
schema-valid expectations per root operation; PUT /mockserver/asyncapi/http turns AsyncAPI channels into
GET expectations serving schema-aware payloads.
GraphQL schema-driven response synthesis. A GraphQL body may carry a schema (SDL or introspection JSON);
MockServer then synthesises a schema-valid {"data": {...}} for a matched query with no hand-authored
response — honouring types, nullability, lists, enums, aliases, __typename, and fragments. Backed by graphql-java (22.x, Java-17-compatible).
gRPC example synthesis from descriptors. A matched gRPC expectation with a successful (grpc-status: 0)
response and no hand-authored body returns a schema-valid example synthesised from the proto descriptor's
response type (scalars, enums, nested/repeated/map fields, oneof, well-known types) instead of an empty
frame. Explicit bodies are never overwritten.
gRPC bidi-stream response templating — a grpcBidiResponse may set templateType (VELOCITY/MUSTACHE)
so its json renders against the matched inbound message.
gRPC Connect protocol (buf.build) unary mocking via ConnectResponse.success(json) / ConnectResponse.error(code, message); real application/grpc traffic is unaffected.
gRPC descriptor management in all clients — upload a compiled descriptor set, list services, and clear,
bringing every client to parity with Java.
Dashboard UI
Performance panel for load scenarios. Author, run, monitor, stop and edit load scenarios from the UI.
A shared named-scenario registry (lifecycle-state badges, multi-select start, per-row edit/start/stop/delete)
sits above two sub-tabs: Run & Monitor (live "Running now" cards, status, the multi-scenario chart and
post-run summary) and Create / Edit (the stage-builder form with generated register-and-start client
code rendered inline below it). The code uses each client's idiomatic load-scenario builders
(loadScenario(...).withProfile(LoadProfile.of(LoadStage.constantVus(...))), etc.) rather than raw JSON —
matching the Mock and Verification code generators — across Java, Node, Python, Go, C#, Ruby and Rust (plus
raw JSON and curl), and regenerates live as you fill in the form. The view follows the task — editing a
scenario switches to Create / Edit, starting a run switches to Run & Monitor. The chart plots every
concurrently-running scenario at once — a
line per scenario plus an aggregate "all scenarios" total — with independent toggles for which metrics to
show (RPS, VUs, in-flight, p50/p95/p99, error rate) and which scenarios to include (all enabled by default).
Each run shows a determinate progress bar (elapsed / total profile duration), green while driving load and
amber while paused.
Contract and Cluster panels.Contract runs an OpenAPI spec against a live service and renders a
pass/fail-per-operation table; Cluster shows state-backend cluster status (node id, coordinator,
members), auto-refreshing.
Monaco code editor for body matchers with syntax highlighting, per-type language modes (JSON, XML,
GraphQL, plaintext) and live JSON / JSON-Schema validation (inline red squiggles before submit). Monaco and
its workers are bundled and served locally (no runtime CDN).
Before→after preview diff when creating or editing a mock — the "Capture as Mock" dialog and the
Composer's Review step show a side-by-side JSON diff of what will be created/changed, via a bundled Monaco JsonDiffViewer.
gRPC services view listing loaded services and methods with per-service health, auto-refreshing.
Scenario state-machine diagram — the selected scenario's states and transitions render as a live Mermaid stateDiagram-v2 with the current state highlighted, built from what the panel observes.
Named-example picker for OpenAPI imports — when a pasted inline spec declares multiple named response
examples, a per-operation dropdown chooses which the generated mock returns (sent as operationsAndResponses).
Set breakpoint from a log row — a log entry's pause action pre-fills a breakpoint matcher from that
request's method and path and jumps to the Breakpoints form.
Duplicate an expectation, plus a priority column — per-row Duplicate opens the Composer with an id-stripped
copy; a P<n> chip and a sortable Priority header show match order.
Usability, responsiveness and new surfaces (an adversarial-review pass): per-row delete/edit of a single
mock; auto-refreshing live panels (Drift, Breakpoints, AsyncAPI, MCP); a Quick/Advanced Composer toggle with
plain-language tooltips; SAML provider mocking; a responsive layout that works on tablet/mobile (collapsing
grid, adaptive "More" navigation, full-screen dialogs); resizable panels; a keyboard-shortcuts help dialog;
baseline-compare; real Mermaid agent-run graphs; and inspect/edit-restart of a running chaos experiment.
Request-log enhancements — timestamps on each entry, regex filtering on method/path with saved named
filter presets, a side-by-side visual diff in "Why didn't this match?", a matcher test playground, and
authoring of capture rules in the Composer.
IDE extensions (VS Code & JetBrains)
Expectation-file schema support.*.mockserver.json(c) files get inline schema validation, autocompletion
and hover docs, driven by the same schema MockServer validates against (generated from mockserver-core).
In-IDE breakpoint debugger over the callback WebSocket — register a matcher, receive paused exchanges, and
Continue / Modify / Abort on requests and responses, including per-frame stream editing. Breakpoints fire only
on traffic through MockServer.
Author, verify and record against a running server — load expectations, save recorded expectations (as
JSON or DSL — record-to-code), generate expectations from an OpenAPI spec, run scratch-request match analysis,
send ad-hoc test requests, view the request log, and reset.
Mock-drift surfacing — a drift report, inline drift diagnostics on the expectation file (VS Code), and a
"update stub to match upstream" quick-fix.
Distributed-trace tooling — Find Requests by Trace (trace id → received requests) and View Trace in Backend
(trace id → open the correlated trace in Jaeger/Tempo/Grafana via a configurable URL template).
LLM authoring and agent-run call graph, an OpenAPI contract-test runner, and WASM module upload/list — in
both extensions.
In-IDE dashboard embedded via JCEF / a webview, with graceful fallback to an external browser.
The Docker image, container name and port are configurable, and the image tag now defaults to the extension's
own version so it can't drift behind the release.
Client libraries
Callbacks across the clients. Class callbacks (httpResponseClassCallback / httpForwardClassCallback)
are now available in Go, .NET, Rust, PHP, Node, Ruby and Python; object/closure callbacks
(mockWithCallback(...), response written in your own language over the callback WebSocket) are in Go, .NET,
Rust, Node and Python. PHP supports class callbacks only (REST-only).
Control-plane auth and TLS/mTLS across the clients. Go, .NET, Rust, PHP, Node and Python clients can now
connect to a secured MockServer — a static or per-request bearer token, a CA certificate to trust the
server's TLS, and a client certificate + key for mutual TLS. Default behaviour is unchanged.
Advanced response builders across the clients. SSE, WebSocket, DNS, binary and gRPC-stream response
builders, OpenAPI import, and verify-zero-interactions are now in the Go, Rust, .NET, PHP and Node clients,
moving them toward parity with Java/Python.
Retrieve expectations as generated client code in every language.retrieve?format=<language> now
produces copy-paste-ready upsert code (and verification code for recorded requests) in Java, JavaScript,
Python, Go, C#, Ruby, Rust and PHP, with correct per-language string escaping; the non-Java clients expose retrieveExpectationsAsCode(format) / retrieveRecordedExpectationsAsCode(format). The dashboard
Library → Export tab offers all eight languages plus a verification-code option.
Client test-framework fixtures and idiomatic auto-cleanup that reset the server between tests — Go
(MockServerT / t.Cleanup), Node (await using via Symbol.asyncDispose), Ruby (RSpec shared context),
.NET (MockServerFixture / IAsyncLifetime), PHP (MockServerTestTrait). A new client_compatibility.html
page documents an 8×8 feature matrix and per-language test-fixture snippets.
Clearer launcher errors — the Go/Node/Python/Ruby/Rust/PHP auto-download launchers detect a 404 on the
release bundle and fail with an actionable message (naming a version that ships bundles, the Docker image, or
the Maven Central jar) instead of a raw 404.
CLI & configuration
--watch live-reload and a mockserver demo subcommand.run --watch live-reloads expectations when
the --init/--openapi file changes (a CLI surface over watchInitializationJson); mockserver demo
starts a server pre-loaded with example expectations and prints getting-started/dashboard URLs and a sample curl.
mockserver import <file> subcommand and client importExpectations(...) — load a JSON expectations file
into an already-running server without restarting it.
Effective-configuration diagnostic — --print-config prints every known property as name = value [source]
(with sensitive values redacted) and exits; the same report is available at runtime from the authenticated GET /mockserver/config.
Readiness endpoint (GET /mockserver/ready) — returns 503 until initializers and OpenAPI seeding
complete, then 200, distinct from the always-200 liveness/status endpoints; the Helm chart now uses it
for the readiness probe.
Fail-fast and typo detection — failOnInitializationError fails startup on a malformed init file instead
of silently continuing with zero expectations, and MockServer now logs a WARN for unrecognised mockserver.* / MOCKSERVER_* keys (e.g. a typo) instead of silently ignoring them.
Graceful shutdown drains in-flight requests — on stop, MockServer waits up to stopDrainMillis
(default 15000) for active requests to complete, avoiding cut connections during rolling restarts.
More configuration properties (matching/proxying, logging, CORS) are editable at runtime from the dashboard
configuration dialog.
WASM custom rules
Richer WASM matcher ABI, authoring SDK, and a test endpoint. A module exporting match_request(ptr, len)
now receives the request method, path and headers (as a JSON envelope) in addition to the body, with
fallback to the legacy body-only match(...). A new dependency-free Rust authoring crate
(mockserver-wasm-sdk) gives typed accessors, and POST /mockserver/wasm/test runs a module against a
sample request and returns { "matched": … } so a module can be validated without creating a live expectation.
Clustering & observability
Cluster status endpoint and metric.GET /mockserver/cluster reports cluster membership/health
(clustered, nodeId, coordinator, clusterName, members), degenerate-but-valid on a single node and
real JGroups membership with the Infinispan backend; a mock_server_cluster_members gauge exports the count.
Drift alerting webhook (driftAlertWebhookEnabled, off by default). Fires a fire-and-forget POST
carrying the drift record whenever a stored drift meets the configured severity threshold, with a
per-signature cooldown. Fully fail-soft — a bad endpoint can never affect drift analysis or the served response.
Control-plane audit logging (controlPlaneAuditEnabled, off by default). An append-only, bounded,
in-memory log of control-plane mutations (who/what/when/where/outcome) recording redacted structural metadata
only — never headers or bodies. Retrieve via GET /mockserver/audit; cleared on reset.
Per-upstream forward/proxy observability — mock_server_forward_request_duration_seconds and mock_server_forward_requests labelled by upstream_host (and status_class), plus server.address/ server.port attributes on the forward span. Host-only labels keep cardinality bounded.
Dropped-log-event visibility — when the event-log ring buffer is full, dropped events are counted and
exported as mock_server_dropped_log_events (previously INFO/DEBUG drops vanished silently), with a single
WARN on the first drop.
Optional per-expectation metrics (perExpectationMetricsEnabled, off by default) — a mock_server_expectation_matched counter labelled by stable expectation id.
Changed
Demo now showcases LLM cost optimisation.npm run demo seeds a crafted seven-call support-agent run
designed to fire all six optimisation signals, so the LLM Optimise tab is populated out of the box. An
optional documented recipe shows how to capture real agent traffic by proxying a headless OpenCode run.
Dashboard navigation. The Optimise tab is renamed LLM Optimise and sits after Chaos; the Sessions tab is renamed Trace and sits after Traffic; the Scenarios state-machine panel moved
from Trace to a tab on the Mocks page. Each tab now shows a one-line description bar, and the Get Started
page leads with the same six features (including LLM Optimise and Performance Testing tiles).
Dashboard visual refresh and scale. A real design system (consistent spacing/shadows/typography,
dark-mode-aware log colours), KPI hero cards and a real time axis on Metrics, skeleton loaders, and humanised
server-error messages. Long lists (Log Messages, Active Expectations, Requests) are now viewport-virtualized
so panels with tens of thousands of entries scroll smoothly, and the dashboard is usable on small screens and
the IDE-embedded view (driven by CSS container queries).
Performance. WASM modules, Mustache templates and OpenAPI schema validators are now parsed/compiled once
and cached (measured ~50–66% less time and allocation on the OpenAPI validation path), and per-request object
churn in the OIDC, SAML and LLM endpoints is reduced. Behaviour and security settings are unchanged.
Faster request matching with many expectations — the incoming request's headers, cookies and query/path
parameters are converted to matcher form once per request and reused across every candidate expectation,
cutting per-request allocations and CPU. Matching behaviour is unchanged.
HttpRequest.withBody((String) null) now leaves the body unset (matching HttpResponse), so getBodyAsString() returns null and the request serializes with no body field. Body matching is
unchanged — a null string body still matches any body. withBody("") is unaffected.
JSON Schema body matching no longer resolves remote $refs (http/https/file/jar/ftp) by default — an
SSRF hardening. Internal/inline refs are unaffected; set jsonSchemaAllowRemoteRefs=true to restore.
Client default MockServer version aligned to the released version across the Node, Rust, Python and PHP
clients, so none defaults to downloading a stale server binary. Several client connection/error-handling
leaks were also fixed (Python/Ruby now always close the HTTP response; the Node client rejects with the real
error message instead of an empty {}).
IDE extension polish — Marketplace-ready icons and landing pages, grouped/iconified actions, a VS Code
Activity Bar side panel and status-bar item, configurable port, and clearer validation warnings before
submitting a file.
Fixed
Correctness & reliability
crossProtocolScenarios was rejected by the expectation schema — present in the model and honoured at
runtime but missing from the validation schema, so any expectation using it was rejected with 400. Added to
the expectation and embedded-OpenAPI schemas.
not(...) expectations now match correctly with fail-fast matching enabled (the default). A negated
matcher could wrongly report a non-match when a non-method field matched before the first mismatching field
(any expectation with an odd number of NOT flags). The fix only short-circuits when no NOT operator is in play
and evaluates all fields otherwise, so the verdict always equals a full evaluation. Affected path, header and body.
Response body matching now has full parity with request body matching. Matching a proxied/forwarded
response body used a stripped-down dispatch missing several behaviours (XML/form→JSON conversion, template
bodies, multipart routing, compressed-byte binary matching) and could swallow an internal NullPointer on a
bodyless response into a silent non-match. Request and response body matching now share a single dispatch;
request matching is unchanged.
Scenario state no longer advances when a matching expectation is skipped by a withPercentage gate
(a consume-then-skip bug); the transition now applies only when the response is actually served, atomically
(compare-and-set) so a clustered backend preserves the "exactly one winner" guarantee.
Configuration round-trip no longer drops properties.ConfigurationDTO mirrored only about half of the
configuration, so many settings (SLO tracking, load generation, drift alerting, HTTP/3, gRPC, DNS, WASM,
clustering, OpenTelemetry, audit, forward pool/retry/circuit-breaker, redaction, and more) were silently lost
when configuration was serialized and reloaded; all are now mirrored, guarded by a reflection-driven test.
Load-injection traffic no longer floods the request log. A running load run filled the bounded event log
and evicted real/LLM traffic (emptying the Traffic/Trace/LLM views); load requests are now kept out of the
driver's event log via an in-process-only flag (gated by loadGenerationSuppressEventLog, default true).
Metrics and SLO samples are unaffected.
Concurrency hardening (code-quality review): thread-safe log timestamps (immutable DateTimeFormatter),
safely-published compiled regexes and lazily-built LLM conversation matchers (volatile), a thread-safe
callback WebSocket registry, exact load-scenario VU accounting, a race-free OIDC device-code poll counter,
atomic SCIM resource updates, gRPC chaos honouring its configured probability, and recycled log entries fully
reset on reuse.
Other correctness fixes — generated curl/Java/HAR output is now correctly escaped; expectation
persistence writes atomically (temp-file + rename); path/matrix parameter names with regex metacharacters
match literally; matchers prefixed with only ?/! no longer throw; VerificationTimes rejects negative
counts; a CONNECT/SOCKS tunnel buffer leak is fixed; one client's reset()/stop() no longer tears down
other clients on the same port; a control-plane body filter no longer matches a request with no body via a
literal "null" (stringification removed); and S3 persistence no longer throws on an empty/missing prefix
listing.
GraalVM Engine leak in the JavaScript template engine — a per-instance native Engine was never closed
and accumulated under per-call construction, exhausting CI forks; it is now a single process-wide shared
engine with a disposing close() on the thread-local context. Output and the Java.type(...) security
boundary are unchanged.
Dashboard favicon.svg (and any SVG) now serves a valid Content-Type: image/svg+xml — the missing svg MIME mapping produced a null header value that crashed Netty's encoder; the mapper now skips
null-valued headers and falls back to application/octet-stream (issue #2358).
mTLS startup with a supplied full-chain certificate on Java 17 — a leaf+CA PEM was appending the CA twice
([leaf, CA, CA]), which Java 17's PKCS12 keystore rejects; the chain is now de-duplicated to [leaf, CA].
Rust client — expectations with a finite times/timeToLive no longer fail with missing field 'unlimited', and VerificationTimes::at_least(n) now serializes the unbounded atMost: -1 sentinel instead
of an impossible between(n, 0).
Dashboard UI
An error boundary keeps the dashboard from crashing to a blank screen when a view fails to load; the Drift
panel surfaces failures instead of reporting false success; the import dialog no longer reports a misleading
"Imported 0 expectations"; the traffic comparison counter/button no longer disagree; non-HTTP expectations no
longer render their id twice; and a "Capture as mock" body matcher can be added when the captured request had
no body. Plus efficiency fixes (single serialization per row on each WebSocket push, memoized traffic rows,
TTL-only countdown timer) and consistent error humanisation.
IDE extensions (VS Code & JetBrains)
The JetBrains plugin is no longer capped to IDE build 253 (untilBuild removed, so it stays available in
current and future IDEs) and no longer risks an AlreadyDisposedException when a project is closed while an
HTTP request is in flight; JetBrains JSON-schema completion/validation for *.mockserver.json(c) now works
in IntelliJ (registered under the correct extension point, with a navigable root and no network schema
fetch). The VS Code extension now activates on onStartupFinished, so the status-bar item and CodeLens
appear immediately on a fresh window.
Request matching & verification
Notted key in MATCHING_KEY mode now asserts key-absence (!X means "no key X present") instead of
aggregating values from every other key.
Closest-expectation diagnostics no longer count non-HTTP fields in the denominator for an HTTP request or
collapse the matched-field count under fail-fast (diagnostic-only).
Faster expectation registration — registering large numbers of expectations on the in-memory backend was
O(n²) (two full reconciliation passes per add); the non-clustered path now does an eviction-only trim,
restoring linear time.
Response-modifier fidelity in codegen — retrieve?format=JAVA now emits a modifier's condition, modifiers, jsonPatch and jsonMergePatch, and the Node responseModifier typedef declares them.
Verification fixes — response verification no longer counts MockServer's own auto-generated no-match 404s; response-aware sequences with mismatched request/response list lengths are rejected instead of padding
with always-matching nulls; an entirely-empty sequence is rejected; a recorded pair with a null request is a
non-match instead of an NPE; failing response-sequence messages now show the responses; and a verification
whose request filter fails to build now completes instead of hanging.
OpenAPI & contract testing
allOf: [ $ref to a scalar ] example generation no longer wraps the scalar in a single-element array
({"baz": ["hello"]} → {"baz": "hello"}), which broke clients typed against the spec (#2357).
OpenAPI handling hardened across both directions (audit follow-up to #2357): range status-code keys
(2XX) no longer crash import and validate correctly; distinct specs sharing an info.title no longer delete
each other's expectations (namespace now keyed by a SHA-256 of the source); expectations→OpenAPI export is
now schema-valid and faithful (path parameters templated, negated/schema matchers preserved, same path+method
responses merged, correct media types); contextPathPrefix is accepted by its schema; pinning an undefined statusCode/exampleName warns and falls back instead of silently returning an empty 200; a webhooks-only
3.1 spec no longer NPEs; and a re-imported URL/file spec now evicts the cache so it picks up current content.
XML response bodies are now real, spec-correct XML for application/xml/text/xml/+xml responses,
serialised using the schema's xml metadata (name/namespace/prefix/attribute/wrapped) per the OpenAPI XML
Object rules, fixing earlier malformed pluralised/recursive output. OAS 3.1 multi-type type arrays are
preserved (["string","null"] → string + nullable). (Behaviour change for XML responses; JSON unchanged.)
OpenAPI example generation honours more JSON-Schema constraints — minItems/maxItems, string pattern, exclusiveMinimum/Maximum, the time format, minProperties, and default/enum on format-less
integer/number schemas. Unconstrained schemas are unchanged.
Build & dependencies
Stop leaking the vulnerable commons-beanutils (GHSA-wxr5-93ph-8wr9 / CVE-2025-48734) to downstream
consumers through velocity-tools-generic — the 1.11.0 pin lived only in dependencyManagement (not
transitive); it is now excluded from velocity-tools-generic and declared directly so the fixed version
propagates (#1981).
Performance under load
CPU no longer climbs as the request/event log fills under /retrieve and clear (issue #2359, a
follow-up to #2329). The read paths ran the expensive request matcher on every log entry — including deleted
tombstones and wrong-type entries — before the cheap type/not-deleted filter, so each /retrieve cost grew
with total log size. The filters are now ordered cheap-predicate-first, and clear skips already-deleted
entries. No behaviour change. Tip for high-throughput users: also clear the log (?type=LOG/ALL or /reset), not just expectations, or lower maxLogEntries.