Wednesday, 26 August 2026

Traffic Parrot 5.62.1 released, what's new?

We have just released version 5.62.1. Here is a list of the changes that came with the release:

Features

  • The messaging Add/Edit mapping editors (JMS, native IBM® MQ and file message) now offer the NOT (negate a matcher) request body matcher, as the HTTP and gRPC editors already do. Choosing it in the Request body dropdown replaces the request body field with a NOT child matcher sub-editor where you pick the matcher to negate and type its value, so you can stub "everything except this" without hand-editing the mapping JSON. The child matcher dropdown offers the leaf matchers that can be negated (equalTo, contains, doesNotContain, matches, doesNotMatch, equalToJson, matchesJson, matchesJsonPath, equalToXml, matchesXml and matchesXPath); the SWIFT and FIX field matchers and the JMS-only binaryEqualTo matcher are not offered as children and are still negated by writing the matcher in the mapping JSON. The mapping is saved as a nested "bodyMatcher": {"not": {"contains": "CANCELLED"}}, reopening it restores the body matcher, child matcher and child value into the sub-editor, and the messaging mappings list now shows a composite matcher as a readable one-line summary such as not (contains 'CANCELLED') instead of the raw matcher JSON (matching how the HTTP and gRPC mapping lists and the messaging import preview already render it). The and and or operators are offered in the same dropdown; see Authoring and and or in the messaging editor.
  • The messaging Add/Edit mapping editors (JMS, native IBM® MQ and file message) now also offer the AND (all sub-matchers match) and OR (any sub-matcher matches) request body matchers, so all three logical operators are now offered in the request body matcher dropdown of every mapping editor that has one (see Logical operators). Choosing AND or OR in the Request body dropdown replaces the request body field with a Sub-matchers panel holding two rows, each one a matcher plus the value to match it against. Add sub-matcher appends a row and the bin button on a row removes it, down to the two sub-matchers that and and or need to mean anything. A row's matcher dropdown offers the same leaf matchers as the NOT child matcher dropdown (equalTo, contains, doesNotContain, matches, doesNotMatch, equalToJson, matchesJson, matchesJsonPath, equalToXml, matchesXml and matchesXPath), and a sub-matcher value is a multi-line field, so a multi-line JSON or XML body can be typed or pasted straight into a sub-matcher row and keeps its line breaks when the mapping is saved and reopened. The mapping is saved as "bodyMatcher": {"and": [{"contains": "ORDER-"}, {"doesNotContain": "DRAFT"}]}, reopening it restores one row per sub-matcher in the order it was saved, and the messaging mappings list shows the matcher as a readable one-line summary such as and (contains 'ORDER-', doesNotContain 'DRAFT') instead of the raw matcher JSON.
  • A JMS response body can now be served from a file in the __files directory, the messaging counterpart of an HTTP file-backed response. Set bodyFileName on a JMS mapping's response (a path under __files, resolved against the __files directory beside the mapping's jms-mappings directory, per-scenario for scenario-scoped mappings) in place of an inline text value; the two are mutually exclusive. Setting both, or referencing a file that does not exist, is rejected at load time and the messaging mappings fail to load until it is corrected (the error names the mapping and the missing file). The file's contents are UTF-8 text and are run through the same Handlebars templating as an inline text body, so a body file can reference the incoming request (for example {{request.body}}) and use the response helpers. In the JMS mapping editor a file-backed response shows a read-only Response from file: note and loads the file's contents into the editable response body field; saving writes your edit back to the file and keeps the bodyFileName reference, so the body stays in the file rather than being copied inline. Exporting a scenario bundles the referenced body file, so file-backed JMS mappings round-trip through import and export. File message mappings can reference a response body file in exactly the same way. Native IBM® MQ mappings cannot: bodyFileName is not part of the IBM® MQ response format, so an IBM® MQ response body stays inline. Support for binary (bytes) response bodies read from a file will follow. See Response body from a file on the JMS page.
  • A gRPC request body matcher can now read the value it matches against from an external __files file through a bodyFileName reference: the same file-backed request body matcher already available for HTTP. Traffic Parrot resolves the file when the mapping loads and matches against its contents on replay exactly as it would an inline value, and the gRPC mappings list now shows the resolved file content (or, for a binary file, the matcher and the file path) in the Request message column instead of the raw bodyFileName reference. Editing a file-backed gRPC request matcher from the mapping editor is covered by the Switch to file and Switch to inline entry below.
  • The HTTP and gRPC mappings list now shows the matcher together with the bodyFileName path for a request body matcher whose value is read from a binary file (an image, PDF or other non-text file), for example binaryEqualTo 'payload.png', truncated to fit the column with the full path on hover, instead of a fixed placeholder that read the same for every binary file and so identified none of them. This applies to the HTTP Request body column, the gRPC Request message column and the rows' hover summaries, and it mirrors what the response body column already shows for a binary file-backed response body. Because the mappings list searches the text it displays, a mapping whose request body matcher is backed by a binary file can now also be found by typing the file name into the list search. A request body matcher backed by a text file still shows the file's content inlined, exactly as before.
  • A gRPC request payload can now be moved into, and out of, an external __files file from the mapping editor, rather than only by hand-editing the mapping JSON on disk. Opening a saved gRPC mapping whose request payload is inline shows a Switch to file button beneath the payload field; clicking it reveals a file name field pre-filled with a name derived from the mapping, and Save writes the payload to that file in __files and rewrites the matcher to the bodyFileName reference form. Re-opening the mapping shows a Content from file: note naming the file, loads the file's contents into the payload field so you can edit them in place, and offers Switch to inline to detach the reference and store the payload in the mapping again. A warning is shown when the file is shared with other mappings, because saving changes the request matcher for all of them. This matches what the HTTP editor already did, and the gRPC response body controls. The controls appear only for a mapping that has already been saved, and only for a single in-scope text matcher: a binary matcher or a request with several body patterns stays read-only in the editor, as on the HTTP form. Note that the file name may include forward-slash subdirectories, which resolve under __files, so requests/example.json is saved as __files/requests/example.json - the same as a response body file. A name that would resolve outside __files is rejected.
  • The request body Switch to file and Switch to inline controls in the mapping editor now cover three more request body matchers: matches JSON (matchesJson), matches GraphQL (matchesGraphQL) and matches JSON schema (matchesJsonSchema). Traffic Parrot already matched all three against a value read from an external __files file, but the editor did not offer to move one out to a file, so a large JSON body, GraphQL query or JSON Schema had to be externalised by hand-editing the mapping JSON on disk. This matters most in the gRPC editor, where matches JSON representation (matchesJson) is the matcher gRPC mappings most often use for the request payload. Saving keeps the matcher you chose rather than swapping it for equalToJson, so what the mapping matches is unchanged.
  • The Static Files page is now listed in the gRPC, JMS and Files menus, as it already was in the HTTP menu. All four entries open the same page, because __files is a single directory shared by every protocol within a scenario, so a file there can back a gRPC request payload, a gRPC response, a JMS or file-message response body, or an HTTP response equally. Previously the page could only be reached from the HTTP menu (or from the Manage files link in the gRPC response body area), which was easy to miss when working entirely in another protocol. The WebSocket and IBM® MQ menus deliberately do not carry the entry: those two do not resolve a bodyFileName, so the entry would advertise a capability they do not have.
  • Traffic Parrot now serves a Model Context Protocol (MCP) endpoint, so an AI assistant can connect to a running instance and read what it holds instead of working only from files you paste into the conversation. Traffic Parrot serves it itself, so there is nothing extra to install and no separate process to keep running: it listens on the management port (8080 by default) at /mcp and takes JSON-RPC 2.0 over HTTP POST, at the bare endpoint URL MCP clients are configured with rather than under /api. A connecting client completes the initialize handshake, which negotiates the protocol revision — the client is answered the revision it asked for when that is one Traffic Parrot speaks (2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05 or 2024-10-07), and the newest, 2025-11-25, when it asked for an unknown revision or for none at all — and which reports the instance's own version and its capabilities, and then lists twelve tools. Six only read — list_mappings, get_mapping, list_received_requests, report_coverage, list_scenarios and verify_mapping_matches — covering the mappings being served, the request journal, endpoint coverage, the defined scenarios, and whether received traffic still matches the mappings loaded now. The other six change something: create_mapping, update_mapping and delete_mapping change what the running instance serves and write the change through to the selected scenario's mapping files, so a scenario directory kept in version control will show it as a local change; select_scenario switches which scenario is being served, and so decides what every other tool reads and writes; generate_mappings_from_openapi builds mappings from a specification file already in the instance's OpenAPI directory, writing them through to the scenario's mapping files in the same way; and cleanup_mappings turns a recording into a flexible mock in a new scenario, leaving the recording untouched. Running a tool (tools/call) returns MCP content blocks, and only the advertised tools can be called. Every tool that can lose work takes dryRun, which defaults to true, so a call that does not say otherwise previews the change and tells the assistant how to commit it. A preview changes nothing in Traffic Parrot, but it is not inert: generate_mappings_from_openapi reads the specification file and fetches any externalValue example URL in it during a preview exactly as it does when applying. By default the endpoint accepts requests from the local machine only and needs no token; to reach it from elsewhere — notably Traffic Parrot in a container with a published port — set trafficparrot.mcp.authenticator=BEARER_TOKEN and trafficparrot.mcp.token, and send Authorization: Bearer <token>. Otherwise, anything that can reach the management port can reach this endpoint, so run Traffic Parrot on your own machine or a trusted network. Switching on the web UI login (trafficparrot.gui.security.mode=LOGIN_PROPERTIES) covers /mcp as well, so the client must then also send the HTTP BASIC credentials from trafficparrot.gui.login.properties; that refusal is an HTTP 401 whose JSON-RPC error names the login property and the credentials file, as against the HTTP 403 the MCP authenticator returns.
  • The HTTP Mapping cleanup results now name the mapping directories the cleaned scenario does not carry. Cleanup copies the source scenario's HTTP mappings and its __files directory and nothing else, so any JMS, native IBM® MQ, file message, gRPC or WebSocket mappings the scenario holds stay behind in the source scenario. That has always been the case, and it is deliberate (the cleanup conventions are HTTP conventions and have no meaning for a JMS or a gRPC mapping); what is new is that cleanup now tells you instead of leaving you to notice. A warning panel headed Mappings the cleaned scenario does not serve appears above the result counters with one entry per directory, naming it and the number of files that stayed behind, for example jms-mappings (3 file(s)) - not copied into the cleaned scenario. Nothing is lost: cleanup never modifies the source scenario, and the warning is there so the cleaned scenario is not mistaken for a complete replacement of the recording it came from and the other mappings dropped at the next promotion. Only a directory that actually holds files is listed, so an HTTP-only scenario shows no panel; the count is of files rather than mappings, because one mapping file can hold several mappings. The same list is returned by POST /api/http/cleanup/execute in a new droppedMappingDirectories field, and by the cleanup_mappings MCP tool, whose dryRun preview reports the same entries a real run would. It is a warning rather than an error: the cleanup succeeded and the errors field stays empty. See What the cleaned scenario does not carry.
  • A JMS request body matcher can now read the value it matches against from an external __files file through a bodyFileName reference, the messaging counterpart of the HTTP and gRPC file-backed request matchers. Traffic Parrot resolves the file when the mapping loads and matches against its contents on replay exactly as it would an inline value, so a large expected payload can live in a file beside the mapping instead of inside it. Exporting a scenario bundles the files referenced by request matchers as well as those referenced by response bodies, so a file-backed matcher round-trips through import and export. A bodyFileName is supported only on a matcher at the top level of the request: nesting one inside an and, or or not operator is refused when the mapping loads, with an error naming the mapping and the matcher. Native IBM® MQ and file-message request matchers keep their expected values inline.
  • Traffic Parrot now publishes the JSON Schemas that describe its own mapping formats, served from the management port (8080 by default), so a tool — or an AI coding agent — can fetch them from the very instance it is targeting and check a mapping before loading it. /schemas/index.json is a machine-readable index with one entry per mapping format (HTTP, which also covers gRPC; JMS; native IBM® MQ; and file messages), each carrying that schema's URL, its version, and the directory the format's mapping files live in; the schemas themselves are served beside it, for example /schemas/http-mapping.schema.json. They ship inside Traffic Parrot, so they always describe the version you are actually running. Alongside them, /helper-policy.json publishes the Handlebars helper safety policy: which response-templating helpers are safe to use, and which are denied because they can run arbitrary code (executeProcess and evaluate). trafficparrot validate can enforce that policy as well as the schemas — set trafficparrot.validate.helper.policy.check and validation fails when a mapping uses a denied helper, which is worth switching on for mappings a machine wrote. See Point the agent at the mapping schema.

Documentation

  • Added a Generate mocks with your own AI agent recipe page. It shows how to have your own AI coding agent (Claude Code, Cursor, or any assistant that can fetch a URL and call an HTTP API) write Traffic Parrot mappings for you: ground the agent on the mapping JSON Schema and the helper policy your instance serves, plus your own API contract, have it check the mapping against the schema, then load it through the admin API. The page opens with a Claude Code quick start and a copy-paste starter prompt that runs end to end against the community Train Travel API sample, so you can try it as-is before swapping in your own contract. It also covers running on a trusted network, the Handlebars helper deny-list (helper-policy.json) and its opt-in trafficparrot.validate.helper.policy.check enforcement in trafficparrot validate, and why an API contract handed to a language model is untrusted input. The mapping-creation endpoints it uses are documented in the Management API specification.
  • Expanded the Management API documentation to cover ten more management endpoints: priming an HTTP mapping and downloading a file from the scenario's __files directory, exporting the HTTP mappings, listing the gRPC mappings, and listing, creating, editing and deleting JMS and native IBM® MQ mappings. Each carries its request and response shapes and the status codes it returns, including the HTTP 409 the JMS and native IBM® MQ endpoints return while the virtual service is running — stop it before adding, editing or deleting a mapping. The WireMock-compatible admin API continues to be covered by reference to WireMock's own API documentation rather than restated here, and the raw specification remains available to download.

Fixes

  • Saving a gRPC mapping with an empty or malformed method name (the package.Service/Method value) now reports a clear validation message instead of failing with an internal server error. In the gRPC Add/Edit mapping form an inline message, Enter a fully-qualified gRPC method as package.Service/Method, appears beneath the gRPC method field and blocks the save; the gRPC management API (POST /grpc/management/mapping and PUT /grpc/management/mapping/{id}) returns HTTP 400 with the same message instead of HTTP 500. Previously an empty or malformed method produced a raw HTTP 500 and stack trace. Mappings imported from an exported zip are unchanged.
  • The ActiveMQ internal broker no longer caps the TCP connection handshake allowance at 10 seconds. Traffic Parrot asks for 60 seconds when it connects to the internal broker, but the broker itself had never advertised a matching allowance, and the OpenWire protocol settles on the shorter of the two ends' values — so 10 seconds was always the limit in force, and a connection slow to complete its handshake (a heavily loaded machine, or many connections opening at once) could be dropped with an inactivity error. The broker now advertises the same 60 seconds, so Traffic Parrot's own connections get the allowance they ask for, and an application that configures a longer allowance on its own ActiveMQ client is no longer capped to 10 seconds by the internal broker. An application left on the ActiveMQ client default is unaffected. AMQP connections are unaffected — this applies to the TCP (OpenWire) transport only.
  • The target scenario name given to HTTP mapping cleanup must now be a name inside the instance's scenarios directory. Previously a name that resolved somewhere else — one climbing out of that directory with .., or an absolute path — was accepted, and the cleaned mappings were written to wherever it pointed. Such a name is now refused: the Cleanup page reports Target scenario '…' must be a name inside the scenarios directory instead of running, and POST /api/http/cleanup/execute returns HTTP 400 carrying the same message in its error field, instead of HTTP 200 after writing the mappings. An ordinary scenario name is unaffected and behaves exactly as before.
  • A request body matcher that reads its value from a file (a bodyFileName reference) must now name a file inside the mapping's __files directory. Previously a bodyFileName that resolved outside it, whether by climbing out with .. or by giving an absolute path, was accepted, and Traffic Parrot read that out-of-directory file and matched against its contents. Such a reference is now rejected when the mapping loads. An ordinary bodyFileName under __files is unaffected and behaves exactly as before.
  • Importing a zip of mappings now refuses any entry that would be written outside the directory being imported into. Previously an entry whose path climbed out with .. was extracted to wherever it pointed, so importing a zip from an untrusted source — which the admin GUI allows in a single click — could create or overwrite a file anywhere the Traffic Parrot process could write. Every file written during an import is now checked to be inside the target directory before it is created, and an entry that fails the check stops the import with an error naming it. An ordinary exported zip is unaffected and imports exactly as before.
  • Renaming a scenario now requires both the existing and the new name to be names inside the instance's scenarios directory. Previously a name that climbed out of that directory with .., or gave an absolute path, was accepted and the scenario directory was moved to wherever it pointed. Such a name is now refused, and a rename rejected for this or any other validation reason returns HTTP 412 carrying the reason instead of HTTP 500 and a stack trace. An ordinary scenario name is unaffected.
  • Importing a gRPC skeleton now refuses a file name that would resolve outside the scenario's gRPC mappings directory, instead of writing the generated mapping there.
  • A path that reads as being inside a permitted directory but points outside it through a symbolic link is now refused, where it was previously accepted. This applies wherever Traffic Parrot checks that a path stays inside a directory, including the mapping conflict preview.
  • The in-GUI configuration file editor now refuses a path that belongs to neither of the directories it manages, rather than falling through and editing it anyway.
  • The Static Files page now takes messaging mappings into account when it decides whether a file is still in use. Deleting or renaming a file referenced only by a JMS or file-message mapping was previously allowed without warning, because the check looked at HTTP and gRPC mappings only, and the mapping was left pointing at a file that no longer existed. The orphan badge now counts references from every protocol, so a file shown as orphaned really is unreferenced.
  • Two mappings can no longer be saved under the same mapping file name. A mapping's file is named after the mapping, so saving a second mapping whose name produces a file name already in use previously overwrote the first; such a save is now refused with a message asking you to rename the mapping, on the GUI, the admin API and the MCP tools alike. Mappings you already have are unaffected: importing and starting up are unchanged, so a scenario that already holds two mappings sharing a file name keeps loading exactly as before — what changes is that re-saving one of them from the editor now asks you to rename it first. The two shapes to expect are two mapping names that produce the same file name (orders/new and orders:new both become orders_new.json) and, on Linux, two names differing only in case. Relatedly, resetting the admin API while two mappings already shared a file name returned HTTP 500; it now completes.
  • Three fixes to the log viewer: the line-number gutter stays aligned with wrapped lines instead of drifting out of step with them; a log file with CRLF line endings no longer renders a stray carriage return in every line; and querying the configured log appenders returns an answer instead of throwing, so the viewer can report which files it is reading.
  • Exporting mappings to CSV no longer silently drops a mapping whose request-body matcher reads its expected body from an external file; it is exported with the rest.
  • Generating a mapping from a captured TEXT message that has no body no longer fails with an internal error.
  • Uploading a protoset file no longer poisons later gRPC proto scans: a bad upload is contained to that upload, instead of making every subsequent scan fail until Traffic Parrot is restarted.
  • Switch to file now reports why it cannot externalise a request body it does not support, instead of appearing to work and silently doing nothing.
  • A failed specification import now shows the reason the server gave, instead of the literal text undefined.
  • Importing an OpenAPI specification whose operation declares a response without content — a description but no content block, as is usual for a 204 No Content on a delete — now generates a mapping whose response has no body. Previously the generated response body was the literal text */*, a placeholder that leaked out of the example generator, and the mock then served that text to every matching call. A response that does declare content, including a declared */* media type carrying an example or a schema, is generated exactly as before. Upgrading does not rewrite mappings you already have; the change applies when a specification is imported, so re-importing the same specification regenerates such mappings without the placeholder body.
  • The file messaging page now reports a mappings-load failure instead of waiting indefinitely for mappings that will never arrive.
  • Property values that look like secrets are now redacted in the configuration Traffic Parrot writes to its log at startup, instead of being logged verbatim.

No comments:

Post a Comment