Labsco
JinHo-von-Choi logo

SooTool

โ˜… 3

from JinHo-von-Choi

Precision Calc MCP: Decimal-only deterministic calculation server for LLM tool use

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeQuick setup

SooTool logo

SooTool

Precision Calc MCP for LLM tool use.

LLM์ด ํ™•๋ฅ  ์ถ”๋ก ์œผ๋กœ ์‚ฐ์ˆ˜๋ฅผ ํ‹€๋ฆฌ๋Š” ๊ตฌ์กฐ์  ํ•œ๊ณ„๋ฅผ ์ฐจ๋‹จํ•˜๊ณ , ๊ทธ ํ‹€๋ฆฌ๋Š” ์ž‘์—…์„ ํ•œ ๋ฒˆ์— 500๊ฑด๊นŒ์ง€ ๊ฒฐ์ •์  ๋ณ‘๋ ฌ๋กœ ๋Œ๋ ค ์‹ค๋ฌด์— ํˆฌ์ž…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ์ •๋ฐ€ ๊ณ„์‚ฐ MCP ์„œ๋ฒ„. Python 3.12 ยท Decimal ์ „์šฉ ์ปค๋„ ยท 18๊ฐœ ๊ณ„์‚ฐ ๋„๋ฉ”์ธ 254๊ฐœ ๊ธฐ๋ณธ ๋„๊ตฌ + 10๊ฐœ admin ์ •์ฑ… ๋„๊ตฌ ยท core.batch 500 items ๋ณ‘๋ ฌ ยท core.pipeline DAG ์ฒด์ธ ยท ๊ฐ์‚ฌ ํŠธ๋ ˆ์ด์Šค ยท ์ •์ฑ… YAML ์™ธ๋ถ€ํ™” ยท 5์ข… ์ „์†ก(stdio/HTTP/SSE/WebSocket/Unix).

์™œ ํ•„์š”ํ•œ๊ฐ€

LLM์€ ์ˆซ์ž๋ฅผ ํ† ํฐ ์‹œํ€€์Šค๋กœ ์ƒ์„ฑํ•œ๋‹ค. ๋ถ€๊ฐ€์„ธ ์—ญ์‚ฐ, ๋ณต๋ฆฌ ์ด์ž, ๋ˆ„์ง„์„ธ ๊ตฌ๊ฐ„, ์–‘๋„์†Œ๋“์„ธ ์žฅ๊ธฐ๋ณด์œ ํŠน๋ณ„๊ณต์ œ, ์ดํ•ญ๋ถ„ํฌ CDF ๊ฐ™์€ ์‹ค๋ฌด ๊ณ„์‚ฐ์—์„œ ๋ฐ˜์˜ฌ๋ฆผ ๋ฐฉํ–ฅยท๊ตฌ๊ฐ„ ๊ฒฝ๊ณ„ยท์ •์ฑ… ํ•ด์„์ด ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ์–ด๊ธ‹๋‚œ๋‹ค. ๊ฒ€์ฆ ์—†์ด LLM ์‚ฐ์ถœ์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์„ธ๋ฌด ์‹ ๊ณ ยท์žฌ๋ฌด ์˜์‚ฌ๊ฒฐ์ •ยท์˜๋ฃŒ ์šฉ๋Ÿ‰ยท๊ณตํ•™ ์„ค๊ณ„์—์„œ ์น˜๋ช…์  ์˜ค์ฐจ๊ฐ€ ๋ˆ„์ ๋œ๋‹ค.

๋ฌธ์ œ์˜ ์ธต์œ„๋Š” ๋‘ ๊ฒน์ด๋‹ค. ์ฒซ์งธ, ๋ชจ๋ธ ์ž์ฒด๊ฐ€ ์‚ฐ์ˆ ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ™•๋ฅ  ์ถ”๋ก ์œผ๋กœ ๊ทธ๋Ÿด๋“ฏํ•œ ์ˆซ์ž๋ฅผ ๋‚ด๋†“์„ ๋ฟ์ด๋ผ ํšŒ๊ณ„ยท์„ธ๋ฌดยท์•ฝ์ œ ์šฉ๋Ÿ‰ ํ˜„์žฅ์—์„œ ์ž˜๋ชป๋œ ์ˆ˜์น˜๊ฐ€ ๊ทธ๋Œ€๋กœ ๋ณด๊ณ ์„œยท์ „ํ‘œยท์ฒ˜๋ฐฉ์— ๋‚จ๋Š”๋‹ค. ๊ฒ€์ฆ ์—ฌ๋ ฅ์ด ๋น ๋“ฏํ•œ ์ „๋ฌธ์ง ์‹ค๋ฌด์—์„œ๋Š” ์˜ค์ฐจ ํ•œ ๊ฑด์ด ์‹ ๊ณ  ์˜ค๋ฅ˜ยทํ™˜๋ถˆยท์˜๋ฃŒ ์‚ฌ๊ณ ๋กœ ์ง๊ฒฐ๋œ๋‹ค.

๋‘˜์งธ, ์ตœ์‹  ๋Œ€ํ˜• LLM์€ ๋‚ด๋ถ€์— ๊ณ„์‚ฐ๊ธฐยทPython ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ๋‚ด์žฅํ•˜๊ณ  ์žˆ์ง€๋งŒ ๊ทธ ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ• ์ง€๋Š” ์—ฌ์ „ํžˆ ๋ชจ๋ธ ์žฌ๋Ÿ‰์ด๋‹ค. MCP ๋„๊ตฌ๋„ ๊ฐ™์€ ์ œ์•ฝ์„ ๊ณต์œ ํ•œ๋‹ค. ๊ตฌ์กฐ์  ํ•œ๊ณ„๊ฐ€ ๋‹จ์ผ ๋ฐฉ์–ด๋ง‰ ํ•˜๋‚˜๋กœ๋Š” ๋‹ซํžˆ์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค. SooTool์€ ๋ชจ๋ธ ๋‚ด์žฅ ๋„๊ตฌ์™€ ๋…๋ฆฝ๋œ ๋‘ ๋ฒˆ์งธ ์ธต์˜ MCP ์„œ๋ฒ„๋กœ์„œ ๊ฒฐ์ •์  Decimal ๊ฒฝ๋กœ, ์™ธ๋ถ€ํ™”๋œ ์ •์ฑ… ๋ฐ์ดํ„ฐ, ๊ฐ์‚ฌ ๊ฐ€๋Šฅํ•œ ํŠธ๋ ˆ์ด์Šค๋ฅผ ์ œ๊ณตํ•ด ๋ฐฉ์–ด ๊นŠ์ด๋ฅผ ๋Š˜๋ฆฐ๋‹ค. ํ˜ธ์ถœ ์—ฌ๋ถ€ ์ž์ฒด๋Š” AI ์žฌ๋Ÿ‰์œผ๋กœ ๋‚จ์ง€๋งŒ, ๋ถˆ๋ฆฌ๋ฉด ๊ฒฐ๊ณผ๋Š” ์‚ฐ์ˆ ์ ์œผ๋กœ ์ •ํ™•ํ•˜๋‹ค๋Š” ์ ์ด ๋ณด์ฆ๋œ๋‹ค.

์…‹์งธ, ์‹ค๋ฌด๋Š” ํ•œ ๊ฑด์”ฉ ๋ฌป์ง€ ์•Š๋Š”๋‹ค. ์ง์› 500๋ช… ์›”๊ธ‰ยท4๋Œ€๋ณดํ—˜ยท์†Œ๋“์„ธ ์ผ๊ด„ ์ •์‚ฐ, ๋Œ€์ถœ 50์ข… NPVยทIRRยท๋“€๋ ˆ์ด์…˜ ๋น„๊ต, ๊ฑฐ๋ž˜๋ช…์„ธ์„œ ์ˆ˜์ฒœ ๊ฑด VAT ์—ญ์‚ฐ, ์–‘๋„์„ธ ์‹œ๋‚˜๋ฆฌ์˜ค ์ˆ˜์‹ญ ๊ฐ€์ง€ ๊ต์ฐจ ๊ฒ€์ฆ์€ ํ•œ ๋ฒˆ์˜ LLM ๋Œ€ํ™”๋กœ๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋‹ค. SooTool์€ core.batch๋กœ N๊ฐœ ๋…๋ฆฝ ์—ฐ์‚ฐ์„ ThreadPool ๋ณ‘๋ ฌ ์‹คํ–‰ํ•˜๊ณ  ์ž…๋ ฅ id ์ˆœ์œผ๋กœ ๊ฒฐ์ •์  ์žฌ์ •๋ ฌํ•˜๋ฉฐ, core.pipeline์œผ๋กœ DAG ์˜์กด(์—ฐ๋ด‰โ†’์„ธ์•กโ†’์‹ค์ˆ˜๋ น์•ก) ์ฒด์ธ์„ ํ•œ ์™•๋ณต์— ๋๋‚ธ๋‹ค. LLM์ด ๋„๊ตฌ ํ˜ธ์ถœ ํ•œ ๋ฒˆ ํ•˜๋ฉด ์‹ค๋ฌด ์ˆ˜๋ฐฑ ํ–‰์˜ ๊ฒฐ์ •์  ๊ณ„์‚ฐ์ด ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋œ๋‹ค.

SooTool์€ ๊ทธ ๊ฒฝ๋กœ๋ฅผ ์›์ฒœ ์ฐจ๋‹จํ•œ๋‹ค.

  • Decimal ์ „์šฉ ์ปค๋„. ์ž…๋ ฅ JSON์€ parse_float=Decimal๋กœ ํŒŒ์‹ฑ๋˜์–ด float์ด ๋„๋ฉ”์ธ ๋‚ด๋ถ€๋กœ ์œ ์ž…๋˜์ง€ ๋ชปํ•œ๋‹ค.
  • ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ… 6์ข…(HALF_EVEN ยท HALF_UP ยท DOWN ยท UP ยท FLOOR ยท CEIL)์„ enum์œผ๋กœ ๊ณ ์ •ํ•˜๊ณ  ๋„๊ตฌ ๊ธฐ๋ณธ๊ฐ’์„ ๊ธˆ์ง€ํ•œ๋‹ค. ํ˜ธ์ถœ์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ์„ ํƒํ•œ๋‹ค(ADR-002).
  • ์„ธ๋ฒ•ยท๋ถ€๋™์‚ฐ ๊ทœ์ œ ๋ฐ์ดํ„ฐ๋ฅผ src/sootool/policies/{domain}/{key}_{year}.yaml๋กœ ์™ธ๋ถ€ํ™”ํ•˜๊ณ  SHA-256 ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ + lru_cache๋กœ ๋กœ๋“œํ•œ๋‹ค(ADR-009).
  • ๋ชจ๋“  ์‘๋‹ต์€ trace.{tool, formula, inputs, steps, output} ํ•„๋“œ๋ฅผ ํฌํ•จํ•œ๋‹ค. ๊ณ„์‚ฐ ๊ทผ๊ฑฐ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ง์ ‘ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค(ADR-003).
  • ๊ฒฐ์ •๋ก . ThreadPool ๊ฒฐ๊ณผ๋Š” ์ž…๋ ฅ id ์ˆœ์œผ๋กœ ์žฌ์ •๋ ฌํ•˜๊ณ , ๋น„๊ฒฐ์ • ํ—ˆ์šฉ ์‹œ non_deterministic:true ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ฐ•์ œํ•œ๋‹ค(ADR-011).

๊ฐ์‚ฌ ํŠธ๋ ˆ์ด์Šค ์‹ค๋ฌผ ์ƒ˜ํ”Œ

"์ด ์ˆซ์ž๋Š” ์–ด๋–ป๊ฒŒ ๋‚˜์™”๋Š”๊ฐ€"์— ์ฆ‰๋‹ตํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ๋„๊ตฌ๋Š” trace ํ•„๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์•„๋ž˜๋Š” finance.npv(rate=0.08, cashflows=[-1000, 300, 400, 500, 200], rounding=HALF_EVEN, decimals=2) ์‹ค์ œ ์‘๋‹ต์ด๋‹ค. ๊ณต์‹ยท์ž…๋ ฅยท์ค‘๊ฐ„ ๋‹จ๊ณ„ยท์ถœ๋ ฅ์ด ์›์ž์ ์œผ๋กœ ๊ธฐ๋ก๋œ๋‹ค.

{
  "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": {
    "hints": [],
    "session_stats": {"tool_calls": 1, "unique_tools": 1}
  }
}

์ค‘๊ฐ„ ๋‹จ๊ณ„์˜ npv_raw๋Š” ๋ฐ˜์˜ฌ๋ฆผ ์ด์ „ ์™„์ „ ์ •๋ฐ€ Decimal ๊ฐ’์œผ๋กœ, ๋ฐ˜์˜ฌ๋ฆผ ์ •์ฑ…(HALF_EVEN)์ด ์†Œ์ˆ˜์  2์ž๋ฆฌ(decimals=2)์— ์ ์šฉ๋œ ๊ฒฐ๊ณผ๊ฐ€ output๊ณผ npv ํ•„๋“œ์— ์ผ์น˜ํ•˜๊ฒŒ ๋…ธ์ถœ๋œ๋‹ค. ๊ฐ์‚ฌ ์ถ”์ ์€ trace ํ•„๋“œ๋งŒ ๋ณด๋ฉด ์ถฉ๋ถ„ํ•˜๋ฉฐ, _meta๋Š” ๋ฏธ๋“ค์›จ์–ด ์ฃผ์ž… ์˜์—ญ(ADR-014)์œผ๋กœ ๊ฒฐ๊ณผ ์‹ ๋ขฐ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค(ADR-011).

๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ (2026-04-24)

20 ์ผ€์ด์Šค(ํ•œ๊ตญ ์†Œ๋“์„ธ 8 ยท ๋ถ€๊ฐ€์„ธ 3 ยท ๋ณต๋ฆฌ 2 ยท ํ™•๋ฅ ํ†ต๊ณ„ 3 ยท ๊ณตํ•™ 2 ยท ์–‘๋„์„ธ 2) ร— ๋Œ€ํ˜• LLM ์‹ค์ธก. exact ๋ฌธ์ž์—ด ์ผ์น˜, approx ์ƒ๋Œ€์˜ค์ฐจ โ‰ค 0.01%, wrong ๊ทธ ์™ธ.

ํ‘œ์ค€ ๋ชจ๋ธ

ProviderModelExactApproxWrong์ •ํ™•์œจ
SooToolDecimal ์ปค๋„2000100%
Googlegemini-2.5-pro133465%
Anthropicclaude-sonnet-4-5331315%
OpenAIgpt-4o241410%

ํ˜„์กด ์ตœ๊ณ  ๋ชจ๋ธ (SOTA)

ProviderModelExactApproxWrong์ •ํ™•์œจ
SooToolDecimal ์ปค๋„2000100%
Googlegemini-3-pro-preview124460%
Anthropicclaude-opus-4-793845%
OpenAIgpt-5.4531225%

๋ชจ๋ธ์„ ์ตœ์‹  SOTA๋กœ ์˜ฌ๋ ค๋„ ์–ด๋А LLM๋„ 20/20์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ•œ๋‹ค. Claude 3โ†’9 (3๋ฐฐ ๊ฐœ์„ ), OpenAI 2โ†’5 (2.5๋ฐฐ), Gemini๋Š” ๋ณดํ•ฉ. ๊ณตํ†ต ์‹คํŒจ ์ง€์ ์€ ๋ˆ„์ง„์„ธ ๊ตฌ๊ฐ„ ๊ฒฝ๊ณ„, ์–‘๋„์†Œ๋“์„ธ ์žฅ๊ธฐ๋ณด์œ ํŠน๋ณ„๊ณต์ œ(์‹ค์„ธ์•ก 8% ์ด์ƒ ์˜ค์ฐจ), ๋ถ€๊ฐ€์„ธ HALF_EVEN ๋ฐ˜์˜ฌ๋ฆผ, AC ์ž„ํ”ผ๋˜์Šค ์ •๋ฐ€๋„๋‹ค. ๋ชจ๋ธ ๋ฐœ์ „๋งŒ์œผ๋กœ ๋‹ซํžˆ์ง€ ์•Š๋Š” ๊ตฌ์กฐ์  ํ•œ๊ณ„๋ฅผ SooTool์ด Decimal + ์ •์ฑ… YAML + ๋ช…์‹œ์  rounding enum ์„ธ ์ธต์œ„๋กœ ๋ฉ”์šด๋‹ค. ์ƒ์„ธ: bench/results/2026-04-24-final.md (ํ‘œ์ค€), bench/results/2026-04-24-sota.md (SOTA).

์„ค์น˜

cd SooTool
uv sync

์‹คํ–‰

๊ธฐ๋ณธ(stdio, MCP ํด๋ผ์ด์–ธํŠธ ์—ฐ๋™):

uv run python -m sootool

์ „์†ก๋ณ„ ๋‹จ์ผ ๊ธฐ๋™:

uv run python -m sootool --transport http      --port 10535
uv run python -m sootool --transport sse-legacy --port 10536
uv run python -m sootool --transport websocket --port 10537
uv run python -m sootool --transport unix      --socket /tmp/sootool.sock

๋‹ค์ค‘ ์ „์†ก ๋™์‹œ ๊ธฐ๋™:

uv run python -m sootool --transports stdio,http,websocket

๊ธฐ๋ณธ ๋ฐ”์ธ๋”ฉ์€ 127.0.0.1. ์™ธ๋ถ€ ๋…ธ์ถœ์€ --host 0.0.0.0 + Bearer ํ† ํฐ์ด ์˜๋ฌด๋‹ค(ADR-014).

Claude Code ์—ฐ๋™

user-scope๋กœ ๊ธ€๋กœ๋ฒŒ ๋“ฑ๋ก (๊ถŒ์žฅ, ์–ด๋А ๋””๋ ‰ํ† ๋ฆฌ์—์„œ๋“  ํ˜ธ์ถœ ๊ฐ€๋Šฅ):

claude mcp add --scope user sootool -- uv run --directory /path/to/SooTool python -m sootool

๋˜๋Š” ํ”„๋กœ์ ํŠธ ์Šค์ฝ”ํ”„๋กœ SooTool ์ €์žฅ์†Œ ๋‚ด์—์„œ๋งŒ:

cd SooTool
claude mcp add sootool -- uv run python -m sootool

๋„๊ตฌ ์นดํƒˆ๋กœ๊ทธ (254๊ฐœ ๊ธฐ๋ณธ + 10๊ฐœ admin, 18 ๊ณ„์‚ฐ ๋„๋ฉ”์ธ + sootool ์šด์˜ ๋„๊ตฌ)

NamespaceCount๋Œ€ํ‘œ ๋„๊ตฌ
core8add, sub, mul, div, calc, batch, pipeline, pipeline_resume
accounting11vat_extract, vat_add, balance, depreciation 3์ข…, interest_compound ์™ธ
finance15pv, fv, npv, irr, loan_schedule, bond_ytm, bond_duration, black_scholes, var_parametric, sharpe ์™ธ
tax10progressive, kr_income, kr_withholding_simple, capital_gains_kr, kr_local_income_tax, kr_education_tax_add, kr_rural_special_tax ์™ธ
realestate8kr_ltv, kr_dti, kr_dsr, kr_acquisition_tax, kr_transfer_tax, rental_yield ์™ธ
stats14descriptive, ttest 3์ข…, chi_square_independence, ci_mean, regression_linear, anova, correlation ์™ธ
probability30normal/binomial/poisson, gamma, beta, exponential, lognormal, chi_square, F, bayes, factorial, nCr, nPr, expected_value
datetime14add/count_business_days, day_count, age, diff, tz_convert, solarโ†”lunar, solar_terms, lunar_holiday, fiscal_year, fiscal_quarter, tax_period_kr, payroll_period
math10integrate_simpson, integrate_gauss_legendre, diff_central, diff_five_point, interpolate_linear, interpolate_cubic_spline, polynomial_roots, polynomial_horner, fft, ifft
geometry15areaยทvolume 7์ข…, vector dot/cross/norm, matrix 4์ข…, haversine
engineering56electrical_*, electrical_ac 11์ข…, fluid, thermal, mechanical, structural, control 5์ข…, si_prefix_convert
units8convert (pint), fx_convert, fx_triangulate, temperature, energy_convert, pressure_convert, data_size_convert, time_small_convert
medical12bmi, bsa, dose_weight_based, egfr, pregnancy_weeks, cha2ds2_vasc, has_bled, framingham_cvd_10y, qtc_bazett/fridericia/framingham/hodges
science11half_life, ideal_gas, molar_mass, stoichiometry, nernst, faraday_electrolysis, battery_capacity, snell_law, thin_lens, bragg, intensity
crypto10gcd, lcm, hash, is_prime, modinv, modpow, egcd, crt, euler_totient, carmichael_lambda
pm5critical_path (CPM), evm, pert, earned_schedule, monte_carlo_schedule
payroll5kr_net_monthly, kr_severance_pay, kr_year_end_tax_settlement, kr_bonus_tax, hourly_to_monthly_net
sootool1+10skill_guide (ํ•ญ์‹œ) + policy_mgmt 10์ข… (admin ๋ชจ๋“œ)

์ „์ฒด ๋„๊ตฌ ์‚ฌ์–‘์€ docs/user_guide.md ๋ฐ sootool.skill_guide MCP ํ˜ธ์ถœ๋กœ ์กฐํšŒํ•œ๋‹ค.

์‹ค์ „ ์˜ˆ์‹œ

์„ธ๋ฌด ์ฒด์ธ ํŒŒ์ดํ”„๋ผ์ธ. ์›”๊ธ‰ 3,000,000์›์„ ์—ฐ์†Œ๋“์œผ๋กœ ํ™˜์‚ฐํ•œ ๋’ค 2026๋…„ ํ•œ๊ตญ ์†Œ๋“์„ธ๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค.

{
  "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}}
    ]
  }
}

์žฌ๋ฌด ์‹œ๋‚˜๋ฆฌ์˜ค ๋น„๊ต ๋ฐฐ์น˜. ๋™์ผ ํ˜„๊ธˆํ๋ฆ„์— ๋Œ€ํ•ด ํ• ์ธ์œจ 3์ข… NPV๋ฅผ ๋™์‹œ ์‚ฐ์ถœํ•œ๋‹ค.

{
  "name": "core.batch",
  "arguments": {
    "items": [
      {"id": "s1", "tool": "finance.npv", "args": {"rate": "0.05", "cashflows": ["-100","30","40","50"], "rounding": "HALF_EVEN", "decimals": 2}},
      {"id": "s2", "tool": "finance.npv", "args": {"rate": "0.08", "cashflows": ["-100","30","40","50"], "rounding": "HALF_EVEN", "decimals": 2}},
      {"id": "s3", "tool": "finance.npv", "args": {"rate": "0.10", "cashflows": ["-100","30","40","50"], "rounding": "HALF_EVEN", "decimals": 2}}
    ]
  }
}

๊ณตํ•™ ๋ ˆ์ด๋†€์ฆˆ ์ˆ˜. ๋ฐ€๋„ยท์†๋„ยทํŠน์„ฑ๊ธธ์ดยท์ ์„ฑ์œผ๋กœ ์ธต๋ฅ˜/์ „์ด/๋‚œ๋ฅ˜ ์˜์—ญ์„ ํŒ์ •ํ•˜๊ณ  trace์— ๊ณต์‹์„ ๋‚จ๊ธด๋‹ค.

{
  "name": "engineering.fluid_reynolds",
  "arguments": {"density": "1000", "velocity": "2", "length": "0.05", "viscosity": "0.001"}
}

ํ†ต๊ณ„ ํšŒ๊ท€ + ์‹ ๋ขฐ๊ตฌ๊ฐ„ ๋ฐฐ์น˜. ๋‹จ์ผ ์™•๋ณต์œผ๋กœ ์„ ํ˜•ํšŒ๊ท€ ๊ณ„์ˆ˜ยทp-value์™€ ํ‰๊ท  95% ์‹ ๋ขฐ๊ตฌ๊ฐ„์„ ๋™์‹œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

{
  "name": "core.batch",
  "arguments": {
    "items": [
      {"id": "reg", "tool": "stats.regression_linear", "args": {"X": [[1],[2],[3],[4]], "y": [2.1, 4.0, 6.2, 8.1]}},
      {"id": "ci",  "tool": "stats.ci_mean",           "args": {"data": [2.1, 4.0, 6.2, 8.1], "confidence": 0.95}}
    ]
  }
}

์‹ค๋ฌด ๋Œ€๋Ÿ‰ ์ฒ˜๋ฆฌ

LLM์ด ํ•œ ๊ฑด์”ฉ ์‚ฐ์ถœํ•˜๋ฉด ์žฌํ˜„์„ฑยท์‹ ๋ขฐ์„ฑ์ด ํ”๋“ค๋ฆฐ๋‹ค. SooTool์€ ํ•œ ํ˜ธ์ถœ๋กœ ์ˆ˜๋ฐฑ ํ–‰์˜ ๊ฒฐ์ •์  ๊ณ„์‚ฐ์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค๊ทœ๋ชจ๋„๊ตฌ ์กฐํ•ฉ๋ฐ˜ํ™˜
๊ธ‰์—ฌ ๋งˆ๊ฐ์ง์› 500๋ช…core.batch + payroll.kr_salaryํ–‰๋ณ„ netยท4๋Œ€๋ณดํ—˜ยท์†Œ๋“์„ธยทtrace
ํˆฌ์ž ๋ฏผ๊ฐ๋„ํ• ์ธ์œจ 9 ร— ํ˜„๊ธˆํ๋ฆ„ 5 = 45 ์ง€์ core.batch + finance.npvยทfinance.irr์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ NPV/IRR ํ‘œ
๊ฑฐ๋ž˜๋ช…์„ธ์„œ VAT ๋ถ„๋ฆฌ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๊ฑดcore.batch + accounting.vat_extract๊ณต๊ธ‰๊ฐ€ ํ•ฉ๊ณ„ยทVAT ํ•ฉ๊ณ„
์ฑ„๊ถŒ ํฌํŠธํด๋ฆฌ์˜ค์ข…๋ชฉ ์ˆ˜์‹ญcore.batch + finance.bond_ytmยทbond_duration์ข…๋ชฉ๋ณ„ ์ˆ˜์ต๋ฅ ยท๋“€๋ ˆ์ด์…˜
์–‘๋„์„ธ ๊ต์ฐจ ๊ฒ€์ฆ๋ณด์œ ๊ธฐ๊ฐ„ 10์ข… ร— ์ทจ๋“ยท์–‘๋„๊ฐ€ ์„ธํŠธcore.batch + tax.capital_gains_kr์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ์‹ค์„ธ์•ก
์„ธ๋ฌด ์ฒด์ธ์›”๊ธ‰โ†’์—ฐ๋ด‰โ†’์†Œ๋“์„ธโ†’์‹ค์ˆ˜๋ น์•ก4 ๋‹จ๊ณ„ core.pipeline๋‹จ์ผ ์™•๋ณต

๊ตฌํ˜„ ์„ธ๋ถ€:

  • core.batch โ€” N๊ฐœ ๋…๋ฆฝ ์—ฐ์‚ฐ์„ ThreadPoolExecutor๋กœ ๋ณ‘๋ ฌ ์‹คํ–‰. id ์ค‘๋ณต ๊ฑฐ๋ถ€, per-item ๊ฒฉ๋ฆฌ(ok|error|timeout|skipped), ์ตœ๋Œ€ 500 items, per-item 10s, batch 60s ์ œํ•œ. ๊ฒฐ๊ณผ๋Š” ์ž…๋ ฅ id ์ˆœ์œผ๋กœ ๊ฒฐ์ •์  ์žฌ์ •๋ ฌ๋œ๋‹ค(ADR-011).
  • core.pipeline โ€” graphlib.TopologicalSorter ๊ธฐ๋ฐ˜ DAG ์‹คํ–‰๊ธฐ. ${step_id.result.field} ์ฐธ์กฐ ๋ฌธ๋ฒ•์œผ๋กœ ๋‹จ๊ณ„ ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ. max_steps=50, max_depth=10, step_timeout_s=2.0, pipeline_timeout_s=30.0(ADR-006).
  • core.pipeline_resume โ€” ์‹คํŒจํ•œ ์Šคํ…์„ TTL 10๋ถ„ in-memory ์บ์‹œ๋กœ๋ถ€ํ„ฐ ๋ถ€๋ถ„ ์žฌ์‹คํ–‰.

์ „์†ก ์ง€์›

Transport์šฉ๋„Flag
stdioClaude CodeยทDesktop ๊ธฐ๋ณธ--transport stdio
httpStreamable HTTP, ๊ถŒ์žฅ ์›๊ฒฉ--transport http
sse-legacy2024-11 ํ”„๋กœํ† ์ฝœ ํ˜ธํ™˜--transport sse-legacy
websocket์ €์ง€์—ฐ ์–‘๋ฐฉํ–ฅ--transport websocket
unix๋กœ์ปฌ ๊ณ ์ฒ˜๋ฆฌ--transport unix --socket PATH
multi๋™์‹œ ๊ธฐ๋™--transports stdio,http,...

๋ชจ๋“  HTTP ๊ณ„์—ด ์ „์†ก์€ Bearer ์ธ์ฆ, Accept-Language ๊ธฐ๋ฐ˜ ๋กœ์ผ€์ผ ๊ฐ์ง€(ko ๊ธฐ๋ณธ), ์ „ ๋„๊ตฌ _meta.hints ์ž๋™ ์ฃผ์ž…, CORS ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ณตํ†ต ๋ฏธ๋“ค์›จ์–ด๋กœ ์ ์šฉํ•œ๋‹ค(ADR-014).

๊ฐœ๋ฐœ

  • ํ…Œ์ŠคํŠธ: make test (pytest 1097๊ฑด, 97% ์ปค๋ฒ„๋ฆฌ์ง€)
  • ๋ฆฐํŠธ: make lint (ruff)
  • ํƒ€์ž…์ฒดํฌ: make typecheck (mypy)
  • ํฌ๋งท: make format
  • ์ „์†ก ์Šค๋ชจํฌ: uv run python scripts/mcp_smoke_{stdio,http,sse,ws,unix}.py

์ƒˆ ๋„๋ฉ”์ธ ๋„๊ตฌ ์ถ”๊ฐ€๋Š” src/sootool/modules/<domain>/<tool>.py์— @REGISTRY.tool(namespace, name, description, version) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ๋„๋ฉ”์ธ __init__.py์—์„œ importํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ์ž๋™ ๋“ฑ๋ก๋œ๋‹ค(ADR-004).

์•„ํ‚คํ…์ฒ˜

์„ค๊ณ„ ๊ฒฐ์ •๊ณผ ๊ทผ๊ฑฐ๋Š” docs/architecture.md ADR-001~017์— ๊ธฐ๋ก๋˜์–ด ์žˆ๋‹ค. ํ•ต์‹ฌ invariant:

  • Decimal-only ๊ฒฝ๊ณ„ ยท ๋ช…์‹œ์  rounding ยท ๊ฐ์‚ฌ ํŠธ๋ ˆ์ด์Šค ยท ๋ชจ๋“ˆ stateless / batch-safe
  • ์ž๋ฃŒํ˜• ์ด์›ํ™”: ํšŒ๊ณ„ยท์„ธ๋ฌดยท๊ธˆ์œต์€ ์ „ ๊ตฌ๊ฐ„ Decimal, ํ†ต๊ณ„ยท๊ธฐํ•˜ยทํ™•๋ฅ ์€ ๋‚ด๋ถ€ float64 + ๊ฒฝ๊ณ„ Decimal ์ง๋ ฌํ™”(ADR-008)
  • ์ •์ฑ… YAML ์™ธ๋ถ€ํ™” + SHA-256 ๋ฌด๊ฒฐ์„ฑ(ADR-009)
  • trace_level noneยทsummaryยทfull + SOOTOOL_MAX_PAYLOAD_KB(๊ธฐ๋ณธ 512KB) ์ดˆ๊ณผ ์‹œ trace.steps tail ์ ˆ๋‹จ(ADR-010)
  • KRWMoney๋Š” Decimal ์ƒ์† ๋Œ€์‹  ํ•ฉ์„ฑ(ADR-013)
  • ๋„๋ฉ”์ธ๋ณ„ *_bulk ๋„๊ตฌ ๊ธˆ์ง€, core.batch ์ผ๋ฐ˜ํ•ด๋กœ ํ†ต์ผ(ADR-006)

์Šคํ‚ฌ ๊ฐ€์ด๋“œ

์—์ด์ „ํŠธ๊ฐ€ ์–ธ์ œ ์–ด๋–ค ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ธฐ์ˆ ํ•œ ํŠธ๋ฆฌ๊ฑฐ ํ…Œ์ด๋ธ”ยท์˜ˆ์‹œยทํ”Œ๋ ˆ์ด๋ถ์€ sootool.skill_guide MCP ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์กฐํšŒํ•œ๋‹ค. ์„น์…˜์€ triggers | examples | anti_patterns | playbooks | all, ์–ธ์–ด๋Š” ko | en.

๋ผ์ด์„ ์Šค

LICENSE ํŒŒ์ผ ์ฐธ์กฐ.