npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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-check

Baixa 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.onnx

3. 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_concloent vol 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ó.
  • inici só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.py abans de publicar. Reescriu runs/section_calibration.json i torna a imprimir la taula de dalt; si els números es mouen, s'han de moure alhora els de src/sections.js i 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.mcpb

pack 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 MCP

Les 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 test

Què 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 seus expected_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.json i 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.