LibreJustice
OfficialClick on "Deploy 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., "@LibreJusticeCherche des décisions du Conseil d'État sur le droit des étrangers"
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.
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.
What you search
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@librejusticeThe skills alone (without the MCP connector) install into any compatible agent through skills:
npx skills add librejustice/librejusticeOn 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-corepure core: parsing, normalisation, extraction, summary, legal refs.lj-extractfield and citation extraction from decisions.lj-sourcessource I/O (Judilibre JSON, opendata ZIP/XML).lj-storePostgres access (tokio-postgres + deadpool) and migrations.lj-llmembedding backends, cache, quantisation, Mistral client (chat/OCR).lj-dtosapi to web contracts (serde).lj-telemetrytracing and OTLP export.lj-apiAPI layer (Axum + MCP rmcp + OAuth).lj-webLeptos front end (SSR + WASM hydration), Tailwind.
apps/shippable binaries:lj-serversingle deployment: API + MCP/OAuth + SSR.lj-ingestingest 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 # migrationslj-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
Available Tools
4 toolsget_decisionGet DecisionARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | A librejustice.fr decision URL, from a search_decisions hit or an inline citation link; search_decisions first if you have neither. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| seat | No | |
| text | Yes | |
| title | Yes | |
| office | No | |
| solution | No | |
| procedure | No | |
| dateLecture | No | |
| legalDomain | No | |
| officialUrl | No | |
| publication | No | |
| commentaires | No | |
| appellateFate | No | |
| docketNumbers | No | |
| caseChronology | No | |
| jurisdictionCode | No | |
| jurisdictionType | Yes |
TDQS
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.
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.
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.
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.
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.
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.
get_legal_textGet Legal TextARead-onlyIdempotentInspect
Fetch a legal text, or one of its articles, as it stood on a given date. Returns the version in force at date (omit for today): full text, status, validity dates, and the timeline of all versions: say which version you quote. The text carries inline markdown links to cross-referenced articles (/texte/, open with get_legal_text; when served at a date, the links point to the same date). commentaires carries institutional commentary anchored on the article (analyses inline, links otherwise). num absent means you hold the whole text; a section entry of articles, fetched by its url, returns all its articles at once. Covers French codes and statutes, plus curated foreign codes and treaties.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | A librejustice.fr article URL `/texte/{code}/{article}`: take it from a search_legal_texts hit or an inline citation link, or compose it: {code} is the code slug ("code-civil", as in facets.legal_instrument), {article} the lowercase article key ("l761-1" for L. 761-1, "1240" for 1240). `/texte/{code}` alone addresses the text itself, which is how a text with no articles (circulaire, publication decree) is read. | |
| code | No | Code slug, when you hold the code and the article apart rather than as a url ("code-civil"). Alone, addresses the text itself. | |
| date | No | Consultation date (YYYY-MM-DD): returns the version in force at that date. Omit for the version currently in force. | |
| textId | No | Légifrance article id (LEGIARTI…), resolved to the article it designates. LEGITEXT and CID are not accepted. | |
| article | No | Lowercase article key, alongside `code` ("l761-1" for L. 761-1, "1240" for 1240). |
Output Schema
| Name | Required | Description |
|---|---|---|
| num | No | |
| url | Yes | |
| code | Yes | |
| etat | No | |
| nota | No | |
| text | No | |
| title | Yes | |
| dateFin | No | |
| omitted | No | |
| articles | No | |
| versions | Yes | |
| dateDebut | No | |
| sourceUrl | No | |
| articleCount | No | |
| commentaires | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool as read-only and idempotent, so the bar is lower for adding behavior context. The description goes well beyond this: it details how versioning works (inline links point to the same date when served at a date), how `commentaires` are delivered (inline or by link), and how absent `num` indicates the whole text. It also clarifies that `section` entries return all articles at once, adding genuinely useful behavioral nuance.
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 dense but efficient. Every clause serves a purpose: the core function, the date semantics, the output contents, linking behavior, commentary handling, coverage scope, and special cases. It is front-loaded with the main purpose and uses compact, technical language without fluff. The length is justified by the tool's complexity.
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 5 optional parameters and an existing output schema, the description covers most operational details: versioning, date handling, link semantics, and edge cases like texts without articles. It does not mention the response format (but the output schema covers that). It could be slightly more explicit about exclusions (e.g., that it does not search or return lists of texts), but it is otherwise complete 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%—every parameter already has a detailed description in the schema. The description adds some context about composing URLs and the distinction between text-level and article-level requests, but this is largely already captured in the parameter descriptions. The baseline of 3 applies because the schema carries the load, and the description does not need to compensate.
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 begins with a clear verb and resource: 'Fetch a legal text, or one of its articles, as it stood on a given date.' It states exactly what is returned (version in force, status, validity dates, timeline) and is easily distinguishable from siblings like search_legal_texts, which is for searching rather than fetching a specific text.
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 tells the agent where to obtain URLs ('take it from a search_legal_texts hit or an inline citation link'), implying a workflow with its sibling. It also explains when to omit the date ('omit for today') and how to handle texts without articles. However, it does not explicitly state when to prefer this tool over search_legal_texts or get_decision, though the context makes it fairly obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_decisionsSearch DecisionsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | '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 |
| seat | No | Restrict 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. | |
| sort | No | Result ordering. Use 'relevance' (default) unless the user wants chronological order. | relevance |
| limit | No | Maximum number of results (default 10). | |
| query | Yes | French 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. | |
| office | No | Filter by specialised judge/office (JLD, JAF, JCP, JEX, juge des enfants, premier président, magistrat désigné). Absent value = ordinary bench. | |
| date_to | No | Latest decision date, inclusive (YYYY-MM-DD). | |
| solution | No | Filter 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_rerank | No | When 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_from | No | Earliest decision date, inclusive (YYYY-MM-DD). | |
| procedure | No | Filter by procedural track (référés, QPC, EU referral, révision, tierce opposition…). Absent value = ordinary contentious procedure. | |
| publication | No | Filter 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_domain | No | Filter 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_article | No | Restrict 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_instrument | No | Restrict 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_code | No | Restrict 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_type | No | Restrict 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
| Name | Required | Description |
|---|---|---|
| hits | Yes | |
| query | Yes | |
| total | Yes | |
| facets | No | |
| pinned | No | |
| filterRewritten | No |
TDQS
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.
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.
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.
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.
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.
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.
search_legal_textsSearch Legal TextsARead-onlyIdempotentInspect
Find legal articles from their subject or wording when the article number is unknown; returns a ranked shortlist with highlighted snippets and the exact total. Query in French, descriptive terms (« délai de recours contentieux refus implicite »); put the code in the code filter (slug or exact name), keep the query for the subject. The response carries a facets block (code, jurisdiction): per filter name, a map of filter value to article count, reuse those keys verbatim to refine. Chain a hit into get_legal_text with its url, plus date when the dispute is governed by an earlier version.
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | Restrict to one code/text by its URL slug ("code-civil", as in facets.code) or exact name. Omit to search the whole navigable referential. | |
| date | No | Consultation date (YYYY-MM-DD): searches the versions valid at that date (point-in-time, same semantics as get_legal_text). Omit to search the versions currently in force. | |
| limit | No | Maximum number of results (default 10). | |
| query | Yes | French query over legal articles. Matches article titles (boosted) and bodies; alias expansion handles acronyms and usual names. | |
| jurisdiction | No | Filter by country/legal order, as an ISO 3166 alpha-2 country code: "FR" (France, the bulk of the corpus) or a foreign code ("SN", "DZ", "MA", "VN", "PE", …); plus "UE" for EU law and "INTL" for treaties/international law. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hits | Yes | |
| query | Yes | |
| total | Yes | |
| facets | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so safety is covered. The description adds substantial behavioral context: returns a ranked shortlist with snippets and exact total, includes a facets block with per-filter article counts, and explains the point-in-time semantics of the date parameter (same as get_legal_text). No contradictions.
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?
Two dense sentences with zero filler. The opening states the purpose, then immediately gives usage, then facets, then chaining – all high-value information. No redundancy with the schema. The structure is front-loaded and every clause carries weight.
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 5-parameter search tool with a documented output schema, the description covers everything an agent needs: purpose, query construction, filter usage, facet-based refinement, and integration with the sibling tool. The point-in-time date semantics are explained. 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%, so each parameter has a baseline description. The description adds value beyond the schema by advising how to structure the query ('put the code in the code filter, keep the query for the subject'), clarifying the code filter as 'as in facets.code', and explicitly tying date semantics to get_legal_text. This meaningfully enhances parameter usage, so above the baseline 3.
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?
States a specific verb (Find), resource (legal articles), and the precise condition (when article number is unknown). Clearly distinguishes from siblings: search_decisions is for case law, get_legal_text is for retrieving a known article by URL. The purpose is unmistakable.
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, actionable guidance: query in French with descriptive terms, put the code in the code filter, keep the query for the subject. Explains how to reuse facets keys verbatim for refinement and how to chain hits into get_legal_text with url and date. This is far beyond vague 'when to use' – it is a usage manual.
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.
4 tool updates
v0.1.0- First observed
get_decision - First observed
get_legal_text - First observed
search_decisions - First observed
search_legal_texts
TDQS
Scored across 4 tools
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.
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.
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.
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
Related MCP Connectors
Eurlex MCP client: Access EU law & Official Journal. https://www.lexsocket.ai/
Search a curated directory of AI tools and MCP servers for law firms. Read-only, free, no auth.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP Server providing AI agents access to over 3 million US court decisions via CourtListener and EU legislation via EUR-Lex, with tools for searching cases, citations, judges, and court information.6MIT
- AlicenseNot gradedqualityDmaintenanceMCP server covering French law via the PISTE platform: 62 tools wrapping the full Légifrance API (legislation, codes, Journal Officiel, jurisprudence…)3AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceMCP server covering French law via the PISTE platform: 8 tools wrapping the JUDILIBRE API (open data judicial decisions from Cour de cassation, courts of appeal and civil courts).2AGPL 3.0
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to search and retrieve French legislation, case law, and EU law integrations from official sources via MCP.54 npm1Apache 2.0