v4.3.0
Changelog - v4.3.0
All notable changes to the law-scrapper-mcp project for version v4.3.0 will be documented in this file.
The format is based on Keep a Changelog 1.1.0,
and this project adheres to Semantic Versioning 2.0.0.
[4.3.0] - 2026-09-06
Failed content loading now looks like a failure: a transient upstream problem during
get_act_details(load_content=True) used to surface as a successful response with no readable
text, and now fails the call itself. A new regression test also pins the guarantee, introduced
when this project migrated to the official MCP SDK, that any domain exception surfaces as a
protocol error (isError=true) rather than a success body with an embedded error field. Every
error message built from caller-sourced or exception text is now length-bounded.
BREAKING — content loading failures are protocol errors
get_act_details(eli=..., load_content=True) used to return a successful response with
is_loaded=false whenever loading failed — an open circuit breaker, a timeout, an HTTP 5xx
from api.sejm.gov.pl, or a conversion error. The only record of the failure was a server log
line, and the response even hinted at retrying the call that had just failed.
Such calls now fail with isError=true. Clients that treated is_loaded=false as "this act has
no text" must distinguish two cases:
content_status="unavailable"in a successful response — the act permanently has no
readable text; retrying will not change that.isError=true— the upstream is unreachable; retrying later may succeed.
This mirrors the change v3.1.1 made for oversized acts, which shipped as a PATCH; it is a
signalling fix, since the contract always meant "success = content loaded".
Added
content_statusfield onget_act_detailsoutput, with valuesnot_requested,loadedand
unavailable. The field is part of the tool'soutputSchemaand itsstructuredContent.
loadedreflects the final in-memory state rather than this call'sload_contentflag, so an
act loaded by an earlier call reportsloadedeven on a metadata-only call that never asked to
load anything.LAW_MCP_ERROR_MESSAGE_MAX_CHARS(default500, range 80-10000) caps the length of error
messages built from an exception's own text, which can quote caller input of unbounded length.
Truncation is announced in the message rather than silent.- Every tool error message now ends with a fixed one-sentence remediation hint, so a caller can
tell "retry shortly" from "this identifier does not exist" without parsing category names.
Seven categories carry a hint:not_found,validation,precondition,content_too_large,
unavailable,upstream,internal.content_too_large(a refusal because the act is too
large to convert) is split out ofpreconditionrather than sharing its "do a step first"
wording — there is no prior step for an oversized act, and the one actionable remedy (fetch the
source file) is already the last sentence of the body.
Changed
ActService._load_contentno longer swallows exceptions. Transient failures propagate; only a
permanent absence of readable text is handled internally, asContentNotAvailableError— no
HTML or PDF URL at all, a 404 on thetext.htmlortext.pdffetch, or an empty extraction
from either format.- An act with neither an HTML nor a PDF text URL no longer triggers a request that its metadata
already proves pointless. - A permanent absence is remembered for as long as the act's metadata stays cached
(LAW_MCP_CACHE_DETAILS_TTL, default one hour): a repeatedload_content=truecall on such an
act answerscontent_status="unavailable"from memory instead of re-fetchingtext.html/
text.pdf. The removed placeholder document used to play that role by accident; without a
replacement every retry would have costapi.sejm.gov.plone or two requests for an answer that
cannot change before the metadata it was derived from expires. - Hints for an act with no readable content no longer point at
read_act_content,search_in_act
or anotherload_content=truecall; one hint names the source PDF URL when the act has one,
alongside the unrelatedanalyze_act_relationshipshint everyget_act_detailsresponse
already carries. An act with no PDF either gets the same explanatory hint without a URL to
offer, rather than one pointing at a file the server itself declined to fetch. - A message built from an exception's own text now ends in a sentence terminator before the
remediation sentence is appended, unless it already ends in one or ends in a URL — so the two
sentences don't run together, and aContentTooLargeErrormessage can still end on a bare,
unpunctuated PDF URL without a stray period being glued onto it. - The set of error categories treated as caller-sourced — and therefore subject to the length
cap — is nowvalidation,not_found,precondition,content_too_largeandunavailable.
unavailableis included becauseApiUnavailableError's text can embed a rawhttpx
exception, which is not authored by this project even though the category itself is not new.
Removed
- The placeholder documents
*No readable content available for {eli}…*and
*Content extraction failed…*. They were stored in the document store as if they were the act,
madeis_loaded=trueuntrue, and were matched bysearch_in_act.
Fixed
- A failure to load content is no longer indistinguishable from an act without text: a transient
upstream failure now propagates asisError=trueinstead of silently reporting
is_loaded=false. validation,not_found,precondition,content_too_largeandunavailableerror messages
are now length-bounded, so text quoting unbounded caller input or upstream detail cannot fill
the caller's whole context window.