Paperasse MCP
Click 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., "@Paperasse MCPJe suis étudiant, est-ce que j'ai droit aux APL ?"
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.
Paperasse MCP
An open-source MCP server that lets AI assistants answer questions about French administrative procedures from official sources only, with a citable link and last update date for every answer. It covers the guides for individuals (service-public.gouv.fr) and for professionals and the self-employed (entreprendre.service-public.gouv.fr).
Status: early development (v0.1.0). Both official feeds, keyword search with synonyms, a dev/test search eval and CI work. There is no hosted version, by design: you install it on your machine (about a minute), so your questions stay local.
Demo

A real MCP client calling the server: question → search_fiche → get_fiche → official text with its link and update date (15 s, sped up). The full 2-minute video, which also shows an English freelancer question with a low_confidence retry and an off-topic question, is attached to the v0.1.0 release. In the demo the keyword rewriting an assistant would do is scripted and labelled; see demo/.
https://github.com/user-attachments/assets/6e271201-e9ae-48b5-8b47-abf22a0778f8
Related MCP server: french-admin-mcp
Why
French administrative procedures are hard to navigate, and general-purpose AI assistants answer questions about them from memory: rules change every year (amounts, thresholds, deadlines), and a confident but outdated answer about the CAF, taxes or a residence permit can cost someone money or a deadline. The official guides already exist, are kept up to date by the DILA and are open data.
Paperasse gives an assistant those guides instead of its memory. It searches the official fiches, returns their text word for word with the official link and last update date, and says when it found nothing relevant. The assistant explains and cites; the server never writes or rewords the content.
Try it
You need uv and about a minute to download the official feeds and build the index:
git clone https://github.com/medkouritahaparis-create/paperasse-mcp.git
cd paperasse-mcp
uv sync
uv run python -m paperasse.ingest # download both official feeds (about 35 MB) into data/
uv run python -m paperasse.store # build the search index data/paperasse.dbTo refresh the data later (the official feeds are updated daily), run the same two commands again.
Claude Code: open Claude Code in the repo folder: .mcp.json registers the server. From anywhere else:
claude mcp add paperasse -- uv --directory /absolute/path/to/paperasse-mcp run main.pyClaude Desktop: add this to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), keeping your other servers, then restart Claude Desktop:
{
"mcpServers": {
"paperasse": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/paperasse-mcp", "run", "main.py"]
}
}
}If Claude Desktop can't find uv, use its full path (the output of which uv) as command.
Then ask, for example: "Je suis étudiant, est-ce que j'ai droit aux APL ?" or "How do I declare my micro-entrepreneur revenue?". The answer should cite a service-public.gouv.fr or entreprendre.service-public.gouv.fr link.
Tools
Tool | What it does |
| Best matching fiches: id, title, summary, official URL, last update date and a |
| Full official text of a fiche, with its URL on each site, update date, online services and legal sources; long fiches come in pages |
Search quality
Measured with evals/questions.jsonl: 93 questions whose expected fiches were labelled by hand from fiche titles, never from search results. They are split into dev (65, used to tune search) and test (28, only reported, never tuned on). Current results on the test split, 2026-10-27 (search code 8b2687b, 3,673 fiches from both feeds):
Test split | n | Top-1 | Top-3 | MRR@10 |
Keywords, as clients are told to send them ("APL étudiant") | 11 | 64% | 73% | 0.72 |
Full sentences, sent as is ("Comment avoir un garant gratuit pour louer ?") | 15 | 33% | 53% | 0.46 |
Freelancers / micro-entrepreneurs (keywords and sentences) | 8 | 38% | 50% | 0.47 |
All answerable | 26 | 46% | 62% | 0.57 |
Same questions rewritten by an LLM client (Claude Haiku 5.5, | 26 | not measured yet |
On dev (61 answerable): 54% top-1, 70% top-3, MRR 0.63. Full report: evals/results/2026-10-27-8b2687b-q0c79b3.md.
What moved the numbers (each change measured before and after; every option tried, kept or rejected, is in docs/decisions.md):
Change | Measured on | Before → after |
Length prior: main guides outrank short Q&A spin-offs | first 48 questions | top-1 44% → 62%, top-3 75% → 79% |
Entreprendre feed + | 13 freelance questions | top-3 0/13 → 4/13 |
Synonyms run as query variants (auto-entrepreneur → micro-entrepreneur, chômage → ARE, enceinte → grossesse) | dev | top-1 32 → 33, top-3 41 → 43 of 61 |
same | test (reported once) | top-1 42% → 46%, top-3 58% → 62%; freelance top-1 2/8 → 3/8, top-3 3/8 → 4/8 |
Full sentences are the weak spot (33% top-1 on test). The search_fiche docstring tells the client model to rewrite questions into official keywords. The --rewrite mode measures exactly that with Claude Haiku and needs an API key; it hasn't been run yet. If rewritten sentences stay weak, the next step is hybrid BM25 + multilingual embeddings fused with RRF (plan).
low_confidence is set on all 6 questions that have no good answer (off-topic, English). On test it is also set on 3 of 12 questions whose rank-1 result is right (false alarms).
Reproduce:
uv run python -m evals.run # writes evals/results/<date>-<code>-q<question set>.md
uv run --group eval python -m evals.run --rewrite # needs ANTHROPIC_API_KEY in .env; ~$0.03, cached afterwardsThe official feeds are updated daily, so numbers can move slightly with the data. Each report records the code commit, the question set and the data snapshot. The test split is small: one question is about 4 points.
Development
uv run pytest # tests (no network, no data needed)
uv run mcp dev main.py # inspect the tools in the MCP Inspector
uv run python -m evals.run # search eval, writes evals/results/
uv run python demo/demo.py # terminal demo (a real MCP client); vhs demo/demo.tape records itCI (.github/workflows/ci.yml) runs the tests on every push and pull request. They need no network, data or API key.
Design choices, with the options considered and the numbers behind them, are in docs/decisions.md.
Roadmap
Ingest both official feeds (Particuliers, Entreprendre) into clean, verbatim fiches
search_fiche/get_fiche: SQLite FTS5 (BM25), length prior,low_confidence, measured synonymsSearch eval with a dev/test split, CI, scripted demo
Run the LLM-rewrite eval (
--rewrite); add hybrid BM25 + embeddings only if rewritten sentences stay weakget_procedure_steps: structured steps and required documentsLégifrance law articles (PISTE API) and
find_local_help(France Services, préfectures, mairies)
Licence and data
The code is under the MIT licence, © 2026 Taha Medkouri.
The content it serves is not covered by that licence: it comes from Service-Public.gouv.fr / DILA (Direction de l'information légale et administrative) and stays under the Licence Ouverte / Etalab. Every tool response credits the source. The data is downloaded at install time and is not stored in this repository. Two feeds, both schema 3.5:
Fiches pratiques et ressources de Service-Public.gouv.fr Particuliers: guides for individuals, on service-public.gouv.fr.
Fiches pratiques et ressources Entreprendre - Service-Public.gouv.fr: guides for businesses and the self-employed, on entreprendre.service-public.gouv.fr.
Disclaimer
This project is not affiliated with, endorsed by or operated by the French administration. It returns official text but is not legal advice. Always check the linked official page.
Available Tools
2 toolsget_ficheA
Read the full official text of a service-public.fr fiche, by id (e.g. "F12006").
Use after search_fiche, before answering. The text is the official wording, in French,
with Markdown headings and [links](url). It often covers several cases ("### En France",
"### À l'étranger"): pick the one that matches the user's situation. When the official text
repeats a block word for word in several cases, it is given once; later copies are replaced by
a line "[Paperasse : identique à « … » plus haut (sous « … »)]" pointing to the first copy.
Returns title, url, urls (the official page on each site, for fiches written for both
individuals and professionals), updated_at, text, online_services (official online procedures with
links) and sources (legal texts). Long fiches come in pages: if `next_offset` is not null,
call again with offset=next_offset to read more. For paged fiches, `outline` lists the
main headings with their offset: call get_fiche(id, offset=...) to jump to a section.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| offset | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so thoroughly. It discloses that the text is official French wording with Markdown headings and links, that multiple cases may appear, how repeated blocks are deduplicated with a specific placeholder line, and what fields are returned including pagination and outline behavior.
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 front-loaded with purpose, then usage, then return and pagination details. Despite its length, every sentence provides useful operational context for a tool with multi-case text, deduplication, and paged output.
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?
Even though an output schema exists, the description adds important context about return fields and paging behavior that helps an agent use the tool correctly. Given the absence of annotations and the complexity of paged, multi-case official text, the description is complete enough to call the tool confidently.
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 0%, so the description must compensate, and it does. It explains the id parameter with a concrete example format and explains offset through the pagination and outline mechanisms, including how to jump to a section with get_fiche(id, offset=...).
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 precise verb and resource: 'Read the full official text of a service-public.fr fiche, by id.' It includes an example id and distinguishes the tool from its sibling by saying to use it after search_fiche. An agent can identify exactly what this tool does and when it follows search.
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?
It explicitly says to use this tool after search_fiche and before answering, and explains how to handle multi-case fiches by picking the case matching the user's situation. It also gives clear pagination instructions: if next_offset is not null, call again with offset=next_offset, and explains outline-based section jumping.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_ficheA
Search official service-public.fr guides (fiches) about a French administrative procedure.
Use this first for any question about French paperwork: CAF (APL, RSA, prime d'activité),
URSSAF, impôts, titre de séjour, carte Vitale, logement social, carte grise,
micro-entreprise, création d'entreprise, etc.
The fiches are in French: always translate the user's question into a few French keywords
using official administrative terms before calling, even if the user writes in another
language (e.g. "I lost my residence permit" -> "perte titre de séjour";
"student housing aid" -> "APL étudiant"; "auto-entrepreneur" or "freelance" ->
"micro-entrepreneur"). Don't pass a full sentence.
`audience`: "all" (default) searches both guides for individuals (service-public.fr) and for
professionals (entreprendre.service-public.fr: self-employed, micro-entrepreneurs, companies,
employers). Pass "particuliers" or "professionnels" only when the user's situation is
clearly one or the other.
Returns up to `limit` (max 10) fiches, best match first, each with id, title, summary,
official url (the page on the site of the requested audience), audiences, updated_at and
`match` (0-1: how much of the query the title and summary cover). Then call get_fiche(id) to read the full text before answering: the summary alone
is not enough to answer.
If `low_confidence` is true, the best result probably doesn't answer the question: retry
once with different French official terms (synonyms, the name of the benefit or document).
If it is still low, don't present these fiches as the answer; say no matching official
guide was found.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| audience | No | all |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does: it discloses result ordering ('best match first'), the cap ('max 10'), the per-result fields, the meaning of the `match` score (0-1 title/summary coverage), and the `low_confidence` signal plus the correct recovery behavior. It also warns that summaries are insufficient for answering, which is a genuine behavioral constraint an agent would otherwise get wrong.
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?
Front-loaded with purpose, then query guidance, then audience, then returns, then the low_confidence fallback – a logical order with no dead sentences. It runs long and the returns paragraph partly restates what the output schema already carries, but the length is earned by the parameter and recovery guidance.
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 search tool with an output schema and no annotations, the description supplies everything an agent needs: query construction rules, audience selection, result limits and ranking, interpretation of the confidence signal, and the mandated follow-up call. Nothing required to invoke it correctly 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 description coverage is 0%, so the description must compensate entirely, and it does for all three parameters: `query` requires translated French administrative keywords with three concrete translation examples and a 'no full sentences' rule, `audience` defines 'all' vs 'particuliers'/'professionnels' with the site each maps to and a default, and `limit` is bounded at max 10.
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 and resource ('search official service-public.fr guides (fiches)') and enumerates the exact subject domain (CAF, URSSAF, impôts, titre de séjour, etc.). It is clearly a retrieval-by-keyword tool and is distinguishable from the sibling get_fiche, which is explicitly named as the follow-up full-text read.
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?
Explicitly says 'Use this first for any question about French paperwork' and then hands off: 'Then call get_fiche(id) to read the full text before answering.' It even prescribes the failure path (retry once on low_confidence with synonyms, then report no match), so when-to-use, what-to-do-next, and when-to-give-up are all covered.
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.
2 tool updates
v0.1.0- First observed
get_fiche - First observed
search_fiche
TDQS
Scored across 2 tools
The two tools form a clean search-then-read pair with explicitly disjoint roles: search_fiche returns ranked summaries with ids, get_fiche reads one fiche by id. The descriptions even state the intended sequence, leaving no plausible way to misselect.
Both tools use the same snake_case verb_noun pattern (search_fiche, get_fiche) over a single consistent resource noun, and the verb semantics match the action (search vs. get). No mixed conventions.
Two tools is on the thin side, but it is a deliberate minimal retrieval surface for a read-only corpus and each tool earns its place. Still, there is no operation beyond search+read, which is borderline for the domain breadth advertised.
Search by keyword/audience plus full-text read with pagination, outline jumping, online services and legal sources covers the core Q&A workflow end to end. Gaps are minor: no browsing/listing of fiches by theme or category and no way to resolve an id without a prior search.
Maintenance
Related MCP Connectors
Sourced answers on FR/EU rules + French company search (SIREN, NAF) for agents, quoted and budgeted
French public services: tax, property, admin, education, healthcare, security, risks, legal texts
French law articles, codes, collective agreements, case law (Judilibre) and IDCC lookup.
French case law (Judilibre) and codes (Légifrance) from official sources, with citation checking.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides access to official French legal databases (Légifrance and JudiLibre) to search and retrieve French legislation, legal codes, case law, and judicial decisions through authenticated APIs.36MIT
- AlicenseAqualityCmaintenanceHelps citizens and businesses navigate French bureaucracy with AI, covering taxes, social charges, benefits, invoices, administrative letters, collective agreements, and retirement.2225 npm1MIT
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to search and retrieve French legislation, case law, and EU law integrations from official sources via MCP.94 npm1Apache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to search and retrieve detailed profiles of 25 million French companies from the official government registry, including directors, activity codes, and establishment data, without requiring an API key.-