Skip to content

Rada Legislation Service

overthelex edited this page May 17, 2026 · 2 revisions

Rada Legislation Service

The Rada MCP Server (mcp_rada) provides AI-powered access to Ukrainian parliamentary data: legislation texts, deputies, bills, voting records, factions, and committees. It fetches data from the official Verkhovna Rada open data portals (data.rada.gov.ua and zakon.rada.gov.ua), caches it in PostgreSQL with configurable TTLs, and exposes it via MCP tools.

Architecture

The service operates within the Model Context Protocol (MCP) framework, supporting a triple transport system:

Transport Use case Entry point
MCP stdio Claude Desktop integration src/index.ts
HTTP REST API Web applications src/http-server.ts (port 3001)
SSE streaming Distributed real-time clients POST /api/tools/:toolName/stream

Infrastructure

Component Default Purpose
PostgreSQL localhost:5433 Structured storage (schema rada)
Redis localhost:6379 Rate limiting, health checks
HTTP port 3001 REST API

Redis is used for rate limiting and health check probes. Qdrant is not used by this service (no vector embeddings).

Service Factory

All services are composed via src/factories/rada-services.ts (createRadaCoreServices()):

RadaCoreServices
  +-- Database (PostgreSQL)
  +-- RadaAPIAdapter (data.rada.gov.ua)
  +-- ZakonRadaAdapter (zakon.rada.gov.ua)
  +-- CostTracker
  +-- DeputyService (7-day cache)
  +-- FactionService
  +-- CommitteeService
  +-- BillService (1-day cache)
  +-- LegislationService (30-day cache)
  +-- VotingService
  +-- CrossReferenceService (links to SecondLayer court cases)
  +-- MCPRadaAPI (tool routing)

Data Sources and Adapters

RadaAPIAdapter (src/adapters/rada-api-adapter.ts)

Fetches structured JSON data from data.rada.gov.ua:

Endpoint Data Notes
/ogd/mps/skl9/mps-data.json Deputies, factions (is_fr=1), committees (type=2), assistants Cached in-memory for 5 min
/ogd/zpr/skl9/billinfo_list-skl9.json Bills (~8 MB, light list) Updated daily by RADA
/ogd/zal/ppz/skl9/json/DDMMYYYY.json Voting records per session date
/ogd/zal/ppz/skl9/dict/dates.txt Available session dates
/ogd/list.json Dataset catalogue

Rate limited to 10 requests/second (100 ms minimum interval).

ZakonRadaAdapter (src/adapters/zakon-rada-adapter.ts)

Fetches legislation HTML from zakon.rada.gov.ua:

  • GET /laws/show/{lawNumber} - full law text
  • GET /laws/search?q={keyword} - search laws by keyword

Parses HTML with Cheerio. Extracts title, metadata, adoption date, and individual articles. Rate limited to 10 rps.

Law Aliases (KNOWN_LAWS)

Alias Law Number
constitution / конституція 254к/96-вр
цивільний кодекс 435-15
кримінальний кодекс 2341-14
сімейний кодекс 2947-14
господарський кодекс 436-15
кпк 4651-17
цпк 1618-15
касу 2755-17
кзпп 1023-12

MCP Tools

Four tools are exposed via MCPRadaAPI:

1. search_parliament_bills

Search bills (zakonoproekty) by query, status, initiator, committee, date range.

Parameter Type Required Description
query string Yes Search term
status enum No registered, first_reading, second_reading, adopted, rejected, all
initiator string No Deputy name or faction
committee string No Committee name
date_from / date_to string No Date range (YYYY-MM-DD)
limit number No Max results (default 20)

2. get_deputy_info

Get detailed information about a deputy. Supports search by name, rada_id, or faction.

Parameter Type Required Description
name string No Full or partial name
rada_id string No RADA system ID
faction string No Faction name (returns member list)
include_voting_record boolean No Include voting statistics
include_assistants boolean No Include assistant list

3. search_legislation_text

Full-text search within Ukrainian laws. Supports aliases and article retrieval.

Parameter Type Required Description
law_identifier string Yes Law number or alias
article string No Specific article number
search_text string No Text to search for
include_court_citations boolean No Cross-reference with SecondLayer court cases

4. analyze_voting_record

AI-powered analysis of a deputy's voting patterns.

Parameter Type Required Description
deputy_name string Yes Deputy full name
date_from / date_to string No Analysis period
bill_number string No Specific bill to check
analyze_patterns boolean No Use AI (OpenAI) for pattern detection

Cache Strategy

All caching uses PostgreSQL cache_expires_at columns. No Redis-based data cache.

Entity TTL Env Override
Deputies 7 days CACHE_TTL_DEPUTIES
Bills 1 day CACHE_TTL_BILLS
Legislation 30 days CACHE_TTL_LAWS
Voting 3 days (hardcoded)

Cache-first retrieval logic:

  1. Check PostgreSQL for non-expired record
  2. On miss: fetch from RADA/Zakon API
  3. Upsert to database with new TTL expiry

Database Schema

PostgreSQL database rada_db (user: rada_mcp, port: 5433). Tables:

Table Purpose Key Fields
deputies Deputy profiles rada_id, full_name, faction_name, committee_name, active
deputy_assistants Assistant records deputy_id (FK), full_name, assistant_type
bills Bills / zakonoproekty bill_number, title, status, stage, registration_date
legislation Full law texts law_number, law_alias, articles (JSONB), full_text_plain
voting_records Session voting results session_date, question_text, bill_number, votes (JSONB)
factions Parliamentary factions faction_id, name, convocation
committees Parliamentary committees committee_id, name, chair_deputy_id
cost_tracking Per-request cost data request_id, tool_name, rada_api_calls
monthly_api_usage Aggregated usage year_month, rada_total_calls, rada_total_bytes
law_court_citations Cross-references to court cases law_number, court_case_number, citation_count

Migrations are in src/migrations/ (001 through 005). Run with npm run migrate.

Full-text search indexes exist on bills.title, legislation.title, legislation.full_text_plain, and voting_records.question_text.

Sync Scripts

Script Command Purpose
sync-laws.ts npm run sync:laws Download 40+ key laws from zakon.rada.gov.ua (Constitution, all major codes, key statutes). Configurable concurrency via CONCURRENCY env (default 3, max 5).
sync-reference-data.ts npm run sync:reference Sync factions, committees, and deputy assistants from data.rada.gov.ua.
sync-week-data.ts npm run build && node dist/scripts/sync-week-data.js Parallel sync of deputies, bills, and voting records for the last week.
import-json-data.ts npm run build && node dist/scripts/import-json-data.js Import JSON data dumps.
cleanup-cache.js npm run cleanup:cache Clean expired cache entries.

Laws Synced by sync-laws.ts

The script syncs 40+ documents including:

  • Constitution of Ukraine
  • Civil, Criminal, Family, Commercial, Tax, Land, Budget, Customs codes
  • Criminal Procedure, Civil Procedure, Administrative Procedure, Commercial Procedure codes
  • Water, Forest, Air, Maritime codes
  • Key laws: state registration, public info access, personal data, electronic documents, anti-corruption, judiciary, advocacy, notaries, banking, financial services, accounting, companies, real estate rights, land lease, mortgage, pledge, bankruptcy, enforcement proceedings

HTTP API Endpoints

Method Path Auth Description
GET /health No Full health check (PostgreSQL + Redis)
GET /health/live No Liveness probe
GET /health/ready No Readiness probe (DB query)
GET /metrics No Prometheus metrics
GET /api/stats No Data statistics (row counts, last update)
GET /api/tools Bearer List available tools
POST /api/tools/:toolName Bearer Execute tool (JSON response)
POST /api/tools/:toolName/stream Bearer Execute tool (SSE streaming)

Authentication: Bearer token via RADA_API_KEYS env var (comma-separated). SSE streaming sends connected, progress, complete/error, end events.

Rate limiting: 300 requests/minute globally (express-rate-limit), 120 req/min on /api/ routes.

Observability

  • Logging: Winston structured JSON logs
  • Metrics: Prometheus (prom-client) - HTTP request duration/count, PG pool connections, Node.js defaults
  • Cost tracking: Per-request tracking of OpenAI tokens, Anthropic tokens, RADA API calls (bytes, cached vs fresh), execution time. Aggregated monthly in monthly_api_usage.

Cross-Reference Service

The CrossReferenceService connects RADA data with SecondLayer court decisions:

  • Calls mcp_backend via HTTP (POST /api/tools/find_relevant_law_articles) to find court cases citing specific laws
  • Stores citations in law_court_citations table
  • Exposes via include_court_citations flag in search_legislation_text tool

Development Commands

cd mcp_rada

# Development
npm run dev:http     # HTTP server with hot-reload (port 3001)
npm run dev          # MCP stdio mode

# Production
npm run build && npm run start:http

# Database
npm run db:setup     # Create DB + run migrations
npm run migrate      # Run migrations only

# Data sync
npm run sync:laws        # Sync legislation texts
npm run sync:reference   # Sync factions, committees, assistants
npm run cleanup:cache    # Clean expired entries

# Testing
npm test             # Jest tests
npm run lint         # ESLint

Dependencies

Key runtime dependencies:

  • @modelcontextprotocol/sdk - MCP protocol
  • @secondlayer/shared - Shared types, BaseDatabase, BaseCostTracker, LLMManager
  • express 5.x - HTTP server
  • cheerio - HTML parsing for zakon.rada.gov.ua
  • axios - HTTP client for RADA APIs
  • pg - PostgreSQL driver
  • redis - Redis client (rate limiting)
  • openai - AI analysis (voting patterns)
  • @anthropic-ai/sdk - Alternative AI provider
  • prom-client - Prometheus metrics
  • winston - Structured logging
  • p-limit - Concurrency control

Unified Gateway Integration

In production with ENABLE_UNIFIED_GATEWAY=true, RADA tools are prefixed with rada_ and accessible through the main backend gateway at mcp_backend:

  • rada_search_parliament_bills
  • rada_get_deputy_info
  • rada_search_legislation_text
  • rada_analyze_voting_record

Clone this wiki locally