domustudio-mcp-server
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., "@domustudio-mcp-serverlist all fornitori in the desa archive"
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.
domustudio-mcp-server
An MCP server that exposes the Danea Domustudio public API — condomini, persone, fornitori — as tools an agent can call.
The API is read-only: its entire public surface is three GET endpoints. This server adds no write path, because there is none to add. Domustudio remains the system of record; anything that must change, changes there, by a human, in the product.
Requirements
Node.js ≥ 22.12
One Domustudio API key per archive (
X-DANEA-API-KEY)
Related MCP server: aruba-fatturazione-elettronica-mcp
Install it in another repository
The package is not on any registry — it installs straight from this repository, pinned to a release tag. One global install serves every repository on the machine.
npm install -g --allow-git=all "github:juriSacchetta/Domustudio-mcp#v0.4.0"--allow-git=all is required on npm 12 and later, which ships
allow-git = "none" as a default and otherwise refuses the install with
EALLOWGIT. To stop passing it every time:
npm config set allow-git allnpm builds dist/ during install, so the machine needs nothing beyond
Node ≥ 22.12 and access to this repository. npm 12 also prints
install scripts blocked … (prepare: npm run build) — that warning is benign
here: it refers to the consumer's tree, and the build has already run inside
npm's isolated step for the git dependency. Confirm the install with:
test -f "$(npm root -g)/domustudio-mcp-server/dist/index.js" && echo installedDo not run the entry point to "check" it: it is a stdio MCP server with no CLI, so it will start and wait for JSON-RPC on stdin rather than print anything.
A global install puts domustudio-mcp on your PATH, which is the name a
shell-launched client needs — confirm with command -v domustudio-mcp. A GUI
client is launched without your PATH and needs the absolute path instead:
echo "$(npm root -g)/domustudio-mcp-server/dist/index.js"See Configure below for both. To upgrade, rerun the install command with a newer tag; every repository on the machine picks it up at once, which is the trade-off of a single global install.
Develop on it here
npm install
npm run buildConfigure
The server reads its credentials from the environment, and falls back to a .env
file in its working directory for anything the environment does not carry.
DOMUSTUDIO_ARCHIVES is a JSON array — one API key addresses exactly one
archive, and several archives may coexist.
Claude Code, one project
Add it at the default local scope: Claude Code stores that in ~/.claude.json
under the project's path, so the server loads in this project only, stays private
to you, and nothing lands in the repository.
claude mcp add domustudio -e DOMUSTUDIO_ARCHIVES='[{"name":"desa","api_key":"..."}]' \
-- domustudio-mcpThe -- is required: everything after it is the server's own command line. A key
passed this way lands in your shell history; to avoid that, drop the -e and put
the key in a .env as below — the server finds it either way.
A committed .mcp.json
.mcp.json sits at the project root and is normally checked in, which is how a
team shares one server definition — and exactly why the key must not appear in
it. Leave the env block out and give each developer their own gitignored
.env:
// .mcp.json — committed, no credentials
{
"mcpServers": {
"domustudio": { "command": "domustudio-mcp" }
}
}# .env at the project root — one per developer, never committed
printf '.env\n' >> .gitignore
printf 'DOMUSTUDIO_ARCHIVES=[{"name":"desa","api_key":"..."}]\n' >> .env
chmod 600 .envIgnore it before you write it. .mcp.json is committed and .env must not
be; nothing in this server can stop a consuming repository from committing one.
Claude Code launches the server with the project root as its working directory,
which is where it looks. If your client launches it somewhere else, name the file
outright in the .mcp.json entry — DOMUSTUDIO_ENV_FILE is a path, not a
secret, so it is safe in a committed file. It has to arrive this way rather than
from inside a .env, since it is what picks the file to read:
{ "mcpServers": { "domustudio": {
"command": "domustudio-mcp",
"env": { "DOMUSTUDIO_ENV_FILE": "/absolute/path/to/.env" }
} } }Real environment variables always win over the file. Keep the array on one line,
or wrap a multi-line one in single quotes — '[ … ]'.
Claude Desktop and other GUI clients
A GUI client is not launched from a shell and does not inherit your PATH, so
the domustudio-mcp bin may not resolve. Give it Node and an absolute path. This
file lives in your user profile, outside any repository, so the key may sit in it:
// claude_desktop_config.json — per user, never committed
{
"mcpServers": {
"domustudio": {
"command": "node",
// output of: echo "$(npm root -g)/domustudio-mcp-server/dist/index.js"
"args": ["/absolute/path/to/domustudio-mcp-server/dist/index.js"],
"env": {
"DOMUSTUDIO_ARCHIVES": "[{\"name\":\"desa\",\"api_key\":\"...\"}]"
}
}
}
}Why ${DOMUSTUDIO_ARCHIVES} does not work
.mcp.json does expand ${VAR}, but supplying the value through
.claude/settings.local.json env did not work: the server never started, and
the failure reproduced with a control confirming the variable was present in the
session. That is what
#4 observed.
Why the expansion missed it — an ordering question between settings env and
.mcp.json loading — was not established, so treat the recipe as "this does not
work", not as a mechanism you can reason around.
The symptom is worth recognising: an unexpanded variable is passed through as the
literal text ${DOMUSTUDIO_ARCHIVES}, which is not JSON, so the server exits 1
and the client reports nothing more useful than
domustudio (CONNECTION_CLOSED): "Connection closed". From 0.2.0 the server
names that literal on stderr instead.
Exporting the variable from a shell rc file does make the expansion work, but it
puts the key in a dotfile — no better than committing it. Prefer .env.
Variables
Variable | Required | Default |
| yes | — |
| no |
|
| no |
|
DOMUSTUDIO_BASE_URL exists for tests and for pointing at a mock; production
should leave it unset. The default is HTTPS even though the OpenAPI servers
entry says http://.
The key is never echoed in a tool result: an authentication failure names the
archive and the header, not the value. The startup line on stderr names the
.env it read, never its contents.
Tools
Tool | What it does |
| Names of the configured archives |
| All condomini; optional local |
| One condominio by |
| Persone, optionally scoped to a condominio; paginated |
| Fornitori of the whole archive; paginated |
All five are annotated readOnlyHint: true, destructiveHint: false.
Every tool takes an optional archivio. With a single archive configured it may
be omitted; with several, omitting it returns an error listing the names.
Every tool takes response_format: markdown (default) renders the main fields
for reading, json returns the full API record. Integer enums are decoded to
{ codice, etichetta }.
What the API does not give you
Persone and fornitori have no identifier. Neither schema contains an id,
and no endpoint accepts one, so there is no get_persona and no
get_fornitore — a person or supplier is reached by filtering a list. The
condominio id is the only stable handle the API exposes, and it is what
domustudio_list_persone takes as condominio_id.
There is no total count. Responses are bare JSON arrays. ha_altre_pagine
is therefore a heuristic — true when the last page read was full — and is
documented as such in the tool descriptions.
A page is reported to hold at most 100 records. The API caps PageSize
there and says nothing when it does, so dimensione_pagina is refused above
that rather than sent and silently truncated. One tutte_le_pagine call
therefore reaches 5 000 records — 100 per page, 50 pages. npm run test:live
measures the cap against a real archive. See
docs/adr/0002.
Development
Command | |
| compile to |
|
|
| eslint over |
| typecheck + full suite |
| suite only, no build |
| suite against the real API (see below) |
| MCP Inspector against |
The suite runs against a local HTTP mock of the Domustudio API and needs no credentials. It covers the client (headers, 1-based paging, retry policy, the truncated-401), configuration and archive resolution, enum decoding, markdown rendering, every tool over an in-memory MCP transport, and the built binary over real stdio.
Running against the real API
Put real credentials in a .env at the repo root — it is gitignored:
printf 'DOMUSTUDIO_ARCHIVES=[{"name":"desa","api_key":"..."}]\n' > .env
chmod 600 .env
npm run test:liveWithout DOMUSTUDIO_LIVE=1 those tests skip, so npm test stays green on a
machine with no credentials. They only read, and assert on shapes and counts —
no record content is printed.
Documentation
CLAUDE.md— API facts an implementation has to knowdocs/adr/— decisions and why they are hard to reverseCONTRIBUTING.md— the loop, the conventions, how to add a toolSECURITY.md— credential handling and how to report a vulnerabilitydocs/read-only-guard.md— the hook that refuses mutating requestsdocs/verification-hook.md— the hook that runs lint and tests
Trademarks
Danea and Domustudio are trademarks of their respective owners. This project is an independent client of the Domustudio public API, is not affiliated with or endorsed by them, and is not supported by them.
License
MIT — see LICENSE. Copyright (c) 2026 Juri Sacchetta.
Available Tools
5 toolsdomustudio_get_condominioLeggi un condominio per idARead-onlyIdempotent
Restituisce il singolo condominio con l'id indicato.
L'API non espone una lettura per id: lo strumento scarica la lista completa dei condomini e seleziona la voce corrispondente.
Args:
condominio_id (number): id Domustudio del condominio
archivio (string, opzionale): archivio da interrogare
response_format ('markdown' | 'json'): default 'markdown'
Restituisce (json): { "archivio": string, "trovato": boolean, "condominio": object | null }
Errori:
"trovato": false se nessun condominio ha quell'id nell'archivio indicato.
L'API Domustudio è di sola lettura: espone solo tre endpoint GET. Domustudio resta il sistema di registrazione — ogni correzione va fatta da un operatore dentro il gestionale.
| Name | Required | Description | Default |
|---|---|---|---|
| archivio | No | Nome dell'archivio Domustudio da interrogare. Opzionale se ne è configurato uno solo; usare domustudio_list_archivi per l'elenco. | |
| condominio_id | Yes | Id Domustudio del condominio (campo 'id'). | |
| response_format | No | 'markdown' per una sintesi leggibile dei campi principali, 'json' per il record completo. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| trovato | Yes | |
| archivio | Yes | |
| condominio | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, and the description adds genuinely new behavioral facts: the API exposes no per-id read so the tool downloads the full list, the exact return shape ({archivio, trovato, condominio}), the not-found failure mode, and that Domustudio remains the system of record so corrections must be made by an operator. This is material context an agent cannot get from annotations or schema.
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 core purpose and the full-list workaround are front-loaded and earn their place. The trailing paragraph about the Domustudio API being read-only and the system of record is somewhat tangential to this specific tool, and the Args block duplicates the schema, but nothing is egregiously verbose.
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 tool with annotations, a full output schema, and 100% parameter coverage, the description supplies the remaining unknowns: the hidden full-list fetch, the trovato:false error case, and the concrete return object. An agent has everything needed to call and interpret it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and all three parameters are documented there (including the archivio cross-reference to domustudio_list_archivi and the response_format enum semantics). The description's Args block restates the same fields with no added syntax, defaults, or edge-case guidance, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Restituisce il singolo condominio con l'id indicato"), which is clearly distinct from the list-style sibling domustudio_list_condomini via the word "singolo". It does not name that sibling explicitly, so an agent must infer the single-vs-list split rather than being told.
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 explains an implementation workaround (no per-id endpoint, so it fetches the whole list and filters) and the single-archivio optionality, which implies usage context. However, it never states when to prefer this over domustudio_list_condomini, nor any exclusion or prerequisite for calling it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domustudio_list_archiviElenca archivi Domustudio configuratiARead-onlyIdempotent
Elenca i nomi degli archivi Domustudio configurati su questo server.
Una chiave API indirizza esattamente un archivio; ogni altro strumento accetta un parametro "archivio" che seleziona quale interrogare. Se ne è configurato uno solo, quel parametro può essere omesso.
Nessun parametro.
Restituisce: { "archivi": string[], // nomi configurati, nell'ordine di configurazione "conteggio": number }
L'API Domustudio è di sola lettura: espone solo tre endpoint GET. Domustudio resta il sistema di registrazione — ogni correzione va fatta da un operatore dentro il gestionale.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| archivi | Yes | |
| conteggio | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint. The description adds meaningful context beyond them: the backend exposes only three GET endpoints, Domustudio remains the system of record, and corrections must be made by an operator. It does not frame this limitation in terms of what the agent should do instead.
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-loads the purpose, then the operational rule, then the return shape. It is somewhat long and the return-value block duplicates the output schema, but each section is purposeful and no sentence is wasted.
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?
Output schema exists, so explaining return values is optional but harmless. With rich annotations, an empty schema, and clear scoping rules, an agent has everything needed to call this tool correctly and to understand its relationship to the siblings.
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?
Zero parameters, so the baseline is 4. The description correctly states 'Nessun parametro,' confirming the empty schema, and adds the cross-tool rule about the 'archivio' parameter expected by sibling tools.
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 ('Elenca i nomi degli archivi Domustudio configurati') and clearly distinguishes itself from siblings by explaining that it is the discovery tool for the archive name that every other tool requires. An agent can identify its role without opening any schema.
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?
Explains the selection logic explicitly: one API key maps to one archive, every other tool takes an 'archivio' parameter, and that parameter may be omitted when only one archive exists. This is clear context, though it stops short of an explicit when-not-to-use or a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domustudio_list_condominiElenca condominiARead-onlyIdempotent
Elenca i condomini presenti in un archivio Domustudio.
L'endpoint restituisce sempre la lista completa: non è paginato e non accetta filtri lato API. Il parametro "ricerca" filtra i risultati localmente su intestazione, città, provincia, indirizzo e codice fiscale.
L'"id" di un condominio è l'unico identificatore stabile esposto dall'API Domustudio, ed è il valore da passare come "condominio_id" a domustudio_list_persone.
Args:
archivio (string, opzionale): archivio da interrogare
ricerca (string, opzionale): sottostringa, confronto case-insensitive
response_format ('markdown' | 'json'): default 'markdown'
Restituisce (json): { "archivio": string, "conteggio": number, "elementi": [ { "id": number, "intestazione": string, "indirizzo": string, "cap": string, "citta": string, "prov": string, "codFisc": string, "amministratore": { "nome": string, "email": string, ... } } ] } In formato markdown vengono mostrati intestazione, id, indirizzo, codice fiscale e amministratore; il formato json riporta il record completo restituito dall'API.
Usare quando: serve l'id di un condominio, o l'anagrafica dello stabile. Non usare per: elencare le persone di un condominio (domustudio_list_persone) o i fornitori (domustudio_list_fornitori).
L'API Domustudio è di sola lettura: espone solo tre endpoint GET. Domustudio resta il sistema di registrazione — ogni correzione va fatta da un operatore dentro il gestionale.
| Name | Required | Description | Default |
|---|---|---|---|
| ricerca | No | Filtro locale su intestazione, città, provincia, indirizzo, codice fiscale. | |
| archivio | No | Nome dell'archivio Domustudio da interrogare. Opzionale se ne è configurato uno solo; usare domustudio_list_archivi per l'elenco. | |
| response_format | No | 'markdown' per una sintesi leggibile dei campi principali, 'json' per il record completo. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| ricerca | No | |
| archivio | Yes | |
| elementi | Yes | |
| conteggio | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds genuinely new behavior: the endpoint is never paginated, accepts no API-side filters (the 'ricerca' filter runs locally), the 'id' is the only stable identifier, and Domustudio is the system of record. It restates read-only, which duplicates annotations, but the pagination/filter/identifier disclosures are substantial.
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 and scope, then structured into Args / Restituisce / Usare quando sections. Some redundancy between the prose and the explicit Args/Restituisce blocks, but every block earns its place and none is padding.
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?
Despite an output schema already existing, the description explains both markdown and json return shapes and the local-filtering model, which is the non-obvious part an agent needs. Combined with annotations and full schema coverage, an agent has everything required to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the 3 baseline applies, but the description adds meaning beyond the schema: 'ricerca' is a case-insensitive substring, and 'id' is framed as the value to pass as 'condominio_id' elsewhere. Only marginal gains over the well-documented schema.
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 ('Elenca i condomini presenti in un archivio Domustudio') and explicitly distinguishes itself from siblings by naming domustudio_list_persone and domustudio_list_fornitori as out-of-scope. An agent can route correctly without opening any schema.
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?
Has explicit 'Usare quando' (need a condominio id or building registry data) and 'Non usare per' clauses with the alternatives named, plus a concrete handoff rule: use the returned 'id' as 'condominio_id' in domustudio_list_persone. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domustudio_list_fornitoriElenca fornitoriARead-onlyIdempotent
Elenca i fornitori di un archivio Domustudio.
L'anagrafica fornitori è globale sull'archivio, non per condominio: non esiste un parametro che la restringa a uno stabile. Come per le persone, il record non contiene alcun id, quindi non esiste una lettura per id; per trovare un fornitore si filtra questo elenco.
Args:
archivio (string, opzionale): archivio da interrogare
attivi (boolean, opzionale): solo attivi (true) o solo non attivi (false); omesso, entrambi
dati_incompleti (boolean, opzionale): filtra sui fornitori con dati incompleti
attivita (string, opzionale): attività del fornitore (parametro Attivita)
impianto_servizio_id (number, opzionale): id del servizio collegato (ImpiantoServizioID)
esercizi_id (number[], opzionale): esercizi del fornitore (EserciziID)
search_query (string, opzionale): passato all'API come SearchQuery, semantica non documentata
order_by (string, opzionale): passato all'API come OrderBy, semantica non documentata
pagina (number): pagina 1-based, default 1
dimensione_pagina (number): elementi per pagina, default 50
tutte_le_pagine (boolean): se true scorre le pagine fino a 50, default false
response_format ('markdown' | 'json'): default 'markdown'
Restituisce (json): stesso involucro paginato di domustudio_list_persone, con elementi della forma { "descr": string, "fornitoreAttivita": string, "codFisc": string, "piva": string, "iban": string, "email": string[], "pec": string[], "tel1": string, "fornitoreInattivo": boolean, "descStatoDurc": string, "dataScadenzaDurc": string, "f24CodTributo": { "codice": number, "etichetta": string }, ... } "ha_altre_pagine" è un'euristica: l'API non restituisce un totale, quindi è vero quando l'ultima pagina letta era piena.
Usare quando: serve un fornitore per attività, partita IVA, IBAN o stato DURC. Non usare per: i condòmini e i soggetti dell'anagrafica persone (domustudio_list_persone).
L'API Domustudio è di sola lettura: espone solo tre endpoint GET. Domustudio resta il sistema di registrazione — ogni correzione va fatta da un operatore dentro il gestionale.
| Name | Required | Description | Default |
|---|---|---|---|
| attivi | No | Stato del fornitore (parametro Attivi). | |
| pagina | No | Numero di pagina, 1-based (parametro PageNumber dell'API). | |
| archivio | No | Nome dell'archivio Domustudio da interrogare. Opzionale se ne è configurato uno solo; usare domustudio_list_archivi per l'elenco. | |
| attivita | No | Attività del fornitore (Attivita). | |
| order_by | No | Ordinamento, inoltrato all'API come OrderBy. | |
| esercizi_id | No | Esercizi del fornitore (EserciziID). | |
| search_query | No | Ricerca libera, inoltrata all'API come SearchQuery. | |
| dati_incompleti | No | Fornitori con dati incompleti (DatiIncompleti). | |
| response_format | No | 'markdown' per una sintesi leggibile dei campi principali, 'json' per il record completo. | markdown |
| tutte_le_pagine | No | Se true, scorre le pagine successive fino a esaurimento o fino a 50 pagine (il campo troncato_al_limite_pagine segnala il taglio). | |
| dimensione_pagina | No | Elementi per pagina (parametro PageSize dell'API). Massimo 100. | |
| impianto_servizio_id | No | Id del servizio collegato al fornitore (ImpiantoServizioID). |
Output Schema
| Name | Required | Description |
|---|---|---|
| pagina | Yes | |
| archivio | Yes | |
| elementi | Yes | |
| conteggio | Yes | |
| pagine_lette | Yes | |
| ha_altre_pagine | Yes | |
| prossima_pagina | No | |
| dimensione_pagina | Yes | |
| troncato_al_limite_pagine | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/non-destructive, and the description adds substantial context beyond them: the record has no id so there is no per-record read, 'ha_altre_pagine' is only a heuristic because the API returns no total, and the whole API is read-only with only three GET endpoints while Domustudio remains the system of record (corrections require an operator). That is exactly the kind of behavioral disclosure annotations cannot carry.
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?
Well front-loaded and sectioned (Args / Restituisce / Usare quando / Non usare), but the Args block largely restates the 100%-covered schema, which is redundant filler. The genuinely additive sentences (no id, pagination heuristic, read-only caveat) are worth their space; the parameter recap is not.
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 12-parameter, zero-required listing tool with an output schema present, the description covers filtering semantics, pagination limits, the return envelope shape, and the system-of-record constraint. An agent has everything needed to call it correctly and to route lookups to it instead of a nonexistent get-by-id.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description earns extra: it spells out omitted=both for 'attivi', flags that hidden 'search_query' and 'order_by' are passed through with undocumented semantics, and caps 'tutte_le_pagine' at 50 pages with a truncation flag. These add meaning beyond the schema without fully re-documenting every field.
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?
Opens with a specific verb+resource ('Elenca i fornitori di un archivio Domustudio') and immediately scopes it: the anagrafica fornitori is global to the archivio, not per condominio. It explicitly names the sibling it is not ('Non usare per: i condòmini e i soggetti dell'anagrafica persone (domustudio_list_persone)'), so an agent can disambiguate without opening either schema.
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?
Gives an explicit when-to-use ('serve un fornitore per attività, partita IVA, IBAN o stato DURC') and an explicit when-not-use with the named alternative (domustudio_list_persone). It also states the critical routing fact that there is no read-by-id, so lookup must go through this filtered list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
domustudio_list_personeElenca persone (anagrafica soggetti)ARead-onlyIdempotent
Elenca le persone dell'anagrafica Domustudio, opzionalmente ristrette a un condominio.
L'API non espone un identificatore per le persone: il record non contiene alcun id, quindi non esiste una lettura per id e non c'è modo di indirizzare una persona singola. Per trovare qualcuno si filtra questo elenco (search_query, oppure condominio_id più una lettura dei risultati).
Args:
archivio (string, opzionale): archivio da interrogare
condominio_id (number, opzionale): restringe a un condominio (parametro CondGendID). Ottenerlo da domustudio_list_condomini
filtro_subentri (1|2|3|4|5): 1 tutti, 2 attivi, 3 ex, 4 contabilità, 5 destinatari comunicazioni. Default 2
esercizio_id (number, opzionale): parametro EsercizioID
tags_id (number[], opzionale): parametro TagsID
search_query (string, opzionale): passato all'API come SearchQuery; la semantica è decisa dall'API, non documentata nello spec
order_by (string, opzionale): passato all'API come OrderBy, semantica non documentata
pagina (number): pagina 1-based, default 1
dimensione_pagina (number): elementi per pagina, default 50
tutte_le_pagine (boolean): se true scorre le pagine fino a 50, default false
response_format ('markdown' | 'json'): default 'markdown'
Restituisce (json): { "archivio": string, "conteggio": number, // elementi in questa risposta "pagina": number, // prima pagina letta "dimensione_pagina": number, "pagine_lette": number, "ha_altre_pagine": boolean, // euristica: l'API non restituisce un totale, quindi è vero quando l'ultima pagina era piena "prossima_pagina": number, // presente solo se ha_altre_pagine "troncato_al_limite_pagine": boolean, "elementi": [ { "descr": string, "codFisc": string, "piva": string, "indirizzo": string, "cap": string, "citta": string, "prov": string, "email": string[], "pec": string[], "tel1": string, "note": string, "preferenzaPagamentoRate": { "codice": number, "etichetta": string }, ... } ] } I campi enumerativi sono restituiti come { codice, etichetta }. Il formato markdown mostra denominazione, codice fiscale, indirizzo, recapiti; json riporta il record completo.
Usare quando: servono i condòmini di uno stabile, i recapiti di un soggetto, o un conteggio per condominio. Non usare per: i fornitori, che stanno in un'anagrafica separata (domustudio_list_fornitori).
L'API Domustudio è di sola lettura: espone solo tre endpoint GET. Domustudio resta il sistema di registrazione — ogni correzione va fatta da un operatore dentro il gestionale.
| Name | Required | Description | Default |
|---|---|---|---|
| pagina | No | Numero di pagina, 1-based (parametro PageNumber dell'API). | |
| tags_id | No | Id dei tag (TagsID). | |
| archivio | No | Nome dell'archivio Domustudio da interrogare. Opzionale se ne è configurato uno solo; usare domustudio_list_archivi per l'elenco. | |
| order_by | No | Ordinamento, inoltrato all'API come OrderBy. | |
| esercizio_id | No | Id dell'esercizio (EsercizioID). | |
| search_query | No | Ricerca libera, inoltrata all'API come SearchQuery. | |
| condominio_id | No | Id del condominio (CondGendID). Omesso, l'API restituisce le persone di tutto l'archivio. | |
| filtro_subentri | No | 1 tutti, 2 attivi, 3 ex, 4 contabilità, 5 destinatari comunicazioni | |
| response_format | No | 'markdown' per una sintesi leggibile dei campi principali, 'json' per il record completo. | markdown |
| tutte_le_pagine | No | Se true, scorre le pagine successive fino a esaurimento o fino a 50 pagine (il campo troncato_al_limite_pagine segnala il taglio). | |
| dimensione_pagina | No | Elementi per pagina (parametro PageSize dell'API). Massimo 100. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pagina | Yes | |
| archivio | Yes | |
| elementi | Yes | |
| conteggio | Yes | |
| pagine_lette | Yes | |
| ha_altre_pagine | Yes | |
| prossima_pagina | No | |
| dimensione_pagina | Yes | |
| troncato_al_limite_pagine | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial extra context: the whole API is read-only with only three GET endpoints, Domustudio remains system of record so corrections need an operator, and the pagination heuristic (ha_altre_pagine is inferred because the API returns no total) plus the 50-page truncation 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?
Front-loaded with the identifying constraint, then args, return shape, and when/when-not. It is long and the args block partially duplicates a 100%-covered schema, but every section carries useful information and is well ordered.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 11 optional parameters, the output schema, and the annotations, the description covers everything needed: pagination caveats, truncation, format choices, and the critical absence of per-record ids. Nothing an agent needs to call 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 coverage is 100%, so baseline is 3, but the description adds meaning beyond the schema: it notes search_query and order_by have API-decided, undocumented semantics, and tells the agent to obtain condominio_id from domustudio_list_condomini. It also enumerates filtro_subentri and defaults, though much of that is already in the schema.
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 ('Elenca le persone dell'anagrafica Domustudio') and immediately clarifies the crucial scope constraint that the API exposes no per-person identifier, so only listing/filtering is possible. It also differentiates from the sibling domustudio_list_fornitori.
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?
Explicit 'Usare quando' (condòmini di uno stabile, recapiti, conteggi per condominio) and 'Non usare per' (fornitori, in a separate registry named as sibling). Also hints at alternatives for finding a single person (filter this list).
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.4.0- First observed
domustudio_get_condominio - First observed
domustudio_list_archivi - First observed
domustudio_list_condomini - First observed
domustudio_list_fornitori - First observed
domustudio_list_persone
TDQS
Scored across 5 tools
Each tool targets a distinct resource: archives, condomini, a single condominio, persone, or fornitori. The descriptions explicitly state when to use each tool and when not to use it, preventing overlap confusion. The only minor redundancy is get_condominio versus list_condomini, but the signature and intent are clearly separated.
All tools share the domustudio_ prefix and use consistent snake_case with a verb_noun pattern: list_archivi, list_condomini, get_condominio, list_persone, list_fornitori. There are no mixed conventions or ambiguous verb styles. The naming is entirely predictable.
Five tools is well-scoped for a read-only integration wrapping three GET endpoints plus archive discovery and a convenience single-condominio lookup. Each tool earns its place, with no thin or bloated surface. The count matches the domain perfectly.
The Domustudio API is explicitly read-only and exposes only three GET endpoints; the server covers all of them plus archive listing and single-condominio retrieval. Missing update/delete operations are by design, not gaps. Agents have workarounds for person and supplier lookup via filtering, and no obvious read path is absent.
Maintenance
Related MCP Connectors
Read and write a CRM built for agents. Every change carries who asserted it and how.
AgentDocs (agentdocs.eu) MCP: read, search, write, comment, share & attach images to Markdown docs.
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Read-only docs for the Accordo CRM framework: what it proves, and where it stops.
Related MCP Servers
- FlicenseBqualityDmaintenanceEnables read-only access to FileMaker databases through the Data API, allowing users to retrieve records, analyze metadata, search across layouts, and infer relationships while maintaining data security.16-
- FlicenseCqualityBmaintenanceExposes read-only Aruba Fatturazione Elettronica API operations for managing electronic invoices, notifications, and providing fiscal document helpers.701-
- FlicenseNot gradedqualityCmaintenanceEnables read-only access to InvoiceNinja data, including invoices, expenses, clients, and tax reports, for AI assistants like Claude.1-
- FlicenseNot gradedqualityCmaintenanceRead-only MCP server for DocuWare that lets you list file cabinets, search documents, view metadata, and download documents.-