{
  "name": "ldata",
  "version": "2.0.0",
  "base_url": "/api",
  "mcp": {
    "transport": "streamable_http",
    "path": "/mcp",
    "note": "tools/list is filtered by pack (config/corpus.yml mcp.pack, or ?pack=core|public|full). tools/call still dispatches any tool in this file. Auth: Authorization Bearer, X-Api-Key, or ?api_key= on /mcp URL.",
    "packs": {
      "core": "search + fetch over every corpus, read-only SQL (sql_query / get_sql_schema), then precision tools: caselaw filters, statute articles as of a date, version history. Default for agents.",
      "public": "core + per-corpus search/get tools (EU, administrative, constitutional, KALI, BOFiP, authorities) and LEGI catalogue/health/quota.",
      "full": "Every tool (HTTP surface)."
    },
    "default_pack": "core"
  },
  "documentation": {
    "llms": "/llms.txt",
    "llms_full": "/llms-full.txt",
    "agent_system": "/agent-system.txt",
    "human": "/docs",
    "openapi": "/openapi.yaml",
    "browse": "/browse"
  },
  "auth": {
    "type": "apiKey",
    "headers": [
      "Authorization: Bearer <key>",
      "X-Api-Key: <key>"
    ],
    "key_prefix": "oj_",
    "dev_key_command": "bin/rails agent:dev_key"
  },
  "agent_hints": {
    "find_not_cite": true,
    "quota": {
      "note": "Every authenticated request costs 1 day unit (including get_decision). No free tier: an account without a subscription gets 402 subscription_required.",
      "recommended_turn": {
        "max_searches": 5,
        "max_full_decisions": 3,
        "prefer_snippets_first": true
      },
      "pro": {
        "day": 500,
        "rpm": 30,
        "max_limit": 50
      },
      "vip": {
        "day": 2000,
        "rpm": 60,
        "max_limit": 50
      }
    },
    "naming": {
      "caselaw_hit": [
        "id",
        "citation",
        "jurisdiction",
        "decision_date",
        "number",
        "outcome",
        "snippet",
        "verify_url",
        "verify_note",
        "possibly_reversed"
      ],
      "decision": [
        "id",
        "citation",
        "decision_date",
        "number",
        "jurisdiction",
        "text",
        "verify_url",
        "verify_note",
        "source_updated_on"
      ],
      "statute_article": [
        "id",
        "citation",
        "text",
        "instrument_slug",
        "instrument_id",
        "legi_status",
        "in_force_on_as_of",
        "as_of",
        "verify_url"
      ],
      "no_aliases": [
        "in_force",
        "status",
        "slug",
        "date",
        "code_slug",
        "article (use visa for caselaw-by-article)"
      ]
    },
    "sample_queries": [
      {
        "tool": "search",
        "query": "\"pension alimentaire\" résidence alternée"
      },
      {
        "tool": "fetch",
        "id": "codes:code-civil/373-2-2",
        "as_of": "2010-06-01"
      },
      {
        "tool": "search_caselaw",
        "q": "\"pension alimentaire\"",
        "jurisdiction": "ca",
        "after": "2022-01-01",
        "syn": true
      },
      {
        "tool": "search_caselaw",
        "number": "21-14.490"
      },
      {
        "tool": "get_statute_article",
        "instrument_slug": "code-civil",
        "number": "373-2-2"
      },
      {
        "tool": "get_statute_article",
        "instrument_slug": "code-civil",
        "number": "373-2-2",
        "as_of": "2010-06-01"
      },
      {
        "tool": "search_caselaw_by_article",
        "visa": "373-2-2",
        "jurisdiction": "cc"
      }
    ]
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search",
        "x-mcp-title": "Search all French legal data",
        "x-mcp-pack": "core",
        "description": "Use first for any legal question: one query over case-law, codes, statutes, EU, admin, constitutional, KALI, BOFiP, circulars, JO. Open hits with fetch.",
        "parameters": {
          "type": "object",
          "properties": {
            "query": {
              "type": "string",
              "description": "Full-text query (FTS5). Phrases in double quotes, e.g. \"pension alimentaire\" résidence."
            },
            "corpora": {
              "type": "string",
              "description": "Comma list to restrict, or all. Default: every legal corpus (caselaw, codes, statutes, admin_caselaw, constitutional, eu, collective_agreements, tax_doctrine, authorities, circulars, official_journal, legislative_dossiers). Opt-in: company_agreements, commercial_notices, public_procurement."
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "description": "Hits per corpus (default 3)"
            }
          },
          "required": [
            "query"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/find",
          "auth": true,
          "query_map": {
            "query": "q"
          }
        },
        "x-returns": {
          "results[]": {
            "id": "<corpus>:<id> — pass to fetch",
            "corpus": "string",
            "title": "string",
            "date": "YYYY-MM-DD",
            "url": "official verify link",
            "snippet": "string"
          },
          "meta.per_corpus": "hits per corpus",
          "meta.unavailable": "corpora that failed (503 etc.)"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "fetch",
        "x-mcp-title": "Open a document",
        "x-mcp-pack": "core",
        "description": "Use to open any hit returned by search, by its id (<corpus>:<id>): text, metadata and the official url to check before citing.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Id from search, e.g. caselaw:607975589ba5988459c49ed9 or codes:code-civil/373-2-2"
            },
            "as_of": {
              "type": "string",
              "description": "codes/statutes only: YYYY-MM-DD, article text in force that day"
            },
            "full": {
              "type": "boolean",
              "description": "Untruncated text (very long documents)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/fetch/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "corpus": "string",
          "title": "string",
          "text": "string",
          "url": "official verify link",
          "metadata": "corpus-specific fields"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "health_check",
        "x-mcp-title": "Service health",
        "x-mcp-pack": "public",
        "description": "Call once at session start to see if corpora are up and how stale they are. No auth.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/health",
          "auth": false
        },
        "x-returns": {
          "status": "ok | stale | degraded",
          "decisions": "integer",
          "legis.articles": "integer",
          "age_days": "integer",
          "stale": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_caselaw",
        "x-mcp-title": "Search judicial case-law",
        "x-mcp-pack": "core",
        "description": "Use to find judicial decisions (Cour de cassation, cours d'appel, TJ, tribunaux de commerce). Not statute text and not administrative courts (CE/CAA/TA).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query. Phrases in double quotes. Proximity: \"a b\" NEAR/20 c. Hyphens in free text are OK (sanitized)."
            },
            "mode": {
              "type": "string",
              "enum": [
                "fts",
                "semantic",
                "hybrid"
              ],
              "description": "fts (default) = keyword FTS5. semantic = vector search, plain-language q (fact patterns work). hybrid = RRF fusion of both — recommended for natural language. semantic/hybrid combine only with jurisdiction/after/before/limit/offset. Hits gain similarity (per-query cosine, not calibrated); meta.semantic_corpus = embedded subset matching filters. Falls back to FTS (meta.mode=fts + meta.semantic_fallback code) if embeddings unavailable."
            },
            "jurisdiction": {
              "type": "string",
              "description": "Court filter: cc, ca, tj, tcom, or comma list e.g. cc,ca"
            },
            "location": {
              "type": "string",
              "description": "Court name or code substring (Versailles, tj31555, 7501)"
            },
            "number": {
              "type": "string",
              "description": "Exact case number after normalization (no RG/n°/pourvoi prefix). e.g. 17/07602 or 21-14.490"
            },
            "article": {
              "type": "string",
              "description": "Statutory visa cited in decisions (e.g. 373-2-2, L132-1)"
            },
            "outcome": {
              "type": "string",
              "enum": [
                "cassation",
                "rejet",
                "irrecevabilite",
                "infirmation",
                "confirmation",
                "autre"
              ]
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive"
            },
            "sort": {
              "type": "string",
              "enum": [
                "authority",
                "rank",
                "date"
              ],
              "description": "Default authority. Prefer rank for broad FTS speed."
            },
            "syn": {
              "type": "boolean",
              "description": "Expand legal synonyms (costs same quota)"
            },
            "reversed": {
              "type": "boolean",
              "description": "Soft filter: CA possibly quashed (court+date)"
            },
            "cites": {
              "type": "string",
              "description": "Decision id → Cassation decisions it cites"
            },
            "cited_by": {
              "type": "string",
              "description": "Cassation id → decisions citing it"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset (use sparingly)"
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string",
            "citation": "French citation string — always show user",
            "jurisdiction": "cc|ca|tj|tcom",
            "decision_date": "YYYY-MM-DD",
            "number": "string",
            "outcome": "raw solution text",
            "snippet": "string",
            "verify_url": "string",
            "verify_note": "string",
            "possibly_reversed": "boolean high-confidence reverse only",
            "reversal_signal": "object status/confidence/method/peer_count/note"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_decision",
        "x-mcp-title": "Get a court decision",
        "x-mcp-pack": "core",
        "description": "Use after search_caselaw to open one decision by id (prefer full=false). Graph fields are find-aids — re-check verify_url before citing.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Decision id from search results"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full judgment text (very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/decisions/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "citation": "string",
          "decision_date": "YYYY-MM-DD",
          "number": "string",
          "jurisdiction": "string",
          "text": "string",
          "source_updated_on": "string|null Judilibre freshness",
          "verify_url": "string",
          "verify_note": "string",
          "cites_pourvois": "pourvoi number → 0..N CC (resolved false if hors fonds)",
          "cites_edges": "materialized citing→cited decision ids (principal/related)",
          "cited_by": "decisions that cite this one",
          "possibly_reversed": "boolean high-confidence reverse only",
          "reversal_signal": "object status/confidence/method/peer_count/note",
          "graph": "object note + reversed_by[] (on CA) or reverses_ca (on CC, high only)"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_caselaw_by_article",
        "x-mcp-title": "Case-law citing an article",
        "x-mcp-pack": "core",
        "description": "Use to find decisions that cite a given article number (visa), not to read the law. For the statute text use get_statute_article.",
        "parameters": {
          "type": "object",
          "properties": {
            "visa": {
              "type": "string",
              "description": "Article number e.g. 373-2-2 or L132-1 (path param; also accepted as code)"
            },
            "code": {
              "type": "string",
              "description": "Alias of visa for older tool bindings"
            },
            "jurisdiction": {
              "type": "string",
              "description": "cc, ca, tj, tcom or comma list"
            },
            "after": {
              "type": "string"
            },
            "before": {
              "type": "string"
            },
            "sort": {
              "type": "string",
              "enum": [
                "authority",
                "rank",
                "date"
              ]
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/caselaw/by-article/{visa}",
          "auth": true,
          "path_param_from": [
            "visa",
            "code"
          ]
        },
        "x-returns": {
          "corpus": "caselaw",
          "visa": "normalized article number",
          "results": "same shape as search_caselaw hits"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "list_codes",
        "x-mcp-title": "List French codes",
        "x-mcp-pack": "public",
        "description": "Use to discover a code's instrument_slug (Code civil, Code du travail, …). Default = codes only. No auth.",
        "parameters": {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "code",
                "text"
              ]
            },
            "nature": {
              "type": "string",
              "description": "CODE, LOI, DECRET, ORDONNANCE, …"
            },
            "q": {
              "type": "string",
              "description": "Filter title/slug/NOR"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes",
          "auth": false
        },
        "x-returns": {
          "instruments[]": {
            "id": "LEGITEXT…",
            "slug": "code-civil",
            "title": "…",
            "kind": "code|text",
            "article_count": "integer"
          },
          "codes[]": "Same rows when defaulting to codes; EMPTY when kind/nature/q filters return non-code instruments — always read instruments[]"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_instrument",
        "x-mcp-title": "Get a code or text",
        "x-mcp-pack": "public",
        "description": "Use to fetch metadata for one LEGI instrument by instrument_slug — not the article text.",
        "parameters": {
          "type": "object",
          "properties": {
            "instrument_slug": {
              "type": "string",
              "description": "e.g. code-civil, code-du-travail"
            }
          },
          "required": [
            "instrument_slug"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes/{instrument_slug}",
          "auth": false
        },
        "x-returns": {
          "instrument.slug": "string",
          "instrument.title": "string",
          "instrument.article_count": "integer",
          "instrument.version_count": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "list_code_articles",
        "x-mcp-title": "List articles of a code",
        "x-mcp-pack": "public",
        "description": "Use to get the table of contents of one code or consolidated text (structure only, no article bodies).",
        "parameters": {
          "type": "object",
          "properties": {
            "instrument_slug": {
              "type": "string"
            },
            "q": {
              "type": "string",
              "description": "Filter number/breadcrumb"
            },
            "as_of": {
              "type": "string",
              "description": "YYYY-MM-DD for TOC as of day"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000
            }
          },
          "required": [
            "instrument_slug"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes/{instrument_slug}/articles",
          "auth": true
        },
        "x-returns": {
          "articles[]": {
            "number": "string",
            "legi_status": "string",
            "in_force_on_as_of": "boolean",
            "path": "array"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_statute_article",
        "x-mcp-title": "Get a statute article (as of a date)",
        "x-mcp-pack": "core",
        "description": "Use to read one article's text (a code or a consolidated law/decree) as in force on as_of. Not a case-law search.",
        "parameters": {
          "type": "object",
          "properties": {
            "instrument_slug": {
              "type": "string",
              "description": "e.g. code-civil"
            },
            "number": {
              "type": "string",
              "description": "e.g. 373-2-2 or L132-1"
            },
            "as_of": {
              "type": "string",
              "description": "YYYY-MM-DD version selection"
            }
          },
          "required": [
            "instrument_slug",
            "number"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes/{instrument_slug}/articles/{number}",
          "auth": true
        },
        "x-returns": {
          "article.citation": "string",
          "article.text": "string",
          "article.structure.instrument_slug": "string",
          "article.vigueur.legi_status": "string",
          "article.vigueur.in_force_on_as_of": "boolean",
          "article.vigueur.as_of": "YYYY-MM-DD",
          "article.verify_url": "Légifrance"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_article_versions",
        "x-mcp-title": "Article version history",
        "x-mcp-pack": "core",
        "description": "Use after get_statute_article when you need that article number's version timeline.",
        "parameters": {
          "type": "object",
          "properties": {
            "instrument_slug": {
              "type": "string"
            },
            "number": {
              "type": "string"
            }
          },
          "required": [
            "instrument_slug",
            "number"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes/{instrument_slug}/articles/{number}/versions",
          "auth": true
        },
        "x-returns": {
          "versions[]": {
            "number": "string",
            "legi_status": "string",
            "date_start": "YYYY-MM-DD",
            "date_end": "YYYY-MM-DD",
            "in_force_on_as_of": "boolean for default as_of=today"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_legislation",
        "x-mcp-title": "Search codes (LEGI)",
        "x-mcp-pack": "core",
        "description": "Use to full-text search article bodies inside codes (C. civ., C. trav., …). Not case-law, not the Journal officiel, not consolidated lois/décrets (use search_statutes).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "instrument_slug": {
              "type": "string",
              "description": "Optional filter (query param code=)"
            },
            "kind": {
              "type": "string",
              "enum": [
                "code",
                "text"
              ]
            },
            "nature": {
              "type": "string"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/codes/search",
          "auth": true,
          "query_map": {
            "instrument_slug": "code"
          }
        },
        "x-returns": {
          "results[]": {
            "instrument_slug": "string",
            "instrument_title": "string",
            "number": "string",
            "legi_status": "string",
            "in_force_on_as_of": "boolean",
            "snippet": "string",
            "href": "string"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "list_statutes",
        "x-mcp-title": "List consolidated texts",
        "x-mcp-pack": "public",
        "description": "Use to discover a consolidated law, decree or arrêté (not a code): slug, NOR or cid. No auth.",
        "parameters": {
          "type": "object",
          "properties": {
            "nature": {
              "type": "string",
              "description": "LOI, DECRET, ORDONNANCE, ARRETE, …"
            },
            "q": {
              "type": "string",
              "description": "Filter title / slug / NOR"
            },
            "nor": {
              "type": "string",
              "description": "Exact NOR (case-insensitive)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/statutes",
          "auth": false
        },
        "x-returns": {
          "instruments[]": {
            "id": "JORFTEXT… / LEGITEXT…",
            "slug": "string",
            "title": "…",
            "kind": "text",
            "nature": "LOI|DECRET|…",
            "nor": "string",
            "article_count": "integer"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_statute",
        "x-mcp-title": "Get a consolidated text",
        "x-mcp-pack": "public",
        "description": "Use to fetch one consolidated non-code text by slug, cid or NOR. Codes 404 — use get_instrument.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Slug, cid, or NOR"
            },
            "instrument_slug": {
              "type": "string"
            },
            "nor": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/statutes/{id}",
          "auth": false,
          "path_param_from": [
            "id",
            "instrument_slug",
            "nor"
          ]
        },
        "x-returns": {
          "instrument.slug": "string",
          "instrument.id": "string",
          "instrument.nature": "string",
          "instrument.nor": "string",
          "links.articles": "TOC href"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_statutes",
        "x-mcp-title": "Search consolidated texts",
        "x-mcp-pack": "core",
        "description": "Use to full-text search consolidated laws and decrees (not codes, not the JO as published). Then open a hit with get_statute_article.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "nature": {
              "type": "string",
              "description": "LOI, DECRET, ORDONNANCE, ARRETE, …"
            },
            "instrument_slug": {
              "type": "string"
            },
            "nor": {
              "type": "string",
              "description": "Exact NOR (case-insensitive)"
            },
            "as_of": {
              "type": "string",
              "description": "YYYY-MM-DD version window"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/statutes/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "instrument_slug": "string",
            "instrument_title": "string",
            "nature": "string",
            "nor": "string",
            "number": "string",
            "legi_status": "string",
            "in_force_on_as_of": "boolean",
            "snippet": "string",
            "href": "/api/statutes/{slug}/articles/{num}"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_sql_schema",
        "x-mcp-title": "SQL schema of a corpus",
        "x-mcp-pack": "core",
        "description": "Use before sql_query: lists the corpus databases, or the tables, columns, indexes and FTS tables of one database.",
        "parameters": {
          "type": "object",
          "properties": {
            "database": {
              "type": "string",
              "enum": [
                "justice",
                "legis",
                "eu",
                "admin",
                "kali",
                "bofip",
                "constit",
                "authorities",
                "circ",
                "jorf",
                "dole",
                "acco",
                "bodacc",
                "boamp"
              ],
              "description": "Omit to list databases"
            }
          },
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/sql/schema",
          "auth": true
        },
        "x-returns": {
          "databases[]": "database/label/available (no database given)",
          "tables[]": "name/type/columns/indexes; virtual = FTS5 (sql shows tokenizer)",
          "note": "FTS join pattern + plan limits"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "sql_query",
        "x-mcp-title": "Read-only SQL on a corpus",
        "x-mcp-pack": "core",
        "description": "Use for counts, aggregations, joins or lists search cannot express: one read-only SQLite SELECT on one corpus database. Call get_sql_schema first.",
        "parameters": {
          "type": "object",
          "properties": {
            "database": {
              "type": "string",
              "enum": [
                "justice",
                "legis",
                "eu",
                "admin",
                "kali",
                "bofip",
                "constit",
                "authorities",
                "circ",
                "jorf",
                "dole",
                "acco",
                "bodacc",
                "boamp"
              ]
            },
            "sql": {
              "type": "string",
              "description": "One SELECT (WITH/EXPLAIN ok). FTS: SELECT d.id FROM documents_fts JOIN documents d ON d.rowid = documents_fts.rowid WHERE documents_fts MATCH 'terme' ORDER BY rank LIMIT 20. Use ? placeholders + bind for values."
            },
            "bind": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Values for ? placeholders, in order (sent as text; SQLite applies the column affinity)"
            },
            "max_rows": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "description": "Rows per page, default 100, max 1000. Aggregate in SQL instead of paging raw rows."
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Rows to skip: pass next_offset from the previous page (keep a stable ORDER BY)"
            },
            "max_cell_chars": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50000,
              "description": "Long text cells are cut here (default 2000)"
            }
          },
          "required": [
            "database",
            "sql"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "POST",
          "path": "/sql",
          "auth": true
        },
        "x-returns": {
          "columns": "string[]",
          "rows": "array of arrays",
          "row_count": "int",
          "has_more": "true when another page exists",
          "truncated_cells": "int",
          "took_ms": "int",
          "next_offset": "offset of the next page, when has_more"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_official_journal",
        "x-mcp-title": "Search the Journal officiel",
        "x-mcp-pack": "full",
        "description": "Use to search the Journal officiel as published (raw JO). Not the consolidated text (that is search_statutes).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "nature": {
              "type": "string",
              "description": "LOI, DECRET, ARRETE, ORDONNANCE, DECISION, AVIS, …"
            },
            "ministry": {
              "type": "string",
              "description": "Substring, case-insensitive (e.g. agriculture) — trigram-indexed"
            },
            "doc_type": {
              "type": "string",
              "enum": [
                "loi",
                "decret",
                "arrete",
                "ordonnance",
                "decision",
                "avis",
                "autre"
              ]
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive on DATE_PUBLI"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "offset": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/official-journal/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "JORFTEXT…",
            "nature": "string",
            "doc_type": "string",
            "title": "string",
            "date": "YYYY-MM-DD",
            "nor": "string",
            "url": "Légifrance jorf/id",
            "snippet": "string"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_official_journal_document",
        "x-mcp-title": "Get a Journal officiel text",
        "x-mcp-pack": "full",
        "description": "Use after search_official_journal to open one JO text by JORFTEXT id (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "JORFTEXT…"
            },
            "full": {
              "type": "boolean"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/official-journal/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "title": "string",
          "text": "string",
          "url": "Légifrance",
          "verify_note": "string",
          "truncated": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_legislative_dossiers",
        "x-mcp-title": "Search legislative dossiers",
        "x-mcp-pack": "full",
        "description": "Use to find travaux préparatoires (legislative dossiers). Not the statute text — use search_statutes or search_official_journal for that.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "dossier_type": {
              "type": "string",
              "enum": [
                "projet_loi",
                "proposition_loi",
                "autre"
              ]
            },
            "after": {
              "type": "string"
            },
            "before": {
              "type": "string"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "offset": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/legislative-dossiers/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "JORFDOLE…",
            "dossier_type": "string",
            "title": "string",
            "url": "Légifrance dossierlegislatif"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_legislative_dossier",
        "x-mcp-title": "Get a legislative dossier",
        "x-mcp-pack": "full",
        "description": "Use after search_legislative_dossiers to open one dossier by JORFDOLE id.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "full": {
              "type": "boolean"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/legislative-dossiers/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "title": "string",
          "url": "string",
          "verify_note": "string"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_company_agreements",
        "x-mcp-title": "Search company agreements",
        "x-mcp-pack": "full",
        "description": "Use to search company-level accords d'entreprise (ACCO). Not industry IDCC conventions (search_collective_agreements).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "idcc": {
              "type": "string",
              "description": "Collective agreement IDCC number attached to the company"
            },
            "siret": {
              "type": "string",
              "description": "14-digit SIRET"
            },
            "after": {
              "type": "string"
            },
            "before": {
              "type": "string"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "offset": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/company-agreements/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "ACCOTEXT…",
            "title": "string",
            "company": "string",
            "idcc": "string",
            "url": "Légifrance acco/id",
            "full_text": "boolean, true if snippet includes unzipped office-file body"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_company_agreement",
        "x-mcp-title": "Get a company agreement",
        "x-mcp-pack": "full",
        "description": "Use after search_company_agreements to open one ACCOTEXT id (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "full": {
              "type": "boolean"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/company-agreements/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "title": "string",
          "company": "string",
          "url": "string",
          "full_text": "boolean",
          "verify_note": "string"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_commercial_notices",
        "x-mcp-title": "Search BODACC notices",
        "x-mcp-pack": "full",
        "description": "Use to search BODACC publication notices (RCS, insolvency, accounts). Not a live SIRENE register.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "edition": {
              "type": "string",
              "enum": [
                "a",
                "b",
                "c"
              ],
              "description": "BODACC edition letter"
            },
            "doc_type": {
              "type": "string",
              "description": "rcs_a, rcs_b, pcl, bilan"
            },
            "siren": {
              "type": "string",
              "description": "9-digit SIREN"
            },
            "after": {
              "type": "string"
            },
            "before": {
              "type": "string"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "offset": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/commercial-notices/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "nojo",
            "public_id": "edition+parution+numero",
            "title": "string",
            "siren": "string",
            "url": "bodacc.fr"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_commercial_notice",
        "x-mcp-title": "Get a BODACC notice",
        "x-mcp-pack": "full",
        "description": "Use after search_commercial_notices to open one notice by nojo or public_id.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "full": {
              "type": "boolean"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/commercial-notices/notices/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "public_id": "string",
          "title": "string",
          "url": "string",
          "verify_note": "string"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_public_procurement",
        "x-mcp-title": "Search BOAMP notices",
        "x-mcp-pack": "full",
        "description": "Use to search BOAMP public-procurement notices.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string"
            },
            "doc_type": {
              "type": "string",
              "description": "Free facet (rectificatif, appel_offre, …)"
            },
            "after": {
              "type": "string"
            },
            "before": {
              "type": "string"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "offset": {
              "type": "integer",
              "minimum": 0
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/public-procurement/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "IDWEB",
            "title": "string",
            "buyer": "string",
            "url": "boamp.fr"
          }
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_public_procurement_notice",
        "x-mcp-title": "Get a BOAMP notice",
        "x-mcp-pack": "full",
        "description": "Use after search_public_procurement to open one notice by IDWEB.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string"
            },
            "full": {
              "type": "boolean"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/public-procurement/notices/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "title": "string",
          "url": "string",
          "verify_note": "string"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_eu_law_and_caselaw",
        "x-mcp-title": "Search EU law and case-law",
        "x-mcp-pack": "public",
        "description": "Use to search EU legislation (EUR-Lex, French) plus CJEU and ECHR case-law. Not French domestic courts.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "source": {
              "type": "string",
              "enum": [
                "eurlex_law",
                "cjeu",
                "echr"
              ],
              "description": "eurlex_law = EU legislation (EUR-Lex), cjeu = Court of Justice of the EU, echr = European Court of Human Rights (HUDOC)"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (document date)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (document date)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/eu/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (CELEX number or HUDOC itemid)",
            "source": "eurlex_law|cjeu|echr",
            "doc_type": "regulation|directive|consolidated|judgment|…",
            "title": "string",
            "date": "YYYY-MM-DD document date",
            "celex": "string|null",
            "ecli": "string|null",
            "url": "EUR-Lex / HUDOC verify link — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_eu_document",
        "x-mcp-title": "Get an EU document",
        "x-mcp-pack": "public",
        "description": "Use after search_eu_law_and_caselaw to open one document by id, CELEX or ECLI (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Document id, CELEX number (e.g. 32009R0004) or ECLI from search results"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/eu/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "source": "eurlex_law|cjeu|echr",
          "title": "string",
          "date": "YYYY-MM-DD",
          "celex": "string|null",
          "ecli": "string|null",
          "url": "EUR-Lex / HUDOC verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_admin_caselaw",
        "x-mcp-title": "Search administrative case-law",
        "x-mcp-pack": "public",
        "description": "Use to find administrative-court decisions (Conseil d'État, CAA, TA). Not judicial caselaw (search_caselaw).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "source": {
              "type": "string",
              "enum": [
                "ce",
                "caa",
                "ta",
                "autre"
              ],
              "description": "ce = Conseil d'État, caa = cours administratives d'appel, ta = tribunaux administratifs, autre = other administrative courts"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (decision date)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (decision date)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/admin-caselaw/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (CETATEXT id)",
            "source": "ce|caa|ta|autre",
            "doc_type": "decision",
            "title": "string",
            "date": "YYYY-MM-DD decision date",
            "number": "string case number",
            "url": "Légifrance verify link — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_admin_decision",
        "x-mcp-title": "Get an administrative decision",
        "x-mcp-pack": "public",
        "description": "Use after search_admin_caselaw to open one decision by CETATEXT id (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "CETATEXT id from search results (e.g. CETATEXT000047520000)"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/admin-caselaw/decisions/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "source": "ce|caa|ta|autre",
          "title": "string",
          "date": "YYYY-MM-DD",
          "number": "string",
          "url": "Légifrance verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_collective_agreements",
        "x-mcp-title": "Search collective agreements",
        "x-mcp-pack": "public",
        "description": "Use to search industry collective agreements (IDCC / KALI). Not company-level ACCO (search_company_agreements).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "idcc": {
              "type": "string",
              "description": "IDCC number of the collective agreement (e.g. 1979)"
            },
            "doc_type": {
              "type": "string",
              "enum": [
                "convention",
                "texte",
                "article"
              ],
              "description": "convention = the agreement itself, texte = avenant/accord/arrêté attached to it, article = one article's body text"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (texte/article date_start)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (texte/article date_start)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/collective-agreements/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (KALICONT/KALITEXT/KALIARTI id)",
            "idcc": "string, IDCC number",
            "doc_type": "convention|texte|article",
            "nature": "string (Convention collective, Avenant, Accord, …)",
            "title": "string",
            "etat": "string (VIGUEUR_ETEN, ABROGE, …)",
            "date_start": "YYYY-MM-DD",
            "date_end": "YYYY-MM-DD",
            "url": "Légifrance verify link — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_collective_agreement_document",
        "x-mcp-title": "Get a collective agreement document",
        "x-mcp-pack": "public",
        "description": "Use after search_collective_agreements to open one KALI id (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "KALI id from search results (e.g. KALIARTI000000000202)"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/collective-agreements/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "idcc": "string",
          "doc_type": "convention|texte|article",
          "nature": "string",
          "title": "string",
          "etat": "string",
          "date_start": "YYYY-MM-DD",
          "date_end": "YYYY-MM-DD",
          "url": "Légifrance verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_tax_doctrine",
        "x-mcp-title": "Search tax doctrine (BOFiP)",
        "x-mcp-pack": "public",
        "description": "Use to search BOFiP tax doctrine. Pass as_of for the version opposable that day.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "doc_type": {
              "type": "string",
              "description": "Normalized content type facet, e.g. commentaire, bareme, lettre_type_modele (no fixed enum, source-driven)"
            },
            "serie": {
              "type": "string",
              "description": "BOFiP series code, e.g. IF, TVA, IR, RFPI"
            },
            "as_of": {
              "type": "string",
              "description": "YYYY-MM-DD — only the version opposable that day (date_start..date_end window)"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD — document date on or after"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD — document date strictly before"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/tax-doctrine/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (version id, BOI-…-YYYYMMDD)",
            "doc_id": "string (BOFiP node id, e.g. 1900-PGP)",
            "doc_type": "string, normalized content type",
            "serie": "string",
            "division": "string",
            "identifiant": "string (juridical id, BOI-…, version-less)",
            "title": "string",
            "date": "YYYY-MM-DD version date",
            "date_start": "YYYY-MM-DD",
            "date_end": "YYYY-MM-DD or null (still in force)",
            "url": "bofip.impots.gouv.fr verify link — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_tax_doctrine_document",
        "x-mcp-title": "Get a BOFiP document",
        "x-mcp-pack": "public",
        "description": "Use after search_tax_doctrine to open one BOI document (version id, BOI-… or node); optional as_of.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Version id, BOI-… identifiant, or node id from search results"
            },
            "as_of": {
              "type": "string",
              "description": "YYYY-MM-DD — version opposable that day"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/tax-doctrine/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "doc_id": "string",
          "doc_type": "string",
          "serie": "string",
          "division": "string",
          "identifiant": "string",
          "title": "string",
          "date": "YYYY-MM-DD",
          "date_start": "YYYY-MM-DD",
          "date_end": "YYYY-MM-DD or null",
          "url": "bofip.impots.gouv.fr verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_constitutional_caselaw",
        "x-mcp-title": "Search Conseil constitutionnel",
        "x-mcp-pack": "public",
        "description": "Use to search Conseil constitutionnel decisions (DC, QPC, electoral, …). Not Cour de cassation or Conseil d'État.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "decision_type": {
              "type": "string",
              "enum": [
                "dc",
                "qpc",
                "lp",
                "an",
                "sen",
                "autre"
              ],
              "description": "dc = contrôle de constitutionnalité, qpc = question prioritaire de constitutionnalité, lp = lois de pays (Nouvelle-Calédonie/Polynésie), an = contentieux électoral Assemblée nationale, sen = contentieux électoral Sénat, autre = other (présidentielle, référendum, incompatibilités, nominations, article 16, ...)"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (decision date)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (decision date)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/constitutional/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (CONSTEXT id)",
            "decision_type": "dc|qpc|lp|an|sen|autre",
            "title": "string",
            "date": "YYYY-MM-DD decision date",
            "number": "string, e.g. 2025-881",
            "solution": "string outcome, e.g. Conformité, Rejet, Inéligibilité",
            "url": "conseil-constitutionnel.fr verify link — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_constitutional_decision",
        "x-mcp-title": "Get a Conseil constitutionnel decision",
        "x-mcp-pack": "public",
        "description": "Use after search_constitutional_caselaw to open one CONSTEXT id (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "CONSTEXT id from search results (e.g. CONSTEXT000051585985)"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/constitutional/decisions/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "decision_type": "dc|qpc|lp|an|sen|autre",
          "title": "string",
          "date": "YYYY-MM-DD",
          "number": "string",
          "solution": "string outcome",
          "url": "conseil-constitutionnel.fr verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_authority_decisions",
        "x-mcp-title": "Search ADLC / CNIL / AMF",
        "x-mcp-pack": "public",
        "description": "Use to search ADLC (competition), CNIL (data protection) or AMF OAM filings (not AMF sanctions).",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + full text (French corpus). Phrases in double quotes."
            },
            "authority": {
              "type": "string",
              "enum": [
                "adlc",
                "cnil",
                "amf"
              ],
              "description": "adlc = Autorité de la concurrence, cnil = CNIL, amf = OAM listed-issuer disclosures (not AMF sanctions)"
            },
            "doc_type": {
              "type": "string",
              "description": "Source-driven, no fixed enum. ADLC: d (contentious decision), a (avis/opinion), mc (mesures conservatoires), dcc (merger control), dex, soa. CNIL: sanction, mise_en_demeure, autorisation_transfert, autorisation_recherche, avis, recommandation_lignes_directrices, and other NATURE_DELIB slugs."
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (decision date)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (decision date)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/authorities/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (CNILTEXT id for cnil, decision number e.g. 26-DCC-149 for adlc)",
            "authority": "adlc|cnil",
            "doc_type": "string (source-driven)",
            "title": "string",
            "date": "YYYY-MM-DD decision date",
            "number": "string",
            "url": "official verify link (autoritedelaconcurrence.fr or legifrance.gouv.fr) — always re-check before citing",
            "snippet": "string"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_authority_document",
        "x-mcp-title": "Get an authority document",
        "x-mcp-pack": "public",
        "description": "Use after search_authority_decisions to open one ADLC or CNIL document by id (AMF hits already carry a PDF url).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "Document id from search results (e.g. CNILTEXT000051881158 or 26-DCC-149)"
            },
            "full": {
              "type": "boolean",
              "description": "If true, full text (can be very long)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/authorities/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "authority": "adlc|cnil",
          "doc_type": "string",
          "title": "string",
          "date": "YYYY-MM-DD",
          "number": "string",
          "url": "official verify link",
          "verify_note": "string",
          "text": "string",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "search_circulars",
        "x-mcp-title": "Search circulars",
        "x-mcp-pack": "full",
        "description": "Use to search government circulaires and instructions. Prefer the official PDF url; full_text=true means the body was extracted.",
        "parameters": {
          "type": "object",
          "properties": {
            "q": {
              "type": "string",
              "description": "FTS5 query over titles + résumé/mots-clés (French corpus). Phrases in double quotes."
            },
            "doc_type": {
              "type": "string",
              "enum": [
                "organisation_services",
                "directives_ministre",
                "interpretation_juridique",
                "autre"
              ],
              "description": "organisation_services = mesures d'organisation interne des services, directives_ministre = directives aux services chargés de leur application, interpretation_juridique = interprétation d'un texte sous réserve de l'appréciation du juge, autre = other/uncategorized"
            },
            "after": {
              "type": "string",
              "description": "YYYY-MM-DD inclusive (date de signature)"
            },
            "before": {
              "type": "string",
              "description": "YYYY-MM-DD exclusive (date de signature)"
            },
            "limit": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "description": "Default 10, max 50"
            },
            "offset": {
              "type": "integer",
              "minimum": 0,
              "description": "Pagination offset"
            }
          },
          "required": [
            "q"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/circulars/search",
          "auth": true
        },
        "x-returns": {
          "results[]": {
            "id": "string (ID_CIRCULAIRE)",
            "doc_type": "organisation_services|directives_ministre|interpretation_juridique|autre",
            "title": "string",
            "date": "YYYY-MM-DD date de signature",
            "number": "string, NOR number (fallback: numéro interne)",
            "ministry": "string, émetteur (auteur or domaine), may be absent",
            "url": "circulaires.legifrance.gouv.fr verify link (PDF) — always re-check before citing",
            "full_text": "boolean, true if snippet is the extracted PDF body, false if metadata only",
            "snippet": "string, PDF body when full_text is true, résumé/mots-clés otherwise"
          },
          "meta.has_more": "boolean"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_circular_document",
        "x-mcp-title": "Get a circular",
        "x-mcp-pack": "full",
        "description": "Use after search_circulars to open one circulaire by ID_CIRCULAIRE (prefer full=false).",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "ID_CIRCULAIRE from search results (e.g. 45652)"
            },
            "full": {
              "type": "boolean",
              "description": "If true, lift the 50000-char cap (only matters when full_text is true)"
            }
          },
          "required": [
            "id"
          ],
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/circulars/documents/{id}",
          "auth": true
        },
        "x-returns": {
          "id": "string",
          "doc_type": "organisation_services|directives_ministre|interpretation_juridique|autre",
          "title": "string",
          "date": "YYYY-MM-DD",
          "number": "string",
          "ministry": "string, may be absent",
          "url": "circulaires.legifrance.gouv.fr verify link (PDF)",
          "full_text": "boolean, true if text is the extracted PDF body, false if metadata only",
          "verify_note": "string",
          "text": "string, PDF body when full_text is true, résumé/mots-clés/destinataire otherwise",
          "truncated": "boolean",
          "text_length": "integer"
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "get_quota",
        "x-mcp-title": "API quota",
        "x-mcp-pack": "public",
        "description": "Use when near quota limits or before a long turn. Shows remaining daily units for this key.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        },
        "x-http": {
          "method": "GET",
          "path": "/me",
          "auth": true
        },
        "x-returns": {
          "plan": "none|pro|vip|internal",
          "quota.day_remaining": "integer",
          "quota.rpm_limit": "integer"
        }
      }
    }
  ]
}
