{"id":49614202,"url":"https://github.com/numikel/law-scrapper-mcp","last_synced_at":"2026-05-04T20:06:06.143Z","repository":{"id":319270410,"uuid":"1078136016","full_name":"numikel/law-scrapper-mcp","owner":"numikel","description":"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.","archived":false,"fork":false,"pushed_at":"2026-02-19T22:31:07.000Z","size":370,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-20T02:49:38.659Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/numikel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-17T09:05:01.000Z","updated_at":"2026-02-19T22:31:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"6cebb25e-19ea-4441-ac10-c04c1baaa51a","html_url":"https://github.com/numikel/law-scrapper-mcp","commit_stats":null,"previous_names":["numikel/law-scrapper-mcp"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/numikel/law-scrapper-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numikel%2Flaw-scrapper-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numikel%2Flaw-scrapper-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numikel%2Flaw-scrapper-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numikel%2Flaw-scrapper-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/numikel","download_url":"https://codeload.github.com/numikel/law-scrapper-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numikel%2Flaw-scrapper-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32622787,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-04T20:06:02.560Z","updated_at":"2026-05-04T20:06:06.127Z","avatar_url":"https://github.com/numikel.png","language":"Python","funding_links":[],"categories":["MCP Servers for Legal"],"sub_categories":["Multilingual \u0026 Regional Legal Models"],"readme":"# Law Scrapper MCP\n\nA 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.\n\n![Python version](https://img.shields.io/badge/python-3.13+-blue.svg)\n![License](https://img.shields.io/badge/license-MIT-green.svg)\n![Version](https://img.shields.io/badge/version-2.3.1-orange.svg)\n\n\u003ca href=\"https://glama.ai/mcp/servers/@numikel/law-scrapper-mcp\"\u003e\n  \u003cimg width=\"380\" height=\"200\" src=\"https://glama.ai/mcp/servers/@numikel/law-scrapper-mcp/badge\" alt=\"Law Scrapper MCP server\" /\u003e\n\u003c/a\u003e\n\n## Features\n\n- **Comprehensive legal act access** - Full access to Polish legal acts from Dziennik Ustaw (DU) and Monitor Polski (MP)\n- **Advanced search and filtering** - Multi-criteria search by date, type, keywords, publisher, and status\n- **Result Store with chained filtering** - Store search results and filter with regex, type/status/year match, date ranges, sorting\n- **Document Store pattern** - Load acts into memory for efficient section-level navigation and search\n- **Detailed document analysis** - Metadata, structure, references, and content retrieval\n- **Content processing** - Automatic PDF-to-text and HTML-to-Markdown conversion\n- **Date calculations** - Specialized date utilities for legal document analysis\n- **System metadata** - Keywords, statuses, document types, and institution data\n- **FastMCP integration** - Built with FastMCP framework, flexible transport options\n- **Async HTTP client** - Efficient httpx client with retry logic and connection pooling\n- **TTL caching** - Intelligent response caching with configurable TTL\n- **Structured logging** - JSON and text log formats for easy debugging\n- **Docker support** - Containerized deployment with docker-compose\n- **Comprehensive documentation** - Examples and clear parameter descriptions\n\n## Requirements\n\n- **Python**: 3.13 or higher\n- **Package manager**: uv (recommended) or pip\n- **Internet connection**: Required for accessing Sejm API endpoints\n- **MCP-compatible tool**: Cursor IDE, Claude Code, or other MCP clients\n\n## Installation\n\n### Using uv (recommended)\n\n```bash\n# Clone the repository\ngit clone https://github.com/numikel/law-scrapper-mcp.git\ncd law-scrapper-mcp\n\n# Install dependencies\nuv sync\n\n# Install with dev dependencies\nuv sync --extra dev\n```\n\n### Using pip\n\n```bash\n# Clone the repository\ngit clone https://github.com/numikel/law-scrapper-mcp.git\ncd law-scrapper-mcp\n\n# Install dependencies\npip install -e .\n```\n\n### Using uvx (no installation required)\n\nFor quick testing without cloning the repository:\n\n```bash\n# Run the server directly from GitHub\nuvx --from git+https://github.com/numikel/law-scrapper-mcp law-scrapper\n```\n\n## Quick start\n\n### STDIO transport (default)\n\nSTDIO is the default transport for MCP communication. Start the server and connect from your MCP client:\n\n```bash\n# Run the server\nuv run python -m law_scrapper_mcp\n\n# Or use the installed script\nlaw-scrapper\n```\n\nConfigure in your MCP client (e.g., Cursor `.cursor/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"law-scrapper-mcp\": {\n      \"command\": \"law-scrapper\"\n    }\n  }\n}\n```\n\nFor Claude Code:\n\n```bash\nclaude mcp add law-scrapper \"uvx --from git+https://github.com/numikel/law-scrapper-mcp law-scrapper\"\n```\n\n### HTTP transport (streamable-http)\n\nRun the server on HTTP with streamable-http transport:\n\n```bash\n# Run with HTTP transport on port 7683\nLAW_MCP_TRANSPORT=streamable-http uv run python -m law_scrapper_mcp\n\n# Or specify custom host and port\nLAW_MCP_TRANSPORT=streamable-http LAW_MCP_HOST=0.0.0.0 LAW_MCP_PORT=8080 uv run python -m law_scrapper_mcp\n```\n\nConfigure in your MCP client:\n\n```json\n{\n  \"mcpServers\": {\n    \"law-scrapper-mcp\": {\n      \"url\": \"http://localhost:7683/mcp\",\n      \"transport\": \"streamable-http\"\n    }\n  }\n}\n```\n\n**Note:** The URL must include the `/mcp` path. FastMCP exposes the streamable-http endpoint at `/mcp`, not at the root. Using `http://localhost:7683` without `/mcp` results in 404 (Not Found).\n\n### Docker\n\nBuild and run with Docker:\n\n```bash\n# Build the image\ndocker build -t law-scrapper-mcp .\n\n# Run with STDIO transport (default)\ndocker run -it law-scrapper-mcp\n\n# Run with HTTP transport on port 7683\ndocker run -it -p 7683:7683 -e LAW_MCP_TRANSPORT=streamable-http law-scrapper-mcp\n```\n\nOr use docker-compose:\n\n```bash\n# Run with STDIO transport\ndocker compose up\n\n# Run with HTTP transport (set TRANSPORT=streamable-http in docker-compose.yml)\ndocker compose -f docker-compose.yml up\n```\n\n## Configuration\n\nAll settings are configured via environment variables with the `LAW_MCP_` prefix:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `LAW_MCP_TRANSPORT` | `stdio` | Transport: `stdio` or `streamable-http` |\n| `LAW_MCP_HOST` | `0.0.0.0` | HTTP server host (when using streamable-http) |\n| `LAW_MCP_PORT` | `7683` | HTTP server port (when using streamable-http) |\n| `LAW_MCP_API_TIMEOUT` | `30.0` | HTTP request timeout in seconds |\n| `LAW_MCP_API_MAX_CONCURRENT` | `10` | Maximum concurrent API requests |\n| `LAW_MCP_API_MAX_RETRIES` | `3` | Maximum API request retries |\n| `LAW_MCP_CACHE_METADATA_TTL` | `86400` | Metadata cache TTL (24 hours) |\n| `LAW_MCP_CACHE_SEARCH_TTL` | `600` | Search results cache TTL (10 minutes) |\n| `LAW_MCP_CACHE_BROWSE_TTL` | `3600` | Browse results cache TTL (1 hour) |\n| `LAW_MCP_CACHE_DETAILS_TTL` | `3600` | Act details cache TTL (1 hour) |\n| `LAW_MCP_CACHE_CHANGES_TTL` | `300` | Changes tracking cache TTL (5 minutes) |\n| `LAW_MCP_CACHE_MAX_ENTRIES` | `1000` | Maximum cache entries |\n| `LAW_MCP_DOC_STORE_MAX_DOCUMENTS` | `10` | Maximum documents in Document Store |\n| `LAW_MCP_DOC_STORE_MAX_SIZE_BYTES` | `5242880` | Maximum Document Store size (5 MB) |\n| `LAW_MCP_DOC_STORE_TTL` | `7200` | Document Store TTL (2 hours) |\n| `LAW_MCP_CIRCUIT_BREAKER_THRESHOLD` | `5` | Failures before circuit breaker opens |\n| `LAW_MCP_CIRCUIT_BREAKER_RECOVERY_TIMEOUT` | `60.0` | Seconds before trying recovery |\n| `LAW_MCP_CIRCUIT_BREAKER_HALF_OPEN_MAX_CALLS` | `3` | Test calls in half-open state |\n| `LAW_MCP_LOG_LEVEL` | `INFO` | Log level: DEBUG, INFO, WARNING, ERROR |\n| `LAW_MCP_LOG_FORMAT` | `text` | Log format: `text` or `json` |\n\nExample environment configuration:\n\n```bash\nexport LAW_MCP_TRANSPORT=streamable-http\nexport LAW_MCP_PORT=7683\nexport LAW_MCP_LOG_LEVEL=DEBUG\nexport LAW_MCP_CACHE_METADATA_TTL=86400\n```\n\n## Tools reference\n\nLaw Scrapper MCP provides 13 tools for legal research and analysis:\n\n### 1. get_system_metadata(category)\n\nRetrieve system metadata for filtering and searching legal acts.\n\n**Parameters:**\n- `category` (string, default: \"all\") - Metadata category: \"keywords\", \"publishers\", \"statuses\", \"types\", \"institutions\", or \"all\"\n\n**Returns:** Keywords, publishers, document types, statuses, and institutions available in the system\n\n**Examples:**\n```\n- Get all available search keywords\n- Retrieve all legal document types\n- List all publishers (DU, MP)\n- Get all document statuses\n- Get complete system metadata\n```\n\n### 2. search_legal_acts(publisher, year, keywords, detail_level, status, type)\n\nSearch for legal acts with advanced filtering options.\n\n**Parameters:**\n- `publisher` (string) - Publisher code: \"DU\" (Dziennik Ustaw) or \"MP\" (Monitor Polski)\n- `year` (integer) - Publication year (e.g., 2024)\n- `keywords` (string) - Search keywords (AND logic - use multiple searches for OR)\n- `detail_level` (string, default: \"standard\") - Response detail: \"minimal\", \"standard\", or \"full\"\n- `status` (string, optional) - Document status filter\n- `type` (string, optional) - Document type filter\n\n**Returns:** List of matching legal acts with metadata\n\n**Search note:** Multiple keywords use AND logic. Search one keyword at a time for OR behavior.\n\n**Examples:**\n```\n- Search DU 2024 for \"environment protection\" acts\n- Find all MP 2023 acts with status \"active\"\n- Search for COVID-19 related legislation\n- Find acts by specific type (e.g., \"regulation\")\n- Get minimal detail results for quick scanning\n```\n\n### 3. browse_acts(publisher, year, detail_level)\n\nBrowse all legal acts published in a specific year by publisher.\n\n**Parameters:**\n- `publisher` (string) - Publisher code: \"DU\" or \"MP\"\n- `year` (integer) - Publication year\n- `detail_level` (string, default: \"standard\") - Response detail: \"minimal\", \"standard\", or \"full\"\n\n**Returns:** Complete list of acts published in the specified year\n\n**Examples:**\n```\n- Browse all DU acts from 2024\n- Get minimal details of all MP acts from 2023\n- Browse full details of DU 2022 legislation\n- Get an overview of acts by publisher and year\n- Track legislation published in a specific year\n```\n\n### 4. filter_results(result_set_id, pattern, field, type_equals, ...)\n\nFilter and narrow down previously retrieved search/browse/changes results.\n\n**Parameters:**\n- `result_set_id` (string) - Result set ID from a previous search/browse/changes call (e.g., \"rs_1\")\n- `pattern` (string, optional) - Regex pattern for text search (supports OR: \"podatek|VAT|akcyza\")\n- `field` (string, default: \"title\") - Field to search: \"title\", \"eli\", \"status\", \"type\", \"publisher\"\n- `type_equals` (string, optional) - Exact match on document type (e.g., \"Ustawa\", \"Rozporządzenie\")\n- `status_equals` (string, optional) - Exact match on status (e.g., \"akt obowiązujący\", \"akt uchylony\")\n- `year_equals` (integer, optional) - Exact match on publication year\n- `date_field` (string, optional) - Date field for range filter: \"promulgation_date\" or \"effective_date\"\n- `date_from` / `date_to` (string, optional) - Date range (YYYY-MM-DD)\n- `sort_by` (string, optional) - Sort field: \"title\", \"year\", \"pos\", \"promulgation_date\", etc.\n- `sort_desc` (boolean, default: false) - Sort descending\n- `limit` (integer, optional) - Maximum results to return\n\n**Returns:** Filtered results with a new `result_set_id` for chained filtering\n\n**Examples:**\n```\n- Filter search results to only \"Rozporządzenie\" type\n- Search titles with regex \"zdrow|apteka|lekar\"\n- Filter by date range and sort by promulgation date\n- Chain filters: first by type, then by regex pattern\n- Get top 10 most recent results\n```\n\n### 5. get_act_details(eli, load_content, detail_level)\n\nRetrieve detailed information about a specific legal act and optionally load its content.\n\n**Parameters:**\n- `eli` (string) - Act identifier in format \"PUBLISHER/YEAR/NUMBER\" (e.g., \"DU/2024/1\")\n- `load_content` (boolean, default: false) - Load act content into Document Store for section reading\n- `detail_level` (string, default: \"standard\") - Response detail: \"minimal\", \"standard\", or \"full\"\n\n**Returns:** Act metadata (title, publication date, status, type, etc.), table of contents if load_content=true\n\n**Examples:**\n```\n- Get metadata for act DU/2024/1\n- Load act content for section-level reading\n- Get full details including table of contents\n- Retrieve act status and publication information\n- Load multiple acts for comparison\n```\n\n### 6. read_act_content(eli, section)\n\nRead content from a specific section of a loaded legal act.\n\n**Parameters:**\n- `eli` (string) - Act identifier (must be loaded first via get_act_details with load_content=true)\n- `section` (string) - Section to read (e.g., \"Art. 1\", \"Chapter 2\", \"Preamble\")\n\n**Returns:** Content of the requested section\n\n**Workflow note:** Must call get_act_details(eli=\"...\", load_content=true) first, then use this tool.\n\n**Examples:**\n```\n- Read Article 1 from loaded act\n- Get Chapter 2 content\n- Read the Preamble section\n- Access specific numbered articles\n- Navigate act by chapters\n```\n\n### 7. search_in_act(eli, query)\n\nSearch for specific terms within a loaded legal act.\n\n**Parameters:**\n- `eli` (string) - Act identifier (must be loaded first via get_act_details with load_content=true)\n- `query` (string) - Search term or phrase\n\n**Returns:** Matching sections with context and location\n\n**Examples:**\n```\n- Find all mentions of \"penalty\" in loaded act\n- Search for specific legal terms\n- Locate articles containing \"fine\" or \"punishment\"\n- Find definitional sections\n- Search for specific references\n```\n\n### 8. analyze_act_relationships(eli, relationship_type)\n\nAnalyze legal relationships and references of an act (amendments, references, etc.).\n\n**Parameters:**\n- `eli` (string) - Act identifier\n- `relationship_type` (string, default: \"all\") - Type: \"amends\", \"amended_by\", \"references\", \"referenced_by\", or \"all\"\n\n**Returns:** List of related acts and their relationships\n\n**Examples:**\n```\n- Find which acts amend this legislation\n- See what acts this legislation amends\n- Get all legal references in the act\n- Find acts that reference this legislation\n- Analyze complete act relationship network\n```\n\n### 9. track_legal_changes(date_from, date_to, publisher, keywords)\n\nTrack legal changes and new acts within a date range.\n\n**Parameters:**\n- `date_from` (string) - Start date (YYYY-MM-DD format)\n- `date_to` (string) - End date (YYYY-MM-DD format)\n- `publisher` (string, optional) - Filter by publisher: \"DU\" or \"MP\"\n- `keywords` (string, optional) - Filter by keywords\n\n**Returns:** Legal acts published in the date range\n\n**Examples:**\n```\n- Track changes from 2024-01-01 to 2024-12-31\n- Find new DU acts from last month\n- Get changes published in past 7 days\n- Track legislation on specific topics over time\n- Monitor legal changes by publisher and date range\n```\n\n### 10. calculate_legal_date(days, months, years, base_date)\n\nCalculate legal dates with intuitive sign convention.\n\n**Parameters:**\n- `days` (integer, default: 0) - Days offset (+future, -past)\n- `months` (integer, default: 0) - Months offset (+future, -past)\n- `years` (integer, default: 0) - Years offset (+future, -past)\n- `base_date` (string, optional) - Base date (YYYY, YYYY-MM, or YYYY-MM-DD format, defaults to today)\n\n**Returns:** Calculated date and relative description\n\n**Sign convention:** Positive = future, Negative = past\n\n**Examples:**\n```\n- Get current date (call with no parameters)\n- Calculate date 30 days in the future (+30)\n- Calculate date 6 months in the past (-6 months)\n- Calculate date 1 year from a specific date\n- Calculate legal deadlines and periods\n```\n\n### 11. compare_acts(eli_a, eli_b)\n\nCompare metadata of two legal acts.\n\n**Parameters:**\n- `eli_a` (string) - ELI identifier of the first act (e.g., \"DU/2024/1692\")\n- `eli_b` (string) - ELI identifier of the second act (e.g., \"DU/2024/1716\")\n\n**Returns:** Comparison of titles, types, statuses, dates, keywords overlap and differences\n\n**Examples:**\n```\n- Compare two acts from the same year\n- Compare old and new versions of legislation\n- Identify metadata differences between related acts\n```\n\n### 12. list_result_sets()\n\nDisplay active result sets stored in memory.\n\n**Returns:** List of result sets with IDs, query summaries, counts, and creation times\n\n### 13. list_loaded_documents()\n\nDisplay documents loaded into the Document Store.\n\n**Returns:** List of loaded documents with ELIs, sizes, section counts, and timestamps\n\n## Document Store workflow\n\nThe Document Store pattern enables efficient content navigation and search within legal acts:\n\n### Workflow steps\n\n1. **Load an act** - Call `get_act_details(eli=\"DU/2024/1\", load_content=true)` to load the act into the Document Store\n2. **Read sections** - Use `read_act_content(eli=\"DU/2024/1\", section=\"Art. 1\")` to read specific sections\n3. **Search within act** - Use `search_in_act(eli=\"DU/2024/1\", query=\"penalty\")` to find terms\n\n### Benefits\n\n- Efficient memory usage (configurable max documents and TTL)\n- Fast section-level navigation without refetching\n- Search within loaded acts without API calls\n- Automatic content processing (PDF→text, HTML→Markdown)\n\n### Configuration\n\n- `LAW_MCP_DOC_STORE_MAX_DOCUMENTS` - How many acts to keep in memory (default: 10)\n- `LAW_MCP_DOC_STORE_MAX_SIZE_BYTES` - Maximum memory usage (default: 5 MB)\n- `LAW_MCP_DOC_STORE_TTL` - How long to keep acts in memory (default: 2 hours)\n\n## Project structure\n\n```\nlaw-scrapper-mcp/\n├── src/law_scrapper_mcp/\n│   ├── __init__.py\n│   ├── __main__.py              # Entry point for python -m\n│   ├── server.py                # FastMCP app, lifespan, transport config\n│   ├── config.py                # Pydantic settings (env vars)\n│   ├── logging_config.py        # Structured logging setup\n│   ├── models/                  # Pydantic models\n│   │   ├── enums.py            # Enumerations\n│   │   ├── api_responses.py    # Sejm API response models\n│   │   ├── tool_inputs.py      # Tool input models\n│   │   └── tool_outputs.py     # Tool output models\n│   ├── client/                  # HTTP client\n│   │   ├── sejm_client.py      # AsyncClient with retry and circuit breaker\n│   │   ├── cache.py            # Async TTL cache implementation\n│   │   ├── circuit_breaker.py  # Circuit breaker for API protection\n│   │   └── exceptions.py       # Custom exceptions (Polish messages)\n│   ├── services/                # Business logic\n│   │   ├── metadata_service.py    # Metadata retrieval\n│   │   ├── search_service.py      # Search and browse\n│   │   ├── act_service.py         # Act details and content\n│   │   ├── changes_service.py     # Change tracking\n│   │   ├── document_store.py      # In-memory act storage\n│   │   ├── result_store.py        # Search result persistence and filtering\n│   │   ├── content_processor.py   # PDF/HTML processing\n│   │   └── response_enrichment.py # Response hints\n│   └── tools/                   # MCP tool definitions\n│       ├── metadata.py          # get_system_metadata\n│       ├── search.py            # search_legal_acts\n│       ├── browse.py            # browse_acts\n│       ├── act_details.py       # get_act_details\n│       ├── act_content.py       # read_act_content\n│       ├── act_search.py        # search_in_act\n│       ├── relationships.py     # analyze_act_relationships\n│       ├── filter_results.py    # filter_results, list_result_sets\n│       ├── changes.py           # track_legal_changes\n│       ├── compare.py           # compare_acts\n│       ├── dates.py             # calculate_legal_date\n│       └── error_handling.py    # Centralized @handle_tool_errors decorator\n├── tests/\n│   ├── unit/                    # Unit tests\n│   └── integration/             # Integration tests with Sejm API\n├── Dockerfile                   # Container image definition\n├── docker-compose.yml           # Multi-service setup\n├── pyproject.toml              # Project metadata and dependencies\n├── uv.lock                      # Reproducible dependency lock\n└── README.md                    # This file\n```\n\n## Docker\n\n### Dockerfile\n\nThe included `Dockerfile` builds a containerized Law Scrapper MCP server:\n\n```dockerfile\nFROM python:3.13-slim\nWORKDIR /app\nCOPY . .\nRUN pip install -e .\nEXPOSE 7683\nCMD [\"law-scrapper\"]\n```\n\nBuild and run:\n\n```bash\n# Build the image\ndocker build -t law-scrapper-mcp .\n\n# Run with STDIO transport\ndocker run -it law-scrapper-mcp\n\n# Run with HTTP transport\ndocker run -it -p 7683:7683 -e LAW_MCP_TRANSPORT=streamable-http law-scrapper-mcp\n\n# With custom settings\ndocker run -it -p 7683:7683 \\\n  -e LAW_MCP_TRANSPORT=streamable-http \\\n  -e LAW_MCP_LOG_LEVEL=DEBUG \\\n  law-scrapper-mcp\n```\n\n### docker-compose.yml\n\nDeployment with docker-compose:\n\n```bash\n# Start service\ndocker compose up -d\n\n# View logs\ndocker compose logs -f\n\n# Stop service\ndocker compose down\n```\n\n## Migration guide (v1 to v2)\n\nIf upgrading from v1.0.2, note these breaking changes:\n\n| v1.0.2 (old) | v2.0.0 (new) | Notes |\n|-------------|------------|-------|\n| `get_current_date` | `calculate_legal_date()` | Call with no parameters for current date |\n| `calculate_date_offset` | `calculate_legal_date(days/months/years)` | Use intuitive +future/-past sign convention |\n| `get_legal_keywords` | `get_system_metadata(category=\"keywords\")` | Consolidated into one tool |\n| `get_legal_publishers` | `get_system_metadata(category=\"publishers\")` | Consolidated into one tool |\n| `get_legal_statuses` | `get_system_metadata(category=\"statuses\")` | Consolidated into one tool |\n| `get_legal_types` | `get_system_metadata(category=\"types\")` | Consolidated into one tool |\n| `get_legal_institutions` | `get_system_metadata(category=\"institutions\")` | Consolidated into one tool |\n| `get_publisher_details` | N/A | Use `get_system_metadata(category=\"publishers\")` |\n| `search_legal_acts` | `search_legal_acts` | Enhanced with `detail_level` parameter |\n| `get_publisher_year_acts` | `browse_acts` | Renamed for clarity |\n| `get_act_comprehensive_details` | `get_act_details` | Added `load_content` and `detail_level` |\n| `get_act_content` | `read_act_content` | Requires pre-loading with `get_act_details` |\n| `get_act_table_of_contents` | `get_act_details` | TOC included in details response |\n| `get_act_relationships` | `analyze_act_relationships` | Renamed for clarity |\n| ELI format | Single string \"DU/2024/1\" | Changed from separate parameters |\n| SSE transport | STDIO (default) | STDIO is default, HTTP via streamable-http |\n| Port 7683 | Port 7683 | Same default HTTP port |\n\n## What's new in v2.3.1\n\n- **uvx / FastMCP fix** — Fixed `NameError: name 'Annotated' is not defined` when running via `uvx --from \"git+https://github.com/numikel/law-scrapper-mcp\" law-scrapper`. Removed `from __future__ import annotations` from `compare.py` so parameter type hints resolve correctly during tool registration.\n\n## What's new in v2.3.0\n\n- **3 new tools** — `compare_acts`, `list_result_sets`, `list_loaded_documents` (total: 13 tools)\n- **Circuit breaker** — Protects against cascading failures when Sejm API is unavailable\n- **Centralized error handling** — `@handle_tool_errors` decorator with error classification and full tracebacks\n- **asyncio.Lock migration** — All stores use `asyncio.Lock` for proper async compatibility\n- **Default search limit** — Search/browse return max 20 results by default to limit token usage\n- **Health endpoint** — `/health` for Docker deployments with streamable-http transport\n- **Polish error messages** — All exception messages in Polish for consistent user experience\n- **Decision tree docstrings** — \"When to use\" / \"When NOT to use\" for all tools\n\n## Development\n\n### Setup\n\n```bash\n# Install dependencies\nuv sync\n\n# Install with dev dependencies\nuv sync --extra dev\n```\n\n### Running tests\n\n```bash\n# Run unit tests\nuv run pytest tests/unit/ -v\n\n# Run integration tests (requires internet)\nuv run pytest tests/integration/ -v -m integration\n\n# Run all tests with coverage\nuv run pytest --cov=law_scrapper_mcp --cov-report=term-missing\n\n# Run with timeout for slow tests\nuv run pytest --timeout=10 -v\n```\n\n### Code quality\n\nThe project follows FastMCP best practices:\n- **Modular architecture** - Separated concerns (models, client, services, tools)\n- **Type hints** - Full type annotation with Pydantic models\n- **Async throughout** - Async/await for all I/O operations\n- **Comprehensive examples** - Minimum 5 examples per tool\n- **Tagged tools** - Organized by category for easy discovery\n- **Annotated parameters** - Clear descriptions for all inputs\n- **Structured logging** - Configurable JSON/text formats\n\n### Running the server\n\n```bash\n# STDIO transport (default)\nuv run python -m law_scrapper_mcp\n\n# HTTP transport\nLAW_MCP_TRANSPORT=streamable-http uv run python -m law_scrapper_mcp\n\n# With debug logging\nLAW_MCP_LOG_LEVEL=DEBUG uv run python -m law_scrapper_mcp\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes using Conventional Commits format\n4. Add tests for new functionality\n5. Ensure all tests pass and coverage is maintained\n6. Push to the branch (`git push origin feature/amazing-feature`)\n7. Open a Pull Request\n\n### Development guidelines\n\n- Follow FastMCP best practices for tool definitions\n- Include comprehensive examples and parameter descriptions\n- Add appropriate tags for tool categorization\n- Write async code throughout\n- Add tests for all new functionality\n- Update CHANGELOG.md with your changes\n- Use English for all code comments and documentation\n\n## License\n\nThis project is licensed under the MIT License. See the LICENSE file for details.\n\n## Author\n\n**[@numikel](https://github.com/numikel)**\n\nDeveloped with help from:\n\n![Cursor](https://img.shields.io/badge/Cursor-2.4.37+-black.svg)\n![Claude Code](https://img.shields.io/badge/Claude_Code-2.1.42+-orange.svg)\n\nAnd with models:\n\n![Claude Opus 4.6](https://img.shields.io/badge/Claude_Opus-4.6-orange.svg)\n![Claude Opus 4.5](https://img.shields.io/badge/Claude_Opus-4.5-orange.svg)\n![Claude Sonnet 4.5](https://img.shields.io/badge/Claude_Sonnet-4.5-orange.svg)\n![Claude Haiku 4.5](https://img.shields.io/badge/Claude_Haiku-4.5-orange.svg)\n\n---\n\n**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.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnumikel%2Flaw-scrapper-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnumikel%2Flaw-scrapper-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnumikel%2Flaw-scrapper-mcp/lists"}