esia-mcp
v1.2.3
Published
Servidor MCP local del detector de text generat per IA "és ia?" (català/castellà). Local MCP server for the "és ia?" on-device Catalan/Spanish AI-text detector.
Maintainers
Readme
és ia? — servidor MCP local
Detector de text generat per IA en català i castellà, com a servidor MCP. Li dius a Claude «analitza els documents d'aquesta carpeta» i el detector els analitza en aquest ordinador, un per un, i torna una taula de veredictes.
El contingut dels documents no surt de la màquina. Tampoc no passa pel model de llenguatge: les eines només tornen el veredicte i quatre números per fitxer, mai el text. És exactament per això que val la pena fer-ho amb MCP en comptes de demanar-li a l'agent que llegeixi la carpeta ell mateix.
És el mateix model i el mateix punt de decisió que esia.cat i que l'extensió de navegador.
Dos motors, triats sols
En node normal (npx esia-mcp) la inferència corre sobre onnxruntime natiu
(~80 ms per document). Dins de Claude Desktop (paquet .mcpb) el servidor corre
en un utilityProcess d'Electron signat amb hardened runtime: macOS mata en
silenci qualsevol procés que carregui una llibreria nativa no signada per la
mateixa app (library validation), així que allà el motor passa sol a
onnxruntime-web (wasm, un fil, ~3 s per document) — mateix model, mateixos
llindars, paritat mesurada |Δ| ≤ 0.006 log-odds. ESIA_FORCE_WASM=1 força el
camí wasm en node normal per provar-lo.
Instal·lació
Cal Node 20 o superior.
1. Afegeix-lo a Claude Desktop
Edita claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"esia": {
"command": "npx",
"args": ["-y", "esia-mcp"]
}
}
}Reinicia Claude Desktop. Hi hauria d'aparèixer el servidor esia amb tres eines.
Si encara no has publicat el paquet a npm, apunta-hi directament la còpia local:
{ "mcpServers": { "esia": { "command": "node", "args": ["/camí/absolut/a/isai/mcp/src/server.js"] } } }
2. Baixa el model abans (recomanat)
La primera anàlisi baixa el model, uns 194 MB. Dins d'una conversa això són uns minuts de silenci, així que val més fer-ho abans des del terminal:
npx esia-mcp --model-checkBaixa el model, el valida, el carrega per comprovar que funciona en aquesta màquina i diu on ha quedat. A partir d'aquí el servidor arrenca en segons i funciona sense connexió.
Per defecte el model va a ~/.cache/esia-mcp/detector-v51-s50-fp16/ i conté:
config.json
tokenizer_config.json
tokenizer.json
onnx/model_fp16.onnx3. ESIA_MODEL_DIR (opcional)
Si ja tens el model en algun lloc — per exemple l'exportació del repositori,
runs/v51/export/detector-v51-s50-fp16 — assenyala-l'hi i no es baixarà res:
{
"mcpServers": {
"esia": {
"command": "npx",
"args": ["-y", "esia-mcp"],
"env": { "ESIA_MODEL_DIR": "/camí/a/detector-v51-s50-fp16" }
}
}
}ESIA_MODEL_DIR és la carpeta del model, no la carpeta que la conté. Si
existeix i és completa, no s'escriu ni es baixa res; si és buida, el model s'hi
baixa en comptes d'anar a la memòria cau.
Com s'utilitza
Un cop configurat, parla-hi normal. Exemples que funcionen:
Analitza tots els documents de la carpeta ~/Documents/treballs i fes-me un resum.
Analitza els documents de ~/Descarregues/entregues, també les subcarpetes, i digue'm quins convindria repassar.
Aquest text, sembla escrit per una persona? [text enganxat]
Claude triarà l'eina, l'executarà en local i et resumirà la taula que li torni.
Les tres eines
| Eina | Entrada | Què fa |
| --- | --- | --- |
| analitza_text | text | Analitza un text enganxat. |
| analitza_fitxers | fitxers (llista de camins absoluts) | Analitza fitxers concrets. |
| analitza_carpeta | carpeta, recursiu (opcional) | Busca i analitza els documents d'una carpeta. |
Formats: .txt, .md, .docx (els .docx es llegeixen amb
mammoth).
Límits per crida, dits sempre explícitament al resultat i mai en silenci:
- 200 fitxers per crida. Si en demanes més, s'analitzen els 200 primers i el resum diu quants han quedat fora.
- Els fitxers de més de 2 MB se salten, amb el motiu a la seva fila.
- Els textos de menys de 80 paraules no s'analitzen: per sota d'aquí el detector no és fiable i preferim dir-ho abans que endevinar.
Què torna
Per fitxer, només això:
{ "fitxer": "/Users/…/treball.docx", "veredicte": "huma", "lectura": 10, "paraules": 451 }veredicte:"huma","ia","barrejat"o"no_concloent".lectura: de 1 a 99. No és una probabilitat. És com de lluny queda el text del punt de decisió, que és el 50. Com més amunt, més s'assembla als textos d'IA que el sistema coneix. En documents llargs és la lectura de la secció que més s'hi assembla.no_concloentvol dir que el text queda prop del punt de decisió i que amb una calibració lleugerament diferent canviaria de banda. És més útil saber-ho que rebre una moneda a l'aire.
I un resum amb els recomptes, més l'avís, un cop per crida i no per fila.
Documents llargs: anàlisi per seccions
Un detector que només mira les primeres ~512 paraules-token jutja un treball de 4.000 paraules per la primera pàgina. Per això els documents llargs es tallen en seccions alineades amb els paràgrafs (~350 paraules, sense partir mai un paràgraf pel mig) i s'analitza cada secció per separat.
El resultat guanya un mapa de seccions:
{
"veredicte": "barrejat",
"veredicte_global": "barrejat",
"lectura": 87,
"paraules": 1443,
"seccions_totals": 4,
"seccions_analitzades": 4,
"seccions": [
{ "n": 1, "paraules": 438, "veredicte": "huma", "lectura": 1, "inici": "abocat durant cadascun dels darrers cinquanta anys l'equival…" },
{ "n": 3, "paraules": 339, "veredicte": "ia", "lectura": 87, "inici": "Fer cervesa artesana en casa és una afició que enganxa, però…" }
]
}barrejatés el veredicte nou i el més útil: hi conviuen seccions que s'assemblen a l'IA i seccions que no. Un text escrit a mitges és el cas real més habitual, i col·lapsar-lo a un sí/no llença l'única cosa accionable que sabem. També el poden provocar citacions, traduccions o una revisió molt intensa — per això el veredicte no és una acusació.inicisón les primeres ~60 lletres de la secció, perquè puguis localitzar-la al teu document. És l'únic text que torna l'eina, i torna a qui ja el té.nés el número de la secció dins del document, no dins de la mostra.
El punt de decisió per secció no és el del document
Analitzar k seccions i marcar el document si en salta alguna són k tirades a
la taxa de fals positiu, així que la garantia «1 de cada 240» no es transfereix
sola. scripts/section_calibration_v51.py va mesurar tot el corpus de test
v5.1 secció a secció amb el model fp16 que es distribueix i va trobar el punt
que la restaura:
| | | | --- | --- | | Llindar per secció | log-odds cru +8,0 (no el +7,7298 del document) | | Banda no concloent | |log-odds − 8,0| < 0,75 | | FPR per secció | 0,26 % | | TPR per secció | 94,6 % | | FPR per document (regla «alguna secció») | 0,41 % | | TPR per document | 98,1 % |
O sigui: la proporció de textos humans marcats per error no empitjora en passar a seccions, perquè el llindar per secció es va calibrar justament per mantenir-la.
Després de qualsevol reentrenament, torna a passar
scripts/section_calibration.pyabans de publicar. Reescriuruns/section_calibration.jsoni torna a imprimir la taula de dalt; si els números es mouen, s'han de moure alhora els desrc/sections.jsi els que hi ha escrits a la caixa. És la porta de recalibració d'aquesta funció.
El límit de 15 seccions
Com a màxim s'analitzen 15 seccions per document. Si n'hi ha més, se'n pren
una mostra uniforme que sempre inclou la primera i l'última, i es diu
explícitament: "s'han analitzat 15 de 43 seccions, mostrejades uniformement".
La mostra és determinista — el mateix document dona sempre les mateixes
seccions. Mai es retalla en silenci.
Les seccions de menys de 80 paraules no s'analitzen (per sota d'aquí el detector no és fiable) i el resultat diu quantes se n'han deixat de banda.
Els textos que només donen una secció segueixen exactament el camí d'abans, amb el punt de decisió per document de sempre: el comportament dels textos curts no ha canviat.
Privadesa
- L'anàlisi s'executa en aquest ordinador, amb el model ONNX en local.
- El contingut dels documents no s'envia a cap servidor i no es passa al model de llenguatge que fa la petició.
- No es desa res: els textos es llegeixen, s'analitzen i es descarten.
- L'única connexió de xarxa que fa aquest programa és baixar el model un
sol cop de
https://model.esia.cat. Un cop baixat, funciona fora de línia.
Límits, dits clarament
Això és un indici estadístic, no una prova.
- Aproximadament 1 de cada 240 textos escrits per persones es marquen com a IA per error.
- El detector no reconeix totes les eines d'IA, i les que no coneix li poden passar per davant.
- Necessita 80 paraules com a mínim. Amb fragments curts, títols o respostes breus el resultat no és fiable.
- Els textos barrejats (una part escrita i una part generada) el confonen.
- Està entrenat en català i castellà. En altres llengües no vol dir res.
- No serveix de base per prendre decisions sobre persones. Si un resultat et preocupa, l'única cosa raonable a fer és parlar amb qui ha escrit el text.
Extensió d'escriptori (.mcpb)
Aquest directori inclou un manifest.json vàlid per empaquetar el servidor com a
Desktop Extension, que s'instal·la fent
doble clic en comptes d'editar JSON a mà.
npx @anthropic-ai/mcpb validate manifest.json
npx @anthropic-ai/mcpb pack . esia-mcp.mcpbpack inclou el node_modules sencer al paquet. Com que onnxruntime-node
porta els binaris natius de totes les plataformes i
@huggingface/transformers importa onnxruntime-web de manera estàtica (no es
pot podar), el .mcpb que en surt és gros. Fes un npm install --omit=dev
abans d'empaquetar, i compta que la instal·lació per npx és la via
recomanada; el .mcpb és una comoditat, no el camí principal.
Desenvolupament
npm install
npm test # syntax + metadades + matemàtiques + paritat + protocol MCPLes proves de paritat i de protocol necessiten el model. Busquen
ESIA_MODEL_DIR, després l'exportació del repositori
(../runs/v51/export/detector-v51-s50-fp16), i si no el troben se salten en
comptes de baixar 194 MB pel seu compte:
ESIA_MODEL_DIR=../runs/v51/export/detector-v51-s50-fp16 npm testQuè cobreix cada prova:
test/reading.test.mjs— el punt de decisió i el càlcul de la lectura, contra valors calculats a mà. Portat de l'extensió perquè els tres productes no divergeixin.test/parity.test.mjs— el motor contra els 18 documents de referència i els seusexpected_log_odds_fp16.test/smoke.test.mjs— engega el servidor de debò i hi parla JSON-RPC per stdio:initialize→tools/list→tools/call. Comprova també que cap byte que no sigui JSON-RPC arriba a stdout, que és la manera silenciosa que té un servidor MCP de deixar de funcionar.test/meta.test.mjs—package.json,manifest.jsoni el README, en step.
English
és ia? is an on-device AI-generated-text detector for Catalan and Spanish, exposed as a local MCP server. Ask Claude to analyse a folder of documents and the detector runs locally, file by file, returning a compact verdict table.
Document text never leaves the machine, and never reaches the LLM — the
tools return verdicts and counts, not content. The only network access this
program ever makes is a one-time model download from model.esia.cat; after
that it works offline.
Install: Node 20+, then add to claude_desktop_config.json:
{ "mcpServers": { "esia": { "command": "npx", "args": ["-y", "esia-mcp"] } } }Pre-warm the ~194 MB model with npx esia-mcp --model-check. Point
ESIA_MODEL_DIR at an existing model directory to skip the download.
Tools: analitza_text (one text), analitza_fitxers (a list of files),
analitza_carpeta (a whole folder). Formats .txt, .md, .docx; 200 files
per call; 80-word minimum.
Long documents are split into paragraph-aligned ~350-word sections and
scored per section, so a 4,000-word essay is judged whole rather than by its
first page. The result carries a section map (seccions) and the document
verdict may be barrejat — some sections look generated, others do not.
At most 15 sections are scored; beyond that a deterministic uniform sample is
taken, always including the first and last, and the coverage is stated
explicitly. The per-section decision point is raw log-odds +2.0, not the
per-document threshold: it was calibrated by scripts/section_calibration.py
so that the document-level false-positive rate under the any-section rule stays
at 0.34%, matching the whole-document guarantee. Rerun that script after any
retrain — it is the recalibration gate.
Limitations. This is a statistical indicator, not proof. Roughly 1 in 240 human-written texts is flagged as AI, the detector does not recognise every AI tool, mixed human/AI texts confuse it, and it means nothing outside Catalan and Spanish. It is not a basis for decisions about people — if a result worries you, talk to whoever wrote the text.
Llicència
MIT.
