Law Scrapper MCP
A comprehensive legal research tool for accessing and analyzing Polish legal acts from the Sejm API, covering both Dziennik Ustaw (Official Journal of Laws) and Monitor Polski (Polish Monitor).
Search & Discovery - Advanced multi-criteria search by year, title, keywords, document type, effectiveness dates, and active status; browse complete annual collections by publisher with pagination support
Document Analysis - Retrieve full metadata, content (PDF/HTML), hierarchical table of contents, legal relationships (references and amendments), and document lifecycle tracking
Reference Data - Access legal keywords, publishers, document statuses (active/repealed/consolidated), document types (laws/regulations/ordinances), and involved institutions (ministries, authorities, organizations)
Date Utilities - Get current date in legal format (YYYY-MM-DD) and calculate date offsets (days/months/years) for legal periods and deadlines
Utilizes Git version control for repository management and development workflow
Hosted on GitHub for source code management, distribution, and collaborative development
Built using Python programming language with FastMCP framework for MCP server implementation
Displays project status badges for Python version, license, and version information
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Law Scrapper MCPFind recent regulations about data protection from the last 2 years"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Law Scrapper MCP
A comprehensive Model Context Protocol (MCP) server for accessing and analyzing Polish legal acts from the Sejm API, enabling AI-powered legal research and document analysis.
Features
Comprehensive legal act access - Full access to Polish legal acts from Dziennik Ustaw (DU) and Monitor Polski (MP)
Advanced search and filtering - Multi-criteria search by date, type, keywords, publisher, and status
Result Store with chained filtering - Store search results and filter with regex, type/status/year match, date ranges, sorting
Document Store pattern - Load acts into memory for efficient section-level navigation and search
Detailed document analysis - Metadata, structure, references, and content retrieval
Content processing - Automatic PDF-to-text and HTML-to-Markdown conversion
Date calculations - Specialized date utilities for legal document analysis
System metadata - Keywords, statuses, document types, and institution data
Official MCP SDK - Built with
mcp[cli]==2.0.0andMCPServer; STDIO and stateless Streamable HTTP transportsAsync HTTP client - Efficient httpx client with retry logic and connection pooling
TTL caching - Intelligent response caching with configurable TTL
Structured logging - JSON and text log formats for easy debugging
Docker support - Containerized deployment with docker-compose
Comprehensive documentation - Examples and clear parameter descriptions
Related MCP server: Slov-Lex MCP Server
Requirements
Python: 3.13 or higher
Package manager: uv (recommended) or pip
Internet connection: Required for accessing Sejm API endpoints
MCP-compatible tool: Cursor IDE, Claude Code, or other MCP clients
Installation
Using uv (recommended)
# Clone the repository
git clone https://github.com/numikel/law-scrapper-mcp.git
cd law-scrapper-mcp
# Install dependencies
uv sync
# Install with dev dependencies
uv sync --extra devUsing pip
# Clone the repository
git clone https://github.com/numikel/law-scrapper-mcp.git
cd law-scrapper-mcp
# Install dependencies
pip install -e .Using uvx (no installation required)
For quick testing without cloning the repository:
# Run the server directly from GitHub
uvx --from git+https://github.com/numikel/law-scrapper-mcp law-scrapperQuick start
STDIO transport (default)
STDIO is the default transport for MCP communication. Start the server and connect from your MCP client:
# Run the server
uv run python -m law_scrapper_mcp
# Or use the installed script
law-scrapperConfigure in your MCP client (e.g., Cursor .cursor/mcp.json):
{
"mcpServers": {
"law-scrapper-mcp": {
"command": "law-scrapper"
}
}
}For Claude Code:
claude mcp add law-scrapper "uvx --from git+https://github.com/numikel/law-scrapper-mcp law-scrapper"HTTP transport (streamable-http)
Run the server on HTTP with streamable-http transport:
# Run with HTTP transport on port 7683
LAW_MCP_TRANSPORT=streamable-http uv run python -m law_scrapper_mcp
# Or specify a custom port (the host stays on loopback unless you configure
# an authentication mode — see "Authenticated remote deployment" below)
LAW_MCP_TRANSPORT=streamable-http LAW_MCP_PORT=8080 uv run python -m law_scrapper_mcpConfigure in your MCP client:
{
"mcpServers": {
"law-scrapper-mcp": {
"url": "http://localhost:7683/mcp",
"transport": "streamable-http"
}
}
}Note: The URL must include the /mcp path. The server exposes stateless Streamable HTTP at /mcp, not at the root. Using http://localhost:7683 without /mcp results in 404 (Not Found).
Docker
Build and run with Docker:
# Build the image
docker build -t law-scrapper-mcp .
# Run with STDIO transport (default)
docker run -it law-scrapper-mcp
# Run with HTTP transport on port 7683
docker run -it -p 7683:7683 -e LAW_MCP_TRANSPORT=streamable-http law-scrapper-mcpOr use docker-compose:
# Run with STDIO transport
docker compose up
# Run with HTTP transport (set TRANSPORT=streamable-http in docker-compose.yml)
docker compose -f docker-compose.yml upCI builds this image and smoke-tests both transports (/health over streamable-http, one initialize over STDIO) on every code change, so a Dockerfile that no longer builds fails the pull request rather than a downstream registry.
Configuration
All settings are configured via environment variables with the LAW_MCP_ prefix:
The list-valued settings — LAW_MCP_ALLOWED_HOSTS, LAW_MCP_ALLOWED_ORIGINS,
LAW_MCP_TRUSTED_PROXIES, LAW_MCP_AUTH_REQUIRED_SCOPES and
LAW_MCP_AUTH_ALGORITHMS — accept either a comma-separated value
(a:*, b:*, the form used throughout this document) or a JSON array
(["a:*", "b:*"]). Both are equivalent; surrounding whitespace is trimmed.
Variable | Default | Description |
|
| Transport: |
|
| HTTP server host (when using streamable-http). Binding beyond loopback requires |
|
| HTTP server port (when using streamable-http) |
|
| Graceful shutdown window in whole seconds for the HTTP server (a fractional value is rejected at startup rather than silently rounded). Keep |
|
| HTTP request timeout in seconds |
|
| Concurrent light API requests (JSON metadata and search) |
|
| Concurrent heavy API requests (act HTML and PDF downloads) |
|
| Sustained outbound request rate towards the Sejm API; accepted range |
|
| Requests allowed back-to-back before the rate applies; accepted range |
|
| Longest pause, in seconds, that a |
|
| Attempts per operation, retries included; accepted range |
|
| Seconds the retry sequence of one operation may plan to wait |
|
| Metadata cache TTL (24 hours) |
|
| Search results cache TTL (10 minutes) |
|
| Browse results cache TTL (1 hour) |
|
| Act details cache TTL (1 hour) |
|
| Changes tracking cache TTL (5 minutes) |
|
| Maximum cache entries |
|
| Maximum documents in Document Store |
|
| Maximum Document Store size (5 MB). Also the conversion threshold: content whose HTML or PDF payload exceeds it is refused with an error naming the source PDF URL — the download is aborted as soon as the body passes the limit (or earlier, from |
|
| Document Store TTL (2 hours) |
|
| Failures before circuit breaker opens |
|
| Seconds before trying recovery |
|
| Test calls in half-open state |
|
| Max |
|
| Max records |
|
|
|
|
|
|
| unset | Override the JWKS URI discovered from |
|
| Scopes a presented token must carry, checked by |
|
| JWT signature algorithm allowlist passed to the decoder; never read from the token header |
|
| Seconds a fetched JWKS key set is cached before re-fetching |
|
| Whether the per-client rate limiter wraps the HTTP app. |
|
| Requests allowed per |
|
| Rate limit window in seconds |
|
| Token bucket capacity — how many requests can arrive back-to-back before |
|
| Log level: |
|
| Log format: |
Logs go to stderr (stdout carries the MCP protocol on the STDIO transport). Every record carries a request_id correlating it with a single tool call — lifespan for records emitted outside one:
2026-08-24 12:00:00,123 - law_scrapper_mcp.tools.search - [a1b2c3d4] - INFO - Stored result set rs_1: 20 results (total 137){"timestamp": "2026-08-24T10:00:00.123456+00:00", "level": "INFO", "logger": "law_scrapper_mcp.tools.search", "request_id": "a1b2c3d4", "message": "Stored result set rs_1: 20 results (total 137)"}Set LAW_MCP_LOG_LEVEL=DEBUG to recover the detail deliberately kept off INFO: search query text and the exception messages behind validation and upstream failures.
Example environment configuration:
export LAW_MCP_TRANSPORT=streamable-http
export LAW_MCP_PORT=7683
export LAW_MCP_LOG_LEVEL=DEBUG
export LAW_MCP_CACHE_METADATA_TTL=86400Authenticated remote deployment
The HTTP transport binds 127.0.0.1 by default and refuses to start on any
other address unless an authentication mode is configured. Two modes exist and
neither falls back to the other.
Bearer token — local and simple deployments:
export LAW_MCP_AUTH_TOKEN=$(openssl rand -base64 32) # min. 32 bytes
LAW_MCP_TRANSPORT=streamable-http \
LAW_MCP_HOST=0.0.0.0 \
LAW_MCP_AUTH_MODE=bearer \
law-scrapperIn production prefer LAW_MCP_AUTH_TOKEN_FILE=/run/secrets/law_mcp_token —
an environment variable is visible in docker inspect and /proc/<pid>/environ.
Setting both sources is a startup error, not a precedence rule.
OAuth 2.1 / OIDC — corporate deployments. Works with any provider publishing OIDC discovery and JWKS:
Provider |
|
Microsoft Entra ID |
|
| |
AWS Cognito |
|
Okta |
|
Auth0 |
|
LAW_MCP_AUTH_MODE=oauth \
LAW_MCP_AUTH_ISSUER=https://login.microsoftonline.com/<tenant>/v2.0 \
LAW_MCP_AUTH_AUDIENCE=api://law-scrapper \
LAW_MCP_AUTH_RESOURCE_SERVER_URL=https://mcp.example.com/mcp \
law-scrapperReachable through a reverse proxy — LAW_MCP_ALLOWED_HOSTS and
LAW_MCP_ALLOWED_ORIGINS default to loopback-only (F18): a request whose
Host or Origin header doesn't match gets 421/403 from the SDK's
DNS-rebinding protection, even with a valid token. This default is
deliberate — widening the allowlist is only permitted once an auth mode is
configured (enforced at startup, D6). A reverse proxy that preserves the
original Host (nginx's proxy_set_header Host $host, Caddy's default)
needs both variables set to the public name, for either auth mode above:
LAW_MCP_ALLOWED_HOSTS='mcp.example.com:*' \
LAW_MCP_ALLOWED_ORIGINS='https://mcp.example.com' \
law-scrapperProviders issuing opaque tokens (GitHub) are not supported — they would require
RFC 7662 introspection. TLS termination stays with the reverse proxy.
/health is intentionally unauthenticated so container healthchecks work; it
exposes the server version and circuit-breaker state. It is exempt from the
rate limiter only for loopback peers — a probe arriving from another host is
metered like any other request.
Rate limiting is always on for HTTP: 60 requests per 60 s, burst 10.
Behind a proxy, set LAW_MCP_TRUSTED_PROXIES (addresses or CIDRs) — otherwise
X-Forwarded-For is ignored and every client shares one bucket.
Tools reference
Law Scrapper MCP provides 13 tools for legal research and analysis:
1. get_system_metadata(category)
Retrieve system metadata for filtering and searching legal acts.
Parameters:
category(string, default: "all") - Metadata category: "keywords", "publishers", "statuses", "types", "institutions", or "all"
Returns: Keywords, publishers, document types, statuses, and institutions available in the system
Examples:
- Get all available search keywords
- Retrieve all legal document types
- List all publishers (DU, MP)
- Get all document statuses
- Get complete system metadata2. search_legal_acts(publisher, year, keywords, detail_level, status, type)
Search for legal acts with advanced filtering options.
Parameters:
publisher(string) - Publisher code: "DU" (Dziennik Ustaw) or "MP" (Monitor Polski)year(integer) - Publication year (e.g., 2024)keywords(string) - Search keywords (AND logic - use multiple searches for OR)detail_level(string, default: "standard") - Response detail: "minimal", "standard", or "full"status(string, optional) - Document status filtertype(string, optional) - Document type filter
Returns: List of matching legal acts with metadata
Search note: Multiple keywords use AND logic. Search one keyword at a time for OR behavior.
Examples:
- Search DU 2024 for "environment protection" acts
- Find all MP 2023 acts with status "active"
- Search for COVID-19 related legislation
- Find acts by specific type (e.g., "regulation")
- Get minimal detail results for quick scanning3. browse_acts(publisher, year, detail_level)
Browse all legal acts published in a specific year by publisher.
Parameters:
publisher(string) - Publisher code: "DU" or "MP"year(integer) - Publication yeardetail_level(string, default: "standard") - Response detail: "minimal", "standard", or "full"
Returns: Complete list of acts published in the specified year
Examples:
- Browse all DU acts from 2024
- Get minimal details of all MP acts from 2023
- Browse full details of DU 2022 legislation
- Get an overview of acts by publisher and year
- Track legislation published in a specific year4. filter_results(result_set_id, pattern, field, type_equals, ...)
Filter and narrow down previously retrieved search/browse/changes results.
Parameters:
result_set_id(string) - Result set ID from a previous search/browse/changes call (e.g., "rs_1")pattern(string, optional) - Regex pattern for text search (supports OR: "podatek|VAT|akcyza")field(string, default: "title") - Field to search: "title", "eli", "status", "type", "publisher"type_equals(string, optional) - Exact match on document type (e.g., "Ustawa", "Rozporządzenie")status_equals(string, optional) - Exact match on status (e.g., "akt obowiązujący", "akt uchylony")year_equals(integer, optional) - Exact match on publication yeardate_field(string, optional) - Date field for range filter: "promulgation_date" or "effective_date"date_from/date_to(string, optional) - Date range (YYYY-MM-DD)sort_by(string, optional) - Sort field: "title", "year", "pos", "promulgation_date", etc.sort_desc(boolean, default: false) - Sort descendinglimit(integer, optional) - Maximum results to return
Returns: Filtered results with a new result_set_id for chained filtering
Examples:
- Filter search results to only "Rozporządzenie" type
- Search titles with regex "zdrow|apteka|lekar"
- Filter by date range and sort by promulgation date
- Chain filters: first by type, then by regex pattern
- Get top 10 most recent resultsResult-set scope. Every stored result set declares whether it is the whole answer
(complete) or a window cut from a larger corpus (page), in the result_set_scope field
of the response and in list_result_sets. The distinction matters because filter_results
narrows the set, not the query: an empty filter over a page set means "no match among
these twenty records", not "no such act exists". Responses say so explicitly — a filter that
matches nothing over a window sets no_match_is_inconclusive. track_legal_changes is the
one tool whose set is always complete, because it stores the whole fetched range.
5. get_act_details(eli, load_content, detail_level)
Retrieve detailed information about a specific legal act and optionally load its content.
Parameters:
eli(string) - Act identifier in format "PUBLISHER/YEAR/NUMBER" (e.g., "DU/2024/1")load_content(boolean, default: false) - Load act content into Document Store for section readingdetail_level(string, default: "standard") - Response detail: "minimal", "standard", or "full"
Returns: Act metadata (title, publication date, status, type, etc.), table of contents if load_content=true
Examples:
- Get metadata for act DU/2024/1
- Load act content for section-level reading
- Get full details including table of contents
- Retrieve act status and publication information
- Load multiple acts for comparison6. read_act_content(eli, section)
Read content from a specific section of a loaded legal act.
Parameters:
eli(string) - Act identifier (must be loaded first via get_act_details with load_content=true)section(string) - Section to read (e.g., "Art. 1", "Chapter 2", "Preamble")
Returns: Content of the requested section
Workflow note: Must call get_act_details(eli="...", load_content=true) first, then use this tool.
Examples:
- Read Article 1 from loaded act
- Get Chapter 2 content
- Read the Preamble section
- Access specific numbered articles
- Navigate act by chapters7. search_in_act(eli, query)
Search for specific terms within a loaded legal act.
Parameters:
eli(string) - Act identifier (must be loaded first via get_act_details with load_content=true)query(string) - Search term or phrase
Returns: Matching sections with context and location
Examples:
- Find all mentions of "penalty" in loaded act
- Search for specific legal terms
- Locate articles containing "fine" or "punishment"
- Find definitional sections
- Search for specific references8. analyze_act_relationships(eli, relationship_type)
Analyze legal relationships and references of an act (amendments, references, etc.).
Parameters:
eli(string) - Act identifierrelationship_type(string, default: "all") - Type: "amends", "amended_by", "references", "referenced_by", or "all"
Returns: List of related acts and their relationships
Examples:
- Find which acts amend this legislation
- See what acts this legislation amends
- Get all legal references in the act
- Find acts that reference this legislation
- Analyze complete act relationship network9. track_legal_changes(date_from, date_to, publisher, keywords)
Track legal changes and new acts within a date range.
Parameters:
date_from(string) - Start date (YYYY-MM-DD format)date_to(string) - End date (YYYY-MM-DD format)publisher(string, optional) - Filter by publisher: "DU" or "MP"keywords(string, optional) - Filter by keywords
Returns: Legal acts published in the date range
Examples:
- Track changes from 2024-01-01 to 2024-12-31
- Find new DU acts from last month
- Get changes published in past 7 days
- Track legislation on specific topics over time
- Monitor legal changes by publisher and date range10. calculate_legal_date(days, months, years, base_date)
Calculate legal dates with intuitive sign convention.
Parameters:
days(integer, default: 0) - Days offset (+future, -past)months(integer, default: 0) - Months offset (+future, -past)years(integer, default: 0) - Years offset (+future, -past)base_date(string, optional) - Base date (YYYY, YYYY-MM, or YYYY-MM-DD format, defaults to today)
Returns: Calculated date and relative description
Sign convention: Positive = future, Negative = past
Examples:
- Get current date (call with no parameters)
- Calculate date 30 days in the future (+30)
- Calculate date 6 months in the past (-6 months)
- Calculate date 1 year from a specific date
- Calculate legal deadlines and periods11. compare_acts(eli_a, eli_b)
Compare metadata of two legal acts.
Parameters:
eli_a(string) - ELI identifier of the first act (e.g., "DU/2024/1692")eli_b(string) - ELI identifier of the second act (e.g., "DU/2024/1716")
Returns: Comparison of titles, types, statuses, dates, keywords overlap and differences
Examples:
- Compare two acts from the same year
- Compare old and new versions of legislation
- Identify metadata differences between related acts12. list_result_sets()
Display active result sets stored in memory.
Returns: List of result sets with IDs, query summaries, counts, and creation times
13. list_loaded_documents()
Display documents loaded into the Document Store.
Returns: List of loaded documents with ELIs, sizes, section counts, and timestamps
Document Store workflow
The Document Store pattern enables efficient content navigation and search within legal acts:
Workflow steps
Load an act - Call
get_act_details(eli="DU/2024/1", load_content=true)to load the act into the Document StoreRead sections - Use
read_act_content(eli="DU/2024/1", section="Art. 1")to read specific sectionsSearch within act - Use
search_in_act(eli="DU/2024/1", query="penalty")to find terms
Benefits
Efficient memory usage (configurable max documents and TTL)
Fast section-level navigation without refetching
Search within loaded acts without API calls
Automatic content processing (PDF→text, HTML→Markdown)
Configuration
LAW_MCP_DOC_STORE_MAX_DOCUMENTS- How many acts to keep in memory (default: 10)LAW_MCP_DOC_STORE_MAX_SIZE_BYTES- Maximum memory usage (default: 5 MB)LAW_MCP_DOC_STORE_TTL- How long to keep acts in memory (default: 2 hours)
Project structure
law-scrapper-mcp/
├── src/law_scrapper_mcp/
│ ├── __init__.py
│ ├── __main__.py # Entry point for python -m
│ ├── server.py # MCPServer, lifespan, transport config
│ ├── config.py # Pydantic settings (env vars)
│ ├── logging_config.py # Structured logging setup
│ ├── models/ # Pydantic models
│ │ ├── enums.py # Enumerations
│ │ ├── api_responses.py # Sejm API response models
│ │ ├── tool_inputs.py # Tool input models
│ │ └── tool_outputs.py # Tool output models
│ ├── client/ # HTTP client
│ │ ├── sejm_client.py # AsyncClient with retry and circuit breaker
│ │ ├── cache.py # Async TTL cache implementation
│ │ ├── circuit_breaker.py # Circuit breaker for API protection
│ │ └── exceptions.py # Custom exceptions (Polish messages)
│ ├── services/ # Business logic
│ │ ├── metadata_service.py # Metadata retrieval
│ │ ├── search_service.py # Search and browse
│ │ ├── act_service.py # Act details and content
│ │ ├── changes_service.py # Change tracking
│ │ ├── document_store.py # In-memory act storage
│ │ ├── result_store.py # Search result persistence and filtering
│ │ ├── content_processor.py # PDF/HTML processing
│ │ └── response_enrichment.py # Response hints
│ └── tools/ # MCP tool definitions
│ ├── metadata.py # get_system_metadata
│ ├── search.py # search_legal_acts
│ ├── browse.py # browse_acts
│ ├── act_details.py # get_act_details
│ ├── act_content.py # read_act_content
│ ├── act_search.py # search_in_act
│ ├── relationships.py # analyze_act_relationships
│ ├── filter_results.py # filter_results, list_result_sets
│ ├── changes.py # track_legal_changes
│ ├── compare.py # compare_acts
│ ├── dates.py # calculate_legal_date
│ └── error_handling.py # Centralized @handle_tool_errors decorator
├── tests/
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests with Sejm API
├── Dockerfile # Container image definition
├── docker-compose.yml # Multi-service setup
├── pyproject.toml # Project metadata and dependencies
├── uv.lock # Reproducible dependency lock
└── README.md # This fileDocker
Security and deployment
The server binds 127.0.0.1 by default; binding beyond loopback (as Docker port publishing requires) fails at startup unless an authentication mode is configured — see "Authenticated remote deployment" above. When exposing the HTTP transport (streamable-http) to a network, place the server behind a reverse proxy (nginx, Caddy, Traefik) with TLS termination — this project verifies bearer tokens and OAuth 2.1/OIDC access tokens, but does not terminate TLS itself. The /health endpoint is unauthenticated and intended for container healthchecks only — do not expose it publicly without access controls. Dependency versions are pinned in uv.lock with security overrides in pyproject.toml (cryptography, urllib3, idna, werkzeug, requests).
Host/Origin allowlist (DNS-rebinding protection): the official MCP SDK only auto-enables Host/Origin validation when the server binds to a literal loopback address (127.0.0.1, localhost, ::1). docker-compose.yml sets LAW_MCP_HOST=0.0.0.0 so Docker can publish the port, which would otherwise leave that validation disabled. server.py passes transport_security explicitly (build_transport_security()) so requests are still validated against the configured allowlist — Host outside it gets 421, Origin outside it gets 403 — independent of the bind address. The allowlist defaults to loopback only (127.0.0.1:* / localhost:* / [::1]:* and the matching http:// origins) and is widened through LAW_MCP_ALLOWED_HOSTS / LAW_MCP_ALLOWED_ORIGINS, which startup validation permits only once an authentication mode is configured. This restores the pre-3.0.0 FastMCP posture for /mcp. It is a defense-in-depth layer, not a substitute for the authentication mode required to bind beyond loopback in the first place.
One deliberate difference from the pre-3.0.0 server: the SDK applies this validation inside the Streamable HTTP app, not as whole-app middleware, so /health is not covered by the allowlist and answers any Host. That is what keeps container healthchecks working when they connect by container name or bridge IP, but it also means /health discloses the server name and version — and, since it now also reports the circuit breaker's circuit_state and failure_count, the health of the Sejm API integration — to anything that can reach the published port. FastMCP guarded /health too. Restrict the published port, or front it with a proxy, if that disclosure matters to you.
Health contract: the response body carries an upstream object. upstream.circuit_state is closed, open, half_open, or unknown before the lifespan has started (or after it has been torn down) — in that unknown case upstream.failure_count is omitted entirely; otherwise it sits alongside circuit_state. /health still answers 200 while the breaker is open: restarting the container cannot repair an outage of api.sejm.gov.pl, and under restart: unless-stopped a 503 would turn someone else's outage into a restart loop.
Dockerfile
The included Dockerfile builds a containerized Law Scrapper MCP server:
FROM python:3.13-slim
WORKDIR /app
COPY . .
RUN pip install -e .
EXPOSE 7683
CMD ["law-scrapper"]Build and run:
# Build the image
docker build -t law-scrapper-mcp .
# Run with STDIO transport
docker run -it law-scrapper-mcp
# Run with HTTP transport, published on the host — the image no longer
# defaults LAW_MCP_HOST to 0.0.0.0, so publishing the port beyond loopback
# requires setting the host explicitly together with an authentication mode
docker run -it -p 7683:7683 \
-e LAW_MCP_TRANSPORT=streamable-http \
-e LAW_MCP_HOST=0.0.0.0 \
-e LAW_MCP_AUTH_MODE=bearer \
-e LAW_MCP_AUTH_TOKEN="$(openssl rand -base64 32)" \
-e LAW_MCP_LOG_LEVEL=DEBUG \
law-scrapper-mcpdocker-compose.yml
Deployment with docker-compose:
# LAW_MCP_AUTH_TOKEN is required — docker-compose.yml fails fast without it
export LAW_MCP_AUTH_TOKEN=$(openssl rand -base64 32)
# Start service
docker compose up -d
# View logs
docker compose logs -f
# Stop service
docker compose downMigration guide (v1 to v2)
If upgrading from v1.0.2, note these breaking changes:
v1.0.2 (old) | v2.0.0 (new) | Notes |
|
| Call with no parameters for current date |
|
| Use intuitive +future/-past sign convention |
|
| Consolidated into one tool |
|
| Consolidated into one tool |
|
| Consolidated into one tool |
|
| Consolidated into one tool |
|
| Consolidated into one tool |
| N/A | Use |
|
| Enhanced with |
|
| Renamed for clarity |
|
| Added |
|
| Requires pre-loading with |
|
| TOC included in details response |
|
| Renamed for clarity |
ELI format | Single string "DU/2024/1" | Changed from separate parameters |
Legacy event-stream transport | STDIO (default) | STDIO is default, HTTP via streamable-http |
Port 7683 | Port 7683 | Same default HTTP port |
What's new in v3.0.0
Official Python MCP SDK — Replaced the prior third-party framework with
mcp[cli]==2.0.0andMCPServer[AppContext]Native structured responses — Tools return
EnrichedResponsewithoutputSchemaand objectstructuredContent(no JSON strings)Protocol-visible errors — Tool failures surface as
isError=trueinstead of in-bodyerrorfieldsStateless Streamable HTTP —
/mcpendpoint only; legacy event-stream transport removedPagination —
PageInfomodel exposed as thepage_infofield withlimit/offseton search, browse, metadata, changes, TOC, sections, and in-act searchTyped
AppContext— Lifespan resources accessed viactx.request_context.lifespan_contextDomain services —
ComparisonService,RelationshipService, andDateServiceextracted from tool adaptersTransport tests — Real STDIO subprocess, loopback HTTP, and MCP conformance in CI
Explicit Host/Origin allowlist on HTTP —
transport_securityis passed explicitly so DNS-rebinding protection applies regardless of the configured bind host; see Security and deployment
Migration guide (v2 to v3)
v2.x (old) | v3.0.0 (new) | Notes |
|
| Parse native MCP structured payload |
|
| Check |
v2.x in-process client | Official | In-memory and transport tests use SDK client |
v2.x direct lifespan access |
| Typed |
Legacy event-stream transport | Removed | STDIO or stateless Streamable HTTP only |
What's new in v2.4.0
Security hardening — Framework upgrade and dependency overrides close 51 Dependabot alerts (cryptography, urllib3, pillow, starlette, and others)
Framework 3.x — Lifespan context API,
app.run()for HTTP transport,@custom_routefor/healthIntegration tests — In-memory client tests for core tools (metadata, search, dates, act details)
CI and Dependabot — Automated quality gates and weekly dependency updates
What's new in v2.3.1
uvx / tool registration fix — Fixed
NameError: name 'Annotated' is not definedwhen running viauvx --from "git+https://github.com/numikel/law-scrapper-mcp" law-scrapper. Removedfrom __future__ import annotationsfromcompare.pyso parameter type hints resolve correctly during tool registration.
What's new in v2.3.0
3 new tools —
compare_acts,list_result_sets,list_loaded_documents(total: 13 tools)Circuit breaker — Protects against cascading failures when Sejm API is unavailable
Centralized error handling —
@handle_tool_errorsdecorator with error classification and full tracebacksasyncio.Lock migration — All stores use
asyncio.Lockfor proper async compatibilityDefault search limit — Search/browse return max 20 results by default to limit token usage
Health endpoint —
/healthfor Docker deployments with streamable-http transportPolish error messages — All exception messages in Polish for consistent user experience
Decision tree docstrings — "When to use" / "When NOT to use" for all tools
Development
Setup
# Install dependencies
uv sync
# Install with dev dependencies
uv sync --extra devRunning tests
# Run unit tests
uv run pytest tests/unit/ -v
# Run integration tests (mocked Sejm API via respx; no live network required)
uv run pytest tests/integration/ -v -m integration
# Run all tests with coverage
uv run pytest --cov=law_scrapper_mcp --cov-report=term-missing
# Run with timeout for slow tests
uv run pytest --timeout=10 -vMCP integration testing
Law Scrapper MCP uses three automated test layers to verify all 13 tools and their MCP protocol interaction:
Layer 1 — unit tests (tests/unit/):
uv run pytest tests/unit/ -vLayer 2 — in-memory integration (official mcp.Client, mocked Sejm API via respx):
uv run pytest tests/integration/test_tools_e2e.py \
tests/integration/test_content_pagination.py \
tests/integration/test_result_pagination.py -v -m integrationLayer 3 — transport integration (real STDIO subprocess and loopback Streamable HTTP):
uv run pytest tests/integration/test_stdio_transport.py \
tests/integration/test_http_transport.py -v -m integrationFull integration suite:
uv run pytest tests/integration/ -v -m integrationWhat the tests verify:
All 13 tools registered with preserved public arguments
Native
structuredContentpayloads withoutputSchema(not JSON strings)isError=trueon tool execution failurespage_info(PageInfo) pagination metadata on paginated outputsStateful workflows: search → filter → load act → read sections → search in content
Real STDIO and HTTP transports against a running server process
Architecture:
Test framework: pytest with asyncio (unit) and anyio (MCP client tests)
HTTP mocking: respx intercepts httpx calls in in-memory integration tests
MCP protocol: Official
mcp.Clientfrom the Python MCP SDKHelpers:
tests/mcp_helpers.py(parse_tool_resultforstructuredContentassertions)CI: Legacy dependency gate, protocol transport tests, and MCP conformance against
/mcp
See tests/TEST_SUITE_SUMMARY.md for the full file layout and patterns.
Code quality
The project follows MCP SDK best practices:
Modular architecture - Separated concerns (models, client, services, tools)
Type hints - Full type annotation with Pydantic models
Async throughout - Async/await for all I/O operations
Comprehensive examples - Minimum 5 examples per tool
Tagged tools - Organized by category for easy discovery
Annotated parameters - Clear descriptions for all inputs
Structured logging - Configurable JSON/text formats
Running the server
# STDIO transport (default)
uv run python -m law_scrapper_mcp
# HTTP transport
LAW_MCP_TRANSPORT=streamable-http uv run python -m law_scrapper_mcp
# With debug logging
LAW_MCP_LOG_LEVEL=DEBUG uv run python -m law_scrapper_mcpContributing
Fork the repository
Create your feature branch (
git checkout -b feature/amazing-feature)Commit your changes using Conventional Commits format
Add tests for new functionality
Ensure all tests pass and coverage is maintained
Push to the branch (
git push origin feature/amazing-feature)Open a Pull Request
Development guidelines
Follow MCP SDK patterns for tool definitions and structured output
Include comprehensive examples and parameter descriptions
Add appropriate tags for tool categorization
Write async code throughout
Add tests for all new functionality
Update CHANGELOG.md with your changes
Use English for all code comments and documentation
License
This project is licensed under the MIT License. See the LICENSE file for details.
Author
Developed with help from:
And with models:
Legal disclaimer: This tool provides access to Polish legal documents for research purposes. Always consult with qualified legal professionals for legal advice and interpretation of laws.
Available Tools
13 toolsanalyze_act_relationshipsA
Przeanalizuj powiązania i referencje między aktami prawnymi.
Zwraca informacje o aktach zmienionych, zmieniających, uchylonych, podstawie prawnej i tekstach jednolitych.
Przykłady:
analyze_act_relationships(eli="DU/2024/1716") - Wszystkie powiązania
analyze_act_relationships(eli="DU/2024/1716", relationship_type="Akty zmienione") - Jakie akty zmienił
analyze_act_relationships(eli="DU/2024/1716", relationship_type="Podstawa prawna") - Na jakiej podstawie powstał
analyze_act_relationships(eli="DU/2024/1716", relationship_type="Akty zmieniające") - Co go zmienia
analyze_act_relationships(eli="DU/2024/1", relationship_type="Akty uznane za uchylone") - Uchylone akty
| Name | Required | Description | Default |
|---|---|---|---|
| eli | Yes | Identyfikator ELI aktu. Format: "{wydawca}/{rok}/{pozycja}". Wydawcy: DU (Dziennik Ustaw), MP (Monitor Polski). Przykłady: "DU/2024/1716", "MP/2023/500", "DU/2024/1". | |
| relationship_type | No | Filtruj po typie powiązania (dokładne dopasowanie do klucza z API). Dostępne typy: 'Akty zmienione', 'Akty zmieniające', 'Akty uchylone', 'Akty uchylające', 'Akty uznane za uchylone', 'Podstawa prawna', 'Podstawa prawna z art.', 'Teksty jednolite'. None = zwróć wszystkie powiązania. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It states that the tool 'returns information' but does not explicitly mention that it is read-only or has no side effects. For a query tool, this is acceptable but could be more explicit about impact (e.g., no state changes).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, with a brief summary followed by illustrative examples. The structure is clear, though the examples partially replicate the schema's parameter list, making it slightly redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that an output schema exists, the description need not explain return values. It sufficiently covers the tool's purpose and usage context. Minor gaps: no mention of error handling or edge cases like invalid ELI formats, but these are not critical for basic usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides 100% coverage of parameter descriptions, including the valid relationship_type values and the ELI format. The tool description adds usage examples but no additional semantic detail beyond what the schema already contains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: analyzing relationships and references between legal acts. It names the specific resource (powiązania i referencje) and provides examples of distinct relationship types, distinguishing it from sibling tools like get_act_details or search_legal_acts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes concrete examples for different relationship_type values, making the intended use implicit. However, it lacks explicit guidance on when to prefer this tool over alternatives (e.g., 'use this when you need to see amendments' or 'not for full act content').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
browse_actsA
Przeglądaj wszystkie akty prawne wydane przez wydawcę w danym roku.
Kiedy użyć: Gdy chcesz przeglądać cały rocznik wydawcy bez filtrowania. Kiedy NIE używać: Gdy szukasz po słowach kluczowych lub tytule → użyj search_legal_acts.
Zwraca listę aktów (domyślnie max 20). Wyniki zapisywane są do result_set_id — użyj filter_results aby je zawęzić.
Przykłady:
browse_acts(publisher="DU", year=2024) - Wszystkie akty DU z 2024
browse_acts(publisher="MP", year=2024) - Wszystkie akty MP z 2024
browse_acts(publisher="DU", year=2024, detail_level="full") - Ze szczegółami
browse_acts(publisher="DU", year=2024, detail_level="minimal") - Tylko podstawowe info
browse_acts(publisher="DU", year=2000) - Akty z roku 2000
browse_acts(publisher="DU", year=2024, limit=20, offset=20) - Druga strona rocznika
| Name | Required | Description | Default |
|---|---|---|---|
| year | Yes | Rok publikacji (np. 2024). | |
| limit | No | Maksymalna liczba wyników do zwrócenia. Domyślnie 20, maksymalnie 100 — wartości powyżej są przycinane, tak samo jak w pozostałych narzędziach listujących. Podawaj najmniejszą wystarczającą wartość. | |
| offset | No | Liczba wyników do pominięcia (paginacja). Użyj razem z limit. Domyślnie 0. | |
| publisher | Yes | Kod wydawcy: 'DU' (Dziennik Ustaw) lub 'MP' (Monitor Polski). | |
| detail_level | No | Poziom szczegółowości: 'minimal' (ELI, tytuł, status), 'standard' (+ typ, daty, obowiązywanie), 'full' (wszystkie pola). Domyślnie 'standard'. | standard |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral disclosure burden. It discloses the default maximum of 20 results and the side effect that results are saved to result_set_id for later filtering. It does not mention permissions or edge cases, but for a read-only browse tool this is reasonable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a one-line purpose, explicit usage rules, a behavior note, and examples. The examples are numerous but each illustrates a distinct parameter combination, and the overall length is justified by the clarity it provides.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, when to use and avoid, return behavior, result_set_id handling, pagination, and parameter variants via examples. An output schema exists, so the return structure is already specified. Nothing critical is missing for an agent to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value through concrete examples showing valid publisher codes (DU/MP), detail_level values, pagination with limit/offset, and year usage. These examples clarify parameter combinations beyond the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Przeglądaj wszystkie akty prawne wydane przez wydawcę w danym roku' (browse all legal acts issued by a publisher in a given year). It clearly differentiates from the sibling search_legal_acts by contrasting browsing a full annual set with searching by keywords or title.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit 'Kiedy użyć' and 'Kiedy NIE używać' sections state exactly when to use this tool versus search_legal_acts. It also advises using filter_results when narrowing is needed, giving the agent clear routing and follow-up guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
calculate_legal_dateA
Oblicz daty na potrzeby prawne (np. terminy, daty wejścia w życie, vacatio legis).
Dodaje lub odejmuje dni, miesiące i lata od daty bazowej (lub dzisiejszej). Wartości dodatnie = przyszłość, ujemne = przeszłość.
Przykłady:
calculate_legal_date(days=14) - Termin 14 dni od dziś (np. termin na odwołanie)
calculate_legal_date(days=30, base_date="2024-06-01") - 30 dni od 1 czerwca 2024
calculate_legal_date(years=1, base_date="2024-01-01") - Rok po 1 stycznia 2024
calculate_legal_date(days=-90) - 90 dni wstecz od dziś
calculate_legal_date(months=6, days=15) - 6 miesięcy i 15 dni od dziś
calculate_legal_date(years=-5, base_date="2024") - 5 lat przed 1 stycznia 2024
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Liczba dni do dodania (+) lub odjęcia (-). Np. days=14 = za 14 dni, days=-14 = 14 dni temu. Domyślnie 0. Wartości logiczne (true/false) są niedozwolone. | |
| years | No | Liczba lat do dodania (+) lub odjęcia (-). Np. years=1 = za rok, years=-5 = 5 lat temu. Domyślnie 0. Wartości logiczne (true/false) są niedozwolone. | |
| months | No | Liczba miesięcy do dodania (+) lub odjęcia (-). Np. months=3 = za 3 miesiące, months=-6 = 6 miesięcy temu. Domyślnie 0. Wartości logiczne (true/false) są niedozwolone. | |
| base_date | No | Data bazowa. Akceptowane formaty: 'YYYY-MM-DD' (np. '2024-01-15'), 'YYYY-MM' (np. '2024-01' → 2024-01-01), 'YYYY' (np. '2024' → 2024-01-01). Jeśli nie podano, używa dzisiejszej daty. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden and does explain sign conventions, default base date, and parameter combinations. However, it does not disclose calendar semantics for edge cases (e.g. adding one month to Jan 31) or invalid input behavior, which are relevant for legal date calculations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose and operation, followed by a compact sign convention and six non-redundant examples. Every sentence contributes to correct invocation, with no filler or repeated schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple calculator with four optional parameters and an output schema present, the description is largely complete: it states what the tool does, how offsets work, and how the base date behaves. Minor edge-case semantics are missing, but they do not block selection or correct invocation in common use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter already has an explanatory description in Polish. The tool description adds value beyond the schema by illustrating real combinations (days=14, months=6, days=15, years=-5) and clarifying base_date formats such as 'YYYY' and 'YYYY-MM'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear purpose—calculating legal dates for deadlines, effective dates, and vacatio legis—and then states the core operation: adding/subtracting days, months, and years from a base date or today. This makes its function distinct from the sibling document/search tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete use cases (e.g. deadlines, entry into force, vacatio legis) and shows how to express future vs past offsets with positive/negative values. It does not explicitly name alternatives or exclusion criteria, but no sibling tool performs date arithmetic, so the usage context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
compare_actsA
Porównaj metadane dwóch aktów prawnych.
Porównuje tytuły, typy, statusy, daty (ogłoszenia, promulgacji, wejścia w życie), słowa kluczowe dwóch aktów. Identyfikuje różnice i wspólne elementy. Nie wymaga wcześniejszego załadowania treści (load_content).
Kiedy użyć: Aby porównać metadane dwóch aktów (np. wersji, powiązanych aktów). Kiedy NIE używać: Do porównania treści → załaduj oba akty i użyj read_act_content.
Przykłady:
compare_acts(eli_a="DU/2024/1692", eli_b="DU/2024/1716") - Porównaj dwa akty z 2024
compare_acts(eli_a="DU/2020/1444", eli_b="DU/2024/1692") - Porównaj starą i nową wersję
compare_acts(eli_a="DU/2024/1", eli_b="DU/2023/2000") - Porównaj akty z różnych lat
compare_acts(eli_a="DU/2024/100", eli_b="MP/2024/200") - Porównaj DU vs MP
compare_acts(eli_a="DU/2021/1500", eli_b="DU/2021/1600") - Porównaj podobne akty
| Name | Required | Description | Default |
|---|---|---|---|
| eli_a | Yes | Identyfikator ELI pierwszego aktu. Format: "{wydawca}/{rok}/{pozycja}". Przykłady: "DU/2024/1716", "MP/2023/500". | |
| eli_b | Yes | Identyfikator ELI drugiego aktu do porównania. Format: "{wydawca}/{rok}/{pozycja}". Przykłady: "DU/2024/1692", "DU/2020/1444". |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full behavioral burden. It clearly states what the tool compares, that it identifies differences and common elements, and that it does not require prior content loading. It does not explicitly label the operation as read-only, but comparing metadata strongly implies a non-mutating action, and the output schema covers return structure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: summary line, detailed scope, usage guidance, exclusions, and examples. It is front-loaded with the most important information. The five examples are somewhat repetitive, but they demonstrate diverse comparison scenarios, so they earn their place without excessive bloat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter comparison tool with an output schema, the description is complete: it states purpose, inputs, scope, prerequisites, exclusions, and examples. An agent has everything needed to select and invoke this tool correctly and to avoid confusing it with content-reading siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents both parameters with format and examples, achieving 100% coverage. The description adds use-case examples that pair eli_a and eli_b in meaningful ways (e.g., versions, different publishers), but this is illustrative rather than necessary parameter semantics. Baseline 3 is appropriate since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Porównaj metadane dwóch aktów prawnych' (compare metadata of two legal acts). It enumerates the exact metadata dimensions (titles, types, statuses, dates, keywords) and explicitly differentiates itself from content comparison via read_act_content, so the tool's role among siblings is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'Kiedy użyć' and 'Kiedy NIE używać' sections, directing the agent to read_act_content for content comparison instead. It also notes that loading content beforehand is not required, which removes a possible mistaken prerequisite.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
filter_resultsA
Filtruj i zawężaj wyniki wcześniejszego wyszukiwania aktów prawnych.
Działa jak grep/filtr na wynikach z search_legal_acts, browse_acts lub track_legal_changes. Wymaga result_set_id zwróconego przez te narzędzia. Przefiltrowane wyniki zapisywane są jako nowy zestaw (nowe result_set_id), który można filtrować dalej.
Limit rozmiaru wejścia: pojedyncze wywołanie przetwarza maksymalnie 100 rekordów (wartość domyślna, konfigurowalna przez operatora). Większy zestaw kończy się błędem, a nie wynikiem częściowym — dzięki temu brak dopasowania zawsze oznacza przeszukanie całego zestawu. Zawęź wyszukiwanie przed filtrowaniem.
Kiedy użyć: Po search_legal_acts/browse_acts/track_legal_changes aby zawęzić wyniki. Kiedy NIE używać: Gdy potrzebujesz nowych wyników z API → użyj search_legal_acts. Kiedy NIE używać: Do dowodzenia, że akt nie istnieje, dopóki pole source_scope odpowiedzi ma wartość 'page' — filtrowane jest wtedy okno, a nie cały zbiór, więc pusty wynik nie rozstrzyga. Odpowiedź sygnalizuje to polem no_match_is_inconclusive.
Przykłady:
filter_results(result_set_id="rs_1", type_equals="Rozporządzenie") - Tylko rozporządzenia
filter_results(result_set_id="rs_1", pattern="zdrow|apteka|lekar") - Akty związane ze zdrowiem
filter_results(result_set_id="rs_1", pattern="podatek|VAT", type_equals="Ustawa") - Ustawy podatkowe
filter_results(result_set_id="rs_1", date_field="promulgation_date", date_from="2024-01-01", date_to="2024-06-30") - Ogłoszone w I połowie 2024
filter_results(result_set_id="rs_1", sort_by="promulgation_date", sort_desc=True, limit=10) - 10 najnowszych na pierwszej stronie
filter_results(result_set_id="rs_1", pattern="\p{L}+ o ochronie") - Wzorzec z klasą unikodową
| Name | Required | Description | Default |
|---|---|---|---|
| field | No | Pole do przeszukania wzorcem RE2. Dostępne: 'title' (domyślne), 'eli', 'status', 'type', 'publisher'. | title |
| limit | No | Maksymalna liczba wyników na stronie odpowiedzi (domyślnie 20, maks. 100). | |
| offset | No | Nieujemne przesunięcie strony wyników. | |
| date_to | No | Koniec zakresu dat (YYYY-MM-DD). Wymaga ustawienia date_field. | |
| pattern | No | Wzorzec wyszukiwania w składni RE2. Wielkość liter jest ignorowana. Obsługiwany podzbiór składni: alternatywa (a|b), klasy znaków ([a-z], \d, \p{L}, [[:alpha:]]), kwantyfikatory (*, +, ?, {n,m}; maksymalnie 4 zmienne zakresy), kotwice (^, $), grupy nieprzechwytujące. Lookaround ((?=...), (?<=...), (?!...)) oraz backreferencje (\1) nie są obsługiwane. Przykłady: 'zdrow|Minister Zdrowia|apteka|lekar', 'budżet.*państw', 'transport|drogow', '\p{L}+ o ochronie' | |
| sort_by | No | Pole do sortowania: 'title', 'year', 'pos', 'promulgation_date', 'effective_date', 'type', 'status'. | |
| date_from | No | Początek zakresu dat (YYYY-MM-DD). Wymaga ustawienia date_field. | |
| sort_desc | No | Sortuj malejąco (True) lub rosnąco (False, domyślnie). | |
| date_field | No | Pole daty do filtrowania zakresem: 'promulgation_date' (data ogłoszenia) lub 'effective_date' (data wejścia w życie). | |
| type_equals | No | Filtruj po typie dokumentu (dokładne dopasowanie). Wartości: 'Ustawa', 'Rozporządzenie', 'Obwieszczenie', 'Komunikat', 'Uchwała', 'Zarządzenie', 'Wyrok', 'Postanowienie', 'Oświadczenie rządowe' | |
| year_equals | No | Filtruj po roku publikacji (dokładne dopasowanie). Np. 2024. | |
| result_set_id | Yes | Identyfikator zestawu wyników z poprzedniego wyszukiwania (np. 'rs_1'). Zwracany przez search_legal_acts, browse_acts lub track_legal_changes w polu result_set_id. | |
| status_equals | No | Filtruj po statusie aktu (dokładne dopasowanie). Wartości: 'akt obowiązujący', 'akt uchylony', 'akt jednorazowy', 'obowiązujący', 'uchylony', 'uznany za uchylony', 'nieobowiązujący' |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description correctly carries the full behavioral burden. It discloses the 100-record input limit, hard-error behavior instead of partial results, creation of a new result_set_id, the ability to chain further filters, and the no_match_is_inconclusive signal. This is unusually transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well structured: purpose first, then core behavioral constraints, then explicit usage rules, then examples. Every section has a clear job, and the examples are dense and illustrative rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter filtering tool, the description covers the full workflow: where the result_set_id comes from, how results are stored as new sets, size limits, error semantics, and the important source_scope caveat. Since an output schema exists, not restating return values is appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds value through composed examples showing result_set_id combined with type_equals, pattern, date ranges, sort_by/limit, and regex syntax, which helps an agent see realistic parameter combinations. It does not systematically redefine parameters, but the schema already covers them well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear, specific operation: filtering and narrowing results from earlier legal-act searches. It names the upstream tools (search_legal_acts, browse_acts, track_legal_changes) and uses a grep/filter analogy, which makes its role distinct and immediately understandable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is an explicit 'Kiedy użyć' section naming the exact preceding tools, plus two explicit 'Kiedy NIE używać' cases: one routing to search_legal_acts when new API results are needed, and one warning against using an empty result as proof that an act does not exist when source_scope is 'page'. This gives an agent clear decision rules.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_act_detailsA
Pobierz szczegółowe informacje o akcie prawnym.
Zwraca metadane: tytuł, status, daty (ogłoszenia, wejścia w życie, uchylenia), słowa kluczowe, spis treści i dostępne formaty (HTML/PDF).
Ustaw load_content=True aby załadować treść — to wymagane przed użyciem read_act_content (czytanie sekcji) i search_in_act (wyszukiwanie w treści).
Kiedy użyć: Aby zobaczyć metadane aktu (status, daty, spis treści). Kiedy NIE używać: Aby czytać treść aktu → użyj read_act_content (po załadowaniu).
Przykłady:
get_act_details(eli="DU/2024/1692") - Metadane i spis treści
get_act_details(eli="DU/2024/1692", load_content=True) - Załaduj treść do analizy
get_act_details(eli="DU/2024/1716") - Sprawdź status, daty i referencje
get_act_details(eli="MP/2024/100") - Akt z Monitora Polskiego
get_act_details(eli="DU/2021/1500") - Sprawdź status i daty obowiązywania
| Name | Required | Description | Default |
|---|---|---|---|
| eli | Yes | Identyfikator ELI aktu. Format: "{wydawca}/{rok}/{pozycja}". Wydawcy: DU (Dziennik Ustaw), MP (Monitor Polski). Przykłady: "DU/2024/1716", "MP/2023/500", "DU/2024/1". | |
| load_content | No | Załaduj treść aktu do Document Store (pamięć). WYMAGANE przed użyciem: read_act_content, search_in_act. Lifecycle: załadowane → TTL 2h → wygasa → wymaga ponownego załadowania. Domyślnie False. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses the significant side effect: setting load_content=True loads the act's content into the Document Store, with a lifecycle (TTL 2h, expiration, reload required) that affects subsequent calls. It describes what the call returns and what it does not do (read content). For a read-oriented tool, this is strong disclosure, though it does not cover edge behaviors like error conditions or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded: purpose sentence, return-value list, prerequisite note, then usage guidance and examples. The five examples are somewhat repetitive but serve as practical invocation patterns. Nothing is wasted, though the load_content prerequisite is stated twice (once in prose, once in the guidance section), a minor redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no further explanation; the description covers what remains: when to use it, when not to, the prerequisite side effect of loading content, and example invocations for both parameters. An agent has everything needed to select and correctly call this tool across its use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds value beyond the schema by providing five concrete usage examples with real ELI identifiers (DU/2024/1692, MP/2024/100) and by clarifying how load_content connects to downstream tools (read_act_content, search_in_act). This reinforces format understanding and invocation patterns beyond the raw parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Pobierz szczegółowe informacje o akcie prawnym') and enumerates exactly what is returned: metadata, title, status, dates, keywords, table of contents, and formats. It also explicitly distinguishes itself from read_act_content by clarifying that content loading is a separate prerequisite, so an agent can tell it apart from sibling tools without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description contains explicit 'Kiedy użyć' and 'Kiedy NIE używać' sections, names the alternative tool (read_act_content) for the excluded case, and states the prerequisite relationship (load_content=True required before read_act_content and search_in_act). This is exactly the when/when-not/alternatives guidance that makes tool selection reliable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_system_metadataA
Pobierz metadane systemu aktów prawnych.
Zwraca dostępne słowa kluczowe, wydawców, typy dokumentów, statusy i instytucje, które można wykorzystać do filtrowania i wyszukiwania aktów prawnych.
Przykłady:
get_system_metadata(category="keywords") - Dostępne słowa kluczowe do wyszukiwania
get_system_metadata(category="types") - Typy dokumentów (Ustawa, Rozporządzenie itp.)
get_system_metadata(category="publishers") - Wydawcy (DU, MP)
get_system_metadata(category="statuses") - Statusy aktów (obowiązujący, uchylony itp.)
get_system_metadata(category="all") - Wszystkie kategorie metadanych
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maksymalna liczba wartości metadanych na stronie odpowiedzi (domyślnie 20, maks. 100). | |
| offset | No | Nieujemne przesunięcie strony metadanych. | |
| category | No | Kategoria metadanych: 'keywords' (słowa kluczowe do wyszukiwania), 'publishers' (wydawcy: DU, MP), 'statuses' (statusy aktów), 'types' (typy dokumentów: Ustawa, Rozporządzenie itp.), 'institutions' (instytucje wydające), 'all' (wszystkie kategorie). Domyślnie 'all'. | all |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses what data it returns and that results can be used for filtering, but does not mention pagination behavior, limits at the endpoint level beyond schema defaults, or any response structure beyond the existing output schema. Adequate but not rich for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Compact paragraph with a clear return summary followed by five concrete examples. No filler or repetition of schema content; the examples earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a rich output schema already present and all 3 parameters fully documented, the description covers the key intent and usage patterns. The only minor gap is the lack of explicit mention of when metadata-prefetching is necessary versus unnecessary, but this is a low-complexity lookup tool, so the definition is effectively complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description's examples genuinely enrich 'category' by mapping each value to real content (DU, MP for publishers; Ustawa, Rozporządzenie for types), going beyond the schema text. This lifts it to 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb ('Pobierz') and resource ('metadane systemu aktów prawnych'), and enumerates exactly what it returns (keywords, publishers, document types, statuses, institutions). It is clearly distinct from document-oriented siblings like search_legal_acts or browse_acts, though it stops short of explicitly naming a sibling it is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The examples with concrete category values (keywords, types, publishers, statuses, all) give an agent actionable when-to-use guidance for filtering and search. However, it never names an alternative tool or states when NOT to use it, leaving some inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_loaded_documentsA
Wyświetl dokumenty załadowane do pamięci (Document Store).
Dokumenty ładowane są przez get_act_details(eli=..., load_content=True). Każdy dokument ma TTL 2h — po tym czasie wymaga ponownego załadowania.
Zwraca jedną stronę listy wraz z metadanymi paginacji (page_info).
Kiedy użyć: Aby sprawdzić jakie akty są załadowane i dostępne do czytania/wyszukiwania. Kiedy NIE używać: Do wyszukiwania aktów → użyj search_legal_acts.
Przykłady:
list_loaded_documents() - Wyświetl pierwszą stronę załadowanych dokumentów
list_loaded_documents(limit=5) - Pierwsze pięć dokumentów
list_loaded_documents(limit=5, offset=5) - Kolejna strona
list_loaded_documents(limit=100) - Cała zawartość Document Store
list_loaded_documents(offset=0) - Jawne przesunięcie od początku
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maksymalna liczba dokumentów na stronie odpowiedzi (domyślnie 20, maks. 100). | |
| offset | No | Nieujemne przesunięcie strony dokumentów. Domyślnie 0. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It discloses that documents are loaded via get_act_details(eli=..., load_content=True), that they expire after 2h TTL, and that the tool returns a single page with pagination metadata (page_info). It doesn't detail the exact page_info fields, but an output schema exists to cover that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured and efficient: a brief lead sentence, essential context about loading and TTL, clear usage guidelines, and a compact example list. Every section earns its place and the description is front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's low complexity (2 optional params, full schema coverage, existing output schema), the description is complete. It tells the agent what the tool does, when to use it, when not to use it, how documents get loaded, and what the response shape is (page_info). Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the two parameters, so the baseline is 3. The description adds value by giving concrete usage examples with limit/offset combinations (e.g., limit=5, offset=5 for next page) and clarifies the pagination behavior, which goes beyond the schema's defaults and constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Wyświetl dokumenty załadowane do pamięci (Document Store)' — clearly stating the tool lists loaded documents. It also explicitly distinguishes itself from search operations by naming search_legal_acts as the alternative, preventing confusion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description has dedicated 'Kiedy użyć' (when to use) and 'Kiedy NIE używać' (when NOT to use) sections, and it names the alternative tool ('Do wyszukiwania aktów → użyj search_legal_acts'). It also adds useful context about TTL (2h) that informs when a document needs reloading.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_result_setsA
Wyświetl aktywne zestawy wyników przechowywane w pamięci.
Każde wyszukiwanie (search_legal_acts, browse_acts, track_legal_changes) oraz filtrowanie (filter_results) tworzy zestaw wyników z unikalnym result_set_id. To narzędzie pokazuje aktywne zestawy (TTL: 1h) wraz z metadanymi paginacji.
Kiedy użyć: Aby sprawdzić jakie result_set_id są dostępne do filtrowania. Kiedy NIE używać: Do wyszukiwania nowych aktów → użyj search_legal_acts.
Przykłady:
list_result_sets() - Pierwsza strona aktywnych zestawów
list_result_sets(limit=5) - Pięć najnowszych wpisów strony
list_result_sets(limit=5, offset=5) - Kolejna strona
list_result_sets(limit=100) - Wszystkie aktywne zestawy
list_result_sets(offset=0) - Jawne przesunięcie od początku
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maksymalna liczba zestawów na stronie odpowiedzi (domyślnie 20, maks. 100). | |
| offset | No | Nieujemne przesunięcie strony zestawów. Domyślnie 0. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the TTL (1h), that only active sets are shown, and that pagination metadata is included. It implies a read-only operation. This is strong, though it doesn't mention auth or error behavior, which is acceptable for a simple list tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with a purpose statement, usage context, exclusions, and examples. It is slightly lengthy but well-organized and front-loaded. Every section adds value; no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with two optional params, and an output schema exists. The description explains the concept of result sets, TTL, and provides examples covering pagination. It doesn't cover edge cases like empty result sets, but that's minor. Overall complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description adds examples of usage (e.g., limit=5, offset=5) that clarify practical limits, but it doesn't add meaning beyond what the schema provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb ('list') and the resource ('active result sets stored in memory'). It distinguishes this tool from siblings by explaining that each search/filter creates a result set and that this tool lists them, and explicitly contrasts with search_legal_acts for new searches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'Kiedy użyć' (when to use) and 'Kiedy NIE używać' (when not to use) sections, naming the alternative tool. The examples illustrate common calling patterns (pagination, limits), giving clear situational guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_act_contentA
Czytaj treść załadowanego aktu prawnego po sekcjach.
WYMAGANIE: Akt musi być wcześniej załadowany za pomocą get_act_details(eli=..., load_content=True).
Bez parametru section zwraca spis treści (listę sekcji). Z parametrem section zwraca treść wybranej sekcji.
Kiedy użyć: Aby czytać treść konkretnej sekcji załadowanego aktu. Kiedy NIE używać: Aby zobaczyć metadane → użyj get_act_details.
Przykłady:
read_act_content(eli="DU/2024/1692") - Spis treści (lista sekcji)
read_act_content(eli="DU/2024/1692", section="Art. 1") - Treść artykułu 1
read_act_content(eli="DU/2024/1692", section="Rozdział 1") - Treść rozdziału 1
read_act_content(eli="DU/2024/1692", section="Dział II") - Treść działu II
read_act_content(eli="MP/2024/100") - Spis treści aktu z MP
| Name | Required | Description | Default |
|---|---|---|---|
| eli | Yes | Identyfikator ELI aktu. Format: "{wydawca}/{rok}/{pozycja}". Wydawcy: DU (Dziennik Ustaw), MP (Monitor Polski). Przykłady: "DU/2024/1716", "MP/2023/500", "DU/2024/1". Akt MUSI być wcześniej załadowany przez get_act_details(eli=..., load_content=True). | |
| limit | No | Maksymalna liczba elementów lub znaków na stronie. Domyślnie zależy od trybu odczytu. | |
| offset | No | Nieujemne przesunięcie początku strony. Domyślnie 0. | |
| section | No | Identyfikator sekcji do odczytania. Można użyć surowego ID (np. 'art_1') lub formy czytelnej (np. 'Art. 1', 'Rozdział 1') - obsługiwane jest elastyczne dopasowanie. Aby poznać dostępne section_id, użyj get_act_details(load_content=true) i sprawdź tabelę treści. Jeśli None — zwraca spis treści z dostępnymi sekcjami. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden well. It discloses the crucial precondition, the branching behavior when section is omitted or present, and flexible optional section matching (raw IDs or readable forms). It could go further by explicitly describing failure behavior when the act isn't loaded or a section isn't found, but it is still well above the minimal achievable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well organized first with a clear one-sentence purpose, then decisive blocks: WYMAGANIE, Kiedy użyć, and Kiedy NIE use. The examples are compact and practical, and no sentence feels wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there are no annotations but the schema is rich and an output schema is present, the description is effectively complete. It covers a precondition, differentiation from siblings, return behavior, optional section semantics, and multiple invocation examples, allowing an agent to select and call the tool without ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema description/question_complete_coverage is 100%, and the schema already explains eli format, section forms, limit/offset behavior, and section meaning. The description adds concrete examples and contextual use, but the semantic load is already primarily carried by the schema, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action and resource: 'Czytaj treść załadowanego aktu prawnego po sekcjach'. It also defines the two output modes (spis treści without section, szkż section content with section), and clearly differentiates the tool from get_act_details for metadata.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides an explicit precondition: the act must first be loaded via get_act_details(eli=..., load_content=True). It also includes explicit 'Kiedy użyć' and 'Kiedy NIE używać' guidance, naming get_act_details as the alternative for metadata retrieval.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_in_actA
Wyszukaj termin w treści załadowanego aktu prawnego.
WYMAGANIE: Akt musi być wcześniej załadowany za pomocą get_act_details(eli=..., load_content=True).
Zwraca jedną stronę trafień z kontekstem, metadanymi paginacji i informacją o sekcji.
Przykłady:
search_in_act(eli="DU/2024/1692", query="straż") - Znajdź "straż" w akcie
search_in_act(eli="DU/2024/1692", query="obowiązek", context_chars=200) - Z krótszym kontekstem
search_in_act(eli="DU/2024/1692", query="art. 5", limit=10, offset=0) - Pierwsza strona trafień
search_in_act(eli="DU/2024/1692", query="kara", limit=5, offset=5) - Kolejna strona trafień
search_in_act(eli="DU/2024/1692", query="termin") - Domyślna strona (do 20 trafień)
| Name | Required | Description | Default |
|---|---|---|---|
| eli | Yes | Identyfikator ELI aktu. Format: "{wydawca}/{rok}/{pozycja}". Wydawcy: DU (Dziennik Ustaw), MP (Monitor Polski). Przykłady: "DU/2024/1716", "MP/2023/500", "DU/2024/1". Akt MUSI być wcześniej załadowany przez get_act_details(eli=..., load_content=True). | |
| limit | No | Maksymalna liczba trafień na stronie. Domyślnie 20, maksimum 100. | |
| query | Yes | Termin do wyszukania w treści aktu (np. 'podatek', 'obowiązek', 'art. 5'). Wielkość liter jest ignorowana. | |
| offset | No | Nieujemne przesunięcie początku strony. Domyślnie 0. | |
| context_chars | No | Liczba znaków kontekstu przed i po każdym trafieniu. Domyślnie 500. Maksymalnie 2000 — wartości większe są przycinane do 2000, a odpowiedź zawiera wtedy wskazówkę o przycięciu. Wywołanie nie kończy się błędem. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full disclosure burden. It discloses the return shape (one page of hits with context, pagination metadata, section info), the prerequisite load behavior, and the non-error truncation behavior for context_chars. It could additionally state what happens if the act was not previously loaded, but the prominent requirement line mitigates this gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded: purpose statement, then requirement, then return format, then examples. Each of the five examples demonstrates a distinct parameter combination (plain search, context_chars, limit/offset, offset continuation, defaults), so none is wasted, though the example block is slightly long.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The output schema covers return values, so the description needn't explain them. The critical precondition, pagination behavior, context truncation edge case, and parameter defaults are all documented. What's missing is routing guidance across sibling tools (when to choose search_in_act over read_act_content or search_legal_acts), but the tool is callable correctly with the information provided.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds marginal value via five examples showing concrete query values, context_chars, and limit/offset pagination combinations, but it does not explain parameters beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Wyszukaj termin w treści załadowanego aktu prawnego' (search a term in the content of a loaded legal act). The qualifier 'załadowanego' (loaded) meaningfully distinguishes it from sibling search_legal_acts (searching act metadata/database) and read_act_content (reading content linearly), so an agent can tell them apart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit, critical precondition: the act must first be loaded via get_act_details(eli=..., load_content=True), stated with a WYMAGANIE (requirement) label and repeated in the eli parameter description and examples. It provides clear usage context and pagination patterns, but does not explicitly state when-not-to-use or name alternatives like search_legal_acts or read_act_content.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_legal_actsA
Wyszukaj polskie akty prawne z Dziennika Ustaw (DU) i Monitora Polskiego (MP).
UWAGA: Wszystkie słowa kluczowe muszą wystąpić jednocześnie (logika AND). Szukaj jednego słowa na raz dla logiki OR.
Kiedy użyć: Gdy znasz słowa kluczowe, tytuł, typ lub kryteria wyszukiwania. Kiedy NIE używać: Gdy chcesz przeglądać cały rocznik → użyj browse_acts.
Po wyszukiwaniu możesz użyć filter_results(result_set_id=...) aby dalej zawęzić wyniki (np. regex na tytułach, filtr po typie dokumentu).
Przykłady:
search_legal_acts(keywords=["podatek"], year=2024) - Akty podatkowe z 2024
search_legal_acts(act_type="Ustawa", title="zdrowotny") - Ustawy o zdrowiu
search_legal_acts(act_type="Rozporządzenie", year=2024, in_force=True) - Obowiązujące rozporządzenia z 2024
search_legal_acts(publisher="MP", year=2024, limit=10) - 10 aktów z MP z 2024
search_legal_acts(date_from="2024-01-01", date_to="2024-06-30") - Akty wchodzące w życie I poł. 2024
search_legal_acts(pub_date_from="2024-03-01", pub_date_to="2024-03-31") - Ogłoszone w marcu 2024
search_legal_acts(title="budżet", year=2024) - Akty budżetowe z 2024
| Name | Required | Description | Default |
|---|---|---|---|
| year | No | Rok publikacji (np. 2024). | |
| limit | No | Maksymalna liczba wyników do zwrócenia. Domyślnie 20. Przydatne do ograniczenia dużych zbiorów. Nie jest przycinana do 100 jak w pozostałych narzędziach listujących, ponieważ trafia wprost do zapytania do api.sejm.gov.pl — publicznej usługi instytucji państwowej. Podawaj najmniejszą wystarczającą wartość. | |
| title | No | Szukaj w tytule aktu (dopasowanie podciągu). Np. 'budżet', 'przeciwpożarow', 'podatek dochodowy'. | |
| offset | No | Liczba wyników do pominięcia (paginacja). Użyj z parametrem limit. | |
| date_to | No | Data wejścia w życie DO (YYYY-MM-DD). Filtruje akty które weszły w życie do tej daty. | |
| act_type | No | Typ dokumentu (dokładne dopasowanie). Dostępne wartości: 'Ustawa', 'Rozporządzenie', 'Obwieszczenie', 'Komunikat', 'Uchwała', 'Zarządzenie', 'Wyrok', 'Postanowienie', 'Oświadczenie rządowe'. Użyj get_system_metadata(category='types') aby zobaczyć pełną listę. | |
| in_force | No | Filtruj po obowiązywaniu: true = tylko akty obecnie obowiązujące, false = tylko akty nieobowiązujące, None = wszystkie. | |
| keywords | No | Słowa kluczowe z systemu Sejmu (logika AND — wiele słów zawęża wyniki). Aby uzyskać logikę OR, wykonaj oddzielne wyszukiwanie dla każdego słowa. Użyj get_system_metadata(category='keywords') aby poznać dostępne słowa kluczowe. | |
| date_from | No | Data wejścia w życie OD (YYYY-MM-DD). Filtruje akty które weszły w życie od tej daty. | |
| publisher | No | Kod wydawcy: 'DU' (Dziennik Ustaw) lub 'MP' (Monitor Polski). Domyślnie 'DU'. | DU |
| pub_date_to | No | Data publikacji/ogłoszenia DO (YYYY-MM-DD). Filtruje po dacie ogłoszenia w dzienniku. | |
| detail_level | No | Poziom szczegółowości wyników: 'minimal' (ELI, tytuł, status), 'standard' (+ typ, daty, obowiązywanie), 'full' (wszystkie pola). Domyślnie 'standard'. | standard |
| pub_date_from | No | Data publikacji/ogłoszenia OD (YYYY-MM-DD). Filtruje po dacie ogłoszenia w dzienniku. |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It discloses important search semantics: keywords use AND logic, OR requires separate searches, and filter_results can be used to further narrow results. It does not explicitly state defaults like publisher=DU or limit=20, but those are already in the input schema; the description adds useful behavioral context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured into a main purpose, an AND-logic warning, explicit when-to-use/when-not-to-use guidance, a follow-up filter_results pointer, and examples. Every section earns its place, and the most important scoping information is front-loaded. Despite covering many behaviors, it remains compact and scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has 13 parameters and 12 siblings, but the description plus full schema coverage and output schema provide enough context for correct invocation. It explains the primary use case, the main alternative, the follow-up tool, and the critical AND/OR semantics, while examples illustrate realistic parameter combinations. Nothing essential for selecting or calling this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, and the description does not need to re-explain parameters. It earns a 4 by adding illustrative multi-parameter examples that clarify intent, such as date_from/date_to for entry into force and pub_date_from/pub_date_to for publication dates. The examples map naturally to the schema properties and show how parameters combine.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Wyszukaj polskie akty prawne z Dziennika Ustaw (DU) i Monitora Polskiego (MP).' It clearly distinguishes itself from browse_acts by stating that browsing whole annual volumes is a different operation, and it routes post-search narrowing to filter_results. An agent can immediately tell what this tool does and how it differs from closely related siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool ('Gdy znasz słowa kluczowe, tytuł, typ lub kryteria wyszukiwania'), when not to use it ('Gdy chcesz przeglądać cały rocznik → użyj browse_acts'), and how to chain it with filter_results afterward. It also provides six concrete examples covering keyword, type, force, publisher, date, and title searches, which leaves little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
track_legal_changesA
Śledź zmiany prawne i nowe publikacje w zakresie dat.
Zwraca akty prawne opublikowane lub zmienione w podanym zakresie dat. Wyniki zapisywane są do result_set_id — użyj filter_results aby je zawęzić (np. po typie dokumentu lub wzorcem regex w tytule).
Przykłady:
track_legal_changes(date_from="2025-01-01") - Zmiany od początku 2025
track_legal_changes(date_from="2024-01-01", date_to="2024-12-31") - Zmiany w 2024
track_legal_changes(date_from="2024-01-01", keywords=["podatek"]) - Zmiany podatkowe w 2024
track_legal_changes(date_from="2024-06-01", publisher="MP") - Zmiany w MP od czerwca 2024
track_legal_changes(date_from="2024-01-01", keywords=["zdrowotny"]) - Zmiany zdrowotne
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maksymalna liczba zmian na stronie odpowiedzi (domyślnie 20, maks. 100). | |
| offset | No | Nieujemne przesunięcie strony zmian. | |
| date_to | No | Data końcowa śledzenia (YYYY-MM-DD). Domyślnie dzisiejsza data. | |
| keywords | No | Słowa kluczowe do filtrowania zmian (logika AND). Np. ['podatek'], ['zdrowotny', 'ubezpieczenie']. | |
| date_from | Yes | Data początkowa śledzenia (YYYY-MM-DD). Np. '2024-01-01'. | |
| publisher | No | Kod wydawcy: 'DU' (Dziennik Ustaw) lub 'MP' (Monitor Polski). Domyślnie 'DU'. | DU |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | Yes | The actual response data |
| hints | No | Suggested next steps |
| metadata | No | Additional metadata |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral disclosure burden. It meaningfully discloses a key side effect: 'Wyniki zapisywane są do result_set_id' and explains that results can be further narrowed with filter_results. This is valuable beyond the schema. It does not mention persistence details, overwrite behavior, or rate limits, but the main stateful behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description leads with the purpose, then explains the result_set_id behavior, and then provides examples. The examples are helpful but somewhat repetitive; several illustrate similar date-only patterns. Still, the structure is front-loaded and every major sentence contributes usable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with six parameters, full schema coverage, and an output schema, the description covers the essential invocation context: date range, result set storage, and post-filtering via filter_results. It could mention how to retrieve the saved results beyond filter_results, such as list_result_sets, but the provided guidance is sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter already has documented semantics in the input schema. The description's examples reinforce valid combinations such as date_from with keywords or publisher, but they do not add substantial meaning beyond what the schema already provides. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific purpose: 'Śledź zmiany prawne i nowe publikacje w zakresie dat' and 'Zwraca akty prawne opublikowane lub zmienione w podanym zakresie dat.' This identifies both the action and the resource. It does not explicitly differentiate from sibling tools like search_legal_acts, but the date-range orientation makes the tool's role reasonably distinct.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for date-based legal change tracking and gives concrete examples of valid parameter combinations. It also directs the agent to use filter_results for narrowing result sets, which is useful downstream guidance. However, it does not explicitly state when to use this tool instead of search_legal_acts, browse_acts, or other siblings, nor does it list exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Every tool targets a distinct action in the legal-research workflow: browsing, searching, loading, reading, filtering, comparing, and computing dates. Potentially similar pairs such as search_legal_acts vs browse_acts vs track_legal_changes are explicitly differentiated in descriptions with separate usage cases.
Tool names follow a consistent lowercase verb_noun pattern (list_loaded_documents, search_legal_acts, get_act_details, calculate_legal_date) with specific, descriptive verbs. There are no mixed casing or style conventions.
13 tools is within the well-scoped range and each tool fills a clear role in the legal research surface, without excessive redundancy or an empty feeling. The count feels justified by the breadth of search, browsing, content loading, relationship analysis, filtering, and date utilities.
The server provides strong coverage for legal research: searching, browsing, loading, reading, comparing metadata, tracking changes, filtering results, and analyzing relationships. Minor gaps exist around retrieving raw HTML/PDF document formats and comparing full act texts directly, but core workflows are fully usable and have no dead ends.
Maintenance
Related MCP Connectors
Semantic search over Polish law and case law, citing the exact in-force article.
Polish law: search statutes (ISAP), court rulings, verify citations. Free tier + paid plans + x402.
Verified Polish open data for AI agents: debt, budget, 460 MPs, votings, judiciary search, RAG.
Polish law via Ansvar Gateway. Cited, OAuth + paid tier.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceEnables querying and analyzing Slovak legislation via natural language, including full-text search, provision retrieval, and EU law integration.992Apache 2.0
- FlicenseNot gradedqualityAmaintenanceEnables AI assistants to access and search Slovak legal regulations from Slov-Lex.sk, including retrieving full law texts, paragraphs, and recent legislative updates.9
- AlicenseAqualityAmaintenanceMCP server for Polish legislation (ISAP / Sejm) — search acts (Dz.U., M.P.) and fetch full texts with ELI identifiers and verifiable citations.31081MIT
- AlicenseNot gradedqualityCmaintenanceEnables semantic search over Polish court judgments and legislative acts via MCP. Allows LLMs to retrieve legal documents using natural language queries.Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/numikel/law-scrapper-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server