Skip to main content
Glama
librejustice

LibreJustice

Official

LibreJustice

librejustice.fr: a free search engine for French and European law, plus current public notices. It links case law from France's administrative and judicial courts to consolidated legal texts and makes them searchable in plain language on the web and through MCP.

Free and open source. ~3.7 million decisions and ~3.6 million legal articles in one database, linked article by article, resynchronised daily. That is the whole point: texts and case law live together, so there is no second server to plug in for the codes and no third one for the citation graph.

  • Case law: Conseil d'État, Cour de cassation, cours d'appel, administrative and judicial first-instance courts, Conseil constitutionnel, CNIL, CNDA (publicly released decisions only), Tribunal des conflits, ECHR, CJEU. Filters by court, date, outcome and cited articles.

  • Legal texts: codes and statutes as they stood on any date (consolidated versions with per-article history), the full Journal officiel, EU law, treaties and bilateral accords, collective agreements, BOFiP, circulaires, and the codes of 59 foreign countries.

  • Public notices: open public procurement opportunities from BOAMP and buyer platforms, deduplicated with submission links and deadlines.

  • Directory: lawyers, companies and courts, linked to their litigation.

Corpus refreshed daily from open sources (Judilibre, DILA/Légifrance, EUR-Lex...).

Related MCP server: mpc-legifrance

What the official sources do not offer

Public databases are silos, each with a search engine bounded by its own fonds (Judilibre covers the judicial courts only; the administrative open data searches CE/CAA/TA by keyword, court and date; Légifrance holds the texts). LibreJustice consolidates them and adds the missing layer:

  • plain-language search (hybrid lexical + semantic) with AI reranking, dynamic facets and similar decisions;

  • the graph: citations extracted and resolved, from a decision to the exact articles it cites at the right version, and from an article back to the decisions that cite it;

  • cross-source deduplication (one decision, one page) and recovery of decisions missing from the official channels;

  • AI summaries per decision, always kept distinct from verbatim excerpts;

  • a remote MCP endpoint for AI assistants.

Using LibreJustice from an AI assistant

The public MCP server is https://librejustice.fr/mcp (OAuth 2.1 with dynamic client registration: no API key to configure). Five tools: search_decisions, get_decision, search_legal_texts, get_legal_text, list_my_activity.

With Claude Code, the plugin installs the connector and the usage skills:

/plugin marketplace add librejustice/librejustice
/plugin install librejustice@librejustice

The skills alone (without the MCP connector) install into any compatible agent through skills:

npx skills add librejustice/librejustice

On claude.ai, LibreJustice is listed in the connector directory. One click, then the OAuth authorisation. With ChatGPT, Le Chat or Perplexity, add a custom connector pointing at https://librejustice.fr/mcp.

Using LibreJustice from your own code

The same corpus in REST, described by openapi.json (OpenAPI 3.1). The key is free: create an account, then a key from your profile. Guide at librejustice.fr/api-guide.

curl -H 'Authorization: Bearer ljk_your_key' \
  'https://librejustice.fr/api/search?q=trouble+anormal+de+voisinage&limit=3'

Five routes: /api/search, /api/search-textes, /api/decision/{id}, /api/texte/{code}/{article} and the same with a trailing /{date} for the version in force that day.

Stack

A single-server node, Postgres + ParadeDB + VectorChord (hybrid BM25 + vector search), API and front end in Rust.

A pure Rust Cargo workspace, split in two roots:

  • packages/ libraries:

    • lj-core pure core: parsing, normalisation, extraction, summary, legal refs.

    • lj-extract field and citation extraction from decisions.

    • lj-sources source I/O (Judilibre JSON, opendata ZIP/XML).

    • lj-store Postgres access (tokio-postgres + deadpool) and migrations.

    • lj-llm embedding backends, cache, quantisation, Mistral client (chat/OCR).

    • lj-dtos api to web contracts (serde).

    • lj-telemetry tracing and OTLP export.

    • lj-api API layer (Axum + MCP rmcp + OAuth).

    • lj-web Leptos front end (SSR + WASM hydration), Tailwind.

  • apps/ shippable binaries:

    • lj-server single deployment: API + MCP/OAuth + SSR.

    • lj-ingest ingest CLI and cron runner.

Build and dev

The Rust toolchain is pinned by rust-toolchain.toml. Tasks run through mise:

mise run test      # rustfmt --check + clippy -D warnings + cargo test --workspace
mise run dev       # merged lj-server (cargo leptos watch, :3000)

For a local database: mise run dbs. The task prepares the Postgres state under LIBREJUSTICE_STATE_DIR, owning the data directory and copying the configuration mounted by the container, before starting it.

Deployment

Single server through podman compose (infra/docker-compose.yml): Postgres (ParadeDB + VectorChord), the merged lj-server binary, a caddy front end and the ingest cron. Fill in .env (see .env.example), then:

mise run ensure-pg                                                          # Postgres state and conf
podman compose -f infra/docker-compose.yml --profile prod up -d --build
podman compose -f infra/docker-compose.yml exec -T cron lj-ingest migrate   # migrations

lj-server serves the API, MCP/OAuth, SSR and the assets. It listens in clear; caddy holds :443 and terminates TLS, so the socket stays bound when the application container is recreated.

The shipped Postgres configuration (infra/pg-conf/) carries what the application requires (extensions, ParadeDB settings, compression) sized for a development machine. A production instance raises shared_buffers and effective_cache_size to match its hardware.

Licence

Apache-2.0.

Available Tools

4 tools
get_decisionGet DecisionA
Read-onlyIdempotent
Inspect

Fetch the full text and metadata of a decision by its url. The text carries inline markdown links to cited articles (/texte/, open with get_legal_text) and cited decisions (/decision/, open with get_decision); a citation spanning several articles (« articles 3 à 6 », « et suivants ») links its first article and appends the others as labelled links right after the span. appellateFate states in one line what became of THIS decision on review (INFIRMATION = reversed, it no longer stands; CONFIRMATION = upheld): read it before citing the decision as authority. caseChronology lists the prior AND subsequent decisions of the same case (appeal, pourvoi, renvoi). An absent fate or chronology never proves no recourse exists, only that none is linked in the corpus. commentaires carries the institutional commentary (official analyses inline, links to the rapporteur public's conclusions and related court documents): context, never the ruling, so quote the decision text and not a commentaire.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesA librejustice.fr decision URL, from a search_decisions hit or an inline citation link; search_decisions first if you have neither.

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlYes
seatNo
textYes
titleYes
officeNo
solutionNo
procedureNo
dateLectureNo
legalDomainNo
officialUrlNo
publicationNo
commentairesNo
appellateFateNo
docketNumbersNo
caseChronologyNo
jurisdictionCodeNo
jurisdictionTypeYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, but the description goes beyond by explaining field semantics: appellateFate (with definitions), caseChronology, and commentaires, including warnings about interpretation ('read it before citing', 'absent fate never proves no recourse', 'context, never the ruling'). It also explains markdown link behavior and multi-article citation handling. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but each sentence adds critical usage or interpretation context. It is structured logically: purpose, link behavior, field semantics, then warnings. While not terse, the density justifies the length and it remains readable and front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description goes beyond by explaining the meaning of fields and how to interpret them, including caveats. It also covers how to open linked resources. Nothing essential is missing for an agent to call it correctly; it even warns about potential misinterpretations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter `url` is fully described in the schema (100% coverage), including where to obtain it (from search_decisions hit or citation link). The description repeats this but adds no new semantic detail beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Fetch the full text and metadata of a decision by its `url`.' It clearly distinguishes from search_decisions (search) and get_legal_text (articles) by specifying the action and input. The purpose is unambiguous 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.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells when to use this tool versus alternatives: it says to use search_decisions first if you don't have a URL, and to use get_legal_text for article links. It also references get_decision for decision links, making the decision tree clear. No inference is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_decisionsSearch DecisionsA
Read-onlyIdempotent
Inspect

Search decisions by meaning and keywords combined. Returns a shortlist: title, url, an overview (aiSummary: AI-written summary of what the decision is about, a machine paraphrase never quotable as the court's words; or snippet: the verbatim passage where your keywords matched) and metadata; get_decision reads the full text. Put constraints in the structured filters (jurisdiction, dates, articles, codes), keep the query for the legal issue. Values within one filter are OR'd; different filters are AND'd. The response carries a facets block: per filter name, a map of filter value to decision count under the current query. Reuse those keys verbatim to refine. Hit metadata fields carry the same tokens under the same names: a hit's jurisdictionCode, legalDomain or solution passes back verbatim into the matching filter.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNo'auto' is the right choice in almost all cases, it picks the regime from the query shape. auto: combines meaning and keyword matching on plain queries; switches to keyword-only when the query contains ET / OU / SAUF or quoted phrases. lexical: force keyword-only matching. Every term becomes required and nothing recovers a miss, so it fits a string you expect word for word (a consecrated formula, the direction of a holding, a party named in the text) and an empty answer is then an answer. semantic: force the meaning+keyword hybrid even on quoted or operator queries (where auto would fall back to keyword-only).auto
seatNoRestrict to one or more seats, as a dotted path from the court type down to the room: "CC", "CC.SOCIALE", "CA.PARIS", "CA.PARIS.P5.C3". A path matches itself and everything below it, so this one filter also covers what jurisdiction_type and jurisdiction_code express. Take the paths from facets.seat.
sortNoResult ordering. Use 'relevance' (default) unless the user wants chronological order.relevance
limitNoMaximum number of results (default 10).
queryYesFrench query, the primary input. Two regimes, pick the right tool for the job: (a) Natural language or descriptive keywords for legal-issue searches; the engine handles synonyms and reformulations. Examples: « responsabilité hôpital infection nosocomiale » ; « étranger malade soins inaccessibles dans son pays d'origine » ; « licenciement discrimination syndicale charge de la preuve ». (b) Quoted exact phrases and ET / OU / SAUF operators for a named entity (company, municipality, person), a precise legal formula, or the direction of a holding: semantic matching ignores negations (« n'est pas X » ranks like « est X »), and only an exact phrase targets which way the court ruled. Examples: « "Société Générale" » ; « "commune de Saint-Denis" SAUF Réunion » ; « "force majeure" ET épidémie ». Using operators or quotes switches the engine to keyword-only matching for the whole query (no synonyms), so do not mix the two regimes.
officeNoFilter by specialised judge/office (JLD, JAF, JCP, JEX, juge des enfants, premier président, magistrat désigné). Absent value = ordinary bench.
date_toNoLatest decision date, inclusive (YYYY-MM-DD).
solutionNoFilter by the ruling of the operative part (référentiel solution). REJET / IRRECEVABILITE / DESISTEMENT / NON_LIEU_A_STATUER are procedural or negative endings; CONFIRMATION / INFIRMATION* / REFORMATION are appeal outcomes; CASSATION* is cassation-specific; ANNULATION covers administrative annulment; SATISFACTION_TOTALE / SATISFACTION_PARTIELLE cover first-instance civil rulings granting the claim.
ai_rerankNoWhen enabled (default), reorders results by actual relevance to the query using an LLM reranker. Keep on for agentic use, shortlist quality is significantly higher. Cost: a few seconds of extra latency. Disable only for high-rate exploratory searches where latency matters more than ranking quality.
date_fromNoEarliest decision date, inclusive (YYYY-MM-DD).
procedureNoFilter by procedural track (référés, QPC, EU referral, révision, tierce opposition…). Absent value = ordinary contentious procedure.
publicationNoFilter by publication, at the grain the Cour de cassation itself uses (any-of, membership is multiple: a decision matches every value whose code it carries). Judicial order: PUBLIE_RAPPORT (annual report, the strongest signal), PUBLIE_BULLETIN, LETTRE_CHAMBRE, COMMUNIQUE, INEDIT_BULLETIN. Administrative order: PUBLIE_LEBON, MENTIONNE_LEBON, INEDIT_LEBON. Lower courts carry no publication statement and match no value.
legal_domainNoFilter by legal domain (curated domain tree): 9 roots and their leaves (e.g. CIVIL_DROIT_LOCATIF). Selecting a root also matches all its leaves.
legal_articleNoRestrict to decisions citing a specific article of a specific code, as a composite key "<instrument>|<article>" where <instrument> is a slug or an exact text name, resolved like legal_instrument (e.g. "code-civil|1240", "code-de-justice-administrative|L761-1"). The instrument prefix is required: the same article number exists in several codes.
legal_instrumentNoRestrict to decisions citing one or more given codes or statutes. Accepts a slug from facets.legal_instrument (e.g. "code-civil") or an exact text name resolved server-side (e.g. "Code civil").
jurisdiction_codeNoRestrict to one or more precise court units by referential code. Code shapes: "cc" (Cour de cassation), "ce" (Conseil d'État), "cnda", "cedh", "cjue"; "ca_<city>", "caa_<city>", "ta_<city>", "tj_<city>", "tcom_<city>" (e.g. "ca_paris", "ta_marseille", "tj_paris", "tcom_lyon"). When unsure, guess with the city name in the code: the error names the nearest valid ones. Each code is a court; a room inside it is reached with seat, which also expresses this filter as a path.
jurisdiction_typeNoRestrict to one or more court categories: TJ (tribunal judiciaire), CA (cour d'appel), CC (Cour de cassation), TCOM (tribunal des activités économiques), TA (tribunal administratif), CAA (cour administrative d'appel), CE (Conseil d'État), CNDA (asylum), CONSTIT (Conseil constitutionnel), TC (Tribunal des conflits), CNIL (sanctions), CEDH and CJUE (European courts).

Output Schema

ParametersJSON Schema
NameRequiredDescription
hitsYes
queryYes
totalYes
facetsNo
pinnedNo
filterRewrittenNo

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description goes beyond by explaining the return structure (shortlist with aiSummary/snippet, facets block, metadata), how filters combine (OR within, AND across), how to reuse facet keys verbatim, and the reranking latency trade-off. It also discloses the semantic matching limitation with negations. No contradictions with annotations; the description adds substantial behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but meticulously structured: it opens with the core purpose, then covers return format, filter semantics, facet usage, and ends with parameter-specific guidance. Every section earns its place given the 17 parameters and complex filtering logic, and the most important points (query regimes, filter combination) are front-loaded. No fluff; all sentences contribute to correct tool usage.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (17 parameters, rich filters, output schema), the description is thorough: it defines the return shortlist, the facets block, how to refine queries, the behavior of each mode, and how to interpret hit metadata. It also points to `get_decision` for full text, covering the workflow. Nothing essential for calling the tool correctly is missing, and the output schema's presence allows the description to avoid re-explaining return types.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, yet the description adds significant meaning: it explains the two query regimes with examples, the mode behavior (auto switching to keyword-only on operators), how seat expresses both jurisdiction_type and jurisdiction_code, how legal_article requires an instrument prefix, and how facets map to filter values. This is far beyond the schema's basic parameter descriptions, providing actionable guidance for proper parameter usage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Search decisions by meaning and keywords combined.' It clearly differentiates itself from siblings by noting 'get_decision reads the full text,' and 'search_legal_texts' is implied as a different search over legal texts. It also explains the scope of filtering for legal issues versus query semantics, making the tool's function unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance, including separating natural-language queries from exact-phrase/operator queries, explaining when to use `mode` (auto/lexical/semantic) and when to disable `ai_rerank`. It also instructs to 'Put constraints in the structured filters... keep the query for the legal issue,' and points to `get_decision` for full-text reading. This fully routes the agent to the right usage and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedget_decision
    • First observedget_legal_text
    • First observedsearch_decisions
    • First observedsearch_legal_texts

TDQS

A4.7/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct entity and action: search_decisions and get_decision for court decisions, search_legal_texts and get_legal_text for legal texts. No overlap in purpose, clear separation between search and retrieval.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern in snake_case: search_decisions, get_decision, get_legal_text, search_legal_texts. The verbs are limited to search and get, and the nouns clearly indicate the entity.

Tool Count5/5

With only 4 tools, the server is tightly scoped for legal research: two search tools and two retrieval tools, covering both decisions and legal texts. This is a reasonable and minimal set that serves its purpose effectively.

Completeness5/5

The tool surface covers the core workflow: searching and retrieving both decisions and legal texts, including versioning and citation links. There are no obvious dead ends—search results chain directly to full-text retrieval, and get_decision links to related decisions and texts. The domain is well-covered for a research-focused server.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers