SooTool
Servidor de cálculo determinista solo con decimales para uso de herramientas LLM
Documentación
SooTool
MCP de cálculo de precisión para uso de herramientas por LLM.
Servidor MCP que se encarga de los cálculos en lugar del LLM. Realiza con precisión Decimal cálculos de impuestos, nóminas, finanzas, estadística e ingeniería, y devuelve junto con ellos la base del cálculo. Ofrece 276 herramientas básicas en 18 dominios de cálculo + 10 herramientas de políticas administrativas, hasta 500 cálculos paralelos a la vez (core.batch), cálculos encadenados por pasos (core.pipeline) y 4 tipos de transporte (stdio/Streamable HTTP/Unix, SSE en desuso). Python 3.12 o superior.
Por qué es necesario
Los LLM no calculan números, generan números plausibles. Por eso fallan a menudo en los límites de los tramos impositivos progresivos, la dirección del redondeo y las tasas impositivas anuales. A continuación se muestra el resultado de resolver los mismos 20 problemas (medido el 24 de abril de 2026).
| Sujeto que resuelve | Correcto (exacto) | Aproximado (error ≤ 0,01 %) | Incorrecto |
|---|---|---|---|
| SooTool | 20 | 0 | 0 |
| gemini-3-pro-preview | 12 | 4 | 4 |
| claude-opus-4-7 | 9 | 3 | 8 |
| gpt-5.4 | 5 | 3 | 12 |
Los puntos de fallo son similares aunque cambie el modelo: límites de tramos del impuesto sobre la renta, deducción especial por tenencia a largo plazo en el impuesto sobre ganancias de capital, redondeo del IVA y precisión de la impedancia de corriente alterna. La composición de los problemas y los datos originales están en bench/.
SooTool fija estos cálculos con tres mecanismos.
- Cálculo exclusivo con Decimal. Los números de entrada se reciben como cadena o Decimal. Los errores de coma flotante no se cuelan en el cálculo.
- Externalización de los valores legales. Las tasas impositivas, deducciones y primas de seguros se guardan en archivos de políticas (YAML) con el artículo legal de referencia y la fecha de entrada en vigor. Si se indica un momento (
as_of), se calcula con los valores vigentes en esa fecha. - Devolución de la base del cálculo. Toda respuesta incluye un
tracecon la fórmula, las entradas, los valores intermedios y el resultado, además de un recibo de verificación de reejecución (_meta.integrity).
Estructura
LLM 에이전트 / CLI / 파이썬 코드
│
│ MCP(stdio, HTTP, Unix) sootool call ... from sootool.sdk import tax
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│ 경계 검사 인자 이름·타입·크기 검증, 숫자 문자열 → Decimal, 인증 범위 확인 │
├──────────────────────────────────────────────────────────────────────────────┤
│ 레지스트리 도구 286개를 이름으로 찾아 실행 (core.batch / core.pipeline 포함) │
├───────────────────────────────┬──────────────────────────────────────────────┤
│ 도메인 도구 │ 정책 로더 │
│ tax · payroll · finance · │ policies/<도메인>/<이름>_<연도>.yaml │
│ realestate · stats · ... │ 해시 검증 → as_of 시점의 시행 버전 선택 │
└───────────────────────────────┴──────────────────────────────────────────────┘
│
▼
{ 결과 필드, trace(공식·입력·단계·출력), 정책 출처와 근거 조문, _meta.integrity(영수증) }
Los tres puntos de entrada (MCP, CLI, SDK) pasan por el mismo registro. Con la misma entrada, el resultado y el recibo son idénticos sea cual sea la vía utilizada.
Inicio rápido
Instalación
pip install sootool # 기호 계산(symbolic.*)까지 쓰려면 pip install "sootool[symbolic]"
Registro en Claude Code
claude mcp add --scope user sootool -- uvx sootool
Para descargar el repositorio y ejecutar el código en desarrollo, regístralo de la siguiente manera.
git clone https://github.com/JinHo-von-Choi/SooTool.git
cd SooTool && uv sync
claude mcp add --scope user sootool -- uv run --directory "$PWD" python -m sootool
Primer cálculo
En un cliente MCP, si preguntas «¿cuál es el impuesto sobre la renta de 2026 para una base imponible de 50 millones de wones?», el agente llamará a tax.kr_income. También puedes ejecutar la misma herramienta directamente desde la terminal.
sootool call tax.kr_income --arg taxable_income=50000000 --arg year=2026 --format raw
{
"tax": "6240000",
"effective_rate": "0.12480000",
"marginal_rate": "0.15",
"breakdown": [ ... 구간별 과세표준과 세액 ... ],
"policy_effective_date": "2026-01-01",
"policy_citations": [{"law": "소득세법", "article": "제55조제1항", "url": "https://www.law.go.kr/법령/소득세법/제55조"}]
}
Cómo leer la respuesta
finance.npv(rate="0.08", cashflows=["-1000","300","400","500","200"], rounding="HALF_EVEN", decimals=2) es una respuesta real.
{
"npv": "164.64",
"trace": {
"tool": "finance.npv",
"formula": "NPV = sum(CF_t / (1+r)^t, t=0..n)",
"inputs": {"rate": "0.08", "cashflows": ["-1000", "300", "400", "500", "200"], "rounding": "HALF_EVEN", "decimals": 2},
"steps": [{"label": "npv_raw", "value": "164.63539696786661172171511042618089308126395968697"}],
"output": "164.64"
},
"_meta": {
"integrity": {
"tool": "finance.npv",
"input_hash": "00da5199...",
"result_hash": "d7a0ecfe...",
"tool_version": "1.0.0",
"sootool_version": "0.2.0"
},
"engine": "decimal"
}
}
| Campo | Significado |
|---|---|
Campos de resultado como npv | Resultado del cálculo. Todos los números son cadenas. |
trace.steps | Cálculo intermedio, incluido el valor antes del redondeo. Sirve para que una persona pueda comprobar el resultado. |
policy_* | Solo aparece en las herramientas de políticas. Fecha de entrada en vigor, estado, artículo legal de referencia y hash del archivo de políticas aplicado. |
_meta.integrity | Recibo. Es el hash de la entrada y del resultado, por lo que se puede volver a ejecutar el mismo cálculo con sootool receipt verify para comparar. |
_meta.engine | Motor de cálculo. decimal (exacto), mpmath (con dígitos especificados), float64 (aproximado), composite, none. |
_meta.hints | Sugerencia de herramientas que podrían usarse a continuación. No afecta al valor del resultado. |
Funciones principales
El redondeo lo elige quien llama
Las herramientas financieras y contables donde la práctica de redondeo varía según el contexto (IVA, flujo de caja, depreciación, cambio de divisa, etc.) aceptan rounding (HALF_EVEN, HALF_UP, DOWN, UP, FLOOR, CEIL) y decimals. El cálculo inverso del IVA usa truncamiento a la unidad (DOWN), la contabilidad general usa HALF_EVEN: cada uso tiene su propia regla. Cuando la ley fija el tratamiento de los decimales (por ejemplo, el impuesto local se trunca por debajo de 10 wones), se sigue esa regla y se indica en la descripción de la herramienta.
Cálculo de políticas con fecha indicada
Las leyes fiscales y las primas de seguros cambian incluso a mitad de año. Las herramientas de políticas aceptan, además de year, as_of (AAAA-MM-DD) y include_proposed.
policies/payroll/kr_4insurance_2026.yaml 2026-01-01 ~ 2026-06-30
policies/payroll/kr_4insurance_2026@2026-07-01.yaml 2026-07-01 ~ 2026-10-31 ◀── as_of="2026-08-15"
policies/payroll/kr_4insurance_2026@2026-11-01.yaml 2026-11-01 ~ 2026-12-31
as_of가 속한 버전으로 계산하고, 응답에 그 버전의 시행일과 근거 조문을 싣는다.
Si no se indica as_of, se usa la versión definitiva de ese año con la fecha de entrada en vigor más tardía. Las enmiendas aún no aprobadas por la Asamblea Nacional (status: proposed) solo se usan cuando include_proposed=true. El procedimiento para modificar los archivos de políticas sin redistribuir el servidor está en docs/policy_management.md.
Varios elementos a la vez: batch y pipeline
core.batch 독립 계산 N건을 병렬로 core.pipeline 앞 단계 결과를 다음 단계 입력으로
┌ s1: finance.npv(rate=0.05) ┐ annual = core.mul(3000000, 12)
├ s2: finance.npv(rate=0.08) ┼─▶ id 순서로 결과 │ ${annual.result.result}
└ s3: finance.npv(rate=0.10) ┘ ▼
tax = tax.kr_income(annual, 2026)
최대 500건, 항목당 10초, 전체 60초 최대 50단계, 깊이 10, 단계당 2초, 전체 30초
core.batch registra por separado el éxito, el error y el tiempo de espera de cada elemento y devuelve los resultados en el orden de entrada. core.pipeline marca los pasos posteriores como skipped si un paso anterior falla, e incluye core.pipeline_resume (conservado 10 minutos) para reanudar desde el punto de fallo.
{
"name": "core.pipeline",
"arguments": {
"steps": [
{"id": "annual", "tool": "core.mul", "args": {"operands": ["3000000", "12"]}},
{"id": "tax", "tool": "tax.kr_income", "args": {"taxable_income": "${annual.result.result}", "year": 2026}}
]
}
}
En la práctica se usa así.
| Tarea | Volumen | Combinación |
|---|---|---|
| Cierre de nómina | 500 empleados | core.batch + payroll.kr_salary |
| Sensibilidad de inversión | 9 tasas de descuento × 5 escenarios de flujo de caja | core.batch + finance.npv, finance.irr |
| Separación del IVA en extractos de transacciones | Cientos de casos | core.batch + accounting.vat_extract |
| Del salario bruto al neto recibido | 4 pasos | core.pipeline |
Cálculo inverso, comparación y explicación
core.solve_for: encuentra el valor de entrada que produce el resultado objetivo. Ejemplo: el salario bruto mensual que da un neto recibido de 3 millones de wones.core.compare: presenta en una tabla los valores y diferencias de cada escenario frente al caso base.core.explain: explica el proceso de cálculo y las políticas aplicadas en frases en coreano o inglés. No cambia las cifras.
Verificación de reejecución con recibo
sootool receipt verify --tool finance.fv \
--arguments '{"present_value":"1000","rate":"0.05","periods":10}' \
--receipt receipt.json
Vuelve a ejecutar la misma herramienta y compara el nombre de la herramienta, el hash de entrada, el hash de resultado, la versión de la herramienta y el hash de políticas. Si se especifica un archivo de clave privada ed25519 en SOOTOOL_RECEIPT_KEY_FILE, el recibo lleva firma.
Catálogo de herramientas (276 básicas + 10 admin, 18 dominios de cálculo + herramientas operativas)
| Namespace | N.º | Herramientas representativas |
|---|---|---|
| core | 11 | add, sub, mul, div, calc (fórmula), batch, pipeline, pipeline_resume, solve_for, compare, explain |
| accounting | 12 | vat_extract, vat_add, balance, 3 de depreciación, 2 de dupont, ratios, income_statement, cashflow_operating, break_even |
| finance | 18 | pv, fv, npv, irr, roi, cagr, payback_period, loan_schedule, bond_ytm, bond_duration, black_scholes, 2 de var, sharpe, sortino |
| tax | 17 | kr_income, kr_comprehensive_income_tax, kr_withholding_simple, capital_gains_kr, kr_gift, kr_inheritance, kr_corporate, kr_eitc, 3 de impuesto local adicional |
| tax_us | 4 | federal_income, capital_gains, state_tax, fica |
| payroll | 15 | kr_salary, kr_gross_from_net, kr_severance_pay, kr_year_end_tax_settlement, kr_overtime_pay, kr_minimum_wage_check, 4 de deducciones |
| realestate | 10 | kr_acquisition_tax, kr_transfer_tax, kr_property_tax, kr_comprehensive, kr_ltv, kr_dti, kr_dsr, kr_subscription_score |
| stats | 14 | descriptive, 3 de prueba t, anova_oneway, regression_linear, ci_mean, bootstrap_ci, pruebas no paramétricas |
| probability | 30 | pdf, cdf y ppf de las distribuciones normal, binomial, Poisson, gamma, beta, exponencial, lognormal, chi-cuadrado y F; bayes, nCr, nPr |
| datetime | 14 | cálculo de días hábiles, day_count, age, diff, tz_convert, conversión de calendario lunar, 24 términos solares, año fiscal, período impositivo del impuesto sobre la renta |
| math | 10 | 2 de integración numérica, 2 de diferenciación numérica, 2 de interpolación, polynomial_roots, polynomial_horner, fft, ifft |
| geometry | 15 | 7 de área y volumen, 3 de vectores, 4 de matrices, haversine |
| engineering | 56 | circuitos eléctricos y de CA, fluidos, transferencia de calor, mecánica de materiales, control, fiabilidad, conversión de prefijos SI |
| units | 8 | convert, fx_convert, fx_triangulate, temperature, conversión de energía, presión, tamaño de datos y tiempo |
| medical | 12 | bmi, bsa, egfr, dose_weight_based, pregnancy_weeks, cha2ds2_vasc, has_bled, framingham_cvd_10y, 4 de QTc |
| science | 11 | half_life, ideal_gas, molar_mass, stoichiometry, nernst, snell_law, thin_lens, bragg y otros |
| crypto | 10 | gcd, lcm, egcd, modinv, modpow, crt, is_prime, euler_totient, carmichael_lambda, hash |
| pm | 5 | critical_path, pert, evm, earned_schedule, monte_carlo_schedule |
| symbolic | 2 | solve, diff (si sootool[symbolic] está instalado) |
| sootool | 2+10 | skill_guide, verify_receipt, 10 de gestión de políticas (4 de escritura solo en modo administrador) |
La versión, el grado de precisión y la descripción de cada herramienta están en docs/tool_catalog.md. Este archivo se genera automáticamente desde el registro.
Ejecución del servidor
sootool # stdio (MCP 클라이언트 기본)
sootool --transport http --http-port 10535 # Streamable HTTP
sootool --transport unix --socket /tmp/sootool.sock # Unix 소켓
sootool --transport stdio,http --socket /tmp/sootool.sock # 여러 전송 동시 기동
| Transporte | Uso | Notas |
|---|---|---|
| stdio | Clientes locales como Claude Code, Claude Desktop, etc. | Valor predeterminado |
| http | Acceso remoto (Streamable HTTP) | Sin estado, por lo que puede colocarse detrás de un balanceador de carga. Puerto predeterminado 10535 |
| unix | Otros procesos del mismo host | El acceso se controla con los permisos del archivo de socket (0600 por defecto) |
| sse-legacy | Compatibilidad con clientes MCP 2024-11 | En desuso. Solo se activa con --enable-sse-legacy. Puerto predeterminado 10536 |
Las reglas de seguridad para el transporte de red son las siguientes.
- El enlace predeterminado es
127.0.0.1. Para abrirlo al exterior con--host 0.0.0.0se necesita--auth-token(oSOOTOOL_AUTH_TOKEN) para arrancar. - Las 4 herramientas de escritura que modifican políticas solo se exponen en stdio y sockets Unix. Para usarlas por red se necesitan todos los elementos de
--admin --remote-admin --admin-token <토큰>, y solo las solicitudes autenticadas con el token de administrador pueden realizar escrituras.
Perfiles de exposición
sootool --profile full # 기본값. 도구 286개를 모두 노출
sootool --profile lean # sootool.search, describe, call, skill_guide 4개만 노출
lean no carga todas las definiciones de herramientas en el contexto. El agente busca herramientas con sootool.search, comprueba los argumentos con sootool.describe y luego ejecuta con sootool.call. El resultado y el recibo son idénticos a los de una llamada directa. sootool.call solo ejecuta herramientas de solo lectura.
Línea de comandos
Si se da un subcomando, se ejecuta la herramienta directamente sin levantar el servidor.
sootool call core.add --arg 'operands=["1.5","2.5"]'
sootool call finance.npv --arg-json '{"rate":"0.1","cashflows":["-100","50","60","70"]}'
sootool call payroll.kr_gross_from_net --arg net_monthly=3000000 --arg year=2026 --format raw
sootool tools list --search 양도세 # 줄임말과 일상 표현으로 검색
sootool tools describe tax.kr_income # 인자와 정책 인자 확인
sootool batch -f items.json # -f - 는 표준입력
sootool policy show --arg domain=tax --arg name=kr_income --arg year=2026
sootool skill-guide --section triggers
sootool version
| Elemento | Contenido |
|---|---|
| Argumentos | Repite --arg 이름=값 o pásalos de una vez con --arg-json. Los argumentos de cadena se usan tal cual; los enteros, booleanos, listas y objetos se leen como JSON. |
| Formato de salida | --format pretty (predeterminado), json (completo), raw (sin trace ni _meta), trace |
| Destino de salida | El resultado va a la salida estándar y los errores a la salida de error, en JSON. |
| Código de salida | 0 éxito, 1 error de herramienta, 2 error de entrada, 3 requiere modo administrador (SOOTOOL_ADMIN_MODE=1), 70 error interno |
Uso como biblioteca de Python
Se llaman las mismas herramientas como funciones sin servidor MCP. El resultado, el recibo y el procesamiento de as_of son iguales que en MCP, y los tipos de resultado están declarados, por lo que el verificador de tipos comprueba los campos.
from sootool.sdk import tax
out = tax.kr_income(taxable_income=50_000_000, year=2026)
out["tax"] # "6240000"
out["_meta"]["integrity"]["input_hash"] # 재실행 검증용 영수증
Para configuraciones donde el agente ejecuta Python en un sandbox, consulta docs/sdk.md.
Indicar al agente las reglas de uso
Aunque se registren las herramientas, el agente a veces calcula mentalmente. Añade la regla «los cálculos numéricos los hace SooTool» con una de las siguientes opciones.
- Haz que llame a
sootool.skill_guideal inicio de la sesión. Devuelve una tabla de disparadores que indica cuándo usar cada herramienta, ejemplos, patrones prohibidos y un manual (section:triggers,examples,anti_patterns,playbooks,all/lang:ko,en). - Reglas para pegar en el archivo de configuración del cliente: Claude Code, Cursor, AGENTS.md
Documentación
| Documento | Contenido |
|---|---|
| Guía de usuario | Resumen de herramientas por dominio, argumentos comunes y reglas de respuesta |
| Catálogo de herramientas | Versión, grado de precisión y descripción de las 286 herramientas |
| Gestión de políticas | Estructura de los archivos de políticas, selección de fecha, procedimientos de actualización y reversión, registro de auditoría |
| SDK | Uso de la biblioteca de Python y configuración del sandbox |
| Paquetes de políticas externos | Creación, verificación e instalación de paquetes de políticas firmados |
| Contrato de estabilidad | Alcance de la compatibilidad garantizada y procedimiento de retirada |
| Libro de recetas | Ejemplos de llamadas por escenario: fiscalidad, finanzas e ingeniería eléctrica |
| Registro de decisiones de arquitectura | Decisiones de diseño y su justificación (ADR) |
| Procedimiento de publicación | Desde el aumento de versión hasta la publicación en PyPI |
Desarrollo
uv sync --extra symbolic
make test # pytest와 커버리지
make lint # ruff
make typecheck # mypy
uv run python scripts/mcp_smoke_test.py # stdio 연결 점검 (http, sse, unix 스크립트도 있다)
Para añadir una herramienta nueva, crea una función en src/sootool/modules/<도메인>/, añade @REGISTRY.tool(namespace, name, description, version) y cárgala desde el dominio __init__.py: quedará registrada. Si cambias la descripción o los tipos de una herramienta, regenera los documentos con scripts/gen_tool_catalog.py y scripts/gen_sdk_stubs.py. Si modificas un archivo de políticas, actualiza el hash con scripts/policy_stamp.py.
Licencia
MIT. Consulta LICENSE.