shiwake-mcp
Pruebas de asientos contables (JET) para auditorías contables. 11 reglas de revisión, cero dependencias.
Documentación
shiwake-mcp
Servidor MCP que realiza un primer cribado de datos de asientos contables. Dependencias: cero.
Recibe asientos del libro mayor, aplica 15 reglas y los devuelve ordenados según la prioridad con la que una persona debería revisarlos. Es una forma de exponer las pruebas de asientos (Journal Entry Testing) del ámbito de la auditoría para que pueda invocarlas un agente de IA.
Por qué no tiene dependencias
No hay nada que entre con npm install. La dependencies de package.json está vacía.
Si se añaden dependencias externas a una herramienta que maneja datos contables, cada vez que se implemente habrá que explicar "qué hace este paquete". En redes de firmas de auditoría o despachos contables, ese coste de explicación supera al del propio desarrollo. Con cero dependencias, todo el código que hay que leer se limita a este repositorio.
El transporte stdio de MCP es JSON-RPC 2.0 separado por líneas. Se puede implementar en unas 200 líneas sin usar SDK.
Cómo ejecutarlo
Se requiere Node.js 20 o superior.
Conectarlo como servidor MCP
Está publicado en npm, así que se puede iniciar con npx. No requiere instalación previa. Solo se descarga este paquete; al no tener dependencias, no entra nada más.
Con Claude Code basta una línea.
claude mcp add shiwake -- npx -y shiwake-mcp
Si se antepone --scope project al nombre, se escribe en .mcp.json dentro del proyecto y se puede compartir con el equipo.
Claude Desktop se configura añadiendo la entrada al archivo de configuración (claude_desktop_config.json).
{
"mcpServers": {
"shiwake": {
"command": "npx",
"args": ["-y", "shiwake-mcp"]
}
}
}
Para fijar una versión concreta, se especifica como shiwake-mcp@0.1.0. Si se prefiere revisar el código antes de ejecutarlo, se puede clonar el repositorio y usar "command": "node" y "args": ["/path/to/shiwake-mcp/src/server.js"] directamente.
Libros mayores grandes: pasar un archivo
Para libros de más de unos cientos de asientos, no se colocan los asientos en la conversación, sino que se pasa la ruta del archivo. Si los asientos se pasan por chat, la IA tendría que reproducirlos todos, y con decenas de miles no caben.
Las carpetas que el servidor puede leer se especifican al arrancar con --data-dir (se puede indicar varias veces; también se puede usar la variable de entorno SHIWAKE_DATA_DIR).
claude mcp add shiwake -- npx -y shiwake-mcp --data-dir /path/to/ledgers
En Claude Desktop, se usa "args": ["-y", "shiwake-mcp", "--data-dir", "C:\\audit\\ledgers"].
Los archivos fuera de las carpetas permitidas no se abren aunque la IA pase su ruta. Si un enlace simbólico o una unión (junction) apunta fuera, se comprueba el destino y tampoco se lee.
Después basta con pedir, por ejemplo, "revisa 2025年度_仕訳帳.csv con screen_journals" y a la herramienta se le pasa file. Las rutas relativas se resuelven desde la primera carpeta indicada. Se pueden leer .json y .csv (UTF-8 y Shift_JIS), con un límite de 256 MB. En mediciones locales, 380 000 registros (CSV de 76 MB) tardan unos 9 segundos y la respuesta ocupa unas 80 000 caracteres.
Probarlo primero localmente
Al clonar el repositorio se incluyen datos de ejemplo (383 registros sintéticos con anomalías conocidas) para comprobar el comportamiento. No se necesita npm install.
git clone https://github.com/USHIKUNDESUYO/shiwake-mcp.git
cd shiwake-mcp
npm run demo
検査対象 383 件
検出 54 件 / 対象仕訳 25 件
重要度 high 13 / medium 16 / low 25
ベンフォード MAD 0.012241 → 許容の限界(n=383)
ルール別:
営業時間外の入力 11 件
キリのよい金額 9 件
!! 承認限度額の直下 7 件
! 重複仕訳 5 件
!! 起票者と承認者が同一 4 件
! 期末直前の大口計上 4 件
! 計上日と入力日の乖離 3 件
! 稀な勘定科目の組み合わせ 3 件
休日の計上 3 件
!! 貸借不一致 2 件
摘要が空 2 件
! 期末後の入力 1 件
確認の優先順位(上位 20 件):
[ 23] JV-0382 2025-09-06 3000000 self_approval, rare_account_pair, weekend_or_holiday, after_hours, round_amount, missing_description
[ 19] JV-0365 2026-03-30 8900000 self_approval, period_end_large, after_hours, round_amount
開発委託費
[ 17] JV-0362 2026-01-22 1200000 unbalanced, rare_account_pair, round_amount
業務委託費計上
(以下省略)
De 383 registros se pasa a 25. La puntuación es la suma de la importancia de cada regla; los asientos que coinciden con varias reglas a la vez aparecen más arriba.
Herramientas
| Herramienta | Qué devuelve |
|---|---|
screen_journals | Aplica todas las reglas y devuelve la lista ordenada por riesgo |
check_balance | Asientos cuyo debe y haber no cuadran, con su diferencia |
benford_analysis | Distribución del primer dígito de los importes, MAD, χ² |
detect_duplicates | Grupos de asientos idénticos |
list_rules | Lista de las reglas implementadas y su propósito |
Todas las herramientas se declaran en las anotaciones de MCP como "solo lectura (readOnlyHint) y sin contacto externo (openWorldHint: false)". No modifican nada ni envían datos a servicios externos.
Los asientos se pasan en journals o mediante la ruta de archivo en file (sección anterior).
Las detecciones individuales (findings) que devuelve screen_journals se limitan a los top asientos principales (50 por defecto). El recuento siempre se hace sobre el total. Si se necesitan todos, se pasa allFindings: true. Las listas de check_balance y detect_duplicates también están limitadas a 200 elementos por defecto.
Los asientos de entrada se aceptan tanto en formato simple como en formato detallado.
{
"id": "JV-0001",
"date": "2026-03-31",
"entered_at": "2026-04-02T23:41:00+09:00",
"debit_account": "売掛金",
"credit_account": "売上高",
"amount": 12000000,
"description": "3月度売上計上",
"created_by": "acc01",
"approved_by": "mgr01"
}
Los casos con más líneas, como el IVA o los asientos compuestos, se pasan en formato detallado.
{
"id": "JV-0002",
"date": "2026-03-31",
"lines": [
{ "account": "外注費", "debit": 1000000 },
{ "account": "仮払消費税", "debit": 100000 },
{ "account": "買掛金", "credit": 1100000 }
]
}
Si hay un asiento que no se puede leer, por defecto se detiene todo y se indica en qué posición y qué parte no se pudo leer. Para omitir las líneas ilegibles y continuar, se pasa skipInvalid: true. Las líneas omitidas se devuelven en invalidRows con su posición, número de comprobante y motivo.
entered_at también acepta solo la fecha. En ese caso se usa para "desfase entre fecha de registro y fecha de entrada", pero no para "entrada fuera del horario laboral".
Lectura de CSV
Se puede pasar directamente un CSV exportado desde el software contable. Los nombres de columna se asignan automáticamente entre las siguientes opciones. Se ignoran diferencias entre caracteres de ancho completo y medio, espacios y anotaciones entre paréntesis como "(税込)".
| Campo | Posibles nombres de columna |
|---|---|
| Número de comprobante | 伝票番号・伝票No・仕訳番号・取引番号・No, etc. |
| Fecha | 日付・取引日・計上日・伝票日付・仕訳日, etc. |
| Fecha y hora de entrada | 入力日時・登録日時・作成日時・入力日, etc. |
| Cuenta deudora / cuenta acreedora | 借方勘定科目・借方科目, 貸方勘定科目・貸方科目 |
| Importe | 借方金額 y 貸方金額, o 金額 |
| Descripción | 摘要・内容 |
| Creador / aprobador | 入力者・起票者・作成者, 承認者 |
Las columnas que no se detectan se especifican con columns (ejemplo: { "date": "伝票日付", "amount": "金額(税込)" }). Las columnas utilizadas se devuelven en source.columnsUsed de la respuesta, así que conviene comprobarlo antes de leer los resultados.
Se asume una fila con debe y haber, y las filas con el mismo número de comprobante y fecha se agrupan en un solo asiento. La cuenta "諸口" (varias contrapartidas) se elimina si, dentro del mismo comprobante, el debe y el haber coinciden. Si no coinciden, se conserva para no ocultar el desajuste.
Las fechas se leen en formatos como 2026/3/31, 20260331, 2026年3月31日, R8.3.31, 令和8年3月31日, etc. Se eliminan los separadores de miles y el símbolo de yen; △ y los paréntesis se tratan como negativos (los importes negativos detienen el proceso por defecto). Si hay una fila de título antes del encabezado, se busca la fila de encabezado y se lee desde ahí. Los errores y exclusiones se indican por número de línea del CSV.
El "formato de importación Yayoi" de Yayoi Kaikei (CSV de 25 o 27 campos sin fila de encabezado) se detecta por el indicador del primer campo y se lee por posición de columna. Los códigos 2000 y 2111 corresponden a un asiento por línea; las líneas de 2110 a 2101 se agrupan en un solo asiento. La fecha de transacción se lee en cualquiera de estos formatos: 20260331, 2026/3/31, R08/03/31. El orden de columnas sigue la tabla de la información de soporte de Yayoi Kaikei "Elementos y formato de descripción de los datos de asientos". Este formato no incluye columna de fecha y hora de entrada, por lo que las tres reglas que la usan (desfase entre fecha de registro y entrada, entrada después del cierre y entrada fuera del horario laboral) no se aplican.
Reglas
| ID | Contenido | Importancia | Qué indica |
|---|---|---|---|
unbalanced | Desajuste entre debe y haber | alta | Entrada manual, error de importación o alteración |
self_approval | Creador y aprobador son la misma persona | alta | La segregación de funciones no funciona |
threshold_avoidance | Justo por debajo del límite de aprobación | alta | Fraccionamiento para evitar la aprobación |
duplicate | Asientos duplicados | media | Doble registro o registro periódico legítimo |
reversal | Asientos de anulación o corrección | media | Anulación o corrección de errores; los pares que cruzan el cierre requieren revisar la atribución temporal |
backdated | Desfase entre fecha de registro y fecha de entrada | media | Error de atribución temporal, registro retroactivo |
post_period_entry | Entrada después del cierre | media | Ajustes tras el cierre; suele reflejar controles ineficaces |
period_end_large | Grandes importes justo antes del cierre | media | Si hay ajuste de resultados, aparece en esta ventana |
rare_account_pair | Combinaciones de cuentas poco habituales | media | Operaciones fuera del flujo normal |
weekend_or_holiday | Registro en día festivo | baja | Operaciones fuera del ciclo de negocio |
after_hours | Entrada fuera del horario laboral | baja | Débil por sí sola, pero efectiva en combinación |
round_amount | Importes redondos | baja | Estimaciones, aproximaciones, reclasificaciones |
missing_description | Descripción vacía | baja | Calidad como evidencia de auditoría |
description_keyword | Palabras clave en la descripción | baja | Ajustes posteriores, registros sin contenido definido |
voucher_gap | Números de comprobante faltantes | baja | Comprobantes eliminados o anulados, omisiones de exportación |
Las condiciones previas se pasan como opciones.
{
"fiscalYearEnd": "03-31",
"businessHours": [9, 18],
"holidays": ["2026-01-01", "2026-01-12"],
"approvalThresholds": [1000000, 5000000],
"backdatedDaysThreshold": 30
}
Si no se pasan approvalThresholds y fiscalYearEnd, las reglas correspondientes no se activan. La decisión es detenerse explícitamente antes que dejar que reglas irrelevantes fallen en vacío y aumenten los falsos positivos.
"Registro en día festivo" excluye por defecto los asientos con fecha de fin de mes. Los asientos de ajuste mensual o de cierre suelen fecharse a fin de mes aunque caiga en sábado o domingo. En años como el ejercicio de marzo de 2024, cuando el 31 de marzo fue domingo, sin esta exclusión todos los ajustes de cierre se marcarían. Para incluir también los fines de mes, se pasa exemptMonthEnd: false.
"Registro en día festivo" detecta automáticamente, además de los sábados y domingos, los días festivos japoneses (incluidos los de compensación y los días de descanso nacional, de 2000 a 2099). Los festivos no se importan de la lista de la Oficina del Gabinete, sino que se calculan a partir de la Ley de Días Festivos. Se ha verificado que coinciden con la lista oficial para todos los días de 2000 a 2027. Los días no laborables propios de la empresa, como las vacaciones de Año Nuevo, se añaden con holidays. Para libros de fuera de Japón, se pasa japaneseHolidays: false.
"Asientos duplicados" y "combinaciones de cuentas poco habituales" comparan las cuentas de debe y haber después de ordenarlas. El orden de las líneas del detalle no afecta al resultado.
"Entrada después del cierre" detecta asientos con fecha anterior o igual al cierre pero registrados después de este. Aquí se concentran los ajustes de cierre y las correcciones posteriores. "Desfase entre fecha de registro y fecha de entrada" solo detecta por defecto retrasos superiores a 30 días, así que un retraso corto como registrar un asiento del 31 de marzo el 10 de abril lo detecta esta regla. Solo se activa cuando están disponibles fiscalYearEnd y entered_at.
"Anulación o corrección" busca pares de asientos con el mismo importe y debe/haber invertidos dentro de un plazo de 30 días (reversalWindowDays) y los devuelve con el número de comprobante de la contraparte. Cada asiento solo puede aparecer en un par. Si el par cruza el cierre del ejercicio, se indica en el motivo, pero no se aumenta la importancia, porque los asientos de reinicio al inicio del ejercicio tienen la misma forma.
Las palabras clave por defecto de "palabras clave en la descripción" son "修正", "訂正", "取消", "調整", "仮計上" e "不明". Se pueden sustituir con descriptionKeywords; si se pasa un array vacío, la regla se detiene. El carácter "仮" por sí solo no está incluido por defecto porque detectaría demasiados casos como pagos anticipados.
"Números de comprobante faltantes" separa el número en prefijo y dígitos finales (JV-0382 → JV- y 382) y busca saltos en la secuencia para cada prefijo. Como lo que falta es el propio asiento, no se añade a la puntuación de los asientos vecinos, sino que se devuelve como lista de números faltantes. Los números en los que falta más de la mitad del rango se consideran no secuenciales y se ignoran. Tampoco se consideran los asientos sin número de comprobante.
Sobre el análisis de Benford
Los límites de decisión del MAD utilizan los valores de la Tabla 5.1 de Nigrini, M. J. Benford's Law (Wiley, 2012). Son valores ampliamente citados en la práctica, pero no están establecidos por ley ni por normas de auditoría.
Si la muestra es inferior a 300 registros, se añade una nota al resultado, porque estos límites presuponen muestras grandes.
Además, Benford es una herramienta para observar propiedades de la población, no para juzgar asientos individuales. Aunque la distribución se desvíe, suele explicarse por la naturaleza del negocio (precios fijos, tarifas reguladas, sectores con muchas operaciones pequeñas).
Limitaciones de esta herramienta
La detección no es prueba de fraude. Todas las reglas detectan también muchas operaciones legítimas. La mayoría de los duplicados son registros periódicos mensuales del mismo importe, y los grandes importes a fin de ejercicio son normales en negocios que facturan al cierre.
Lo único que hace esta herramienta es decidir por dónde empezar a revisar la población. Evaluar los asientos detectados sigue siendo trabajo humano.
Esto es lo que esta herramienta no puede hacer:
- Sustituir los procedimientos de auditoría en sí (no proporciona evidencia de auditoría suficiente y adecuada)
- Concluir sobre la existencia o no de fraude
- Juzgar la validez sustantiva de las cuentas
- Determinar el tratamiento fiscal
No puede utilizarse como base para formar una opinión de auditoría ni para una declaración fiscal.
Tratamiento de datos reales
examples/ contiene datos sintéticos. Se generan con una semilla fija, por lo que node examples/generate.js produce siempre los mismos archivos.
.gitignore excluye *.csv, *.xlsx, journals.json y /data/. Es una salvaguarda para no commitear datos reales de asientos.
El servidor no sale a la red. Solo lee de stdin y de los archivos .json y .csv dentro de las carpetas permitidas con --data-dir al arrancar. Solo escribe en stdout; no escribe en archivos.
Pruebas
npm test
Se ejecutan 107 pruebas. Las del servidor MCP se escriben lanzándolo como proceso hijo y enviándole JSON-RPC real.
El CI se ejecuta con Node 20 / 22 / 24. Además de las pruebas, comprueba que no se han añadido dependencias, que no se ha generado package-lock.json y que los datos de ejemplo con semilla fija siguen coincidiendo al regenerarlos. Cero dependencias es una premisa de este repositorio, así que se protege con CI y no con atención humana.
Artículo explicativo
El proceso de creación y las decisiones de diseño de este servidor están documentados en un artículo.
Licencia
MIT
Autor
Hoshino Ushio (contador público certificado e impuestos)