norm-mcp
The server exposes five MCP tools to read, verify, link, and search Italian legal norms from Normattiva.it, with built-in network safeguards and local cached state.
normattiva_leggi_articolo: read the verified text of an Italian law article by source name (or alias) and article number; optional historical date (vigenza).normattiva_link: generate a Markdown citation[text](permalink)for an article, optionally verifying that the URN is valid.normattiva_trova_fonte: search the local verified table of legal sources by name or alias without making network requests.normattiva_leggi_urn: read the text for an already-known Normattiva URN, e.g. a normative reference found inside another article.normattiva_stato_rete: inspect local protection state such as cache, quotas, cooldown, and last incident without touching the network.All tools include conservative network usage: shared SQLite cache, rate limiting, cooldowns, offline mode, and protective status in responses; historical/abrogated/preambolo results are clearly flagged.
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., "@norm-mcpLeggi l'articolo 2043 del codice civile"
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.
normattiva-mcp
CLI e server MCP per leggere, verificare e citare norme italiane da Normattiva.it, pensati per essere usati anche da modelli LLM economici (es. DeepSeek 4 flash). Il testo di un articolo viene sempre dall'API di Normattiva, mai dal permalink del portale (2.000 volte più pesante per lo stesso contenuto — vedi ARCHITETTURA.md).
Cosa fa
Da terminale (norm --help):
norm leggi <fonte> <articolo>— legge il testo verificato di un articolo (norm leggi "codice civile" 2043)norm link <fonte> <articolo>— costruisce la citazione Markdown, verificandola per difettonorm urn <urn>— legge un URN già in mano (es. un rinvio trovato in un testo)norm fonti [testo]— elenca le fonti verificate, o ne cerca unanorm doctor— controlla se l'endpoint del testo rispondenorm stato— mostra localmente cache, quote, cooldown e ultimo incidentenorm skill— installa e aggiorna la skill Agent Skills per gli assistentinorm verifica --tutte— mostra prima il costo stimato; esegue solo con--esegui, dopo avere prenotato tutto il budget necessario
Come server MCP (norm-mcp), cinque strumenti:
normattiva_leggi_articolo— stessa lettura dinorm legginormattiva_link— stessa citazione dinorm linknormattiva_trova_fonte— cerca una fonte nella tabella, nessuna retenormattiva_leggi_urn— stessa lettura dinorm urnnormattiva_stato_rete— stato locale della protezione, senza rete
Una futura ricerca full-text non è ancora esposta: se verrà aggiunta, dovrà usare solo un canale Open Data ufficiale adatto al volume richiesto.
Related MCP server: Dutch-law-mcp
Installazione
Richiede uv e Python 3.12-3.14.
uv tool install --editable .Installa entrambi i comandi (norm, norm-mcp) in ~/.local/bin, restando
sincronizzati col sorgente (utile durante lo sviluppo; per un uso normale
basta uv tool install normattiva-mcp una volta pubblicato su PyPI).
Collegare il server MCP a un assistente
Esempio per Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"normattiva": {
"command": "/Users/tuonome/.local/bin/norm-mcp",
"args": []
}
}
}Riavvia l'app dopo aver modificato il file. Il server parla solo su stdio, nessuna porta di rete aperta.
Installare la skill Agent Skills
La skill portabile normattiva-mcp segue lo
standard aperto Agent Skills e non contiene estensioni
specifiche di un singolo modello. È inclusa anche nel pacchetto Python, così la CLI
può installarla dopo un'installazione da PyPI, uv tool o pipx.
norm skill list
norm skill install opencode
norm skill install claude-code
norm skill install codex
norm skill install pi
norm skill install allinstall all installa soltanto nei client rilevati tramite il loro binario o la
directory di configurazione e indica quelli saltati. Indicando un client preciso,
l'installazione viene invece eseguita anche se il relativo binario non è sul PATH.
Il livello predefinito è personale. Per installarla solo nel progetto corrente:
norm skill install opencode --level projectLe destinazioni sono quelle native dei client: ~/.claude/skills,
~/.agents/skills, ~/.config/opencode/skills e ~/.pi/agent/skills; a livello
progetto diventano rispettivamente .claude/skills, .agents/skills,
.opencode/skills e .pi/skills. norm skill update aggiorna le copie già
installate, norm skill show mostra la sorgente e norm skill uninstall <client>
la rimuove dal client indicato.
Per collaudare un modello, il protocollo incluso parte da operazioni locali, usa al
massimo un canary reale e richiede che la ripetizione identica sia servita dalla
cache. Gli errori e l'arresto su critico/bloccato vanno provati solo con mock o
server locale.
Uso prudente della rete
Avvertenza: osservazioni empiriche indicano che, dopo un numero elevato di richieste, Normattiva.it può smettere di rispondere in modo persistente da uno specifico indirizzo IP pur restando raggiungibile da altre reti. Non vi è una conferma ufficiale che si tratti di un ban, e sintomi analoghi possono dipendere anche da filtri o problemi di instradamento. Considerare comunque concreto il rischio: usare l'MCP con parsimonia, evitare raffiche e parallelismo e fermarsi al primo errore o cooldown senza tentare di proseguire tramite altre reti.
Il programma usa soltanto l'endpoint Open Data documentato POST .../atto/dettaglio-atto-urn, mai scraping HTML, browser automation, proxy
o cambio di IP/VPN. Il permalink è generato come link, ma non viene scaricato.
Un database SQLite condiviso coordina CLI, MCP e processi concorrenti: una
sola richiesta reale alla volta, almeno 5 secondi fra richieste e cache
condivisa. Il testo vigente resta in cache 7 giorni, quello storico 30;
gli errori deterministici 400/404 un'ora. NORMATTIVA_OFFLINE=1 usa solo
la cache; se il database protettivo non è disponibile, non viene inviata
nessuna richiesta.
I limiti seguenti sono cautele locali del progetto, non limiti comunicati da Normattiva: 30 consultazioni e 2 diagnosi per 24 ore mobili, con un massimo assoluto di 60. Si possono solo ridurre con le variabili d'ambiente; non aumentare da flag CLI o tool MCP. Ogni tentativo HTTP, anche fallito, consuma quota e non esistono retry automatici.
Configurazione facoltativa: NORMATTIVA_STATO_DB sceglie il file SQLite;
NORMATTIVA_OFFLINE=1 disabilita la rete; NORMATTIVA_LIMITE_CONSULTAZIONI,
NORMATTIVA_LIMITE_DIAGNOSI e NORMATTIVA_LIMITE_ASSOLUTO possono soltanto
ridurre le rispettive soglie. NORMATTIVA_CONTATTO_USER_AGENT aggiunge un
contatto volontario al User-Agent stabile del progetto.
Un 429 comporta il rispetto di Retry-After e comunque almeno 6 ore di
pausa; 401/403/409 24 ore; 5xx o risposta malformata 15 minuti. Timeout,
reset e TLS sono eventi indeterminati, non prova di ban, e avviano un
cooldown crescente. Durante il cooldown, avvisa l'utente e non ritentare:
non cambiare IP, VPN o proxy per proseguire.
Ogni risposta MCP che può usare la rete include protezione_rete; la CLI
scrive il consumo reale su stderr (per esempio consultazione 7/30 — totale 9/60). A 50%, 80% e 90% il livello diventa rispettivamente attenzione o
critico. Quando è critico o bloccato, il modello deve fermare il workflow
e avvertire l'utente. Prima di un'attività con più consultazioni, usa
norm stato o normattiva_stato_rete.
norm doctor non esegue rete durante un cooldown e fa al massimo una
richiesta. La verifica completa è limitata a una ogni 7 giorni e parte solo
se il budget intero è prenotabile. Prima di aumentare i volumi o offrire il
servizio a terzi, chiedere al gestore indicazioni scritte su limiti, canale
bulk e modalità d'uso preferite. Future operazioni massive devono usare solo
eventuali canali ufficiali asincroni/bulk, mai un fan-out articolo per articolo.
Documentazione
CLAUDE.md — mappa del progetto, regole vincolanti
ARCHITETTURA.md — come è fatto e perché
Licenza
Il codice di questo repository è distribuito con licenza MIT (vedi LICENSE).
I dati restituiti dagli strumenti (testi normativi, metadati degli atti) provengono da Normattiva.it, Istituto Poligrafico e Zecca dello Stato, e sono distribuiti con licenza Creative Commons Attribuzione 4.0 Internazionale (CC BY 4.0). Ogni risposta degli strumenti include l'attribuzione richiesta dalla licenza.
Available Tools
5 toolsnormattiva_leggi_articoloLeggi il testo verificato di un articoloARead-onlyIdempotent
Legge un articolo dato nome o alias della fonte (es. codice civile, l.fall.) e numero, anche con estensione ("21novies"). Per i codici storici è la via affidabile: usa prima normattiva_trova_fonte se l'alias non è certo. Controlla sempre esito: preambolo non è l'articolo; abrogato è informazione; vigenza_storica indica testo non vigente. vigenza (YYYY-MM-DD) chiede una data storica.
| Name | Required | Description | Default |
|---|---|---|---|
| fonte | Yes | ||
| vigenza | No | ||
| articolo | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| urn | Yes | |
| esito | Yes | |
| testo | No | |
| avvisi | No | |
| heading | No | |
| incipit | No | |
| caratteri | No | |
| messaggio | No | |
| permalink | Yes | |
| attribuzione | Yes | |
| aggiornamenti | No | |
| protezione_rete | Yes | |
| vigenza_storica | No | |
| data_abrogazione | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds meaningful behavioral detail beyond the readOnly/idempotent annotations: it documents the `esito` field, warns that `preambolo` is not the article, clarifies that `abrogato` is informational, and explains `vigenza_storica` as non-current text. This is exactly the kind of output-behavior context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but every sentence earns its place: first the core function, then the routing guidance, then the critical output caveats, then the historical-date parameter. The use of semicolon-separated `esito` values keeps it compact without losing clarity.
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 read-only lookup tool with an output schema already present, the description provides enough context to select and invoke it correctly. It covers input semantics, uncertainty handling, special output states, and historical-date behavior, so no critical operational gap remains.
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%, but the description compensates well: `fonte` is explained as name/alias with examples, `articolo` is explained as number with extension, and `vigenza` is explained as a YYYY-MM-DD historical date. All three parameters receive meaningful semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action: reading an article by source name/alias and article number, including extension forms like "21novies". It also positions the tool against siblings by naming normattiva_trova_fonte as the pre-step for uncertain aliases and implying article lookup by name rather than by URN.
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 tells the agent to use normattiva_trova_fonte first when the alias is uncertain, and labels this tool as the reliable path for historical codes. It also gives clear operational guidance around checking `esito` and providing a `vigenza` date for historical text.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
normattiva_leggi_urnLeggi un URN Normattiva già disponibileARead-onlyIdempotent
Legge un URN completo ottenuto altrove. Verifica esito: anche una risposta 200 può essere un preambolo; abrogato e vigenza_storica non sono diritto vigente. Per fonte più articolo usa normattiva_leggi_articolo, che passa dalla tabella verificata.
| Name | Required | Description | Default |
|---|---|---|---|
| urn | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| urn | Yes | |
| esito | Yes | |
| testo | No | |
| avvisi | No | |
| heading | No | |
| incipit | No | |
| caratteri | No | |
| messaggio | No | |
| permalink | Yes | |
| attribuzione | Yes | |
| aggiornamenti | No | |
| protezione_rete | Yes | |
| vigenza_storica | No | |
| data_abrogazione | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, the description adds critical runtime caveats: the agent must check `esito`, a 200 response may still be only a preamble, and abrogated or historical-validity results are not current law. These are exactly the kind of behavioral warnings that prevent incorrect interpretation of results.
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 three concise sentences with no filler. The first sentence states the core operation, the second adds essential result-interpretation guidance, and the third routes to an alternative tool. Every sentence earns its place and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that this tool has one simple parameter, rich annotations covering read-only/idempotent/non-destructive behavior, and an output schema, the description covers the key operational nuance and sibling routing. It tells the agent what to verify in the response and warns about false positives. Nothing critical is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no description for the single `urn` parameter (0% coverage), so the description must compensate. It adds meaningful context by calling the URN 'completo' and specifying that it was 'ottenuto altrove', which differentiates it from source/article inputs. It does not include a URN format example, but for a single simple parameter this is adequate.
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 opens with a specific action, 'Legge un URN completo ottenuto altrove', clearly defining the tool as reading a complete Normattiva URN obtained elsewhere. It also distinguishes itself from the sibling normattiva_leggi_articolo by clarifying that source-plus-article requests belong to that tool. The purpose is unambiguous and well differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when this tool is appropriate: when a complete URN is already available. It also gives a concrete alternative, instructing the agent to use normattiva_leggi_articolo for source-plus-article queries because that tool uses the verified table. This is clear direction with a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
normattiva_linkCostruisci la citazione Markdown di un articoloARead-onlyIdempotent
Costruisce [testo](permalink) senza il testo integrale. Per difetto verifica=true consulta l'API: il permalink può rispondere 200 anche a un URN sbagliato. verifica=false è locale e non prova esistenza o vigenza; restituisce comunque lo stato locale di protezione. Non ignorare avvisi su abrogato o preambolo.
| Name | Required | Description | Default |
|---|---|---|---|
| fonte | Yes | ||
| vigenza | No | ||
| articolo | Yes | ||
| verifica | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| avvisi | No | |
| avviso | No | |
| markdown | Yes | |
| verificato | Yes | |
| protezione_rete | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only and idempotent. The description adds meaningful behavioral detail: verifica=true calls the API and can return 200 for wrong URNs, verifica=false is local and does not prove existence or validity, and warnings about repealed acts or preambles must not be ignored.
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?
Three dense sentences with no filler. The core purpose is front-loaded, verification behavior is explained next, and the operational warning closes the description efficiently.
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?
The output schema covers return values, and the description supplies the most important caveats: false 200 responses, local versus API verification, and warning handling. A small gap remains around the expected formats for fonte, articolo, and vigenza, but the overall picture is sufficient for an agent.
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. It thoroughly explains the verifica parameter and its default behavior, but it leaves fonte, articolo, and vigenza to be inferred from their titles and domain knowledge.
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 opens with a specific verb and resource: it 'Costruisce [testo](permalink)' without including full text. This clearly distinguishes the tool from siblings like normattiva_leggi_articolo, which presumably retrieves article content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes the context clear: use this tool when you need a Markdown citation link, not the full article text. It does not explicitly name sibling alternatives or state when not to use it, but the scope is evident.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
normattiva_stato_reteMostra stato locale di quota, cache e cooldownARead-onlyIdempotent
Non usa la rete. Mostra rapporto di protezione e aggregati giornalieri (richieste reali, cache hit, errori, densità e cooldown). Usalo prima di un'attività con più consultazioni.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| rapporto | Yes | |
| aggregati_giornalieri | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses a key behavioral trait not captured by annotations: it does not use the network and operates on local state ('Non usa la rete', 'stato locale'). It also explains what the report contains (real requests, cache hits, errors, density, cooldown), which is useful context beyond the readOnly/idempotent/non-destructive annotations. There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, with the most important fact (no network, local state) front-loaded and the usage guidance placed second. There is no filler, repetition, or irrelevant detail.
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 zero-parameter, read-only status tool with an output schema present, the description is complete: it says what the tool does, that it is local, what metrics it shows, and when to invoke it. No return-format explanation is needed because the output schema already covers that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the description has nothing to explain. Per the baseline for parameterless tools, a score of 4 is appropriate; the description does not attempt to invent unnecessary parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Mostra' / shows) and a clear resource: local state of quota, cache, and cooldown, along with daily aggregates. It also distinguishes itself from the sibling lookup tools by explicitly saying it does not use the network ('Non usa la rete'), making its role as a status/health tool unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit timing guidance: use it before an activity with multiple consultations ('Usalo prima di un'attività con più consultazioni'). It does not name alternatives or exclusions, but this is clear, actionable context for an agent choosing between this status tool and the sibling legal-research tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
normattiva_trova_fonteCerca una fonte nella tabella verificataARead-onlyIdempotent
Cerca nome o alias nella tabella locale: tipo, data, numero, allegato e stato, senza rete. Usalo prima di un codice storico: un allegato indovinato può puntare a un atto diverso. Una fonte assente qui non è assente dall'ordinamento.
| Name | Required | Description | Default |
|---|---|---|---|
| testo | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| data | No | |
| nota | No | |
| tipo | No | |
| alias | No | |
| stato | No | |
| numero | No | |
| trovata | Yes | |
| allegato | No | |
| nota_stato | No | |
| disponibile | No | |
| nome_canonico | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and non-destructive. The description adds valuable behavioral context beyond annotations: the tool searches only a local table without network access, and it cautions that the local table is not a complete representation of the legal order. This helps the agent calibrate expectations about result completeness.
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 three sentences, each earning its place: first defines the action and scope, second gives usage guidance with rationale, third states a critical limitation. It is front-loaded with the core purpose and contains no filler.
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 simple one-parameter tool with an output schema and annotations covering safety, the description is complete. It covers what the tool does, its offline/local scope, when to use it, what caveats apply to the result, and the meaning of the sole parameter. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the burden. It compensates by indicating that the 'testo' parameter is the 'nome o alias' to search for in the local table. While it does not provide format examples or edge cases, it gives the essential semantic meaning for the single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Cerca') and resource ('tabella locale'), and lists the searchable attributes: 'tipo, data, numero, allegato e stato'. It distinguishes the tool from network-based siblings by explicitly noting it works 'senza rete', making its offline nature clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage context: 'Usalo prima di un codice storico' and warns that 'un allegato indovinato può puntare a un atto diverso'. It also provides a clear limitation ('Una fonte assente qui non è assente dall'ordinamento') which functions as when-not-to-conclude absence. It does not name sibling alternatives, but the context is sufficient.
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.
5 tool updates
v0.2.0- Changed
normattiva_leggi_articolo4 fields changed- added
Output schema / $defsAdded value: +{ + "ProtezioneReteOutput": { + "description": "Stato corrente e operazioni distinte, incluso un recupero storico.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "rapporti": { + "items": { + "$ref": "#/$defs/RapportoReteOutput" + }, + "title": "Rapporti", + "type": "array" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "ProtezioneReteOutput", + "type": "object" + }, + "RapportoReteOutput": { + "description": "Parte serializzabile del rapporto SQLite, senza dati di ricerca.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "RapportoReteOutput", + "type": "object" + } +} - changed
Output schema / descriptionPrevious value: -"Un solo schema per i tre esiti possibili (`esito` discrimina), così i\ndue strumenti che leggono un articolo condividono un'unica forma di\nuscita — nessuna copia divergente fra loro."New value: +"Schema comune per articolo, abrogato e preambolo." - added
Output schema / properties / protezione_reteAdded value: +{ + "$ref": "#/$defs/ProtezioneReteOutput" +} - changed
Output schema / requiredPrevious value: -[ - "esito", - "urn", - "permalink", - "attribuzione" -]New value: +[ + "esito", + "urn", + "permalink", + "attribuzione", + "protezione_rete" +]
- Changed
normattiva_leggi_urn4 fields changed- added
Output schema / $defsAdded value: +{ + "ProtezioneReteOutput": { + "description": "Stato corrente e operazioni distinte, incluso un recupero storico.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "rapporti": { + "items": { + "$ref": "#/$defs/RapportoReteOutput" + }, + "title": "Rapporti", + "type": "array" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "ProtezioneReteOutput", + "type": "object" + }, + "RapportoReteOutput": { + "description": "Parte serializzabile del rapporto SQLite, senza dati di ricerca.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "RapportoReteOutput", + "type": "object" + } +} - changed
Output schema / descriptionPrevious value: -"Un solo schema per i tre esiti possibili (`esito` discrimina), così i\ndue strumenti che leggono un articolo condividono un'unica forma di\nuscita — nessuna copia divergente fra loro."New value: +"Schema comune per articolo, abrogato e preambolo." - added
Output schema / properties / protezione_reteAdded value: +{ + "$ref": "#/$defs/ProtezioneReteOutput" +} - changed
Output schema / requiredPrevious value: -[ - "esito", - "urn", - "permalink", - "attribuzione" -]New value: +[ + "esito", + "urn", + "permalink", + "attribuzione", + "protezione_rete" +]
- Changed
normattiva_link4 fields changed- added
Output schema / $defsAdded value: +{ + "ProtezioneReteOutput": { + "description": "Stato corrente e operazioni distinte, incluso un recupero storico.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "rapporti": { + "items": { + "$ref": "#/$defs/RapportoReteOutput" + }, + "title": "Rapporti", + "type": "array" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "ProtezioneReteOutput", + "type": "object" + }, + "RapportoReteOutput": { + "description": "Parte serializzabile del rapporto SQLite, senza dati di ricerca.", + "properties": { + "acquisita_il": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Acquisita Il" + }, + "attivita": { + "title": "Attivita", + "type": "string" + }, + "avviso": { + "title": "Avviso", + "type": "string" + }, + "consumo_attivita": { + "title": "Consumo Attivita", + "type": "string" + }, + "consumo_globale": { + "title": "Consumo Globale", + "type": "string" + }, + "cooldown_fino": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Cooldown Fino" + }, + "livello": { + "title": "Livello", + "type": "string" + }, + "origine": { + "title": "Origine", + "type": "string" + }, + "richieste_residue": { + "title": "Richieste Residue", + "type": "integer" + }, + "ultimo_incidente": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Ultimo Incidente" + } + }, + "required": [ + "origine", + "attivita", + "consumo_attivita", + "consumo_globale", + "richieste_residue", + "livello", + "avviso" + ], + "title": "RapportoReteOutput", + "type": "object" + } +} - added
Output schema / properties / avvisiAdded value: +{ + "items": { + "type": "string" + }, + "title": "Avvisi", + "type": "array" +} - added
Output schema / properties / protezione_reteAdded value: +{ + "$ref": "#/$defs/ProtezioneReteOutput" +} - changed
Output schema / requiredPrevious value: -[ - "markdown", - "verificato" -]New value: +[ + "markdown", + "verificato", + "protezione_rete" +]
- Added
normattiva_stato_rete - Changed
normattiva_trova_fonte3 fields changed- added
Output schema / properties / disponibile / anyOfAdded value: +[ + { + "type": "boolean" + }, + { + "type": "null" + } +] - changed
Output schema / properties / disponibile / defaultPrevious value: -trueNew value: +null - removed
Output schema / properties / disponibile / typeRemoved value: -"boolean"
4 tool updates
v0.1.1- First observed
normattiva_leggi_articolo - First observed
normattiva_leggi_urn - First observed
normattiva_link - First observed
normattiva_trova_fonte
TDQS
Scored across 5 tools
Each tool has a distinct job: source lookup, article read, URN read, permalink construction, and network status. The only mild overlap is between normattiva_leggi_articolo and normattiva_leggi_urn, but the descriptions clearly separate them by input type.
All tool names share the normattiva_ prefix and use snake_case, with several following an action-first pattern like normattiva_leggi_articolo and normattiva_trova_fonte. normattiva_link and normattiva_stato_rete deviate slightly from the verb_noun style, but the overall pattern is still recognizable and predictable.
Five tools is a tight, well-scoped count for a Normattiva citation and retrieval server. Each tool contributes a distinct capability and none feels redundant or missing from the core workflow.
The set covers the main workflow: finding a source, reading an article, resolving a URN, generating a permalink, and checking network status. A full-text search or article-list endpoint would be a useful addition, but the current surface is functional for citation-oriented tasks with no hard dead ends.
Maintenance
Related MCP Connectors
Resolve, search and verify legal citations against the official sources, with provenance.
- LegalizeOAuthdev.legalize
Official MCP connector for Legalize: read and search its whole open corpus, at any point in time.
Japan Law MCP — Japanese national laws & ordinances via the e-Gov Law API.
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Related MCP Servers
- FlicenseAqualityCmaintenanceLocal MCP server that provides Italian legal assistance by querying a local corpus of Italian legislation, integrated with Claude Desktop.3-
- AlicenseAqualityFmaintenanceEnables querying over 3,200 Dutch statutes (AVG, Wetboek van Strafrecht, Burgerlijk Wetboek, etc.) with verbatim, citation-grounded text from official sources, directly from MCP-compatible AI assistants.1848 npm13Apache 2.0
- AlicenseNot gradedqualityFmaintenanceMCP server for Italian law – indexes statutes from Normattiva such as Codice Civile, Codice Penale, and more, with EU implementation mapping.61 npm1Apache 2.0
- AlicenseAqualityAmaintenanceAn MCP server for Italian law, enabling live access to legislation via Normattiva and case law from the Constitutional Court, Supreme Court, and administrative courts, with citation verification.14Apache 2.0