[{"data":1,"prerenderedAt":11053},["ShallowReactive",2],{"content-/journal-api-mcp-tutorial":3,"all-pages-for-dir":11036,"related-/journal-api-mcp-tutorial":11037,"og-image-/journal-api-mcp-tutorial":11052},{"id":4,"title":5,"body":6,"category":11018,"concepts":11018,"description":11019,"extension":11020,"meta":11021,"navigation":299,"ogImage":11018,"path":11022,"project_name":11018,"published":11023,"publishedAt":11024,"seo":11025,"source":11026,"stem":11027,"tags":11028,"todo":11018,"unpublished":11023,"updatedAt":11018,"__hash__":11035},"pages/2026-07/2026-07-14/journal-api-mcp-tutorial.md","自作APIをMCP化するハンズオン。ミニ仕訳帳APIを作り、生のまま使い、包んでから使って比べる",{"type":7,"value":8,"toc":11002},"minimark",[9,13,22,25,28,31,73,76,159,166,169,177,180,183,195,200,203,251,258,274,280,2917,2920,3032,3042,5683,5689,5695,5698,5720,5723,5729,5738,5748,5751,5757,5764,5770,5773,5779,5786,5790,5793,5817,5820,5831,5890,5905,5908,5923,5928,5931,5937,5940,5946,5953,5960,5964,5967,5973,5976,5990,5996,6001,6005,6018,6024,6030,6640,6643,6646,6653,6659,6900,6917,7488,7491,7497,8137,8140,8164,8168,8179,8845,8848,8876,8885,9993,10002,10008,10251,10255,10266,10411,10424,10427,10492,10495,10501,10504,10509,10666,10673,10676,10682,10688,10695,10750,10756,10763,10766,10770,10773,10867,10874,10877,10880,10885,10888,10894,10898,10901,10910,10913,10916,10919,10945,10948,10998],[10,11,5],"h1",{"id":12},"自作apiをmcp化するハンズオンミニ仕訳帳apiを作り生のまま使い包んでから使って比べる",[14,15,16,21],"p",{},[17,18,20],"a",{"href":19},"/freee-mcp-anatomy","前の記事","で、freee公式MCPサーバー「freee-mcp」のソースコードを読んだ。277本のエンドポイントに対してツールは15個、うちAPI呼び出しを担うのは5個の汎用ツールで、残りは認証や事業所切り替えなどの補助だった。OpenAPIスキーマは実行時の門番になり、仕様の知識はAgent Skillsに分離され、コードの大部分は認証とエラー整形と記録の配管だった。読み終えて、方向はわかった。ただ、他人のコードを読んだだけの理解は、自分で書いた理解より一段浅い。",[14,23,24],{},"そこで今回は、同じ構造のミニチュアを自分で作る。仕訳帳のAPIを1本自作し、まず生のままAIエージェントに使わせて、何が起きるかを見る。次にそのAPIをMCPサーバーで包み、同じ依頼をもう一度投げて、何が変わったかを見る。読むだけでは掴みきれなかった「包む」の意味を、手元のターミナルで確かめるハンズオンだ。",[14,26,27],{},"登場するコードは全文この記事に載せた。コマンドと出力はすべて私のPC（Windows 11）での実測値で、「たぶんこうなるはず」の出力は1行もない。所要時間は、コードを写経して動かすだけなら1時間程度、Before/Afterの実験まで再現するなら2時間程度だ。",[14,29,30],{},"前提は次のとおり。",[32,33,34,47,59,70],"ul",{},[35,36,37,38,46],"li",{},"Python 3.11 と ",[17,39,45],{"href":40,"target":41,"rel":42},"https://docs.astral.sh/uv/","_blank",[43,44],"noopener","noreferrer","→ uv（Pythonのパッケージ管理ツール）","。pipでも代替できる",[35,48,49,50,54,55,58],{},"コマンドはGit Bash（またはWSL等のPOSIXシェル）想定で書いてある。PowerShellで写経する場合は ",[51,52,53],"code",{},"export"," を ",[51,56,57],{},"$env:"," に読み替える",[35,60,61,62,65,66,69],{},"MCPクライアント。この記事ではClaude Codeを使う（Claude DesktopなどMCP対応クライアントなら流れは同じ）。インストールとログインは済ませておく。実測に使ったのは 2.1.208 で、実験のモデルを合わせたい場合は ",[51,63,64],{},"claude -p"," に ",[51,67,68],{},"--model"," を付ける",[35,71,72],{},"ライブラリのバージョン: fastapi 0.139.0 / uvicorn 0.51.0 / mcp 1.28.1 / httpx 0.28.1 / pytest 9.1.1",[14,74,75],{},"プロジェクトの準備はこれだけでよい。",[77,78,83],"pre",{"className":79,"code":80,"language":81,"meta":82,"style":82},"language-bash shiki shiki-themes vitesse-light vitesse-light","uv init journal-mcp-tutorial --python 3.11\ncd journal-mcp-tutorial\nuv add fastapi uvicorn httpx \"mcp[cli]\"\nuv add --dev pytest\n","bash","",[51,84,85,109,119,146],{"__ignoreMap":82},[86,87,90,94,98,101,105],"span",{"class":88,"line":89},"line",1,[86,91,93],{"class":92},"senZ8","uv",[86,95,97],{"class":96},"sdGka"," init",[86,99,100],{"class":96}," journal-mcp-tutorial",[86,102,104],{"class":103},"snbK4"," --python",[86,106,108],{"class":107},"sM54T"," 3.11\n",[86,110,112,116],{"class":88,"line":111},2,[86,113,115],{"class":114},"sz8Xr","cd",[86,117,118],{"class":96}," journal-mcp-tutorial\n",[86,120,122,124,127,130,133,136,140,143],{"class":88,"line":121},3,[86,123,93],{"class":92},[86,125,126],{"class":96}," add",[86,128,129],{"class":96}," fastapi",[86,131,132],{"class":96}," uvicorn",[86,134,135],{"class":96}," httpx",[86,137,139],{"class":138},"sMJiu"," \"",[86,141,142],{"class":96},"mcp[cli]",[86,144,145],{"class":138},"\"\n",[86,147,149,151,153,156],{"class":88,"line":148},4,[86,150,93],{"class":92},[86,152,126],{"class":96},[86,154,155],{"class":103}," --dev",[86,157,158],{"class":96}," pytest\n",[14,160,161,162,165],{},"将来のバージョン差で挙動が変わったら、",[51,163,164],{},"uv add \"fastapi==0.139.0\" \"uvicorn==0.51.0\" \"mcp[cli]==1.28.1\" \"httpx==0.28.1\""," のように前提のバージョンへ固定すればよい。",[14,167,168],{},"先に出来上がりの全体像を見せておく。この講座を最後までやると、ディレクトリはこうなる（Step番号は本文の見出しに対応していて、読み進めながら1本ずつ増えていく）。",[77,170,175],{"className":171,"code":173,"language":174},[172],"language-text","journal-mcp-tutorial/\n├── api.py             # Step 1で書く: ミニ仕訳帳API（FastAPI・約150行）\n├── test_api.py        # Step 1で書く: 試算表の期待値と貸借一致のpytest\n├── server.py          # Step 3で書く: APIを包むMCPサーバー（FastMCP・約170行）\n├── inspect_tools.py   # Step 4で書く: tools/listを覗くMCPクライアント\n├── .mcp.json          # Step 4で書く: Claude Code接続定義（キーは環境変数から展開）\n├── journal_mcp.log    # server.pyが実行時に書く操作ログ（JSONL）\n├── pyproject.toml     # uvの依存定義（uv addが自動更新）\n├── uv.lock            # 依存のロックファイル（自動生成）\n├── .python-version    # 3.11（uv initが生成）\n├── .venv/             # 仮想環境（自動生成）\n└── main.py            # uv initが作るひな形。この講座では使わないので消してよい\n","text",[51,176,173],{"__ignoreMap":82},[14,178,179],{},"自分で書くのは上の5本だけで、コードはすべて本文に全文を載せる。",[14,181,182],{},"この記事の三者関係を先に図にしておく。クラウドは出てこない。全部、読者のPCの中で完結する。",[184,185,186,191],"figure",{},[187,188],"img",{"src":189,"alt":190},"/images/journal-api-mcp-tutorial/figure-01.svg","登場する三者は全部、読者のPCの中で動く。Claude CodeとMCPサーバー（server.py）はstdioで、MCPサーバーとミニ仕訳帳API（api.py）はHTTPでつながり、APIキーはMCPサーバーの環境変数にだけ置かれる",[192,193,194],"figcaption",{},"図1: 登場する三者は全部、読者のPCの中で動く。APIキーの置き場所がこの記事の伏線になる",[196,197,199],"h2",{"id":198},"step-1-ミニ仕訳帳apiを作る","Step 1: ミニ仕訳帳APIを作る",[14,201,202],{},"題材は会計ドメインで最小のもの、仕訳帳にした。扱うのは1行仕訳（借方1科目、貸方1科目）だけで、複合仕訳はスコープ外。エンドポイントは3本に絞る。",[204,205,206,219],"table",{},[207,208,209],"thead",{},[210,211,212,216],"tr",{},[213,214,215],"th",{},"メソッドとパス",[213,217,218],{},"内容",[220,221,222,235,243],"tbody",{},[210,223,224,228],{},[225,226,227],"td",{},"GET /journal-entries",[225,229,230,231,234],{},"仕訳一覧（",[51,232,233],{},"month=YYYY-MM"," で絞り込み）",[210,236,237,240],{},[225,238,239],{},"POST /journal-entries",[225,241,242],{},"仕訳の登録",[210,244,245,248],{},[225,246,247],{},"GET /trial-balance",[225,249,250],{},"勘定科目別の残高試算表",[14,252,253,254,257],{},"勘定科目は7科目のホワイトリスト制にする。現金、普通預金（以上、資産）、買掛金（負債）、資本金（純資産）、売上高（収益）、仕入高、消耗品費（以上、費用）。リストにない科目は422エラーで弾く。認証は ",[51,255,256],{},"X-API-Key"," ヘッダーで、キーを持たない呼び出しは401で拒否する。この「キーを持つ者しか叩けない」という性質が、後半の実験で効いてくる。",[14,259,260,261,265,266,269,270,273],{},"残高試算表には、会計の人向けの設計を1つ入れた。科目ごとに",[262,263,264],"strong",{},"残高の側（balance_side）","と",[262,267,268],{},"正常残高側（normal_side）","を別の属性として返す。前者は「借方合計 − 貸方合計」の符号で決まる実際の残高の側、後者は科目の区分から決まる性質（資産と費用は借方、負債と純資産と収益は貸方）だ。2つは独立に決まるから、食い違ったとき（現金なのに貸方残、つまり残高がマイナス）に ",[51,271,272],{},"is_abnormal: true"," を機械的に立てられる。",[14,275,276,279],{},[51,277,278],{},"api.py"," の全文がこれだ。",[77,281,285],{"className":282,"code":283,"filename":278,"language":284,"meta":82,"style":82},"language-python shiki shiki-themes vitesse-light vitesse-light","\"\"\"ミニ仕訳帳API — FastAPI製の教材用API。\n\nfreee Public APIの1/100模型。1行仕訳（借方1・貸方1）だけを扱う。複合仕訳はスコープ外。\n起動: uv run uvicorn api:app\n\"\"\"\n\nimport datetime as dt\n\nfrom fastapi import Depends, FastAPI, Header, HTTPException, Query\nfrom pydantic import BaseModel, Field, field_validator\n\n# 教材用の固定キー。実務では環境変数や秘密管理サービスに置く\nAPI_KEY = \"sk-journal-tutorial-2026\"\n\n# 勘定科目ホワイトリスト（科目 → 区分）\nACCOUNTS: dict[str, str] = {\n    \"現金\": \"資産\",\n    \"普通預金\": \"資産\",\n    \"買掛金\": \"負債\",\n    \"資本金\": \"純資産\",\n    \"売上高\": \"収益\",\n    \"仕入高\": \"費用\",\n    \"消耗品費\": \"費用\",\n}\n\n# 区分 → 残高の正常な側\nNORMAL_SIDE: dict[str, str] = {\n    \"資産\": \"借方\",\n    \"費用\": \"借方\",\n    \"負債\": \"貸方\",\n    \"純資産\": \"貸方\",\n    \"収益\": \"貸方\",\n}\n\n\nclass JournalEntryIn(BaseModel):\n    \"\"\"仕訳の入力。1行仕訳（借方1・貸方1）のみ。\"\"\"\n\n    date: dt.date\n    debit_account: str\n    credit_account: str\n    amount: int = Field(gt=0, description=\"金額（正の整数・円）\")\n    description: str = \"\"\n\n    @field_validator(\"debit_account\", \"credit_account\")\n    @classmethod\n    def account_must_be_known(cls, v: str) -> str:\n        if v not in ACCOUNTS:\n            allowed = \"、\".join(ACCOUNTS)\n            raise ValueError(f\"勘定科目「{v}」は使えません。使える科目: {allowed}\")\n        return v\n\n\nclass JournalEntry(JournalEntryIn):\n    id: int\n\n\ndef seed_entries() -> list[JournalEntry]:\n    rows = [\n        (\"2026-07-01\", \"現金\", \"資本金\", 100_000, \"開業出資\"),\n        (\"2026-07-05\", \"仕入高\", \"現金\", 30_000, \"商品仕入\"),\n        (\"2026-07-10\", \"現金\", \"売上高\", 80_000, \"売上計上\"),\n        (\"2026-07-12\", \"消耗品費\", \"現金\", 5_000, \"事務用品\"),\n        (\"2026-07-20\", \"普通預金\", \"現金\", 50_000, \"預け入れ\"),\n    ]\n    return [\n        JournalEntry(\n            id=i, date=d, debit_account=dr, credit_account=cr, amount=a, description=desc\n        )\n        for i, (d, dr, cr, a, desc) in enumerate(rows, start=1)\n    ]\n\n\nENTRIES: list[JournalEntry] = seed_entries()\n\n\ndef build_trial_balance(entries: list[JournalEntry]) -> dict:\n    \"\"\"残高試算表を組み立てる純粋関数。\n\n    balance_side は「借方合計 − 貸方合計」の符号で決める（正→借方、負→貸方、0→残高なし）。\n    normal_side は区分から決まる正常残高側で、両者が食い違えば is_abnormal を立てる。\n    \"\"\"\n    accounts = []\n    for account, category in ACCOUNTS.items():\n        debit_total = sum(e.amount for e in entries if e.debit_account == account)\n        credit_total = sum(e.amount for e in entries if e.credit_account == account)\n        if debit_total == 0 and credit_total == 0:\n            continue  # 動きのない科目は載せない\n        net = debit_total - credit_total\n        balance_side = \"借方\" if net > 0 else \"貸方\" if net \u003C 0 else None\n        normal_side = NORMAL_SIDE[category]\n        accounts.append(\n            {\n                \"account\": account,\n                \"category\": category,\n                \"debit_total\": debit_total,\n                \"credit_total\": credit_total,\n                \"balance_side\": balance_side,\n                \"balance\": abs(net),\n                \"normal_side\": normal_side,\n                \"is_abnormal\": balance_side is not None and balance_side != normal_side,\n            }\n        )\n    debit_sum = sum(a[\"debit_total\"] for a in accounts)\n    credit_sum = sum(a[\"credit_total\"] for a in accounts)\n    return {\n        \"accounts\": accounts,\n        \"total\": {\n            \"debit_total\": debit_sum,\n            \"credit_total\": credit_sum,\n            \"in_balance\": debit_sum == credit_sum,\n        },\n    }\n\n\ndef require_api_key(x_api_key: str | None = Header(default=None)) -> None:\n    if x_api_key != API_KEY:\n        raise HTTPException(\n            status_code=401, detail=\"APIキーが不正です。X-API-Key ヘッダーを確認してください。\"\n        )\n\n\napp = FastAPI(\n    title=\"ミニ仕訳帳API\",\n    description=\"教材用のミニ仕訳帳。1行仕訳の登録・一覧・残高試算表だけができる。\",\n    version=\"0.1.0\",\n    dependencies=[Depends(require_api_key)],\n)\n\n\n@app.get(\"/journal-entries\")\ndef list_journal_entries(\n    month: str | None = Query(default=None, pattern=r\"^\\d{4}-\\d{2}$\"),\n) -> list[JournalEntry]:\n    \"\"\"仕訳一覧。month=YYYY-MM で対象月に絞り込める。\"\"\"\n    if month is None:\n        return ENTRIES\n    return [e for e in ENTRIES if e.date.strftime(\"%Y-%m\") == month]\n\n\n@app.post(\"/journal-entries\", status_code=201)\ndef register_journal_entry(entry: JournalEntryIn) -> JournalEntry:\n    \"\"\"仕訳を1件登録する。\"\"\"\n    next_id = max((e.id for e in ENTRIES), default=0) + 1\n    stored = JournalEntry(id=next_id, **entry.model_dump())\n    ENTRIES.append(stored)\n    return stored\n\n\n@app.get(\"/trial-balance\")\ndef get_trial_balance() -> dict:\n    \"\"\"勘定科目別の残高試算表。\"\"\"\n    return build_trial_balance(ENTRIES)\n","python",[51,286,287,295,301,306,311,317,322,339,344,380,403,408,415,431,436,442,473,497,517,538,559,580,601,621,627,632,638,662,682,701,721,740,759,764,769,774,794,805,810,827,838,848,892,907,912,941,949,983,1003,1029,1069,1078,1083,1088,1103,1114,1119,1124,1149,1160,1206,1250,1294,1338,1382,1388,1396,1405,1464,1470,1530,1535,1540,1545,1568,1573,1578,1608,1616,1621,1627,1633,1639,1650,1677,1727,1768,1793,1802,1818,1866,1885,1898,1904,1921,1937,1954,1971,1988,2010,2027,2062,2068,2073,2110,2144,2151,2168,2182,2199,2215,2236,2242,2248,2253,2258,2303,2319,2329,2354,2359,2364,2369,2381,2398,2414,2431,2451,2456,2461,2466,2491,2501,2562,2577,2587,2601,2609,2662,2667,2672,2704,2729,2739,2786,2821,2838,2846,2851,2856,2878,2894,2904],{"__ignoreMap":82},[86,288,289,292],{"class":88,"line":89},[86,290,291],{"class":138},"\"\"\"",[86,293,294],{"class":96},"ミニ仕訳帳API — FastAPI製の教材用API。\n",[86,296,297],{"class":88,"line":111},[86,298,300],{"emptyLinePlaceholder":299},true,"\n",[86,302,303],{"class":88,"line":121},[86,304,305],{"class":96},"freee Public APIの1/100模型。1行仕訳（借方1・貸方1）だけを扱う。複合仕訳はスコープ外。\n",[86,307,308],{"class":88,"line":148},[86,309,310],{"class":96},"起動: uv run uvicorn api:app\n",[86,312,314],{"class":88,"line":313},5,[86,315,316],{"class":138},"\"\"\"\n",[86,318,320],{"class":88,"line":319},6,[86,321,300],{"emptyLinePlaceholder":299},[86,323,325,329,333,336],{"class":88,"line":324},7,[86,326,328],{"class":327},"sHkkW","import",[86,330,332],{"class":331},"sG7-3"," datetime ",[86,334,335],{"class":327},"as",[86,337,338],{"class":331}," dt\n",[86,340,342],{"class":88,"line":341},8,[86,343,300],{"emptyLinePlaceholder":299},[86,345,347,350,353,355,358,362,365,367,370,372,375,377],{"class":88,"line":346},9,[86,348,349],{"class":327},"from",[86,351,352],{"class":331}," fastapi ",[86,354,328],{"class":327},[86,356,357],{"class":331}," Depends",[86,359,361],{"class":360},"shFtX",",",[86,363,364],{"class":331}," FastAPI",[86,366,361],{"class":360},[86,368,369],{"class":331}," Header",[86,371,361],{"class":360},[86,373,374],{"class":331}," HTTPException",[86,376,361],{"class":360},[86,378,379],{"class":331}," Query\n",[86,381,383,385,388,390,393,395,398,400],{"class":88,"line":382},10,[86,384,349],{"class":327},[86,386,387],{"class":331}," pydantic ",[86,389,328],{"class":327},[86,391,392],{"class":331}," BaseModel",[86,394,361],{"class":360},[86,396,397],{"class":331}," Field",[86,399,361],{"class":360},[86,401,402],{"class":331}," field_validator\n",[86,404,406],{"class":88,"line":405},11,[86,407,300],{"emptyLinePlaceholder":299},[86,409,411],{"class":88,"line":410},12,[86,412,414],{"class":413},"sxvE3","# 教材用の固定キー。実務では環境変数や秘密管理サービスに置く\n",[86,416,418,421,424,426,429],{"class":88,"line":417},13,[86,419,420],{"class":103},"API_KEY",[86,422,423],{"class":360}," =",[86,425,139],{"class":138},[86,427,428],{"class":96},"sk-journal-tutorial-2026",[86,430,145],{"class":138},[86,432,434],{"class":88,"line":433},14,[86,435,300],{"emptyLinePlaceholder":299},[86,437,439],{"class":88,"line":438},15,[86,440,441],{"class":413},"# 勘定科目ホワイトリスト（科目 → 区分）\n",[86,443,445,448,451,454,457,460,462,465,468,470],{"class":88,"line":444},16,[86,446,447],{"class":103},"ACCOUNTS",[86,449,450],{"class":360},":",[86,452,453],{"class":331}," dict",[86,455,456],{"class":360},"[",[86,458,459],{"class":114},"str",[86,461,361],{"class":360},[86,463,464],{"class":114}," str",[86,466,467],{"class":360},"]",[86,469,423],{"class":360},[86,471,472],{"class":360}," {\n",[86,474,476,479,482,485,487,489,492,494],{"class":88,"line":475},17,[86,477,478],{"class":138},"    \"",[86,480,481],{"class":96},"現金",[86,483,484],{"class":138},"\"",[86,486,450],{"class":360},[86,488,139],{"class":138},[86,490,491],{"class":96},"資産",[86,493,484],{"class":138},[86,495,496],{"class":360},",\n",[86,498,500,502,505,507,509,511,513,515],{"class":88,"line":499},18,[86,501,478],{"class":138},[86,503,504],{"class":96},"普通預金",[86,506,484],{"class":138},[86,508,450],{"class":360},[86,510,139],{"class":138},[86,512,491],{"class":96},[86,514,484],{"class":138},[86,516,496],{"class":360},[86,518,520,522,525,527,529,531,534,536],{"class":88,"line":519},19,[86,521,478],{"class":138},[86,523,524],{"class":96},"買掛金",[86,526,484],{"class":138},[86,528,450],{"class":360},[86,530,139],{"class":138},[86,532,533],{"class":96},"負債",[86,535,484],{"class":138},[86,537,496],{"class":360},[86,539,541,543,546,548,550,552,555,557],{"class":88,"line":540},20,[86,542,478],{"class":138},[86,544,545],{"class":96},"資本金",[86,547,484],{"class":138},[86,549,450],{"class":360},[86,551,139],{"class":138},[86,553,554],{"class":96},"純資産",[86,556,484],{"class":138},[86,558,496],{"class":360},[86,560,562,564,567,569,571,573,576,578],{"class":88,"line":561},21,[86,563,478],{"class":138},[86,565,566],{"class":96},"売上高",[86,568,484],{"class":138},[86,570,450],{"class":360},[86,572,139],{"class":138},[86,574,575],{"class":96},"収益",[86,577,484],{"class":138},[86,579,496],{"class":360},[86,581,583,585,588,590,592,594,597,599],{"class":88,"line":582},22,[86,584,478],{"class":138},[86,586,587],{"class":96},"仕入高",[86,589,484],{"class":138},[86,591,450],{"class":360},[86,593,139],{"class":138},[86,595,596],{"class":96},"費用",[86,598,484],{"class":138},[86,600,496],{"class":360},[86,602,604,606,609,611,613,615,617,619],{"class":88,"line":603},23,[86,605,478],{"class":138},[86,607,608],{"class":96},"消耗品費",[86,610,484],{"class":138},[86,612,450],{"class":360},[86,614,139],{"class":138},[86,616,596],{"class":96},[86,618,484],{"class":138},[86,620,496],{"class":360},[86,622,624],{"class":88,"line":623},24,[86,625,626],{"class":360},"}\n",[86,628,630],{"class":88,"line":629},25,[86,631,300],{"emptyLinePlaceholder":299},[86,633,635],{"class":88,"line":634},26,[86,636,637],{"class":413},"# 区分 → 残高の正常な側\n",[86,639,641,644,646,648,650,652,654,656,658,660],{"class":88,"line":640},27,[86,642,643],{"class":103},"NORMAL_SIDE",[86,645,450],{"class":360},[86,647,453],{"class":331},[86,649,456],{"class":360},[86,651,459],{"class":114},[86,653,361],{"class":360},[86,655,464],{"class":114},[86,657,467],{"class":360},[86,659,423],{"class":360},[86,661,472],{"class":360},[86,663,665,667,669,671,673,675,678,680],{"class":88,"line":664},28,[86,666,478],{"class":138},[86,668,491],{"class":96},[86,670,484],{"class":138},[86,672,450],{"class":360},[86,674,139],{"class":138},[86,676,677],{"class":96},"借方",[86,679,484],{"class":138},[86,681,496],{"class":360},[86,683,685,687,689,691,693,695,697,699],{"class":88,"line":684},29,[86,686,478],{"class":138},[86,688,596],{"class":96},[86,690,484],{"class":138},[86,692,450],{"class":360},[86,694,139],{"class":138},[86,696,677],{"class":96},[86,698,484],{"class":138},[86,700,496],{"class":360},[86,702,704,706,708,710,712,714,717,719],{"class":88,"line":703},30,[86,705,478],{"class":138},[86,707,533],{"class":96},[86,709,484],{"class":138},[86,711,450],{"class":360},[86,713,139],{"class":138},[86,715,716],{"class":96},"貸方",[86,718,484],{"class":138},[86,720,496],{"class":360},[86,722,724,726,728,730,732,734,736,738],{"class":88,"line":723},31,[86,725,478],{"class":138},[86,727,554],{"class":96},[86,729,484],{"class":138},[86,731,450],{"class":360},[86,733,139],{"class":138},[86,735,716],{"class":96},[86,737,484],{"class":138},[86,739,496],{"class":360},[86,741,743,745,747,749,751,753,755,757],{"class":88,"line":742},32,[86,744,478],{"class":138},[86,746,575],{"class":96},[86,748,484],{"class":138},[86,750,450],{"class":360},[86,752,139],{"class":138},[86,754,716],{"class":96},[86,756,484],{"class":138},[86,758,496],{"class":360},[86,760,762],{"class":88,"line":761},33,[86,763,626],{"class":360},[86,765,767],{"class":88,"line":766},34,[86,768,300],{"emptyLinePlaceholder":299},[86,770,772],{"class":88,"line":771},35,[86,773,300],{"emptyLinePlaceholder":299},[86,775,777,781,785,788,791],{"class":88,"line":776},36,[86,778,780],{"class":779},"stQ0i","class",[86,782,784],{"class":783},"sSkh3"," JournalEntryIn",[86,786,787],{"class":360},"(",[86,789,790],{"class":92},"BaseModel",[86,792,793],{"class":360},"):\n",[86,795,797,800,803],{"class":88,"line":796},37,[86,798,799],{"class":138},"    \"\"\"",[86,801,802],{"class":96},"仕訳の入力。1行仕訳（借方1・貸方1）のみ。",[86,804,316],{"class":138},[86,806,808],{"class":88,"line":807},38,[86,809,300],{"emptyLinePlaceholder":299},[86,811,813,816,818,821,824],{"class":88,"line":812},39,[86,814,815],{"class":331},"    date",[86,817,450],{"class":360},[86,819,820],{"class":331}," dt",[86,822,823],{"class":360},".",[86,825,826],{"class":331},"date\n",[86,828,830,833,835],{"class":88,"line":829},40,[86,831,832],{"class":331},"    debit_account",[86,834,450],{"class":360},[86,836,837],{"class":114}," str\n",[86,839,841,844,846],{"class":88,"line":840},41,[86,842,843],{"class":331},"    credit_account",[86,845,450],{"class":360},[86,847,837],{"class":114},[86,849,851,854,856,859,861,863,865,869,872,875,877,880,882,884,887,889],{"class":88,"line":850},42,[86,852,853],{"class":331},"    amount",[86,855,450],{"class":360},[86,857,858],{"class":114}," int",[86,860,423],{"class":360},[86,862,397],{"class":331},[86,864,787],{"class":360},[86,866,868],{"class":867},"s4oTP","gt",[86,870,871],{"class":360},"=",[86,873,874],{"class":107},"0",[86,876,361],{"class":360},[86,878,879],{"class":867}," description",[86,881,871],{"class":360},[86,883,484],{"class":138},[86,885,886],{"class":96},"金額（正の整数・円）",[86,888,484],{"class":138},[86,890,891],{"class":360},")\n",[86,893,895,898,900,902,904],{"class":88,"line":894},43,[86,896,897],{"class":331},"    description",[86,899,450],{"class":360},[86,901,464],{"class":114},[86,903,423],{"class":360},[86,905,906],{"class":138}," \"\"\n",[86,908,910],{"class":88,"line":909},44,[86,911,300],{"emptyLinePlaceholder":299},[86,913,915,918,921,923,925,928,930,932,934,937,939],{"class":88,"line":914},45,[86,916,917],{"class":360},"    @",[86,919,920],{"class":92},"field_validator",[86,922,787],{"class":360},[86,924,484],{"class":138},[86,926,927],{"class":96},"debit_account",[86,929,484],{"class":138},[86,931,361],{"class":360},[86,933,139],{"class":138},[86,935,936],{"class":96},"credit_account",[86,938,484],{"class":138},[86,940,891],{"class":360},[86,942,944,946],{"class":88,"line":943},46,[86,945,917],{"class":360},[86,947,948],{"class":114},"classmethod\n",[86,950,952,955,958,960,963,965,968,970,972,975,978,980],{"class":88,"line":951},47,[86,953,954],{"class":779},"    def",[86,956,957],{"class":92}," account_must_be_known",[86,959,787],{"class":360},[86,961,962],{"class":331},"cls",[86,964,361],{"class":360},[86,966,967],{"class":331}," v",[86,969,450],{"class":360},[86,971,464],{"class":114},[86,973,974],{"class":360},")",[86,976,977],{"class":360}," ->",[86,979,464],{"class":114},[86,981,982],{"class":360},":\n",[86,984,986,989,992,995,998,1001],{"class":88,"line":985},48,[86,987,988],{"class":327},"        if",[86,990,991],{"class":331}," v ",[86,993,994],{"class":779},"not",[86,996,997],{"class":779}," in",[86,999,1000],{"class":103}," ACCOUNTS",[86,1002,982],{"class":360},[86,1004,1006,1009,1011,1013,1016,1018,1020,1023,1025,1027],{"class":88,"line":1005},49,[86,1007,1008],{"class":331},"            allowed ",[86,1010,871],{"class":360},[86,1012,139],{"class":138},[86,1014,1015],{"class":96},"、",[86,1017,484],{"class":138},[86,1019,823],{"class":360},[86,1021,1022],{"class":331},"join",[86,1024,787],{"class":360},[86,1026,447],{"class":103},[86,1028,891],{"class":360},[86,1030,1032,1035,1038,1040,1043,1046,1049,1052,1055,1058,1060,1063,1065,1067],{"class":88,"line":1031},50,[86,1033,1034],{"class":327},"            raise",[86,1036,1037],{"class":114}," ValueError",[86,1039,787],{"class":360},[86,1041,1042],{"class":779},"f",[86,1044,1045],{"class":96},"\"勘定科目「",[86,1047,1048],{"class":103},"{",[86,1050,1051],{"class":331},"v",[86,1053,1054],{"class":103},"}",[86,1056,1057],{"class":96},"」は使えません。使える科目: ",[86,1059,1048],{"class":103},[86,1061,1062],{"class":331},"allowed",[86,1064,1054],{"class":103},[86,1066,484],{"class":96},[86,1068,891],{"class":360},[86,1070,1072,1075],{"class":88,"line":1071},51,[86,1073,1074],{"class":327},"        return",[86,1076,1077],{"class":331}," v\n",[86,1079,1081],{"class":88,"line":1080},52,[86,1082,300],{"emptyLinePlaceholder":299},[86,1084,1086],{"class":88,"line":1085},53,[86,1087,300],{"emptyLinePlaceholder":299},[86,1089,1091,1093,1096,1098,1101],{"class":88,"line":1090},54,[86,1092,780],{"class":779},[86,1094,1095],{"class":783}," JournalEntry",[86,1097,787],{"class":360},[86,1099,1100],{"class":92},"JournalEntryIn",[86,1102,793],{"class":360},[86,1104,1106,1109,1111],{"class":88,"line":1105},55,[86,1107,1108],{"class":114},"    id",[86,1110,450],{"class":360},[86,1112,1113],{"class":114}," int\n",[86,1115,1117],{"class":88,"line":1116},56,[86,1118,300],{"emptyLinePlaceholder":299},[86,1120,1122],{"class":88,"line":1121},57,[86,1123,300],{"emptyLinePlaceholder":299},[86,1125,1127,1130,1133,1136,1138,1141,1143,1146],{"class":88,"line":1126},58,[86,1128,1129],{"class":779},"def",[86,1131,1132],{"class":92}," seed_entries",[86,1134,1135],{"class":360},"()",[86,1137,977],{"class":360},[86,1139,1140],{"class":331}," list",[86,1142,456],{"class":360},[86,1144,1145],{"class":331},"JournalEntry",[86,1147,1148],{"class":360},"]:\n",[86,1150,1152,1155,1157],{"class":88,"line":1151},59,[86,1153,1154],{"class":331},"    rows ",[86,1156,871],{"class":360},[86,1158,1159],{"class":360}," [\n",[86,1161,1163,1166,1168,1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1194,1196,1198,1201,1203],{"class":88,"line":1162},60,[86,1164,1165],{"class":360},"        (",[86,1167,484],{"class":138},[86,1169,1170],{"class":96},"2026-07-01",[86,1172,484],{"class":138},[86,1174,361],{"class":360},[86,1176,139],{"class":138},[86,1178,481],{"class":96},[86,1180,484],{"class":138},[86,1182,361],{"class":360},[86,1184,139],{"class":138},[86,1186,545],{"class":96},[86,1188,484],{"class":138},[86,1190,361],{"class":360},[86,1192,1193],{"class":107}," 100_000",[86,1195,361],{"class":360},[86,1197,139],{"class":138},[86,1199,1200],{"class":96},"開業出資",[86,1202,484],{"class":138},[86,1204,1205],{"class":360},"),\n",[86,1207,1209,1211,1213,1216,1218,1220,1222,1224,1226,1228,1230,1232,1234,1236,1239,1241,1243,1246,1248],{"class":88,"line":1208},61,[86,1210,1165],{"class":360},[86,1212,484],{"class":138},[86,1214,1215],{"class":96},"2026-07-05",[86,1217,484],{"class":138},[86,1219,361],{"class":360},[86,1221,139],{"class":138},[86,1223,587],{"class":96},[86,1225,484],{"class":138},[86,1227,361],{"class":360},[86,1229,139],{"class":138},[86,1231,481],{"class":96},[86,1233,484],{"class":138},[86,1235,361],{"class":360},[86,1237,1238],{"class":107}," 30_000",[86,1240,361],{"class":360},[86,1242,139],{"class":138},[86,1244,1245],{"class":96},"商品仕入",[86,1247,484],{"class":138},[86,1249,1205],{"class":360},[86,1251,1253,1255,1257,1260,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280,1283,1285,1287,1290,1292],{"class":88,"line":1252},62,[86,1254,1165],{"class":360},[86,1256,484],{"class":138},[86,1258,1259],{"class":96},"2026-07-10",[86,1261,484],{"class":138},[86,1263,361],{"class":360},[86,1265,139],{"class":138},[86,1267,481],{"class":96},[86,1269,484],{"class":138},[86,1271,361],{"class":360},[86,1273,139],{"class":138},[86,1275,566],{"class":96},[86,1277,484],{"class":138},[86,1279,361],{"class":360},[86,1281,1282],{"class":107}," 80_000",[86,1284,361],{"class":360},[86,1286,139],{"class":138},[86,1288,1289],{"class":96},"売上計上",[86,1291,484],{"class":138},[86,1293,1205],{"class":360},[86,1295,1297,1299,1301,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1327,1329,1331,1334,1336],{"class":88,"line":1296},63,[86,1298,1165],{"class":360},[86,1300,484],{"class":138},[86,1302,1303],{"class":96},"2026-07-12",[86,1305,484],{"class":138},[86,1307,361],{"class":360},[86,1309,139],{"class":138},[86,1311,608],{"class":96},[86,1313,484],{"class":138},[86,1315,361],{"class":360},[86,1317,139],{"class":138},[86,1319,481],{"class":96},[86,1321,484],{"class":138},[86,1323,361],{"class":360},[86,1325,1326],{"class":107}," 5_000",[86,1328,361],{"class":360},[86,1330,139],{"class":138},[86,1332,1333],{"class":96},"事務用品",[86,1335,484],{"class":138},[86,1337,1205],{"class":360},[86,1339,1341,1343,1345,1348,1350,1352,1354,1356,1358,1360,1362,1364,1366,1368,1371,1373,1375,1378,1380],{"class":88,"line":1340},64,[86,1342,1165],{"class":360},[86,1344,484],{"class":138},[86,1346,1347],{"class":96},"2026-07-20",[86,1349,484],{"class":138},[86,1351,361],{"class":360},[86,1353,139],{"class":138},[86,1355,504],{"class":96},[86,1357,484],{"class":138},[86,1359,361],{"class":360},[86,1361,139],{"class":138},[86,1363,481],{"class":96},[86,1365,484],{"class":138},[86,1367,361],{"class":360},[86,1369,1370],{"class":107}," 50_000",[86,1372,361],{"class":360},[86,1374,139],{"class":138},[86,1376,1377],{"class":96},"預け入れ",[86,1379,484],{"class":138},[86,1381,1205],{"class":360},[86,1383,1385],{"class":88,"line":1384},65,[86,1386,1387],{"class":360},"    ]\n",[86,1389,1391,1394],{"class":88,"line":1390},66,[86,1392,1393],{"class":327},"    return",[86,1395,1159],{"class":360},[86,1397,1399,1402],{"class":88,"line":1398},67,[86,1400,1401],{"class":331},"        JournalEntry",[86,1403,1404],{"class":360},"(\n",[86,1406,1408,1411,1413,1416,1418,1421,1423,1426,1428,1431,1433,1436,1438,1441,1443,1446,1448,1451,1453,1455,1457,1459,1461],{"class":88,"line":1407},68,[86,1409,1410],{"class":867},"            id",[86,1412,871],{"class":360},[86,1414,1415],{"class":331},"i",[86,1417,361],{"class":360},[86,1419,1420],{"class":867}," date",[86,1422,871],{"class":360},[86,1424,1425],{"class":331},"d",[86,1427,361],{"class":360},[86,1429,1430],{"class":867}," debit_account",[86,1432,871],{"class":360},[86,1434,1435],{"class":331},"dr",[86,1437,361],{"class":360},[86,1439,1440],{"class":867}," credit_account",[86,1442,871],{"class":360},[86,1444,1445],{"class":331},"cr",[86,1447,361],{"class":360},[86,1449,1450],{"class":867}," amount",[86,1452,871],{"class":360},[86,1454,17],{"class":331},[86,1456,361],{"class":360},[86,1458,879],{"class":867},[86,1460,871],{"class":360},[86,1462,1463],{"class":331},"desc\n",[86,1465,1467],{"class":88,"line":1466},69,[86,1468,1469],{"class":360},"        )\n",[86,1471,1473,1476,1479,1481,1484,1486,1488,1491,1493,1496,1498,1501,1503,1506,1508,1510,1513,1515,1518,1520,1523,1525,1528],{"class":88,"line":1472},70,[86,1474,1475],{"class":327},"        for",[86,1477,1478],{"class":331}," i",[86,1480,361],{"class":360},[86,1482,1483],{"class":360}," (",[86,1485,1425],{"class":331},[86,1487,361],{"class":360},[86,1489,1490],{"class":331}," dr",[86,1492,361],{"class":360},[86,1494,1495],{"class":331}," cr",[86,1497,361],{"class":360},[86,1499,1500],{"class":331}," a",[86,1502,361],{"class":360},[86,1504,1505],{"class":331}," desc",[86,1507,974],{"class":360},[86,1509,997],{"class":327},[86,1511,1512],{"class":114}," enumerate",[86,1514,787],{"class":360},[86,1516,1517],{"class":331},"rows",[86,1519,361],{"class":360},[86,1521,1522],{"class":867}," start",[86,1524,871],{"class":360},[86,1526,1527],{"class":107},"1",[86,1529,891],{"class":360},[86,1531,1533],{"class":88,"line":1532},71,[86,1534,1387],{"class":360},[86,1536,1538],{"class":88,"line":1537},72,[86,1539,300],{"emptyLinePlaceholder":299},[86,1541,1543],{"class":88,"line":1542},73,[86,1544,300],{"emptyLinePlaceholder":299},[86,1546,1548,1551,1553,1555,1557,1559,1561,1563,1565],{"class":88,"line":1547},74,[86,1549,1550],{"class":103},"ENTRIES",[86,1552,450],{"class":360},[86,1554,1140],{"class":331},[86,1556,456],{"class":360},[86,1558,1145],{"class":331},[86,1560,467],{"class":360},[86,1562,423],{"class":360},[86,1564,1132],{"class":331},[86,1566,1567],{"class":360},"()\n",[86,1569,1571],{"class":88,"line":1570},75,[86,1572,300],{"emptyLinePlaceholder":299},[86,1574,1576],{"class":88,"line":1575},76,[86,1577,300],{"emptyLinePlaceholder":299},[86,1579,1581,1583,1586,1588,1591,1593,1595,1597,1599,1602,1604,1606],{"class":88,"line":1580},77,[86,1582,1129],{"class":779},[86,1584,1585],{"class":92}," build_trial_balance",[86,1587,787],{"class":360},[86,1589,1590],{"class":331},"entries",[86,1592,450],{"class":360},[86,1594,1140],{"class":331},[86,1596,456],{"class":360},[86,1598,1145],{"class":331},[86,1600,1601],{"class":360},"])",[86,1603,977],{"class":360},[86,1605,453],{"class":114},[86,1607,982],{"class":360},[86,1609,1611,1613],{"class":88,"line":1610},78,[86,1612,799],{"class":138},[86,1614,1615],{"class":96},"残高試算表を組み立てる純粋関数。\n",[86,1617,1619],{"class":88,"line":1618},79,[86,1620,300],{"emptyLinePlaceholder":299},[86,1622,1624],{"class":88,"line":1623},80,[86,1625,1626],{"class":96},"    balance_side は「借方合計 − 貸方合計」の符号で決める（正→借方、負→貸方、0→残高なし）。\n",[86,1628,1630],{"class":88,"line":1629},81,[86,1631,1632],{"class":96},"    normal_side は区分から決まる正常残高側で、両者が食い違えば is_abnormal を立てる。\n",[86,1634,1636],{"class":88,"line":1635},82,[86,1637,1638],{"class":138},"    \"\"\"\n",[86,1640,1642,1645,1647],{"class":88,"line":1641},83,[86,1643,1644],{"class":331},"    accounts ",[86,1646,871],{"class":360},[86,1648,1649],{"class":360}," []\n",[86,1651,1653,1656,1659,1661,1664,1667,1669,1671,1674],{"class":88,"line":1652},84,[86,1654,1655],{"class":327},"    for",[86,1657,1658],{"class":331}," account",[86,1660,361],{"class":360},[86,1662,1663],{"class":331}," category ",[86,1665,1666],{"class":327},"in",[86,1668,1000],{"class":103},[86,1670,823],{"class":360},[86,1672,1673],{"class":331},"items",[86,1675,1676],{"class":360},"():\n",[86,1678,1680,1683,1685,1688,1690,1693,1695,1698,1701,1704,1706,1709,1712,1715,1717,1720,1723,1725],{"class":88,"line":1679},85,[86,1681,1682],{"class":331},"        debit_total ",[86,1684,871],{"class":360},[86,1686,1687],{"class":114}," sum",[86,1689,787],{"class":360},[86,1691,1692],{"class":331},"e",[86,1694,823],{"class":360},[86,1696,1697],{"class":331},"amount ",[86,1699,1700],{"class":327},"for",[86,1702,1703],{"class":331}," e ",[86,1705,1666],{"class":327},[86,1707,1708],{"class":331}," entries ",[86,1710,1711],{"class":327},"if",[86,1713,1714],{"class":331}," e",[86,1716,823],{"class":360},[86,1718,1719],{"class":331},"debit_account ",[86,1721,1722],{"class":779},"==",[86,1724,1658],{"class":331},[86,1726,891],{"class":360},[86,1728,1730,1733,1735,1737,1739,1741,1743,1745,1747,1749,1751,1753,1755,1757,1759,1762,1764,1766],{"class":88,"line":1729},86,[86,1731,1732],{"class":331},"        credit_total ",[86,1734,871],{"class":360},[86,1736,1687],{"class":114},[86,1738,787],{"class":360},[86,1740,1692],{"class":331},[86,1742,823],{"class":360},[86,1744,1697],{"class":331},[86,1746,1700],{"class":327},[86,1748,1703],{"class":331},[86,1750,1666],{"class":327},[86,1752,1708],{"class":331},[86,1754,1711],{"class":327},[86,1756,1714],{"class":331},[86,1758,823],{"class":360},[86,1760,1761],{"class":331},"credit_account ",[86,1763,1722],{"class":779},[86,1765,1658],{"class":331},[86,1767,891],{"class":360},[86,1769,1771,1773,1776,1778,1781,1784,1787,1789,1791],{"class":88,"line":1770},87,[86,1772,988],{"class":327},[86,1774,1775],{"class":331}," debit_total ",[86,1777,1722],{"class":779},[86,1779,1780],{"class":107}," 0",[86,1782,1783],{"class":779}," and",[86,1785,1786],{"class":331}," credit_total ",[86,1788,1722],{"class":779},[86,1790,1780],{"class":107},[86,1792,982],{"class":360},[86,1794,1796,1799],{"class":88,"line":1795},88,[86,1797,1798],{"class":327},"            continue",[86,1800,1801],{"class":413},"  # 動きのない科目は載せない\n",[86,1803,1805,1808,1810,1812,1815],{"class":88,"line":1804},89,[86,1806,1807],{"class":331},"        net ",[86,1809,871],{"class":360},[86,1811,1775],{"class":331},[86,1813,1814],{"class":779},"-",[86,1816,1817],{"class":331}," credit_total\n",[86,1819,1821,1824,1826,1828,1830,1832,1835,1838,1841,1843,1846,1848,1850,1852,1854,1856,1859,1861,1863],{"class":88,"line":1820},90,[86,1822,1823],{"class":331},"        balance_side ",[86,1825,871],{"class":360},[86,1827,139],{"class":138},[86,1829,677],{"class":96},[86,1831,484],{"class":138},[86,1833,1834],{"class":327}," if",[86,1836,1837],{"class":331}," net ",[86,1839,1840],{"class":779},">",[86,1842,1780],{"class":107},[86,1844,1845],{"class":327}," else",[86,1847,139],{"class":138},[86,1849,716],{"class":96},[86,1851,484],{"class":138},[86,1853,1834],{"class":327},[86,1855,1837],{"class":331},[86,1857,1858],{"class":779},"\u003C",[86,1860,1780],{"class":107},[86,1862,1845],{"class":327},[86,1864,1865],{"class":327}," None\n",[86,1867,1869,1872,1874,1877,1879,1882],{"class":88,"line":1868},91,[86,1870,1871],{"class":331},"        normal_side ",[86,1873,871],{"class":360},[86,1875,1876],{"class":103}," NORMAL_SIDE",[86,1878,456],{"class":360},[86,1880,1881],{"class":331},"category",[86,1883,1884],{"class":360},"]\n",[86,1886,1888,1891,1893,1896],{"class":88,"line":1887},92,[86,1889,1890],{"class":331},"        accounts",[86,1892,823],{"class":360},[86,1894,1895],{"class":331},"append",[86,1897,1404],{"class":360},[86,1899,1901],{"class":88,"line":1900},93,[86,1902,1903],{"class":360},"            {\n",[86,1905,1907,1910,1913,1915,1917,1919],{"class":88,"line":1906},94,[86,1908,1909],{"class":138},"                \"",[86,1911,1912],{"class":96},"account",[86,1914,484],{"class":138},[86,1916,450],{"class":360},[86,1918,1658],{"class":331},[86,1920,496],{"class":360},[86,1922,1924,1926,1928,1930,1932,1935],{"class":88,"line":1923},95,[86,1925,1909],{"class":138},[86,1927,1881],{"class":96},[86,1929,484],{"class":138},[86,1931,450],{"class":360},[86,1933,1934],{"class":331}," category",[86,1936,496],{"class":360},[86,1938,1940,1942,1945,1947,1949,1952],{"class":88,"line":1939},96,[86,1941,1909],{"class":138},[86,1943,1944],{"class":96},"debit_total",[86,1946,484],{"class":138},[86,1948,450],{"class":360},[86,1950,1951],{"class":331}," debit_total",[86,1953,496],{"class":360},[86,1955,1957,1959,1962,1964,1966,1969],{"class":88,"line":1956},97,[86,1958,1909],{"class":138},[86,1960,1961],{"class":96},"credit_total",[86,1963,484],{"class":138},[86,1965,450],{"class":360},[86,1967,1968],{"class":331}," credit_total",[86,1970,496],{"class":360},[86,1972,1974,1976,1979,1981,1983,1986],{"class":88,"line":1973},98,[86,1975,1909],{"class":138},[86,1977,1978],{"class":96},"balance_side",[86,1980,484],{"class":138},[86,1982,450],{"class":360},[86,1984,1985],{"class":331}," balance_side",[86,1987,496],{"class":360},[86,1989,1991,1993,1996,1998,2000,2003,2005,2008],{"class":88,"line":1990},99,[86,1992,1909],{"class":138},[86,1994,1995],{"class":96},"balance",[86,1997,484],{"class":138},[86,1999,450],{"class":360},[86,2001,2002],{"class":114}," abs",[86,2004,787],{"class":360},[86,2006,2007],{"class":331},"net",[86,2009,1205],{"class":360},[86,2011,2013,2015,2018,2020,2022,2025],{"class":88,"line":2012},100,[86,2014,1909],{"class":138},[86,2016,2017],{"class":96},"normal_side",[86,2019,484],{"class":138},[86,2021,450],{"class":360},[86,2023,2024],{"class":331}," normal_side",[86,2026,496],{"class":360},[86,2028,2030,2032,2035,2037,2039,2042,2045,2048,2051,2053,2055,2058,2060],{"class":88,"line":2029},101,[86,2031,1909],{"class":138},[86,2033,2034],{"class":96},"is_abnormal",[86,2036,484],{"class":138},[86,2038,450],{"class":360},[86,2040,2041],{"class":331}," balance_side ",[86,2043,2044],{"class":779},"is",[86,2046,2047],{"class":779}," not",[86,2049,2050],{"class":327}," None",[86,2052,1783],{"class":779},[86,2054,2041],{"class":331},[86,2056,2057],{"class":779},"!=",[86,2059,2024],{"class":331},[86,2061,496],{"class":360},[86,2063,2065],{"class":88,"line":2064},102,[86,2066,2067],{"class":360},"            }\n",[86,2069,2071],{"class":88,"line":2070},103,[86,2072,1469],{"class":360},[86,2074,2076,2079,2081,2083,2085,2087,2089,2091,2093,2095,2097,2100,2103,2105,2108],{"class":88,"line":2075},104,[86,2077,2078],{"class":331},"    debit_sum ",[86,2080,871],{"class":360},[86,2082,1687],{"class":114},[86,2084,787],{"class":360},[86,2086,17],{"class":331},[86,2088,456],{"class":360},[86,2090,484],{"class":138},[86,2092,1944],{"class":96},[86,2094,484],{"class":138},[86,2096,467],{"class":360},[86,2098,2099],{"class":327}," for",[86,2101,2102],{"class":331}," a ",[86,2104,1666],{"class":327},[86,2106,2107],{"class":331}," accounts",[86,2109,891],{"class":360},[86,2111,2113,2116,2118,2120,2122,2124,2126,2128,2130,2132,2134,2136,2138,2140,2142],{"class":88,"line":2112},105,[86,2114,2115],{"class":331},"    credit_sum ",[86,2117,871],{"class":360},[86,2119,1687],{"class":114},[86,2121,787],{"class":360},[86,2123,17],{"class":331},[86,2125,456],{"class":360},[86,2127,484],{"class":138},[86,2129,1961],{"class":96},[86,2131,484],{"class":138},[86,2133,467],{"class":360},[86,2135,2099],{"class":327},[86,2137,2102],{"class":331},[86,2139,1666],{"class":327},[86,2141,2107],{"class":331},[86,2143,891],{"class":360},[86,2145,2147,2149],{"class":88,"line":2146},106,[86,2148,1393],{"class":327},[86,2150,472],{"class":360},[86,2152,2154,2157,2160,2162,2164,2166],{"class":88,"line":2153},107,[86,2155,2156],{"class":138},"        \"",[86,2158,2159],{"class":96},"accounts",[86,2161,484],{"class":138},[86,2163,450],{"class":360},[86,2165,2107],{"class":331},[86,2167,496],{"class":360},[86,2169,2171,2173,2176,2178,2180],{"class":88,"line":2170},108,[86,2172,2156],{"class":138},[86,2174,2175],{"class":96},"total",[86,2177,484],{"class":138},[86,2179,450],{"class":360},[86,2181,472],{"class":360},[86,2183,2185,2188,2190,2192,2194,2197],{"class":88,"line":2184},109,[86,2186,2187],{"class":138},"            \"",[86,2189,1944],{"class":96},[86,2191,484],{"class":138},[86,2193,450],{"class":360},[86,2195,2196],{"class":331}," debit_sum",[86,2198,496],{"class":360},[86,2200,2202,2204,2206,2208,2210,2213],{"class":88,"line":2201},110,[86,2203,2187],{"class":138},[86,2205,1961],{"class":96},[86,2207,484],{"class":138},[86,2209,450],{"class":360},[86,2211,2212],{"class":331}," credit_sum",[86,2214,496],{"class":360},[86,2216,2218,2220,2223,2225,2227,2230,2232,2234],{"class":88,"line":2217},111,[86,2219,2187],{"class":138},[86,2221,2222],{"class":96},"in_balance",[86,2224,484],{"class":138},[86,2226,450],{"class":360},[86,2228,2229],{"class":331}," debit_sum ",[86,2231,1722],{"class":779},[86,2233,2212],{"class":331},[86,2235,496],{"class":360},[86,2237,2239],{"class":88,"line":2238},112,[86,2240,2241],{"class":360},"        },\n",[86,2243,2245],{"class":88,"line":2244},113,[86,2246,2247],{"class":360},"    }\n",[86,2249,2251],{"class":88,"line":2250},114,[86,2252,300],{"emptyLinePlaceholder":299},[86,2254,2256],{"class":88,"line":2255},115,[86,2257,300],{"emptyLinePlaceholder":299},[86,2259,2261,2263,2266,2268,2271,2273,2275,2278,2280,2282,2284,2286,2289,2291,2294,2297,2299,2301],{"class":88,"line":2260},116,[86,2262,1129],{"class":779},[86,2264,2265],{"class":92}," require_api_key",[86,2267,787],{"class":360},[86,2269,2270],{"class":331},"x_api_key",[86,2272,450],{"class":360},[86,2274,464],{"class":114},[86,2276,2277],{"class":779}," |",[86,2279,2050],{"class":327},[86,2281,423],{"class":360},[86,2283,369],{"class":331},[86,2285,787],{"class":360},[86,2287,2288],{"class":867},"default",[86,2290,871],{"class":360},[86,2292,2293],{"class":327},"None",[86,2295,2296],{"class":360},"))",[86,2298,977],{"class":360},[86,2300,2050],{"class":327},[86,2302,982],{"class":360},[86,2304,2306,2309,2312,2314,2317],{"class":88,"line":2305},117,[86,2307,2308],{"class":327},"    if",[86,2310,2311],{"class":331}," x_api_key ",[86,2313,2057],{"class":779},[86,2315,2316],{"class":103}," API_KEY",[86,2318,982],{"class":360},[86,2320,2322,2325,2327],{"class":88,"line":2321},118,[86,2323,2324],{"class":327},"        raise",[86,2326,374],{"class":331},[86,2328,1404],{"class":360},[86,2330,2332,2335,2337,2340,2342,2345,2347,2349,2352],{"class":88,"line":2331},119,[86,2333,2334],{"class":867},"            status_code",[86,2336,871],{"class":360},[86,2338,2339],{"class":107},"401",[86,2341,361],{"class":360},[86,2343,2344],{"class":867}," detail",[86,2346,871],{"class":360},[86,2348,484],{"class":138},[86,2350,2351],{"class":96},"APIキーが不正です。X-API-Key ヘッダーを確認してください。",[86,2353,145],{"class":138},[86,2355,2357],{"class":88,"line":2356},120,[86,2358,1469],{"class":360},[86,2360,2362],{"class":88,"line":2361},121,[86,2363,300],{"emptyLinePlaceholder":299},[86,2365,2367],{"class":88,"line":2366},122,[86,2368,300],{"emptyLinePlaceholder":299},[86,2370,2372,2375,2377,2379],{"class":88,"line":2371},123,[86,2373,2374],{"class":331},"app ",[86,2376,871],{"class":360},[86,2378,364],{"class":331},[86,2380,1404],{"class":360},[86,2382,2384,2387,2389,2391,2394,2396],{"class":88,"line":2383},124,[86,2385,2386],{"class":867},"    title",[86,2388,871],{"class":360},[86,2390,484],{"class":138},[86,2392,2393],{"class":96},"ミニ仕訳帳API",[86,2395,484],{"class":138},[86,2397,496],{"class":360},[86,2399,2401,2403,2405,2407,2410,2412],{"class":88,"line":2400},125,[86,2402,897],{"class":867},[86,2404,871],{"class":360},[86,2406,484],{"class":138},[86,2408,2409],{"class":96},"教材用のミニ仕訳帳。1行仕訳の登録・一覧・残高試算表だけができる。",[86,2411,484],{"class":138},[86,2413,496],{"class":360},[86,2415,2417,2420,2422,2424,2427,2429],{"class":88,"line":2416},126,[86,2418,2419],{"class":867},"    version",[86,2421,871],{"class":360},[86,2423,484],{"class":138},[86,2425,2426],{"class":96},"0.1.0",[86,2428,484],{"class":138},[86,2430,496],{"class":360},[86,2432,2434,2437,2440,2443,2445,2448],{"class":88,"line":2433},127,[86,2435,2436],{"class":867},"    dependencies",[86,2438,2439],{"class":360},"=[",[86,2441,2442],{"class":331},"Depends",[86,2444,787],{"class":360},[86,2446,2447],{"class":331},"require_api_key",[86,2449,2450],{"class":360},")],\n",[86,2452,2454],{"class":88,"line":2453},128,[86,2455,891],{"class":360},[86,2457,2459],{"class":88,"line":2458},129,[86,2460,300],{"emptyLinePlaceholder":299},[86,2462,2464],{"class":88,"line":2463},130,[86,2465,300],{"emptyLinePlaceholder":299},[86,2467,2469,2472,2475,2477,2480,2482,2484,2487,2489],{"class":88,"line":2468},131,[86,2470,2471],{"class":360},"@",[86,2473,2474],{"class":92},"app",[86,2476,823],{"class":360},[86,2478,2479],{"class":92},"get",[86,2481,787],{"class":360},[86,2483,484],{"class":138},[86,2485,2486],{"class":96},"/journal-entries",[86,2488,484],{"class":138},[86,2490,891],{"class":360},[86,2492,2494,2496,2499],{"class":88,"line":2493},132,[86,2495,1129],{"class":779},[86,2497,2498],{"class":92}," list_journal_entries",[86,2500,1404],{"class":360},[86,2502,2504,2507,2509,2511,2513,2515,2517,2520,2522,2524,2526,2528,2530,2533,2535,2538,2540,2543,2546,2549,2552,2555,2558,2560],{"class":88,"line":2503},133,[86,2505,2506],{"class":331},"    month",[86,2508,450],{"class":360},[86,2510,464],{"class":114},[86,2512,2277],{"class":779},[86,2514,2050],{"class":327},[86,2516,423],{"class":360},[86,2518,2519],{"class":331}," Query",[86,2521,787],{"class":360},[86,2523,2288],{"class":867},[86,2525,871],{"class":360},[86,2527,2293],{"class":327},[86,2529,361],{"class":360},[86,2531,2532],{"class":867}," pattern",[86,2534,871],{"class":360},[86,2536,2537],{"class":779},"r",[86,2539,484],{"class":138},[86,2541,2542],{"class":114},"^\\d",[86,2544,2545],{"class":107},"{4}",[86,2547,1814],{"class":2548},"sLkVR",[86,2550,2551],{"class":114},"\\d",[86,2553,2554],{"class":107},"{2}",[86,2556,2557],{"class":114},"$",[86,2559,484],{"class":138},[86,2561,1205],{"class":360},[86,2563,2565,2567,2569,2571,2573,2575],{"class":88,"line":2564},134,[86,2566,974],{"class":360},[86,2568,977],{"class":360},[86,2570,1140],{"class":331},[86,2572,456],{"class":360},[86,2574,1145],{"class":331},[86,2576,1148],{"class":360},[86,2578,2580,2582,2585],{"class":88,"line":2579},135,[86,2581,799],{"class":138},[86,2583,2584],{"class":96},"仕訳一覧。month=YYYY-MM で対象月に絞り込める。",[86,2586,316],{"class":138},[86,2588,2590,2592,2595,2597,2599],{"class":88,"line":2589},136,[86,2591,2308],{"class":327},[86,2593,2594],{"class":331}," month ",[86,2596,2044],{"class":779},[86,2598,2050],{"class":327},[86,2600,982],{"class":360},[86,2602,2604,2606],{"class":88,"line":2603},137,[86,2605,1074],{"class":327},[86,2607,2608],{"class":103}," ENTRIES\n",[86,2610,2612,2614,2617,2620,2622,2624,2626,2629,2631,2633,2635,2638,2640,2643,2645,2647,2650,2652,2654,2657,2660],{"class":88,"line":2611},138,[86,2613,1393],{"class":327},[86,2615,2616],{"class":360}," [",[86,2618,2619],{"class":331},"e ",[86,2621,1700],{"class":327},[86,2623,1703],{"class":331},[86,2625,1666],{"class":327},[86,2627,2628],{"class":103}," ENTRIES",[86,2630,1834],{"class":327},[86,2632,1714],{"class":331},[86,2634,823],{"class":360},[86,2636,2637],{"class":331},"date",[86,2639,823],{"class":360},[86,2641,2642],{"class":331},"strftime",[86,2644,787],{"class":360},[86,2646,484],{"class":138},[86,2648,2649],{"class":96},"%Y-%m",[86,2651,484],{"class":138},[86,2653,974],{"class":360},[86,2655,2656],{"class":779}," ==",[86,2658,2659],{"class":331}," month",[86,2661,1884],{"class":360},[86,2663,2665],{"class":88,"line":2664},139,[86,2666,300],{"emptyLinePlaceholder":299},[86,2668,2670],{"class":88,"line":2669},140,[86,2671,300],{"emptyLinePlaceholder":299},[86,2673,2675,2677,2679,2681,2684,2686,2688,2690,2692,2694,2697,2699,2702],{"class":88,"line":2674},141,[86,2676,2471],{"class":360},[86,2678,2474],{"class":92},[86,2680,823],{"class":360},[86,2682,2683],{"class":92},"post",[86,2685,787],{"class":360},[86,2687,484],{"class":138},[86,2689,2486],{"class":96},[86,2691,484],{"class":138},[86,2693,361],{"class":360},[86,2695,2696],{"class":867}," status_code",[86,2698,871],{"class":360},[86,2700,2701],{"class":107},"201",[86,2703,891],{"class":360},[86,2705,2707,2709,2712,2714,2717,2719,2721,2723,2725,2727],{"class":88,"line":2706},142,[86,2708,1129],{"class":779},[86,2710,2711],{"class":92}," register_journal_entry",[86,2713,787],{"class":360},[86,2715,2716],{"class":331},"entry",[86,2718,450],{"class":360},[86,2720,784],{"class":331},[86,2722,974],{"class":360},[86,2724,977],{"class":360},[86,2726,1095],{"class":331},[86,2728,982],{"class":360},[86,2730,2732,2734,2737],{"class":88,"line":2731},143,[86,2733,799],{"class":138},[86,2735,2736],{"class":96},"仕訳を1件登録する。",[86,2738,316],{"class":138},[86,2740,2742,2745,2747,2750,2753,2755,2757,2760,2762,2764,2766,2768,2771,2774,2776,2778,2780,2783],{"class":88,"line":2741},144,[86,2743,2744],{"class":331},"    next_id ",[86,2746,871],{"class":360},[86,2748,2749],{"class":114}," max",[86,2751,2752],{"class":360},"((",[86,2754,1692],{"class":331},[86,2756,823],{"class":360},[86,2758,2759],{"class":331},"id ",[86,2761,1700],{"class":327},[86,2763,1703],{"class":331},[86,2765,1666],{"class":327},[86,2767,2628],{"class":103},[86,2769,2770],{"class":360},"),",[86,2772,2773],{"class":867}," default",[86,2775,871],{"class":360},[86,2777,874],{"class":107},[86,2779,974],{"class":360},[86,2781,2782],{"class":779}," +",[86,2784,2785],{"class":107}," 1\n",[86,2787,2789,2792,2794,2796,2798,2801,2803,2806,2808,2811,2813,2815,2818],{"class":88,"line":2788},145,[86,2790,2791],{"class":331},"    stored ",[86,2793,871],{"class":360},[86,2795,1095],{"class":331},[86,2797,787],{"class":360},[86,2799,2800],{"class":867},"id",[86,2802,871],{"class":360},[86,2804,2805],{"class":331},"next_id",[86,2807,361],{"class":360},[86,2809,2810],{"class":779}," **",[86,2812,2716],{"class":331},[86,2814,823],{"class":360},[86,2816,2817],{"class":331},"model_dump",[86,2819,2820],{"class":360},"())\n",[86,2822,2824,2827,2829,2831,2833,2836],{"class":88,"line":2823},146,[86,2825,2826],{"class":103},"    ENTRIES",[86,2828,823],{"class":360},[86,2830,1895],{"class":331},[86,2832,787],{"class":360},[86,2834,2835],{"class":331},"stored",[86,2837,891],{"class":360},[86,2839,2841,2843],{"class":88,"line":2840},147,[86,2842,1393],{"class":327},[86,2844,2845],{"class":331}," stored\n",[86,2847,2849],{"class":88,"line":2848},148,[86,2850,300],{"emptyLinePlaceholder":299},[86,2852,2854],{"class":88,"line":2853},149,[86,2855,300],{"emptyLinePlaceholder":299},[86,2857,2859,2861,2863,2865,2867,2869,2871,2874,2876],{"class":88,"line":2858},150,[86,2860,2471],{"class":360},[86,2862,2474],{"class":92},[86,2864,823],{"class":360},[86,2866,2479],{"class":92},[86,2868,787],{"class":360},[86,2870,484],{"class":138},[86,2872,2873],{"class":96},"/trial-balance",[86,2875,484],{"class":138},[86,2877,891],{"class":360},[86,2879,2881,2883,2886,2888,2890,2892],{"class":88,"line":2880},151,[86,2882,1129],{"class":779},[86,2884,2885],{"class":92}," get_trial_balance",[86,2887,1135],{"class":360},[86,2889,977],{"class":360},[86,2891,453],{"class":114},[86,2893,982],{"class":360},[86,2895,2897,2899,2902],{"class":88,"line":2896},152,[86,2898,799],{"class":138},[86,2900,2901],{"class":96},"勘定科目別の残高試算表。",[86,2903,316],{"class":138},[86,2905,2907,2909,2911,2913,2915],{"class":88,"line":2906},153,[86,2908,1393],{"class":327},[86,2910,1585],{"class":331},[86,2912,787],{"class":360},[86,2914,1550],{"class":103},[86,2916,891],{"class":360},[14,2918,2919],{},"保存はインメモリで、シード仕訳を5件入れてある。開業出資10万円、仕入3万円、売上8万円、消耗品5千円、預け入れ5万円。この5件に対する残高試算表は手で計算できて、次の表になるはずだ。",[204,2921,2922,2938],{},[207,2923,2924],{},[210,2925,2926,2929,2932,2935],{},[213,2927,2928],{},"科目",[213,2930,2931],{},"借方合計",[213,2933,2934],{},"貸方合計",[213,2936,2937],{},"残高",[220,2939,2940,2953,2965,2977,2989,3001,3013],{},[210,2941,2942,2944,2947,2950],{},[225,2943,481],{},[225,2945,2946],{},"180,000",[225,2948,2949],{},"85,000",[225,2951,2952],{},"借方 95,000",[210,2954,2955,2957,2960,2962],{},[225,2956,504],{},[225,2958,2959],{},"50,000",[225,2961,874],{},[225,2963,2964],{},"借方 50,000",[210,2966,2967,2969,2972,2974],{},[225,2968,587],{},[225,2970,2971],{},"30,000",[225,2973,874],{},[225,2975,2976],{},"借方 30,000",[210,2978,2979,2981,2984,2986],{},[225,2980,608],{},[225,2982,2983],{},"5,000",[225,2985,874],{},[225,2987,2988],{},"借方 5,000",[210,2990,2991,2993,2995,2998],{},[225,2992,566],{},[225,2994,874],{},[225,2996,2997],{},"80,000",[225,2999,3000],{},"貸方 80,000",[210,3002,3003,3005,3007,3010],{},[225,3004,545],{},[225,3006,874],{},[225,3008,3009],{},"100,000",[225,3011,3012],{},"貸方 100,000",[210,3014,3015,3020,3025,3029],{},[225,3016,3017],{},[262,3018,3019],{},"合計",[225,3021,3022],{},[262,3023,3024],{},"265,000",[225,3026,3027],{},[262,3028,3024],{},[225,3030,3031],{},"借方残計 180,000 ＝ 貸方残計 180,000",[14,3033,3034,3035,3037,3038,3041],{},"「はずだ」で終わらせず、この期待値表をそのままテストに固定する。貸借一致（借方合計＝貸方合計）と残高の一致（借方残計＝貸方残計）は複式簿記の恒等式なので、目視レビューではなくテストコードに検証させるのが確実だ。おまけに、現金の残高を超える支払いを登録したら ",[51,3036,2034],{}," が立つことも確かめる。",[51,3039,3040],{},"test_api.py"," の全文はこうなる。",[77,3043,3045],{"className":282,"code":3044,"filename":3040,"language":284,"meta":82,"style":82},"\"\"\"ミニ仕訳帳APIのテスト。\n\nシード5件に対する残高試算表の期待値表をそのまま固定し、\n貸借一致・異常残高の検知までを自動で確かめる。\n実行: uv run pytest -q\n\"\"\"\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nimport api\n\nclient = TestClient(api.app)\nHEADERS = {\"X-API-Key\": api.API_KEY}\n\n\n@pytest.fixture(autouse=True)\ndef reset_entries():\n    \"\"\"各テストの前にシード5件の状態へ戻す（テスト間の独立性を保つ）。\"\"\"\n    api.ENTRIES[:] = api.seed_entries()\n    yield\n\n\n# ---- 期待値表（シード5件に対する残高試算表） ----\nEXPECTED_ROWS = {\n    \"現金\": {\"debit_total\": 180_000, \"credit_total\": 85_000, \"balance_side\": \"借方\", \"balance\": 95_000},\n    \"普通預金\": {\"debit_total\": 50_000, \"credit_total\": 0, \"balance_side\": \"借方\", \"balance\": 50_000},\n    \"仕入高\": {\"debit_total\": 30_000, \"credit_total\": 0, \"balance_side\": \"借方\", \"balance\": 30_000},\n    \"消耗品費\": {\"debit_total\": 5_000, \"credit_total\": 0, \"balance_side\": \"借方\", \"balance\": 5_000},\n    \"売上高\": {\"debit_total\": 0, \"credit_total\": 80_000, \"balance_side\": \"貸方\", \"balance\": 80_000},\n    \"資本金\": {\"debit_total\": 0, \"credit_total\": 100_000, \"balance_side\": \"貸方\", \"balance\": 100_000},\n}\n\n\ndef get_trial_balance() -> dict:\n    res = client.get(\"/trial-balance\", headers=HEADERS)\n    assert res.status_code == 200\n    return res.json()\n\n\ndef test_trial_balance_matches_expected_table():\n    \"\"\"①期待値表そのもの（全科目・is_abnormalはすべてfalse）。\"\"\"\n    tb = get_trial_balance()\n    rows = {a[\"account\"]: a for a in tb[\"accounts\"]}\n    assert set(rows) == set(EXPECTED_ROWS)\n    for account, expected in EXPECTED_ROWS.items():\n        actual = rows[account]\n        for key, value in expected.items():\n            assert actual[key] == value, f\"{account}.{key}: {actual[key]} != {value}\"\n        assert actual[\"is_abnormal\"] is False, f\"{account} が異常残高扱いになっている\"\n\n\ndef test_debit_total_equals_credit_total():\n    \"\"\"②借方合計＝貸方合計（265,000円）。\"\"\"\n    total = get_trial_balance()[\"total\"]\n    assert total[\"debit_total\"] == 265_000\n    assert total[\"credit_total\"] == 265_000\n    assert total[\"in_balance\"] is True\n\n\ndef test_debit_balances_equal_credit_balances():\n    \"\"\"③借方残の合計＝貸方残の合計（180,000円）。\"\"\"\n    accounts = get_trial_balance()[\"accounts\"]\n    debit_balances = sum(a[\"balance\"] for a in accounts if a[\"balance_side\"] == \"借方\")\n    credit_balances = sum(a[\"balance\"] for a in accounts if a[\"balance_side\"] == \"貸方\")\n    assert debit_balances == 180_000\n    assert credit_balances == 180_000\n\n\ndef test_abnormal_balance_is_detected():\n    \"\"\"④現金がマイナスになる仕訳を追加すると is_abnormal: true が立つ。\"\"\"\n    res = client.post(\n        \"/journal-entries\",\n        headers=HEADERS,\n        json={\n            \"date\": \"2026-07-31\",\n            \"debit_account\": \"仕入高\",\n            \"credit_account\": \"現金\",\n            \"amount\": 200_000,\n            \"description\": \"残高を超える仕入（異常検知テスト）\",\n        },\n    )\n    assert res.status_code == 201\n    cash = next(a for a in get_trial_balance()[\"accounts\"] if a[\"account\"] == \"現金\")\n    assert cash[\"balance_side\"] == \"貸方\"  # 資産なのに貸方残\n    assert cash[\"normal_side\"] == \"借方\"\n    assert cash[\"is_abnormal\"] is True\n\n\ndef test_register_and_list():\n    \"\"\"正常登録（201）と一覧・month絞り込み。\"\"\"\n    res = client.post(\n        \"/journal-entries\",\n        headers=HEADERS,\n        json={\n            \"date\": \"2026-08-01\",\n            \"debit_account\": \"消耗品費\",\n            \"credit_account\": \"現金\",\n            \"amount\": 3_300,\n            \"description\": \"コピー用紙\",\n        },\n    )\n    assert res.status_code == 201\n    assert res.json()[\"id\"] == 6\n\n    all_entries = client.get(\"/journal-entries\", headers=HEADERS).json()\n    assert len(all_entries) == 6\n    july = client.get(\"/journal-entries\", params={\"month\": \"2026-07\"}, headers=HEADERS).json()\n    assert len(july) == 5\n    august = client.get(\"/journal-entries\", params={\"month\": \"2026-08\"}, headers=HEADERS).json()\n    assert len(august) == 1\n\n\ndef test_missing_or_wrong_api_key_returns_401():\n    assert client.get(\"/journal-entries\").status_code == 401\n    assert client.get(\"/journal-entries\", headers={\"X-API-Key\": \"wrong\"}).status_code == 401\n\n\n@pytest.mark.parametrize(\n    \"patch\",\n    [\n        {\"debit_account\": \"雑費\"},  # ホワイトリスト外の科目\n        {\"amount\": 0},  # 正の整数でない\n        {\"amount\": -100},\n        {\"date\": \"2026/07/25\"},  # YYYY-MM-DD でない\n    ],\n)\ndef test_invalid_input_returns_422(patch):\n    body = {\n        \"date\": \"2026-07-25\",\n        \"debit_account\": \"消耗品費\",\n        \"credit_account\": \"現金\",\n        \"amount\": 3_300,\n        \"description\": \"バリデーションテスト\",\n    } | patch\n    res = client.post(\"/journal-entries\", headers=HEADERS, json=body)\n    assert res.status_code == 422\n\n\ndef test_unknown_account_error_lists_allowed_accounts():\n    \"\"\"422のエラー文に「使える科目」の案内が入る（エラー整形の伏線）。\"\"\"\n    res = client.post(\n        \"/journal-entries\",\n        headers=HEADERS,\n        json={\n            \"date\": \"2026-07-26\",\n            \"debit_account\": \"雑費\",\n            \"credit_account\": \"現金\",\n            \"amount\": 1_200,\n            \"description\": \"エラー系の固定依頼文と同じ内容\",\n        },\n    )\n    assert res.status_code == 422\n    message = res.json()[\"detail\"][0][\"msg\"]\n    assert \"雑費\" in message\n    assert \"現金\" in message  # 使える科目一覧が含まれる\n",[51,3046,3047,3054,3058,3063,3068,3073,3077,3081,3087,3103,3107,3114,3118,3139,3166,3170,3174,3198,3207,3216,3239,3244,3248,3252,3257,3266,3334,3398,3462,3526,3590,3654,3658,3662,3666,3680,3713,3731,3744,3748,3752,3761,3770,3781,3824,3847,3869,3885,3908,3977,4015,4019,4023,4032,4041,4061,4083,4103,4124,4128,4132,4141,4150,4168,4224,4279,4291,4302,4306,4310,4319,4328,4342,4352,4363,4371,4390,4408,4426,4442,4462,4466,4471,4486,4543,4571,4595,4615,4619,4623,4632,4641,4655,4665,4675,4681,4700,4718,4736,4751,4770,4774,4778,4792,4817,4821,4857,4875,4935,4953,5009,5026,5030,5034,5043,5070,5118,5122,5126,5144,5155,5160,5185,5204,5224,5248,5253,5257,5270,5279,5298,5316,5334,5348,5367,5377,5417,5432,5436,5440,5449,5458,5472,5482,5492,5498,5517,5535,5553,5568,5587,5591,5595,5609,5648,5664],{"__ignoreMap":82},[86,3048,3049,3051],{"class":88,"line":89},[86,3050,291],{"class":138},[86,3052,3053],{"class":96},"ミニ仕訳帳APIのテスト。\n",[86,3055,3056],{"class":88,"line":111},[86,3057,300],{"emptyLinePlaceholder":299},[86,3059,3060],{"class":88,"line":121},[86,3061,3062],{"class":96},"シード5件に対する残高試算表の期待値表をそのまま固定し、\n",[86,3064,3065],{"class":88,"line":148},[86,3066,3067],{"class":96},"貸借一致・異常残高の検知までを自動で確かめる。\n",[86,3069,3070],{"class":88,"line":313},[86,3071,3072],{"class":96},"実行: uv run pytest -q\n",[86,3074,3075],{"class":88,"line":319},[86,3076,316],{"class":138},[86,3078,3079],{"class":88,"line":324},[86,3080,300],{"emptyLinePlaceholder":299},[86,3082,3083,3085],{"class":88,"line":341},[86,3084,328],{"class":327},[86,3086,158],{"class":331},[86,3088,3089,3091,3093,3095,3098,3100],{"class":88,"line":346},[86,3090,349],{"class":327},[86,3092,129],{"class":331},[86,3094,823],{"class":360},[86,3096,3097],{"class":331},"testclient ",[86,3099,328],{"class":327},[86,3101,3102],{"class":331}," TestClient\n",[86,3104,3105],{"class":88,"line":382},[86,3106,300],{"emptyLinePlaceholder":299},[86,3108,3109,3111],{"class":88,"line":405},[86,3110,328],{"class":327},[86,3112,3113],{"class":331}," api\n",[86,3115,3116],{"class":88,"line":410},[86,3117,300],{"emptyLinePlaceholder":299},[86,3119,3120,3123,3125,3128,3130,3133,3135,3137],{"class":88,"line":417},[86,3121,3122],{"class":331},"client ",[86,3124,871],{"class":360},[86,3126,3127],{"class":331}," TestClient",[86,3129,787],{"class":360},[86,3131,3132],{"class":331},"api",[86,3134,823],{"class":360},[86,3136,2474],{"class":331},[86,3138,891],{"class":360},[86,3140,3141,3144,3146,3149,3151,3153,3155,3157,3160,3162,3164],{"class":88,"line":433},[86,3142,3143],{"class":103},"HEADERS",[86,3145,423],{"class":360},[86,3147,3148],{"class":360}," {",[86,3150,484],{"class":138},[86,3152,256],{"class":96},[86,3154,484],{"class":138},[86,3156,450],{"class":360},[86,3158,3159],{"class":331}," api",[86,3161,823],{"class":360},[86,3163,420],{"class":103},[86,3165,626],{"class":360},[86,3167,3168],{"class":88,"line":438},[86,3169,300],{"emptyLinePlaceholder":299},[86,3171,3172],{"class":88,"line":444},[86,3173,300],{"emptyLinePlaceholder":299},[86,3175,3176,3178,3181,3183,3186,3188,3191,3193,3196],{"class":88,"line":475},[86,3177,2471],{"class":360},[86,3179,3180],{"class":92},"pytest",[86,3182,823],{"class":360},[86,3184,3185],{"class":92},"fixture",[86,3187,787],{"class":360},[86,3189,3190],{"class":867},"autouse",[86,3192,871],{"class":360},[86,3194,3195],{"class":327},"True",[86,3197,891],{"class":360},[86,3199,3200,3202,3205],{"class":88,"line":499},[86,3201,1129],{"class":779},[86,3203,3204],{"class":92}," reset_entries",[86,3206,1676],{"class":360},[86,3208,3209,3211,3214],{"class":88,"line":519},[86,3210,799],{"class":138},[86,3212,3213],{"class":96},"各テストの前にシード5件の状態へ戻す（テスト間の独立性を保つ）。",[86,3215,316],{"class":138},[86,3217,3218,3221,3223,3225,3228,3230,3232,3234,3237],{"class":88,"line":540},[86,3219,3220],{"class":331},"    api",[86,3222,823],{"class":360},[86,3224,1550],{"class":103},[86,3226,3227],{"class":360},"[:]",[86,3229,423],{"class":360},[86,3231,3159],{"class":331},[86,3233,823],{"class":360},[86,3235,3236],{"class":331},"seed_entries",[86,3238,1567],{"class":360},[86,3240,3241],{"class":88,"line":561},[86,3242,3243],{"class":327},"    yield\n",[86,3245,3246],{"class":88,"line":582},[86,3247,300],{"emptyLinePlaceholder":299},[86,3249,3250],{"class":88,"line":603},[86,3251,300],{"emptyLinePlaceholder":299},[86,3253,3254],{"class":88,"line":623},[86,3255,3256],{"class":413},"# ---- 期待値表（シード5件に対する残高試算表） ----\n",[86,3258,3259,3262,3264],{"class":88,"line":629},[86,3260,3261],{"class":103},"EXPECTED_ROWS",[86,3263,423],{"class":360},[86,3265,472],{"class":360},[86,3267,3268,3270,3272,3274,3276,3278,3280,3282,3284,3286,3289,3291,3293,3295,3297,3299,3302,3304,3306,3308,3310,3312,3314,3316,3318,3320,3322,3324,3326,3328,3331],{"class":88,"line":634},[86,3269,478],{"class":138},[86,3271,481],{"class":96},[86,3273,484],{"class":138},[86,3275,450],{"class":360},[86,3277,3148],{"class":360},[86,3279,484],{"class":138},[86,3281,1944],{"class":96},[86,3283,484],{"class":138},[86,3285,450],{"class":360},[86,3287,3288],{"class":107}," 180_000",[86,3290,361],{"class":360},[86,3292,139],{"class":138},[86,3294,1961],{"class":96},[86,3296,484],{"class":138},[86,3298,450],{"class":360},[86,3300,3301],{"class":107}," 85_000",[86,3303,361],{"class":360},[86,3305,139],{"class":138},[86,3307,1978],{"class":96},[86,3309,484],{"class":138},[86,3311,450],{"class":360},[86,3313,139],{"class":138},[86,3315,677],{"class":96},[86,3317,484],{"class":138},[86,3319,361],{"class":360},[86,3321,139],{"class":138},[86,3323,1995],{"class":96},[86,3325,484],{"class":138},[86,3327,450],{"class":360},[86,3329,3330],{"class":107}," 95_000",[86,3332,3333],{"class":360},"},\n",[86,3335,3336,3338,3340,3342,3344,3346,3348,3350,3352,3354,3356,3358,3360,3362,3364,3366,3368,3370,3372,3374,3376,3378,3380,3382,3384,3386,3388,3390,3392,3394,3396],{"class":88,"line":640},[86,3337,478],{"class":138},[86,3339,504],{"class":96},[86,3341,484],{"class":138},[86,3343,450],{"class":360},[86,3345,3148],{"class":360},[86,3347,484],{"class":138},[86,3349,1944],{"class":96},[86,3351,484],{"class":138},[86,3353,450],{"class":360},[86,3355,1370],{"class":107},[86,3357,361],{"class":360},[86,3359,139],{"class":138},[86,3361,1961],{"class":96},[86,3363,484],{"class":138},[86,3365,450],{"class":360},[86,3367,1780],{"class":107},[86,3369,361],{"class":360},[86,3371,139],{"class":138},[86,3373,1978],{"class":96},[86,3375,484],{"class":138},[86,3377,450],{"class":360},[86,3379,139],{"class":138},[86,3381,677],{"class":96},[86,3383,484],{"class":138},[86,3385,361],{"class":360},[86,3387,139],{"class":138},[86,3389,1995],{"class":96},[86,3391,484],{"class":138},[86,3393,450],{"class":360},[86,3395,1370],{"class":107},[86,3397,3333],{"class":360},[86,3399,3400,3402,3404,3406,3408,3410,3412,3414,3416,3418,3420,3422,3424,3426,3428,3430,3432,3434,3436,3438,3440,3442,3444,3446,3448,3450,3452,3454,3456,3458,3460],{"class":88,"line":664},[86,3401,478],{"class":138},[86,3403,587],{"class":96},[86,3405,484],{"class":138},[86,3407,450],{"class":360},[86,3409,3148],{"class":360},[86,3411,484],{"class":138},[86,3413,1944],{"class":96},[86,3415,484],{"class":138},[86,3417,450],{"class":360},[86,3419,1238],{"class":107},[86,3421,361],{"class":360},[86,3423,139],{"class":138},[86,3425,1961],{"class":96},[86,3427,484],{"class":138},[86,3429,450],{"class":360},[86,3431,1780],{"class":107},[86,3433,361],{"class":360},[86,3435,139],{"class":138},[86,3437,1978],{"class":96},[86,3439,484],{"class":138},[86,3441,450],{"class":360},[86,3443,139],{"class":138},[86,3445,677],{"class":96},[86,3447,484],{"class":138},[86,3449,361],{"class":360},[86,3451,139],{"class":138},[86,3453,1995],{"class":96},[86,3455,484],{"class":138},[86,3457,450],{"class":360},[86,3459,1238],{"class":107},[86,3461,3333],{"class":360},[86,3463,3464,3466,3468,3470,3472,3474,3476,3478,3480,3482,3484,3486,3488,3490,3492,3494,3496,3498,3500,3502,3504,3506,3508,3510,3512,3514,3516,3518,3520,3522,3524],{"class":88,"line":684},[86,3465,478],{"class":138},[86,3467,608],{"class":96},[86,3469,484],{"class":138},[86,3471,450],{"class":360},[86,3473,3148],{"class":360},[86,3475,484],{"class":138},[86,3477,1944],{"class":96},[86,3479,484],{"class":138},[86,3481,450],{"class":360},[86,3483,1326],{"class":107},[86,3485,361],{"class":360},[86,3487,139],{"class":138},[86,3489,1961],{"class":96},[86,3491,484],{"class":138},[86,3493,450],{"class":360},[86,3495,1780],{"class":107},[86,3497,361],{"class":360},[86,3499,139],{"class":138},[86,3501,1978],{"class":96},[86,3503,484],{"class":138},[86,3505,450],{"class":360},[86,3507,139],{"class":138},[86,3509,677],{"class":96},[86,3511,484],{"class":138},[86,3513,361],{"class":360},[86,3515,139],{"class":138},[86,3517,1995],{"class":96},[86,3519,484],{"class":138},[86,3521,450],{"class":360},[86,3523,1326],{"class":107},[86,3525,3333],{"class":360},[86,3527,3528,3530,3532,3534,3536,3538,3540,3542,3544,3546,3548,3550,3552,3554,3556,3558,3560,3562,3564,3566,3568,3570,3572,3574,3576,3578,3580,3582,3584,3586,3588],{"class":88,"line":703},[86,3529,478],{"class":138},[86,3531,566],{"class":96},[86,3533,484],{"class":138},[86,3535,450],{"class":360},[86,3537,3148],{"class":360},[86,3539,484],{"class":138},[86,3541,1944],{"class":96},[86,3543,484],{"class":138},[86,3545,450],{"class":360},[86,3547,1780],{"class":107},[86,3549,361],{"class":360},[86,3551,139],{"class":138},[86,3553,1961],{"class":96},[86,3555,484],{"class":138},[86,3557,450],{"class":360},[86,3559,1282],{"class":107},[86,3561,361],{"class":360},[86,3563,139],{"class":138},[86,3565,1978],{"class":96},[86,3567,484],{"class":138},[86,3569,450],{"class":360},[86,3571,139],{"class":138},[86,3573,716],{"class":96},[86,3575,484],{"class":138},[86,3577,361],{"class":360},[86,3579,139],{"class":138},[86,3581,1995],{"class":96},[86,3583,484],{"class":138},[86,3585,450],{"class":360},[86,3587,1282],{"class":107},[86,3589,3333],{"class":360},[86,3591,3592,3594,3596,3598,3600,3602,3604,3606,3608,3610,3612,3614,3616,3618,3620,3622,3624,3626,3628,3630,3632,3634,3636,3638,3640,3642,3644,3646,3648,3650,3652],{"class":88,"line":723},[86,3593,478],{"class":138},[86,3595,545],{"class":96},[86,3597,484],{"class":138},[86,3599,450],{"class":360},[86,3601,3148],{"class":360},[86,3603,484],{"class":138},[86,3605,1944],{"class":96},[86,3607,484],{"class":138},[86,3609,450],{"class":360},[86,3611,1780],{"class":107},[86,3613,361],{"class":360},[86,3615,139],{"class":138},[86,3617,1961],{"class":96},[86,3619,484],{"class":138},[86,3621,450],{"class":360},[86,3623,1193],{"class":107},[86,3625,361],{"class":360},[86,3627,139],{"class":138},[86,3629,1978],{"class":96},[86,3631,484],{"class":138},[86,3633,450],{"class":360},[86,3635,139],{"class":138},[86,3637,716],{"class":96},[86,3639,484],{"class":138},[86,3641,361],{"class":360},[86,3643,139],{"class":138},[86,3645,1995],{"class":96},[86,3647,484],{"class":138},[86,3649,450],{"class":360},[86,3651,1193],{"class":107},[86,3653,3333],{"class":360},[86,3655,3656],{"class":88,"line":742},[86,3657,626],{"class":360},[86,3659,3660],{"class":88,"line":761},[86,3661,300],{"emptyLinePlaceholder":299},[86,3663,3664],{"class":88,"line":766},[86,3665,300],{"emptyLinePlaceholder":299},[86,3667,3668,3670,3672,3674,3676,3678],{"class":88,"line":771},[86,3669,1129],{"class":779},[86,3671,2885],{"class":92},[86,3673,1135],{"class":360},[86,3675,977],{"class":360},[86,3677,453],{"class":114},[86,3679,982],{"class":360},[86,3681,3682,3685,3687,3690,3692,3694,3696,3698,3700,3702,3704,3707,3709,3711],{"class":88,"line":776},[86,3683,3684],{"class":331},"    res ",[86,3686,871],{"class":360},[86,3688,3689],{"class":331}," client",[86,3691,823],{"class":360},[86,3693,2479],{"class":331},[86,3695,787],{"class":360},[86,3697,484],{"class":138},[86,3699,2873],{"class":96},[86,3701,484],{"class":138},[86,3703,361],{"class":360},[86,3705,3706],{"class":867}," headers",[86,3708,871],{"class":360},[86,3710,3143],{"class":103},[86,3712,891],{"class":360},[86,3714,3715,3718,3721,3723,3726,3728],{"class":88,"line":796},[86,3716,3717],{"class":327},"    assert",[86,3719,3720],{"class":331}," res",[86,3722,823],{"class":360},[86,3724,3725],{"class":331},"status_code ",[86,3727,1722],{"class":779},[86,3729,3730],{"class":107}," 200\n",[86,3732,3733,3735,3737,3739,3742],{"class":88,"line":807},[86,3734,1393],{"class":327},[86,3736,3720],{"class":331},[86,3738,823],{"class":360},[86,3740,3741],{"class":331},"json",[86,3743,1567],{"class":360},[86,3745,3746],{"class":88,"line":812},[86,3747,300],{"emptyLinePlaceholder":299},[86,3749,3750],{"class":88,"line":829},[86,3751,300],{"emptyLinePlaceholder":299},[86,3753,3754,3756,3759],{"class":88,"line":840},[86,3755,1129],{"class":779},[86,3757,3758],{"class":92}," test_trial_balance_matches_expected_table",[86,3760,1676],{"class":360},[86,3762,3763,3765,3768],{"class":88,"line":850},[86,3764,799],{"class":138},[86,3766,3767],{"class":96},"①期待値表そのもの（全科目・is_abnormalはすべてfalse）。",[86,3769,316],{"class":138},[86,3771,3772,3775,3777,3779],{"class":88,"line":894},[86,3773,3774],{"class":331},"    tb ",[86,3776,871],{"class":360},[86,3778,2885],{"class":331},[86,3780,1567],{"class":360},[86,3782,3783,3785,3787,3789,3791,3793,3795,3797,3799,3802,3804,3806,3808,3810,3813,3815,3817,3819,3821],{"class":88,"line":909},[86,3784,1154],{"class":331},[86,3786,871],{"class":360},[86,3788,3148],{"class":360},[86,3790,17],{"class":331},[86,3792,456],{"class":360},[86,3794,484],{"class":138},[86,3796,1912],{"class":96},[86,3798,484],{"class":138},[86,3800,3801],{"class":360},"]:",[86,3803,2102],{"class":331},[86,3805,1700],{"class":327},[86,3807,2102],{"class":331},[86,3809,1666],{"class":327},[86,3811,3812],{"class":331}," tb",[86,3814,456],{"class":360},[86,3816,484],{"class":138},[86,3818,2159],{"class":96},[86,3820,484],{"class":138},[86,3822,3823],{"class":360},"]}\n",[86,3825,3826,3828,3831,3833,3835,3837,3839,3841,3843,3845],{"class":88,"line":914},[86,3827,3717],{"class":327},[86,3829,3830],{"class":114}," set",[86,3832,787],{"class":360},[86,3834,1517],{"class":331},[86,3836,974],{"class":360},[86,3838,2656],{"class":779},[86,3840,3830],{"class":114},[86,3842,787],{"class":360},[86,3844,3261],{"class":103},[86,3846,891],{"class":360},[86,3848,3849,3851,3853,3855,3858,3860,3863,3865,3867],{"class":88,"line":943},[86,3850,1655],{"class":327},[86,3852,1658],{"class":331},[86,3854,361],{"class":360},[86,3856,3857],{"class":331}," expected ",[86,3859,1666],{"class":327},[86,3861,3862],{"class":103}," EXPECTED_ROWS",[86,3864,823],{"class":360},[86,3866,1673],{"class":331},[86,3868,1676],{"class":360},[86,3870,3871,3874,3876,3879,3881,3883],{"class":88,"line":951},[86,3872,3873],{"class":331},"        actual ",[86,3875,871],{"class":360},[86,3877,3878],{"class":331}," rows",[86,3880,456],{"class":360},[86,3882,1912],{"class":331},[86,3884,1884],{"class":360},[86,3886,3887,3889,3892,3894,3897,3899,3902,3904,3906],{"class":88,"line":985},[86,3888,1475],{"class":327},[86,3890,3891],{"class":331}," key",[86,3893,361],{"class":360},[86,3895,3896],{"class":331}," value ",[86,3898,1666],{"class":327},[86,3900,3901],{"class":331}," expected",[86,3903,823],{"class":360},[86,3905,1673],{"class":331},[86,3907,1676],{"class":360},[86,3909,3910,3913,3916,3918,3921,3923,3925,3928,3930,3933,3935,3937,3939,3941,3943,3945,3947,3949,3952,3954,3957,3959,3961,3963,3965,3968,3970,3973,3975],{"class":88,"line":1005},[86,3911,3912],{"class":327},"            assert",[86,3914,3915],{"class":331}," actual",[86,3917,456],{"class":360},[86,3919,3920],{"class":331},"key",[86,3922,467],{"class":360},[86,3924,2656],{"class":779},[86,3926,3927],{"class":331}," value",[86,3929,361],{"class":360},[86,3931,3932],{"class":779}," f",[86,3934,484],{"class":96},[86,3936,1048],{"class":103},[86,3938,1912],{"class":331},[86,3940,1054],{"class":103},[86,3942,823],{"class":96},[86,3944,1048],{"class":103},[86,3946,3920],{"class":331},[86,3948,1054],{"class":103},[86,3950,3951],{"class":96},": ",[86,3953,1048],{"class":103},[86,3955,3956],{"class":331},"actual",[86,3958,456],{"class":360},[86,3960,3920],{"class":331},[86,3962,467],{"class":360},[86,3964,1054],{"class":103},[86,3966,3967],{"class":96}," != ",[86,3969,1048],{"class":103},[86,3971,3972],{"class":331},"value",[86,3974,1054],{"class":103},[86,3976,145],{"class":96},[86,3978,3979,3982,3984,3986,3988,3990,3992,3994,3997,4000,4002,4004,4006,4008,4010,4012],{"class":88,"line":1031},[86,3980,3981],{"class":327},"        assert",[86,3983,3915],{"class":331},[86,3985,456],{"class":360},[86,3987,484],{"class":138},[86,3989,2034],{"class":96},[86,3991,484],{"class":138},[86,3993,467],{"class":360},[86,3995,3996],{"class":779}," is",[86,3998,3999],{"class":327}," False",[86,4001,361],{"class":360},[86,4003,3932],{"class":779},[86,4005,484],{"class":96},[86,4007,1048],{"class":103},[86,4009,1912],{"class":331},[86,4011,1054],{"class":103},[86,4013,4014],{"class":96}," が異常残高扱いになっている\"\n",[86,4016,4017],{"class":88,"line":1071},[86,4018,300],{"emptyLinePlaceholder":299},[86,4020,4021],{"class":88,"line":1080},[86,4022,300],{"emptyLinePlaceholder":299},[86,4024,4025,4027,4030],{"class":88,"line":1085},[86,4026,1129],{"class":779},[86,4028,4029],{"class":92}," test_debit_total_equals_credit_total",[86,4031,1676],{"class":360},[86,4033,4034,4036,4039],{"class":88,"line":1090},[86,4035,799],{"class":138},[86,4037,4038],{"class":96},"②借方合計＝貸方合計（265,000円）。",[86,4040,316],{"class":138},[86,4042,4043,4046,4048,4050,4053,4055,4057,4059],{"class":88,"line":1105},[86,4044,4045],{"class":331},"    total ",[86,4047,871],{"class":360},[86,4049,2885],{"class":331},[86,4051,4052],{"class":360},"()[",[86,4054,484],{"class":138},[86,4056,2175],{"class":96},[86,4058,484],{"class":138},[86,4060,1884],{"class":360},[86,4062,4063,4065,4068,4070,4072,4074,4076,4078,4080],{"class":88,"line":1116},[86,4064,3717],{"class":327},[86,4066,4067],{"class":331}," total",[86,4069,456],{"class":360},[86,4071,484],{"class":138},[86,4073,1944],{"class":96},[86,4075,484],{"class":138},[86,4077,467],{"class":360},[86,4079,2656],{"class":779},[86,4081,4082],{"class":107}," 265_000\n",[86,4084,4085,4087,4089,4091,4093,4095,4097,4099,4101],{"class":88,"line":1121},[86,4086,3717],{"class":327},[86,4088,4067],{"class":331},[86,4090,456],{"class":360},[86,4092,484],{"class":138},[86,4094,1961],{"class":96},[86,4096,484],{"class":138},[86,4098,467],{"class":360},[86,4100,2656],{"class":779},[86,4102,4082],{"class":107},[86,4104,4105,4107,4109,4111,4113,4115,4117,4119,4121],{"class":88,"line":1126},[86,4106,3717],{"class":327},[86,4108,4067],{"class":331},[86,4110,456],{"class":360},[86,4112,484],{"class":138},[86,4114,2222],{"class":96},[86,4116,484],{"class":138},[86,4118,467],{"class":360},[86,4120,3996],{"class":779},[86,4122,4123],{"class":327}," True\n",[86,4125,4126],{"class":88,"line":1151},[86,4127,300],{"emptyLinePlaceholder":299},[86,4129,4130],{"class":88,"line":1162},[86,4131,300],{"emptyLinePlaceholder":299},[86,4133,4134,4136,4139],{"class":88,"line":1208},[86,4135,1129],{"class":779},[86,4137,4138],{"class":92}," test_debit_balances_equal_credit_balances",[86,4140,1676],{"class":360},[86,4142,4143,4145,4148],{"class":88,"line":1252},[86,4144,799],{"class":138},[86,4146,4147],{"class":96},"③借方残の合計＝貸方残の合計（180,000円）。",[86,4149,316],{"class":138},[86,4151,4152,4154,4156,4158,4160,4162,4164,4166],{"class":88,"line":1296},[86,4153,1644],{"class":331},[86,4155,871],{"class":360},[86,4157,2885],{"class":331},[86,4159,4052],{"class":360},[86,4161,484],{"class":138},[86,4163,2159],{"class":96},[86,4165,484],{"class":138},[86,4167,1884],{"class":360},[86,4169,4170,4173,4175,4177,4179,4181,4183,4185,4187,4189,4191,4193,4195,4197,4200,4202,4204,4206,4208,4210,4212,4214,4216,4218,4220,4222],{"class":88,"line":1340},[86,4171,4172],{"class":331},"    debit_balances ",[86,4174,871],{"class":360},[86,4176,1687],{"class":114},[86,4178,787],{"class":360},[86,4180,17],{"class":331},[86,4182,456],{"class":360},[86,4184,484],{"class":138},[86,4186,1995],{"class":96},[86,4188,484],{"class":138},[86,4190,467],{"class":360},[86,4192,2099],{"class":327},[86,4194,2102],{"class":331},[86,4196,1666],{"class":327},[86,4198,4199],{"class":331}," accounts ",[86,4201,1711],{"class":327},[86,4203,1500],{"class":331},[86,4205,456],{"class":360},[86,4207,484],{"class":138},[86,4209,1978],{"class":96},[86,4211,484],{"class":138},[86,4213,467],{"class":360},[86,4215,2656],{"class":779},[86,4217,139],{"class":138},[86,4219,677],{"class":96},[86,4221,484],{"class":138},[86,4223,891],{"class":360},[86,4225,4226,4229,4231,4233,4235,4237,4239,4241,4243,4245,4247,4249,4251,4253,4255,4257,4259,4261,4263,4265,4267,4269,4271,4273,4275,4277],{"class":88,"line":1384},[86,4227,4228],{"class":331},"    credit_balances ",[86,4230,871],{"class":360},[86,4232,1687],{"class":114},[86,4234,787],{"class":360},[86,4236,17],{"class":331},[86,4238,456],{"class":360},[86,4240,484],{"class":138},[86,4242,1995],{"class":96},[86,4244,484],{"class":138},[86,4246,467],{"class":360},[86,4248,2099],{"class":327},[86,4250,2102],{"class":331},[86,4252,1666],{"class":327},[86,4254,4199],{"class":331},[86,4256,1711],{"class":327},[86,4258,1500],{"class":331},[86,4260,456],{"class":360},[86,4262,484],{"class":138},[86,4264,1978],{"class":96},[86,4266,484],{"class":138},[86,4268,467],{"class":360},[86,4270,2656],{"class":779},[86,4272,139],{"class":138},[86,4274,716],{"class":96},[86,4276,484],{"class":138},[86,4278,891],{"class":360},[86,4280,4281,4283,4286,4288],{"class":88,"line":1390},[86,4282,3717],{"class":327},[86,4284,4285],{"class":331}," debit_balances ",[86,4287,1722],{"class":779},[86,4289,4290],{"class":107}," 180_000\n",[86,4292,4293,4295,4298,4300],{"class":88,"line":1398},[86,4294,3717],{"class":327},[86,4296,4297],{"class":331}," credit_balances ",[86,4299,1722],{"class":779},[86,4301,4290],{"class":107},[86,4303,4304],{"class":88,"line":1407},[86,4305,300],{"emptyLinePlaceholder":299},[86,4307,4308],{"class":88,"line":1466},[86,4309,300],{"emptyLinePlaceholder":299},[86,4311,4312,4314,4317],{"class":88,"line":1472},[86,4313,1129],{"class":779},[86,4315,4316],{"class":92}," test_abnormal_balance_is_detected",[86,4318,1676],{"class":360},[86,4320,4321,4323,4326],{"class":88,"line":1532},[86,4322,799],{"class":138},[86,4324,4325],{"class":96},"④現金がマイナスになる仕訳を追加すると is_abnormal: true が立つ。",[86,4327,316],{"class":138},[86,4329,4330,4332,4334,4336,4338,4340],{"class":88,"line":1537},[86,4331,3684],{"class":331},[86,4333,871],{"class":360},[86,4335,3689],{"class":331},[86,4337,823],{"class":360},[86,4339,2683],{"class":331},[86,4341,1404],{"class":360},[86,4343,4344,4346,4348,4350],{"class":88,"line":1542},[86,4345,2156],{"class":138},[86,4347,2486],{"class":96},[86,4349,484],{"class":138},[86,4351,496],{"class":360},[86,4353,4354,4357,4359,4361],{"class":88,"line":1547},[86,4355,4356],{"class":867},"        headers",[86,4358,871],{"class":360},[86,4360,3143],{"class":103},[86,4362,496],{"class":360},[86,4364,4365,4368],{"class":88,"line":1570},[86,4366,4367],{"class":867},"        json",[86,4369,4370],{"class":360},"={\n",[86,4372,4373,4375,4377,4379,4381,4383,4386,4388],{"class":88,"line":1575},[86,4374,2187],{"class":138},[86,4376,2637],{"class":96},[86,4378,484],{"class":138},[86,4380,450],{"class":360},[86,4382,139],{"class":138},[86,4384,4385],{"class":96},"2026-07-31",[86,4387,484],{"class":138},[86,4389,496],{"class":360},[86,4391,4392,4394,4396,4398,4400,4402,4404,4406],{"class":88,"line":1580},[86,4393,2187],{"class":138},[86,4395,927],{"class":96},[86,4397,484],{"class":138},[86,4399,450],{"class":360},[86,4401,139],{"class":138},[86,4403,587],{"class":96},[86,4405,484],{"class":138},[86,4407,496],{"class":360},[86,4409,4410,4412,4414,4416,4418,4420,4422,4424],{"class":88,"line":1610},[86,4411,2187],{"class":138},[86,4413,936],{"class":96},[86,4415,484],{"class":138},[86,4417,450],{"class":360},[86,4419,139],{"class":138},[86,4421,481],{"class":96},[86,4423,484],{"class":138},[86,4425,496],{"class":360},[86,4427,4428,4430,4433,4435,4437,4440],{"class":88,"line":1618},[86,4429,2187],{"class":138},[86,4431,4432],{"class":96},"amount",[86,4434,484],{"class":138},[86,4436,450],{"class":360},[86,4438,4439],{"class":107}," 200_000",[86,4441,496],{"class":360},[86,4443,4444,4446,4449,4451,4453,4455,4458,4460],{"class":88,"line":1623},[86,4445,2187],{"class":138},[86,4447,4448],{"class":96},"description",[86,4450,484],{"class":138},[86,4452,450],{"class":360},[86,4454,139],{"class":138},[86,4456,4457],{"class":96},"残高を超える仕入（異常検知テスト）",[86,4459,484],{"class":138},[86,4461,496],{"class":360},[86,4463,4464],{"class":88,"line":1629},[86,4465,2241],{"class":360},[86,4467,4468],{"class":88,"line":1635},[86,4469,4470],{"class":360},"    )\n",[86,4472,4473,4475,4477,4479,4481,4483],{"class":88,"line":1641},[86,4474,3717],{"class":327},[86,4476,3720],{"class":331},[86,4478,823],{"class":360},[86,4480,3725],{"class":331},[86,4482,1722],{"class":779},[86,4484,4485],{"class":107}," 201\n",[86,4487,4488,4491,4493,4496,4498,4501,4503,4505,4507,4509,4511,4513,4515,4517,4519,4521,4523,4525,4527,4529,4531,4533,4535,4537,4539,4541],{"class":88,"line":1652},[86,4489,4490],{"class":331},"    cash ",[86,4492,871],{"class":360},[86,4494,4495],{"class":114}," next",[86,4497,787],{"class":360},[86,4499,4500],{"class":331},"a ",[86,4502,1700],{"class":327},[86,4504,2102],{"class":331},[86,4506,1666],{"class":327},[86,4508,2885],{"class":331},[86,4510,4052],{"class":360},[86,4512,484],{"class":138},[86,4514,2159],{"class":96},[86,4516,484],{"class":138},[86,4518,467],{"class":360},[86,4520,1834],{"class":327},[86,4522,1500],{"class":331},[86,4524,456],{"class":360},[86,4526,484],{"class":138},[86,4528,1912],{"class":96},[86,4530,484],{"class":138},[86,4532,467],{"class":360},[86,4534,2656],{"class":779},[86,4536,139],{"class":138},[86,4538,481],{"class":96},[86,4540,484],{"class":138},[86,4542,891],{"class":360},[86,4544,4545,4547,4550,4552,4554,4556,4558,4560,4562,4564,4566,4568],{"class":88,"line":1679},[86,4546,3717],{"class":327},[86,4548,4549],{"class":331}," cash",[86,4551,456],{"class":360},[86,4553,484],{"class":138},[86,4555,1978],{"class":96},[86,4557,484],{"class":138},[86,4559,467],{"class":360},[86,4561,2656],{"class":779},[86,4563,139],{"class":138},[86,4565,716],{"class":96},[86,4567,484],{"class":138},[86,4569,4570],{"class":413},"  # 資産なのに貸方残\n",[86,4572,4573,4575,4577,4579,4581,4583,4585,4587,4589,4591,4593],{"class":88,"line":1729},[86,4574,3717],{"class":327},[86,4576,4549],{"class":331},[86,4578,456],{"class":360},[86,4580,484],{"class":138},[86,4582,2017],{"class":96},[86,4584,484],{"class":138},[86,4586,467],{"class":360},[86,4588,2656],{"class":779},[86,4590,139],{"class":138},[86,4592,677],{"class":96},[86,4594,145],{"class":138},[86,4596,4597,4599,4601,4603,4605,4607,4609,4611,4613],{"class":88,"line":1770},[86,4598,3717],{"class":327},[86,4600,4549],{"class":331},[86,4602,456],{"class":360},[86,4604,484],{"class":138},[86,4606,2034],{"class":96},[86,4608,484],{"class":138},[86,4610,467],{"class":360},[86,4612,3996],{"class":779},[86,4614,4123],{"class":327},[86,4616,4617],{"class":88,"line":1795},[86,4618,300],{"emptyLinePlaceholder":299},[86,4620,4621],{"class":88,"line":1804},[86,4622,300],{"emptyLinePlaceholder":299},[86,4624,4625,4627,4630],{"class":88,"line":1820},[86,4626,1129],{"class":779},[86,4628,4629],{"class":92}," test_register_and_list",[86,4631,1676],{"class":360},[86,4633,4634,4636,4639],{"class":88,"line":1868},[86,4635,799],{"class":138},[86,4637,4638],{"class":96},"正常登録（201）と一覧・month絞り込み。",[86,4640,316],{"class":138},[86,4642,4643,4645,4647,4649,4651,4653],{"class":88,"line":1887},[86,4644,3684],{"class":331},[86,4646,871],{"class":360},[86,4648,3689],{"class":331},[86,4650,823],{"class":360},[86,4652,2683],{"class":331},[86,4654,1404],{"class":360},[86,4656,4657,4659,4661,4663],{"class":88,"line":1900},[86,4658,2156],{"class":138},[86,4660,2486],{"class":96},[86,4662,484],{"class":138},[86,4664,496],{"class":360},[86,4666,4667,4669,4671,4673],{"class":88,"line":1906},[86,4668,4356],{"class":867},[86,4670,871],{"class":360},[86,4672,3143],{"class":103},[86,4674,496],{"class":360},[86,4676,4677,4679],{"class":88,"line":1923},[86,4678,4367],{"class":867},[86,4680,4370],{"class":360},[86,4682,4683,4685,4687,4689,4691,4693,4696,4698],{"class":88,"line":1939},[86,4684,2187],{"class":138},[86,4686,2637],{"class":96},[86,4688,484],{"class":138},[86,4690,450],{"class":360},[86,4692,139],{"class":138},[86,4694,4695],{"class":96},"2026-08-01",[86,4697,484],{"class":138},[86,4699,496],{"class":360},[86,4701,4702,4704,4706,4708,4710,4712,4714,4716],{"class":88,"line":1956},[86,4703,2187],{"class":138},[86,4705,927],{"class":96},[86,4707,484],{"class":138},[86,4709,450],{"class":360},[86,4711,139],{"class":138},[86,4713,608],{"class":96},[86,4715,484],{"class":138},[86,4717,496],{"class":360},[86,4719,4720,4722,4724,4726,4728,4730,4732,4734],{"class":88,"line":1973},[86,4721,2187],{"class":138},[86,4723,936],{"class":96},[86,4725,484],{"class":138},[86,4727,450],{"class":360},[86,4729,139],{"class":138},[86,4731,481],{"class":96},[86,4733,484],{"class":138},[86,4735,496],{"class":360},[86,4737,4738,4740,4742,4744,4746,4749],{"class":88,"line":1990},[86,4739,2187],{"class":138},[86,4741,4432],{"class":96},[86,4743,484],{"class":138},[86,4745,450],{"class":360},[86,4747,4748],{"class":107}," 3_300",[86,4750,496],{"class":360},[86,4752,4753,4755,4757,4759,4761,4763,4766,4768],{"class":88,"line":2012},[86,4754,2187],{"class":138},[86,4756,4448],{"class":96},[86,4758,484],{"class":138},[86,4760,450],{"class":360},[86,4762,139],{"class":138},[86,4764,4765],{"class":96},"コピー用紙",[86,4767,484],{"class":138},[86,4769,496],{"class":360},[86,4771,4772],{"class":88,"line":2029},[86,4773,2241],{"class":360},[86,4775,4776],{"class":88,"line":2064},[86,4777,4470],{"class":360},[86,4779,4780,4782,4784,4786,4788,4790],{"class":88,"line":2070},[86,4781,3717],{"class":327},[86,4783,3720],{"class":331},[86,4785,823],{"class":360},[86,4787,3725],{"class":331},[86,4789,1722],{"class":779},[86,4791,4485],{"class":107},[86,4793,4794,4796,4798,4800,4802,4804,4806,4808,4810,4812,4814],{"class":88,"line":2075},[86,4795,3717],{"class":327},[86,4797,3720],{"class":331},[86,4799,823],{"class":360},[86,4801,3741],{"class":331},[86,4803,4052],{"class":360},[86,4805,484],{"class":138},[86,4807,2800],{"class":96},[86,4809,484],{"class":138},[86,4811,467],{"class":360},[86,4813,2656],{"class":779},[86,4815,4816],{"class":107}," 6\n",[86,4818,4819],{"class":88,"line":2112},[86,4820,300],{"emptyLinePlaceholder":299},[86,4822,4823,4826,4828,4830,4832,4834,4836,4838,4840,4842,4844,4846,4848,4850,4853,4855],{"class":88,"line":2146},[86,4824,4825],{"class":331},"    all_entries ",[86,4827,871],{"class":360},[86,4829,3689],{"class":331},[86,4831,823],{"class":360},[86,4833,2479],{"class":331},[86,4835,787],{"class":360},[86,4837,484],{"class":138},[86,4839,2486],{"class":96},[86,4841,484],{"class":138},[86,4843,361],{"class":360},[86,4845,3706],{"class":867},[86,4847,871],{"class":360},[86,4849,3143],{"class":103},[86,4851,4852],{"class":360},").",[86,4854,3741],{"class":331},[86,4856,1567],{"class":360},[86,4858,4859,4861,4864,4866,4869,4871,4873],{"class":88,"line":2153},[86,4860,3717],{"class":327},[86,4862,4863],{"class":114}," len",[86,4865,787],{"class":360},[86,4867,4868],{"class":331},"all_entries",[86,4870,974],{"class":360},[86,4872,2656],{"class":779},[86,4874,4816],{"class":107},[86,4876,4877,4880,4882,4884,4886,4888,4890,4892,4894,4896,4898,4901,4904,4906,4909,4911,4913,4915,4918,4920,4923,4925,4927,4929,4931,4933],{"class":88,"line":2170},[86,4878,4879],{"class":331},"    july ",[86,4881,871],{"class":360},[86,4883,3689],{"class":331},[86,4885,823],{"class":360},[86,4887,2479],{"class":331},[86,4889,787],{"class":360},[86,4891,484],{"class":138},[86,4893,2486],{"class":96},[86,4895,484],{"class":138},[86,4897,361],{"class":360},[86,4899,4900],{"class":867}," params",[86,4902,4903],{"class":360},"={",[86,4905,484],{"class":138},[86,4907,4908],{"class":96},"month",[86,4910,484],{"class":138},[86,4912,450],{"class":360},[86,4914,139],{"class":138},[86,4916,4917],{"class":96},"2026-07",[86,4919,484],{"class":138},[86,4921,4922],{"class":360},"},",[86,4924,3706],{"class":867},[86,4926,871],{"class":360},[86,4928,3143],{"class":103},[86,4930,4852],{"class":360},[86,4932,3741],{"class":331},[86,4934,1567],{"class":360},[86,4936,4937,4939,4941,4943,4946,4948,4950],{"class":88,"line":2184},[86,4938,3717],{"class":327},[86,4940,4863],{"class":114},[86,4942,787],{"class":360},[86,4944,4945],{"class":331},"july",[86,4947,974],{"class":360},[86,4949,2656],{"class":779},[86,4951,4952],{"class":107}," 5\n",[86,4954,4955,4958,4960,4962,4964,4966,4968,4970,4972,4974,4976,4978,4980,4982,4984,4986,4988,4990,4993,4995,4997,4999,5001,5003,5005,5007],{"class":88,"line":2201},[86,4956,4957],{"class":331},"    august ",[86,4959,871],{"class":360},[86,4961,3689],{"class":331},[86,4963,823],{"class":360},[86,4965,2479],{"class":331},[86,4967,787],{"class":360},[86,4969,484],{"class":138},[86,4971,2486],{"class":96},[86,4973,484],{"class":138},[86,4975,361],{"class":360},[86,4977,4900],{"class":867},[86,4979,4903],{"class":360},[86,4981,484],{"class":138},[86,4983,4908],{"class":96},[86,4985,484],{"class":138},[86,4987,450],{"class":360},[86,4989,139],{"class":138},[86,4991,4992],{"class":96},"2026-08",[86,4994,484],{"class":138},[86,4996,4922],{"class":360},[86,4998,3706],{"class":867},[86,5000,871],{"class":360},[86,5002,3143],{"class":103},[86,5004,4852],{"class":360},[86,5006,3741],{"class":331},[86,5008,1567],{"class":360},[86,5010,5011,5013,5015,5017,5020,5022,5024],{"class":88,"line":2217},[86,5012,3717],{"class":327},[86,5014,4863],{"class":114},[86,5016,787],{"class":360},[86,5018,5019],{"class":331},"august",[86,5021,974],{"class":360},[86,5023,2656],{"class":779},[86,5025,2785],{"class":107},[86,5027,5028],{"class":88,"line":2238},[86,5029,300],{"emptyLinePlaceholder":299},[86,5031,5032],{"class":88,"line":2244},[86,5033,300],{"emptyLinePlaceholder":299},[86,5035,5036,5038,5041],{"class":88,"line":2250},[86,5037,1129],{"class":779},[86,5039,5040],{"class":92}," test_missing_or_wrong_api_key_returns_401",[86,5042,1676],{"class":360},[86,5044,5045,5047,5049,5051,5053,5055,5057,5059,5061,5063,5065,5067],{"class":88,"line":2255},[86,5046,3717],{"class":327},[86,5048,3689],{"class":331},[86,5050,823],{"class":360},[86,5052,2479],{"class":331},[86,5054,787],{"class":360},[86,5056,484],{"class":138},[86,5058,2486],{"class":96},[86,5060,484],{"class":138},[86,5062,4852],{"class":360},[86,5064,3725],{"class":331},[86,5066,1722],{"class":779},[86,5068,5069],{"class":107}," 401\n",[86,5071,5072,5074,5076,5078,5080,5082,5084,5086,5088,5090,5092,5094,5096,5098,5100,5102,5104,5107,5109,5112,5114,5116],{"class":88,"line":2260},[86,5073,3717],{"class":327},[86,5075,3689],{"class":331},[86,5077,823],{"class":360},[86,5079,2479],{"class":331},[86,5081,787],{"class":360},[86,5083,484],{"class":138},[86,5085,2486],{"class":96},[86,5087,484],{"class":138},[86,5089,361],{"class":360},[86,5091,3706],{"class":867},[86,5093,4903],{"class":360},[86,5095,484],{"class":138},[86,5097,256],{"class":96},[86,5099,484],{"class":138},[86,5101,450],{"class":360},[86,5103,139],{"class":138},[86,5105,5106],{"class":96},"wrong",[86,5108,484],{"class":138},[86,5110,5111],{"class":360},"}).",[86,5113,3725],{"class":331},[86,5115,1722],{"class":779},[86,5117,5069],{"class":107},[86,5119,5120],{"class":88,"line":2305},[86,5121,300],{"emptyLinePlaceholder":299},[86,5123,5124],{"class":88,"line":2321},[86,5125,300],{"emptyLinePlaceholder":299},[86,5127,5128,5130,5132,5134,5137,5139,5142],{"class":88,"line":2331},[86,5129,2471],{"class":360},[86,5131,3180],{"class":92},[86,5133,823],{"class":360},[86,5135,5136],{"class":92},"mark",[86,5138,823],{"class":360},[86,5140,5141],{"class":92},"parametrize",[86,5143,1404],{"class":360},[86,5145,5146,5148,5151,5153],{"class":88,"line":2356},[86,5147,478],{"class":138},[86,5149,5150],{"class":96},"patch",[86,5152,484],{"class":138},[86,5154,496],{"class":360},[86,5156,5157],{"class":88,"line":2361},[86,5158,5159],{"class":360},"    [\n",[86,5161,5162,5165,5167,5169,5171,5173,5175,5178,5180,5182],{"class":88,"line":2366},[86,5163,5164],{"class":360},"        {",[86,5166,484],{"class":138},[86,5168,927],{"class":96},[86,5170,484],{"class":138},[86,5172,450],{"class":360},[86,5174,139],{"class":138},[86,5176,5177],{"class":96},"雑費",[86,5179,484],{"class":138},[86,5181,4922],{"class":360},[86,5183,5184],{"class":413},"  # ホワイトリスト外の科目\n",[86,5186,5187,5189,5191,5193,5195,5197,5199,5201],{"class":88,"line":2371},[86,5188,5164],{"class":360},[86,5190,484],{"class":138},[86,5192,4432],{"class":96},[86,5194,484],{"class":138},[86,5196,450],{"class":360},[86,5198,1780],{"class":107},[86,5200,4922],{"class":360},[86,5202,5203],{"class":413},"  # 正の整数でない\n",[86,5205,5206,5208,5210,5212,5214,5216,5219,5222],{"class":88,"line":2383},[86,5207,5164],{"class":360},[86,5209,484],{"class":138},[86,5211,4432],{"class":96},[86,5213,484],{"class":138},[86,5215,450],{"class":360},[86,5217,5218],{"class":779}," -",[86,5220,5221],{"class":107},"100",[86,5223,3333],{"class":360},[86,5225,5226,5228,5230,5232,5234,5236,5238,5241,5243,5245],{"class":88,"line":2400},[86,5227,5164],{"class":360},[86,5229,484],{"class":138},[86,5231,2637],{"class":96},[86,5233,484],{"class":138},[86,5235,450],{"class":360},[86,5237,139],{"class":138},[86,5239,5240],{"class":96},"2026/07/25",[86,5242,484],{"class":138},[86,5244,4922],{"class":360},[86,5246,5247],{"class":413},"  # YYYY-MM-DD でない\n",[86,5249,5250],{"class":88,"line":2416},[86,5251,5252],{"class":360},"    ],\n",[86,5254,5255],{"class":88,"line":2433},[86,5256,891],{"class":360},[86,5258,5259,5261,5264,5266,5268],{"class":88,"line":2453},[86,5260,1129],{"class":779},[86,5262,5263],{"class":92}," test_invalid_input_returns_422",[86,5265,787],{"class":360},[86,5267,5150],{"class":331},[86,5269,793],{"class":360},[86,5271,5272,5275,5277],{"class":88,"line":2458},[86,5273,5274],{"class":331},"    body ",[86,5276,871],{"class":360},[86,5278,472],{"class":360},[86,5280,5281,5283,5285,5287,5289,5291,5294,5296],{"class":88,"line":2463},[86,5282,2156],{"class":138},[86,5284,2637],{"class":96},[86,5286,484],{"class":138},[86,5288,450],{"class":360},[86,5290,139],{"class":138},[86,5292,5293],{"class":96},"2026-07-25",[86,5295,484],{"class":138},[86,5297,496],{"class":360},[86,5299,5300,5302,5304,5306,5308,5310,5312,5314],{"class":88,"line":2468},[86,5301,2156],{"class":138},[86,5303,927],{"class":96},[86,5305,484],{"class":138},[86,5307,450],{"class":360},[86,5309,139],{"class":138},[86,5311,608],{"class":96},[86,5313,484],{"class":138},[86,5315,496],{"class":360},[86,5317,5318,5320,5322,5324,5326,5328,5330,5332],{"class":88,"line":2493},[86,5319,2156],{"class":138},[86,5321,936],{"class":96},[86,5323,484],{"class":138},[86,5325,450],{"class":360},[86,5327,139],{"class":138},[86,5329,481],{"class":96},[86,5331,484],{"class":138},[86,5333,496],{"class":360},[86,5335,5336,5338,5340,5342,5344,5346],{"class":88,"line":2503},[86,5337,2156],{"class":138},[86,5339,4432],{"class":96},[86,5341,484],{"class":138},[86,5343,450],{"class":360},[86,5345,4748],{"class":107},[86,5347,496],{"class":360},[86,5349,5350,5352,5354,5356,5358,5360,5363,5365],{"class":88,"line":2564},[86,5351,2156],{"class":138},[86,5353,4448],{"class":96},[86,5355,484],{"class":138},[86,5357,450],{"class":360},[86,5359,139],{"class":138},[86,5361,5362],{"class":96},"バリデーションテスト",[86,5364,484],{"class":138},[86,5366,496],{"class":360},[86,5368,5369,5372,5374],{"class":88,"line":2579},[86,5370,5371],{"class":360},"    }",[86,5373,2277],{"class":779},[86,5375,5376],{"class":331}," patch\n",[86,5378,5379,5381,5383,5385,5387,5389,5391,5393,5395,5397,5399,5401,5403,5405,5407,5410,5412,5415],{"class":88,"line":2589},[86,5380,3684],{"class":331},[86,5382,871],{"class":360},[86,5384,3689],{"class":331},[86,5386,823],{"class":360},[86,5388,2683],{"class":331},[86,5390,787],{"class":360},[86,5392,484],{"class":138},[86,5394,2486],{"class":96},[86,5396,484],{"class":138},[86,5398,361],{"class":360},[86,5400,3706],{"class":867},[86,5402,871],{"class":360},[86,5404,3143],{"class":103},[86,5406,361],{"class":360},[86,5408,5409],{"class":867}," json",[86,5411,871],{"class":360},[86,5413,5414],{"class":331},"body",[86,5416,891],{"class":360},[86,5418,5419,5421,5423,5425,5427,5429],{"class":88,"line":2603},[86,5420,3717],{"class":327},[86,5422,3720],{"class":331},[86,5424,823],{"class":360},[86,5426,3725],{"class":331},[86,5428,1722],{"class":779},[86,5430,5431],{"class":107}," 422\n",[86,5433,5434],{"class":88,"line":2611},[86,5435,300],{"emptyLinePlaceholder":299},[86,5437,5438],{"class":88,"line":2664},[86,5439,300],{"emptyLinePlaceholder":299},[86,5441,5442,5444,5447],{"class":88,"line":2669},[86,5443,1129],{"class":779},[86,5445,5446],{"class":92}," test_unknown_account_error_lists_allowed_accounts",[86,5448,1676],{"class":360},[86,5450,5451,5453,5456],{"class":88,"line":2674},[86,5452,799],{"class":138},[86,5454,5455],{"class":96},"422のエラー文に「使える科目」の案内が入る（エラー整形の伏線）。",[86,5457,316],{"class":138},[86,5459,5460,5462,5464,5466,5468,5470],{"class":88,"line":2706},[86,5461,3684],{"class":331},[86,5463,871],{"class":360},[86,5465,3689],{"class":331},[86,5467,823],{"class":360},[86,5469,2683],{"class":331},[86,5471,1404],{"class":360},[86,5473,5474,5476,5478,5480],{"class":88,"line":2731},[86,5475,2156],{"class":138},[86,5477,2486],{"class":96},[86,5479,484],{"class":138},[86,5481,496],{"class":360},[86,5483,5484,5486,5488,5490],{"class":88,"line":2741},[86,5485,4356],{"class":867},[86,5487,871],{"class":360},[86,5489,3143],{"class":103},[86,5491,496],{"class":360},[86,5493,5494,5496],{"class":88,"line":2788},[86,5495,4367],{"class":867},[86,5497,4370],{"class":360},[86,5499,5500,5502,5504,5506,5508,5510,5513,5515],{"class":88,"line":2823},[86,5501,2187],{"class":138},[86,5503,2637],{"class":96},[86,5505,484],{"class":138},[86,5507,450],{"class":360},[86,5509,139],{"class":138},[86,5511,5512],{"class":96},"2026-07-26",[86,5514,484],{"class":138},[86,5516,496],{"class":360},[86,5518,5519,5521,5523,5525,5527,5529,5531,5533],{"class":88,"line":2840},[86,5520,2187],{"class":138},[86,5522,927],{"class":96},[86,5524,484],{"class":138},[86,5526,450],{"class":360},[86,5528,139],{"class":138},[86,5530,5177],{"class":96},[86,5532,484],{"class":138},[86,5534,496],{"class":360},[86,5536,5537,5539,5541,5543,5545,5547,5549,5551],{"class":88,"line":2848},[86,5538,2187],{"class":138},[86,5540,936],{"class":96},[86,5542,484],{"class":138},[86,5544,450],{"class":360},[86,5546,139],{"class":138},[86,5548,481],{"class":96},[86,5550,484],{"class":138},[86,5552,496],{"class":360},[86,5554,5555,5557,5559,5561,5563,5566],{"class":88,"line":2853},[86,5556,2187],{"class":138},[86,5558,4432],{"class":96},[86,5560,484],{"class":138},[86,5562,450],{"class":360},[86,5564,5565],{"class":107}," 1_200",[86,5567,496],{"class":360},[86,5569,5570,5572,5574,5576,5578,5580,5583,5585],{"class":88,"line":2858},[86,5571,2187],{"class":138},[86,5573,4448],{"class":96},[86,5575,484],{"class":138},[86,5577,450],{"class":360},[86,5579,139],{"class":138},[86,5581,5582],{"class":96},"エラー系の固定依頼文と同じ内容",[86,5584,484],{"class":138},[86,5586,496],{"class":360},[86,5588,5589],{"class":88,"line":2880},[86,5590,2241],{"class":360},[86,5592,5593],{"class":88,"line":2896},[86,5594,4470],{"class":360},[86,5596,5597,5599,5601,5603,5605,5607],{"class":88,"line":2906},[86,5598,3717],{"class":327},[86,5600,3720],{"class":331},[86,5602,823],{"class":360},[86,5604,3725],{"class":331},[86,5606,1722],{"class":779},[86,5608,5431],{"class":107},[86,5610,5612,5615,5617,5619,5621,5623,5625,5627,5630,5632,5635,5637,5639,5641,5644,5646],{"class":88,"line":5611},154,[86,5613,5614],{"class":331},"    message ",[86,5616,871],{"class":360},[86,5618,3720],{"class":331},[86,5620,823],{"class":360},[86,5622,3741],{"class":331},[86,5624,4052],{"class":360},[86,5626,484],{"class":138},[86,5628,5629],{"class":96},"detail",[86,5631,484],{"class":138},[86,5633,5634],{"class":360},"][",[86,5636,874],{"class":107},[86,5638,5634],{"class":360},[86,5640,484],{"class":138},[86,5642,5643],{"class":96},"msg",[86,5645,484],{"class":138},[86,5647,1884],{"class":360},[86,5649,5651,5653,5655,5657,5659,5661],{"class":88,"line":5650},155,[86,5652,3717],{"class":327},[86,5654,139],{"class":138},[86,5656,5177],{"class":96},[86,5658,484],{"class":138},[86,5660,997],{"class":779},[86,5662,5663],{"class":331}," message\n",[86,5665,5667,5669,5671,5673,5675,5677,5680],{"class":88,"line":5666},156,[86,5668,3717],{"class":327},[86,5670,139],{"class":138},[86,5672,481],{"class":96},[86,5674,484],{"class":138},[86,5676,997],{"class":779},[86,5678,5679],{"class":331}," message  ",[86,5681,5682],{"class":413},"# 使える科目一覧が含まれる\n",[14,5684,5685,5688],{},[51,5686,5687],{},"TestClient"," はAPIをインプロセスで叩くので、サーバーの起動なしにテストが走る。実行結果はこうだった。",[77,5690,5693],{"className":5691,"code":5692,"language":174},[172],"$ uv run pytest -q\n...........\n11 passed, 1 warning in 1.29s\n",[51,5694,5692],{"__ignoreMap":82},[14,5696,5697],{},"テストが通ったら、サーバーを起動してブラウザで開く。",[77,5699,5701],{"className":79,"code":5700,"language":81,"meta":82,"style":82},"uv run uvicorn api:app\n# INFO:  Uvicorn running on http://127.0.0.1:8000\n",[51,5702,5703,5715],{"__ignoreMap":82},[86,5704,5705,5707,5710,5712],{"class":88,"line":89},[86,5706,93],{"class":92},[86,5708,5709],{"class":96}," run",[86,5711,132],{"class":96},[86,5713,5714],{"class":96}," api:app\n",[86,5716,5717],{"class":88,"line":111},[86,5718,5719],{"class":413},"# INFO:  Uvicorn running on http://127.0.0.1:8000\n",[14,5721,5722],{},"このターミナルはサーバーが占有するので、以降のcurlやclaudeは別のターミナルから叩く。",[14,5724,5725,5728],{},[51,5726,5727],{},"http://127.0.0.1:8000/docs"," を開くと、書いた覚えのないAPIリファレンス画面（Swagger UI）が生えている。",[184,5730,5731,5735],{},[187,5732],{"src":5733,"alt":5734},"/images/journal-api-mcp-tutorial/swagger-docs.png","ミニ仕訳帳APIのSwagger UI。GET /journal-entries、POST /journal-entries、GET /trial-balanceの3エンドポイントと、それぞれのパラメータとスキーマが自動生成されている",[192,5736,5737],{},"図2: /docs に自動で生えるSwagger UI。裏では /openapi.json が機械可読の仕様を配っている",[14,5739,5740,5741,5744,5745,5747],{},"これはFastAPIが、コードのPydanticモデルからOpenAPIスキーマ（",[51,5742,5743],{},"/openapi.json","）を自動生成し、その上に人間向けの画面をかぶせたものだ。",[17,5746,20],{"href":19},"で見たとおり、freeeの人間向けAPIリファレンスも大元は同じOpenAPIスキーマで、freee-mcpはそれを実行時の門番として使っていた。いま手元の3エンドポイントで起きたことは、freeeの277本で起きていることの、おおよそ1/100の模型になっている。",[14,5749,5750],{},"curlでも叩いておく。認証が効いていること、期待値表どおりの試算表が返ることの確認だ。",[77,5752,5755],{"className":5753,"code":5754,"language":174},[172],"$ curl -s -i http://127.0.0.1:8000/journal-entries\nHTTP/1.1 401 Unauthorized\n（ヘッダー略）\n{\"detail\":\"APIキーが不正です。X-API-Key ヘッダーを確認してください。\"}\n\n$ curl -s -H \"X-API-Key: sk-journal-tutorial-2026\" http://127.0.0.1:8000/trial-balance\n{\"accounts\":[{\"account\":\"現金\",\"category\":\"資産\",\"debit_total\":180000,\"credit_total\":85000,\n\"balance_side\":\"借方\",\"balance\":95000,\"normal_side\":\"借方\",\"is_abnormal\":false},\n（中略: 期待値表と同じ6科目が続く）\n],\"total\":{\"debit_total\":265000,\"credit_total\":265000,\"in_balance\":true}}\n",[51,5756,5754],{"__ignoreMap":82},[14,5758,5759,5760,5763],{},"登録（POST）はWindowsだと1つ罠がある。日本語入りのJSONをコマンドラインの ",[51,5761,5762],{},"-d '{...}'"," で渡すと、Git Bashからcurl.exeへの引数変換で文字が壊れ、400（body parse error）になる。後のStep 2の実験でも、エージェントが同じ箇所で2回とも400を踏んでいる。ボディをファイルに保存して渡せば通る。逆に、レスポンスの日本語が化けて見えるときはコンソールの文字コードによる表示側の問題で、格納データは無事なことが多い。",[77,5765,5768],{"className":5766,"code":5767,"language":174},[172],"$ printf '%s' '{\"date\":\"2026-07-25\",\"debit_account\":\"消耗品費\",\"credit_account\":\"現金\",\"amount\":3300,\"description\":\"コピー用紙\"}' > body.json\n$ curl -s -X POST -H \"X-API-Key: sk-journal-tutorial-2026\" -H \"Content-Type: application/json\" --data @body.json http://127.0.0.1:8000/journal-entries\n{\"date\":\"2026-07-25\",\"debit_account\":\"消耗品費\",\"credit_account\":\"現金\",\"amount\":3300,\"description\":\"コピー用紙\",\"id\":6}\n",[51,5769,5767],{"__ignoreMap":82},[14,5771,5772],{},"ホワイトリスト外の科目は、バリデータが書いたガイダンス付きの422で返る。",[77,5774,5777],{"className":5775,"code":5776,"language":174},[172],"$ printf '%s' '{\"date\":\"2026-07-26\",\"debit_account\":\"雑費\",\"credit_account\":\"現金\",\"amount\":1200,\"description\":\"来客用お茶\"}' > body2.json\n$ curl -s -X POST -H \"X-API-Key: sk-journal-tutorial-2026\" -H \"Content-Type: application/json\" --data @body2.json http://127.0.0.1:8000/journal-entries\n{\"detail\":[{\"type\":\"value_error\",\"loc\":[\"body\",\"debit_account\"],\n\"msg\":\"Value error, 勘定科目「雑費」は使えません。使える科目: 現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費\",\n\"input\":\"雑費\",\"ctx\":{\"error\":{}}}]}\n",[51,5778,5776],{"__ignoreMap":82},[14,5780,5781,5782,5785],{},"これでAPIは完成だ。人間の開発者としては、",[51,5783,5784],{},"/docs"," を見ながらこのAPIを使える。次の問いは「AIエージェントはこれをどう使うか」になる。",[196,5787,5789],{"id":5788},"step-2-生のまま使わせてみるbefore体験","Step 2: 生のまま使わせてみる（Before体験）",[14,5791,5792],{},"MCPを持ち出す前に、生のAPIをそのままエージェントに使わせて、何が起きるかを記録しておく。あとでMCP経由と比べるので、条件を固定した統制実験にする。",[32,5794,5795,5801,5807],{},[35,5796,5797,5800],{},[262,5798,5799],{},"依頼文を固定する","。正常系「2026-07-25付で、消耗品費 3,300円を現金で支払った仕訳を登録して。」とエラー系「2026-07-26付で、雑費 1,200円を現金で支払った仕訳を登録して。」の2本。雑費はホワイトリスト外なので、後者は必ず422を踏む",[35,5802,5803,5806],{},[262,5804,5805],{},"毎回シード状態に戻す","。各実験の前にAPIを再起動して、5件のシード仕訳だけの状態から始める",[35,5808,5809,5812,5813,5816],{},[262,5810,5811],{},"キーは会話の外で渡す","。環境変数 ",[51,5814,5815],{},"JOURNAL_API_KEY"," にキーを設定した上で、「キーは環境変数にある。値を会話やコマンドの出力に書き出さないで」と依頼に含める。会話にキーを貼り付ける比較は生API側に不公平なので、やらない",[14,5818,5819],{},"観測するのは3点。①キーの扱い（値が会話に出たか）②承認の粒度（何に対して許可を出すことになるか）③エラーからの復旧（422を受けたときの挙動）だ。",[14,5821,5822,5823,5826,5827,5830],{},"実験のエージェントにはClaude Code（モデルはclaude-fable-5）を使い、実録を残すためにヘッドレスモードで走らせた。読者が再現するときは、対話モードのClaude Codeで同じ依頼文を打てばよい。ただしエージェントの挙動は確率的で、ターン数や途中の調査手順は実行ごとに変わる（この記事の検証でも、同じ依頼がターン数7で完走した回がある）。再現されるのは逐一のログではなく、仕様の読解やエラーの調査がエージェント側の仕事として毎回積まれる、という構造の方だ。実測に使ったコマンドはこれだ（",[51,5824,5825],{},"--strict-mcp-config"," はMCPサーバーを一切読み込まない指定で、Before側にMCPを混ぜないための統制。",[51,5828,5829],{},"--allowedTools \"Bash\""," はシェルコマンドの実行だけを許可する）。",[77,5832,5834],{"className":79,"code":5833,"language":81,"meta":82,"style":82},"export JOURNAL_API_KEY=\"sk-journal-tutorial-2026\"\nclaude -p '（前置き＋依頼文）' --allowedTools \"Bash\" --strict-mcp-config --output-format stream-json --verbose\n",[51,5835,5836,5851],{"__ignoreMap":82},[86,5837,5838,5840,5843,5845,5847,5849],{"class":88,"line":89},[86,5839,53],{"class":779},[86,5841,5842],{"class":867}," JOURNAL_API_KEY",[86,5844,871],{"class":360},[86,5846,484],{"class":138},[86,5848,428],{"class":96},[86,5850,145],{"class":138},[86,5852,5853,5856,5859,5862,5865,5868,5871,5873,5876,5878,5881,5884,5887],{"class":88,"line":111},[86,5854,5855],{"class":92},"claude",[86,5857,5858],{"class":103}," -p",[86,5860,5861],{"class":138}," '",[86,5863,5864],{"class":96},"（前置き＋依頼文）",[86,5866,5867],{"class":138},"'",[86,5869,5870],{"class":103}," --allowedTools",[86,5872,139],{"class":138},[86,5874,5875],{"class":96},"Bash",[86,5877,484],{"class":138},[86,5879,5880],{"class":103}," --strict-mcp-config",[86,5882,5883],{"class":103}," --output-format",[86,5885,5886],{"class":96}," stream-json",[86,5888,5889],{"class":103}," --verbose\n",[14,5891,5892,5893,5896,5897,5900,5901,5904],{},"長い日本語プロンプトをシングルクォートに詰めるのが面倒なら、前置きと依頼文をまとめて ",[51,5894,5895],{},"prompt.txt"," に保存し、",[51,5898,5899],{},"claude -p \"$(cat prompt.txt)\""," と渡してもよい。また、",[51,5902,5903],{},"--output-format stream-json --verbose"," の出力は1行1イベントの生JSONで流れてくる。以下に載せる実録は、そこからツール呼び出しの行を抜粋して整形したものだ。",[14,5906,5907],{},"依頼文の前には、APIの場所を伝える前置きを付けた。全文を載せる。",[5909,5910,5911,5920],"blockquote",{},[14,5912,5913,5916,5917,5919],{},[51,5914,5915],{},"http://127.0.0.1:8000"," でミニ仕訳帳APIが動いている。APIリファレンスは ",[51,5918,5727],{},"（機械可読版は /openapi.json）。認証は X-API-Key ヘッダーで、キーは環境変数 JOURNAL_API_KEY に入っている。キーの値を会話やコマンドの出力に書き出さないこと。",[14,5921,5922],{},"依頼: 2026-07-25付で、消耗品費 3,300円を現金で支払った仕訳を登録して。",[5924,5925,5927],"h3",{"id":5926},"正常系の実録-6ターンの内訳","正常系の実録: 6ターンの内訳",[14,5929,5930],{},"エージェントの動きを実録から抜き出す。",[77,5932,5935],{"className":5933,"code":5934,"language":174},[172],"[1] curl -s http://127.0.0.1:8000/openapi.json\n    → OpenAPIスキーマ全体を取得して読解\n[2] curl -X POST http://127.0.0.1:8000/journal-entries \\\n      -H \"X-API-Key: $JOURNAL_API_KEY\" -H \"Content-Type: application/json\" \\\n      -d '{\"date\":\"2026-07-25\",\"debit_account\":\"消耗品費\",...}'\n    → {\"detail\":\"There was an error parsing the body\"}（HTTP 400）\n[3] .tmp-entry.json を作成（JSONボディをファイルに退避）\n[4] curl -X POST ... --data-binary @.tmp-entry.json\n    → {\"date\":\"2026-07-25\",...,\"id\":6}（HTTP 201）\n[5] rm .tmp-entry.json\n",[51,5936,5934],{"__ignoreMap":82},[14,5938,5939],{},"登録には成功した。ターン数は6。上の抜粋のツール呼び出し5手に、最後の報告を加えた往復数で、以下この数え方で書く。挙動として記録しておきたい点が3つある。",[14,5941,5942,5943,5945],{},"第一に、エージェントは仕様の読解から始めた。",[51,5944,5743],{}," を丸ごと取得して、エンドポイントとスキーマを解析してからPOSTを組み立てている。仕様を読む作業が毎回の実行時間に乗る、というのが生API方式の構造だ。",[14,5947,5948,5949,5952],{},"第二に、Step 1で私が踏んだWindowsのエンコーディング問題を、エージェントも同じように踏んだ。日本語入りJSONをインラインの ",[51,5950,5951],{},"-d"," で送って400を受け、ファイル退避のワークアラウンドに切り替えて成功している。回復できたのは立派だが、この2手はエージェントがシェルのコマンドラインで引数を組み立てているから発生している。",[14,5954,5955,5956,5959],{},"第三に、キーの扱いは正しかった。全コマンドで ",[51,5957,5958],{},"$JOURNAL_API_KEY"," の変数参照を使い、値そのものは実録のどこにも出現しなかった（実録ファイルをキー文字列でgrepして0件）。ただし、この正しさは「エージェントが毎回の生成でそう振る舞ったから」成立している点は覚えておいてほしい。次の実験でそこが崩れる。",[5924,5961,5963],{"id":5962},"エラー系の実録-422を受けたエージェントは何をしたか","エラー系の実録: 422を受けたエージェントは何をしたか",[14,5965,5966],{},"同じ前置きで、雑費の依頼を投げる。前半は正常系と同じ（openapi.json読解、400、ファイル退避）で、そこから先がこうなった（ターン数は7）。",[77,5968,5971],{"className":5969,"code":5970,"language":174},[172],"[4] curl -X POST ... --data-binary @.tmp-entry.json\n    → 422 {\"msg\":\"Value error, 勘定科目「雑費」は使えません。\n       使える科目: 現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費\",...}\n[5] Grep pattern=\"雑費|消耗品費|ALLOWED|勘定科目\" path=api.py -C 3\n    → api.py のソースコードからホワイトリスト定義を発見\n       （このgrep結果の中に API_KEY = \"sk-journal-tutorial-2026\" の行が含まれた）\n[6] 登録せず停止。「消耗品費として登録する／api.pyに雑費を追加する」の\n    2択をユーザーに提示。「会計記録の科目を私の判断で勝手に置き換えるべきではない」\n",[51,5972,5970],{"__ignoreMap":82},[14,5974,5975],{},"最終的な判断は良かった。勝手に科目を読み替えず、選択肢を提示して人間に確認を求めている。会計記録に対するエージェントの振る舞いとしては満点だ。",[14,5977,5978,5979,5982,5983,5985,5986,5989],{},"問題は手順",[86,5980,5981],{},"5","で起きた。422の原因を調べるために、エージェントはAPIのソースコード ",[51,5984,278],{}," をgrepした。その結果の前後3行に、ハードコードされたAPIキーの定義行が含まれていた。",[262,5987,5988],{},"キーの値が、エージェントの会話コンテキストに転がり込んだ","。",[14,5991,5992,5993,5995],{},"これは「エージェントがキーをechoした」のではない。依頼どおり、キーを書き出そうとはしていない。原因調査でソースファイルを覗いたら、そこにキーが書いてあった、という事故だ。教材だからキーを ",[51,5994,278],{}," に直書きしたのだが、皮肉なことに、その手抜きが「秘密は置き場所の構造で守るしかない」ことの実演になった。エージェントの善意や注意力は、たまたま通りかかったファイルの中身までは制御できない。",[14,5997,5998,6000],{},[17,5999,20],{"href":19},"に描いた「生API直叩き」のシーケンス図の世界そのものだ。仕様の読解も、エンコーディング事故の復旧も、エラーの原因調査も、全部エージェントの仕事として毎回積まれる。そして秘密の管理は、エージェントの毎回の振る舞いに依存する。",[196,6002,6004],{"id":6003},"step-3-mcpサーバーで包む","Step 3: MCPサーバーで包む",[14,6006,6007,6008,6013,6014,6017],{},"ここからが本題だ。いま作ったAPIを、MCP公式Python SDK（",[17,6009,6012],{"href":6010,"target":41,"rel":6011},"https://github.com/modelcontextprotocol/python-sdk",[43,44],"→ modelcontextprotocol/python-sdk（GitHub）","）の ",[51,6015,6016],{},"FastMCP"," で包む。エンドポイント3本をツール3本に1対1で対応させる。freee-mcpは277本を5個の汎用ツールに畳み込んでいたが、あれは277本あるからの設計で、3本なら1対1が素直だ（この分岐の話は最後の節でもう一度出てくる）。なお、freee-mcpの門番（validatePathForServiceによるパスの実在検証）に相当する部品は今回は登場しない。パスはserver.pyのコードに固定されていて、エージェントがパス文字列を渡す余地自体がないからだ。",[14,6019,6020,6023],{},[51,6021,6022],{},"server.py"," は4つの部品でできている。部品ごとに、freee-mcpのどの実装の縮小版かを添えて示す。",[14,6025,6026,6029],{},[262,6027,6028],{},"部品1: 設定とログ","。APIキーと接続先は環境変数から読む。ツール呼び出しの記録はJSONLで1呼び出し1行。",[77,6031,6033],{"className":282,"code":6032,"filename":6022,"language":284,"meta":82,"style":82},"\"\"\"ミニ仕訳帳APIを包むMCPサーバー — freee-mcpの縮小再現。\n\n公式Python SDK（mcp）のFastMCPを使い、stdioトランスポートで動く。\n起動: uv run server.py（実際はMCPクライアントがサブプロセスとして起動する）\n\"\"\"\n\nimport datetime as dt\nimport json\nimport os\nfrom pathlib import Path\nfrom typing import Any\n\nimport httpx\nfrom mcp.server.fastmcp import FastMCP\nfrom mcp.server.fastmcp.exceptions import ToolError\nfrom mcp.types import ToolAnnotations\n\n# 資格情報と接続先は環境変数から読む。キーはツールの宣言にも引数にも現れない。\n# freee-mcp対応: OAuthトークンをサーバー内部で解決してBearerヘッダーに付ける（src/api/client.ts）\nAPI_KEY = os.environ.get(\"JOURNAL_API_KEY\", \"\")\nBASE_URL = os.environ.get(\"JOURNAL_API_BASE_URL\", \"http://127.0.0.1:8000\")\n\n# 使える勘定科目（api.pyのホワイトリストと同じ7科目）。\n# freee-mcpはこの種の仕様知識をOpenAPIスキーマとAgent Skillsから引くが、ツール3本なら手書きが素直\nACCOUNTS = \"現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費\"\n\nLOG_PATH = Path(__file__).with_name(\"journal_mcp.log\")\n\nmcp = FastMCP(\"journal\")\n\n\ndef write_log(tool: str, args: dict[str, Any], status: str) -> None:\n    \"\"\"ツール呼び出し1回=JSONL1行の操作ログ。\n\n    freee-mcp対応: リモート版の「1リクエスト=1ログ行」（canonical log line）の縮小版。\n    ただしこれは監査証跡ではない——実行者の識別・改ざん検知・API側記録との突合がなく、\n    ただのテキストファイルなのでいくらでも書き換えられる。\n    \"\"\"\n    record = {\n        \"time\": dt.datetime.now().isoformat(timespec=\"seconds\"),\n        \"tool\": tool,\n        \"args\": args,\n        \"status\": status,\n    }\n    with LOG_PATH.open(\"a\", encoding=\"utf-8\") as f:\n        f.write(json.dumps(record, ensure_ascii=False) + \"\\n\")\n",[51,6034,6035,6042,6046,6051,6056,6060,6064,6074,6081,6088,6100,6112,6116,6123,6145,6170,6186,6190,6195,6200,6233,6269,6273,6278,6283,6296,6300,6331,6335,6356,6360,6364,6416,6423,6427,6432,6437,6442,6446,6455,6500,6515,6530,6545,6549,6593],{"__ignoreMap":82},[86,6036,6037,6039],{"class":88,"line":89},[86,6038,291],{"class":138},[86,6040,6041],{"class":96},"ミニ仕訳帳APIを包むMCPサーバー — freee-mcpの縮小再現。\n",[86,6043,6044],{"class":88,"line":111},[86,6045,300],{"emptyLinePlaceholder":299},[86,6047,6048],{"class":88,"line":121},[86,6049,6050],{"class":96},"公式Python SDK（mcp）のFastMCPを使い、stdioトランスポートで動く。\n",[86,6052,6053],{"class":88,"line":148},[86,6054,6055],{"class":96},"起動: uv run server.py（実際はMCPクライアントがサブプロセスとして起動する）\n",[86,6057,6058],{"class":88,"line":313},[86,6059,316],{"class":138},[86,6061,6062],{"class":88,"line":319},[86,6063,300],{"emptyLinePlaceholder":299},[86,6065,6066,6068,6070,6072],{"class":88,"line":324},[86,6067,328],{"class":327},[86,6069,332],{"class":331},[86,6071,335],{"class":327},[86,6073,338],{"class":331},[86,6075,6076,6078],{"class":88,"line":341},[86,6077,328],{"class":327},[86,6079,6080],{"class":331}," json\n",[86,6082,6083,6085],{"class":88,"line":346},[86,6084,328],{"class":327},[86,6086,6087],{"class":331}," os\n",[86,6089,6090,6092,6095,6097],{"class":88,"line":382},[86,6091,349],{"class":327},[86,6093,6094],{"class":331}," pathlib ",[86,6096,328],{"class":327},[86,6098,6099],{"class":331}," Path\n",[86,6101,6102,6104,6107,6109],{"class":88,"line":405},[86,6103,349],{"class":327},[86,6105,6106],{"class":331}," typing ",[86,6108,328],{"class":327},[86,6110,6111],{"class":331}," Any\n",[86,6113,6114],{"class":88,"line":410},[86,6115,300],{"emptyLinePlaceholder":299},[86,6117,6118,6120],{"class":88,"line":417},[86,6119,328],{"class":327},[86,6121,6122],{"class":331}," httpx\n",[86,6124,6125,6127,6130,6132,6135,6137,6140,6142],{"class":88,"line":433},[86,6126,349],{"class":327},[86,6128,6129],{"class":331}," mcp",[86,6131,823],{"class":360},[86,6133,6134],{"class":331},"server",[86,6136,823],{"class":360},[86,6138,6139],{"class":331},"fastmcp ",[86,6141,328],{"class":327},[86,6143,6144],{"class":331}," FastMCP\n",[86,6146,6147,6149,6151,6153,6155,6157,6160,6162,6165,6167],{"class":88,"line":438},[86,6148,349],{"class":327},[86,6150,6129],{"class":331},[86,6152,823],{"class":360},[86,6154,6134],{"class":331},[86,6156,823],{"class":360},[86,6158,6159],{"class":331},"fastmcp",[86,6161,823],{"class":360},[86,6163,6164],{"class":331},"exceptions ",[86,6166,328],{"class":327},[86,6168,6169],{"class":331}," ToolError\n",[86,6171,6172,6174,6176,6178,6181,6183],{"class":88,"line":444},[86,6173,349],{"class":327},[86,6175,6129],{"class":331},[86,6177,823],{"class":360},[86,6179,6180],{"class":331},"types ",[86,6182,328],{"class":327},[86,6184,6185],{"class":331}," ToolAnnotations\n",[86,6187,6188],{"class":88,"line":475},[86,6189,300],{"emptyLinePlaceholder":299},[86,6191,6192],{"class":88,"line":499},[86,6193,6194],{"class":413},"# 資格情報と接続先は環境変数から読む。キーはツールの宣言にも引数にも現れない。\n",[86,6196,6197],{"class":88,"line":519},[86,6198,6199],{"class":413},"# freee-mcp対応: OAuthトークンをサーバー内部で解決してBearerヘッダーに付ける（src/api/client.ts）\n",[86,6201,6202,6204,6206,6209,6211,6214,6216,6218,6220,6222,6224,6226,6228,6231],{"class":88,"line":540},[86,6203,420],{"class":103},[86,6205,423],{"class":360},[86,6207,6208],{"class":331}," os",[86,6210,823],{"class":360},[86,6212,6213],{"class":331},"environ",[86,6215,823],{"class":360},[86,6217,2479],{"class":331},[86,6219,787],{"class":360},[86,6221,484],{"class":138},[86,6223,5815],{"class":96},[86,6225,484],{"class":138},[86,6227,361],{"class":360},[86,6229,6230],{"class":138}," \"\"",[86,6232,891],{"class":360},[86,6234,6235,6238,6240,6242,6244,6246,6248,6250,6252,6254,6257,6259,6261,6263,6265,6267],{"class":88,"line":561},[86,6236,6237],{"class":103},"BASE_URL",[86,6239,423],{"class":360},[86,6241,6208],{"class":331},[86,6243,823],{"class":360},[86,6245,6213],{"class":331},[86,6247,823],{"class":360},[86,6249,2479],{"class":331},[86,6251,787],{"class":360},[86,6253,484],{"class":138},[86,6255,6256],{"class":96},"JOURNAL_API_BASE_URL",[86,6258,484],{"class":138},[86,6260,361],{"class":360},[86,6262,139],{"class":138},[86,6264,5915],{"class":96},[86,6266,484],{"class":138},[86,6268,891],{"class":360},[86,6270,6271],{"class":88,"line":582},[86,6272,300],{"emptyLinePlaceholder":299},[86,6274,6275],{"class":88,"line":603},[86,6276,6277],{"class":413},"# 使える勘定科目（api.pyのホワイトリストと同じ7科目）。\n",[86,6279,6280],{"class":88,"line":623},[86,6281,6282],{"class":413},"# freee-mcpはこの種の仕様知識をOpenAPIスキーマとAgent Skillsから引くが、ツール3本なら手書きが素直\n",[86,6284,6285,6287,6289,6291,6294],{"class":88,"line":629},[86,6286,447],{"class":103},[86,6288,423],{"class":360},[86,6290,139],{"class":138},[86,6292,6293],{"class":96},"現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費",[86,6295,145],{"class":138},[86,6297,6298],{"class":88,"line":634},[86,6299,300],{"emptyLinePlaceholder":299},[86,6301,6302,6305,6307,6310,6312,6315,6317,6320,6322,6324,6327,6329],{"class":88,"line":640},[86,6303,6304],{"class":103},"LOG_PATH",[86,6306,423],{"class":360},[86,6308,6309],{"class":331}," Path",[86,6311,787],{"class":360},[86,6313,6314],{"class":114},"__file__",[86,6316,4852],{"class":360},[86,6318,6319],{"class":331},"with_name",[86,6321,787],{"class":360},[86,6323,484],{"class":138},[86,6325,6326],{"class":96},"journal_mcp.log",[86,6328,484],{"class":138},[86,6330,891],{"class":360},[86,6332,6333],{"class":88,"line":664},[86,6334,300],{"emptyLinePlaceholder":299},[86,6336,6337,6340,6342,6345,6347,6349,6352,6354],{"class":88,"line":684},[86,6338,6339],{"class":331},"mcp ",[86,6341,871],{"class":360},[86,6343,6344],{"class":331}," FastMCP",[86,6346,787],{"class":360},[86,6348,484],{"class":138},[86,6350,6351],{"class":96},"journal",[86,6353,484],{"class":138},[86,6355,891],{"class":360},[86,6357,6358],{"class":88,"line":703},[86,6359,300],{"emptyLinePlaceholder":299},[86,6361,6362],{"class":88,"line":723},[86,6363,300],{"emptyLinePlaceholder":299},[86,6365,6366,6368,6371,6373,6376,6378,6380,6382,6385,6387,6389,6391,6393,6395,6398,6401,6404,6406,6408,6410,6412,6414],{"class":88,"line":742},[86,6367,1129],{"class":779},[86,6369,6370],{"class":92}," write_log",[86,6372,787],{"class":360},[86,6374,6375],{"class":331},"tool",[86,6377,450],{"class":360},[86,6379,464],{"class":114},[86,6381,361],{"class":360},[86,6383,6384],{"class":331}," args",[86,6386,450],{"class":360},[86,6388,453],{"class":331},[86,6390,456],{"class":360},[86,6392,459],{"class":114},[86,6394,361],{"class":360},[86,6396,6397],{"class":331}," Any",[86,6399,6400],{"class":360},"],",[86,6402,6403],{"class":331}," status",[86,6405,450],{"class":360},[86,6407,464],{"class":114},[86,6409,974],{"class":360},[86,6411,977],{"class":360},[86,6413,2050],{"class":327},[86,6415,982],{"class":360},[86,6417,6418,6420],{"class":88,"line":761},[86,6419,799],{"class":138},[86,6421,6422],{"class":96},"ツール呼び出し1回=JSONL1行の操作ログ。\n",[86,6424,6425],{"class":88,"line":766},[86,6426,300],{"emptyLinePlaceholder":299},[86,6428,6429],{"class":88,"line":771},[86,6430,6431],{"class":96},"    freee-mcp対応: リモート版の「1リクエスト=1ログ行」（canonical log line）の縮小版。\n",[86,6433,6434],{"class":88,"line":776},[86,6435,6436],{"class":96},"    ただしこれは監査証跡ではない——実行者の識別・改ざん検知・API側記録との突合がなく、\n",[86,6438,6439],{"class":88,"line":796},[86,6440,6441],{"class":96},"    ただのテキストファイルなのでいくらでも書き換えられる。\n",[86,6443,6444],{"class":88,"line":807},[86,6445,1638],{"class":138},[86,6447,6448,6451,6453],{"class":88,"line":812},[86,6449,6450],{"class":331},"    record ",[86,6452,871],{"class":360},[86,6454,472],{"class":360},[86,6456,6457,6459,6462,6464,6466,6468,6470,6473,6475,6478,6481,6484,6486,6489,6491,6493,6496,6498],{"class":88,"line":829},[86,6458,2156],{"class":138},[86,6460,6461],{"class":96},"time",[86,6463,484],{"class":138},[86,6465,450],{"class":360},[86,6467,820],{"class":331},[86,6469,823],{"class":360},[86,6471,6472],{"class":331},"datetime",[86,6474,823],{"class":360},[86,6476,6477],{"class":331},"now",[86,6479,6480],{"class":360},"().",[86,6482,6483],{"class":331},"isoformat",[86,6485,787],{"class":360},[86,6487,6488],{"class":867},"timespec",[86,6490,871],{"class":360},[86,6492,484],{"class":138},[86,6494,6495],{"class":96},"seconds",[86,6497,484],{"class":138},[86,6499,1205],{"class":360},[86,6501,6502,6504,6506,6508,6510,6513],{"class":88,"line":840},[86,6503,2156],{"class":138},[86,6505,6375],{"class":96},[86,6507,484],{"class":138},[86,6509,450],{"class":360},[86,6511,6512],{"class":331}," tool",[86,6514,496],{"class":360},[86,6516,6517,6519,6522,6524,6526,6528],{"class":88,"line":850},[86,6518,2156],{"class":138},[86,6520,6521],{"class":96},"args",[86,6523,484],{"class":138},[86,6525,450],{"class":360},[86,6527,6384],{"class":331},[86,6529,496],{"class":360},[86,6531,6532,6534,6537,6539,6541,6543],{"class":88,"line":894},[86,6533,2156],{"class":138},[86,6535,6536],{"class":96},"status",[86,6538,484],{"class":138},[86,6540,450],{"class":360},[86,6542,6403],{"class":331},[86,6544,496],{"class":360},[86,6546,6547],{"class":88,"line":909},[86,6548,2247],{"class":360},[86,6550,6551,6554,6557,6559,6562,6564,6566,6568,6570,6572,6575,6577,6579,6582,6584,6586,6589,6591],{"class":88,"line":914},[86,6552,6553],{"class":327},"    with",[86,6555,6556],{"class":103}," LOG_PATH",[86,6558,823],{"class":360},[86,6560,6561],{"class":331},"open",[86,6563,787],{"class":360},[86,6565,484],{"class":138},[86,6567,17],{"class":96},[86,6569,484],{"class":138},[86,6571,361],{"class":360},[86,6573,6574],{"class":867}," encoding",[86,6576,871],{"class":360},[86,6578,484],{"class":138},[86,6580,6581],{"class":96},"utf-8",[86,6583,484],{"class":138},[86,6585,974],{"class":360},[86,6587,6588],{"class":327}," as",[86,6590,3932],{"class":331},[86,6592,982],{"class":360},[86,6594,6595,6598,6600,6603,6605,6607,6609,6612,6614,6617,6619,6622,6624,6627,6629,6631,6633,6636,6638],{"class":88,"line":943},[86,6596,6597],{"class":331},"        f",[86,6599,823],{"class":360},[86,6601,6602],{"class":331},"write",[86,6604,787],{"class":360},[86,6606,3741],{"class":331},[86,6608,823],{"class":360},[86,6610,6611],{"class":331},"dumps",[86,6613,787],{"class":360},[86,6615,6616],{"class":331},"record",[86,6618,361],{"class":360},[86,6620,6621],{"class":867}," ensure_ascii",[86,6623,871],{"class":360},[86,6625,6626],{"class":327},"False",[86,6628,974],{"class":360},[86,6630,2782],{"class":779},[86,6632,139],{"class":138},[86,6634,6635],{"class":103},"\\n",[86,6637,484],{"class":138},[86,6639,891],{"class":360},[14,6641,6642],{},"環境変数からキーを読む1行が、Before体験で起きた事故への答えになる。キーを扱うコードがこのファイルに集約され、後で見るとおり、ツールの宣言にも引数にもキーというフィールドは存在しなくなる。会話にキーを書く必要が、構造として消える。freee-mcpのリモート版はさらに徹底していて、freeeの実トークンをサーバー内部の保管場所から一度も外に出さない。方向は同じで、規模が違うだけだ。",[14,6644,6645],{},"ここで正確を期しておくと、MCPという仕様が「キーは環境変数で管理せよ」と定めているわけではない。今回のサーバー実装でそう作った、という話であり、構造として言えるのは「キーを扱うコードがサーバー側に集約され、ツールの引数にキーが現れない設計が自然になる」ところまでだ。",[14,6647,6648,6649,6652],{},"ログの方は、freee-mcpリモート版の「1リクエスト=1ログ行」の縮小版だが、コメントに書いたとおり、これを監査証跡と呼んではいけない。誰が実行したかの識別がなく、改ざんを検知できず、API側の記録との突合もない、ただの編集可能なテキストファイルだ。会計の人向けに言えば、現金出納帳を鉛筆で書いているようなもので、記録があることと証跡であることの間には距離がある。freee-mcpの「1リクエスト=1ログ行」でも、この距離がゼロになるわけではない。監査証跡の議論は",[17,6650,6651],{"href":19},"前の記事の統制の節","に書いたので、ここでは「操作ログ」という呼び名を守ることだけ決めておく。",[14,6654,6655,6658],{},[262,6656,6657],{},"部品2: エラーの整形","。FastAPIの422をLLM向けのガイダンス文に翻訳する。",[77,6660,6662],{"className":282,"code":6661,"filename":6022,"language":284,"meta":82,"style":82},"def format_422(detail: list[dict]) -> str:\n    \"\"\"FastAPIのバリデーションエラーを読み下し、次の行動を促す文に変える。\n\n    freee-mcp対応: 生の401/403/429に日本語の対処ガイダンスを添えるエラー整形\n    （src/openapi/client-mode.ts の formatErrorMessage 系）の縮小版。\n    \"\"\"\n    lines = [\n        f\"- {'.'.join(str(x) for x in item.get('loc', [])[1:])}: {item.get('msg', '')}\"\n        for item in detail\n    ]\n    return (\n        \"入力エラーで受け付けられませんでした。\\n\"\n        + \"\\n\".join(lines)\n        + f\"\\n使える勘定科目: {ACCOUNTS}。日付は YYYY-MM-DD、金額は正の整数（円）です。\"\n    )\n",[51,6663,6664,6692,6699,6703,6708,6713,6717,6726,6821,6833,6837,6844,6855,6877,6896],{"__ignoreMap":82},[86,6665,6666,6668,6671,6673,6675,6677,6679,6681,6684,6686,6688,6690],{"class":88,"line":89},[86,6667,1129],{"class":779},[86,6669,6670],{"class":92}," format_422",[86,6672,787],{"class":360},[86,6674,5629],{"class":331},[86,6676,450],{"class":360},[86,6678,1140],{"class":331},[86,6680,456],{"class":360},[86,6682,6683],{"class":114},"dict",[86,6685,1601],{"class":360},[86,6687,977],{"class":360},[86,6689,464],{"class":114},[86,6691,982],{"class":360},[86,6693,6694,6696],{"class":88,"line":111},[86,6695,799],{"class":138},[86,6697,6698],{"class":96},"FastAPIのバリデーションエラーを読み下し、次の行動を促す文に変える。\n",[86,6700,6701],{"class":88,"line":121},[86,6702,300],{"emptyLinePlaceholder":299},[86,6704,6705],{"class":88,"line":148},[86,6706,6707],{"class":96},"    freee-mcp対応: 生の401/403/429に日本語の対処ガイダンスを添えるエラー整形\n",[86,6709,6710],{"class":88,"line":313},[86,6711,6712],{"class":96},"    （src/openapi/client-mode.ts の formatErrorMessage 系）の縮小版。\n",[86,6714,6715],{"class":88,"line":319},[86,6716,1638],{"class":138},[86,6718,6719,6722,6724],{"class":88,"line":324},[86,6720,6721],{"class":331},"    lines ",[86,6723,871],{"class":360},[86,6725,1159],{"class":360},[86,6727,6728,6730,6733,6735,6737,6739,6741,6743,6745,6747,6749,6751,6754,6756,6758,6761,6763,6766,6768,6770,6772,6774,6777,6779,6781,6784,6786,6789,6791,6793,6795,6798,6800,6802,6804,6806,6808,6810,6812,6815,6817,6819],{"class":88,"line":341},[86,6729,6597],{"class":779},[86,6731,6732],{"class":96},"\"- ",[86,6734,1048],{"class":103},[86,6736,5867],{"class":138},[86,6738,823],{"class":96},[86,6740,5867],{"class":138},[86,6742,823],{"class":360},[86,6744,1022],{"class":331},[86,6746,787],{"class":360},[86,6748,459],{"class":114},[86,6750,787],{"class":360},[86,6752,6753],{"class":331},"x",[86,6755,974],{"class":360},[86,6757,2099],{"class":327},[86,6759,6760],{"class":331}," x ",[86,6762,1666],{"class":327},[86,6764,6765],{"class":331}," item",[86,6767,823],{"class":360},[86,6769,2479],{"class":331},[86,6771,787],{"class":360},[86,6773,5867],{"class":138},[86,6775,6776],{"class":96},"loc",[86,6778,5867],{"class":138},[86,6780,361],{"class":360},[86,6782,6783],{"class":360}," [])[",[86,6785,1527],{"class":107},[86,6787,6788],{"class":360},":])",[86,6790,1054],{"class":103},[86,6792,3951],{"class":96},[86,6794,1048],{"class":103},[86,6796,6797],{"class":331},"item",[86,6799,823],{"class":360},[86,6801,2479],{"class":331},[86,6803,787],{"class":360},[86,6805,5867],{"class":138},[86,6807,5643],{"class":96},[86,6809,5867],{"class":138},[86,6811,361],{"class":360},[86,6813,6814],{"class":138}," ''",[86,6816,974],{"class":360},[86,6818,1054],{"class":103},[86,6820,145],{"class":96},[86,6822,6823,6825,6828,6830],{"class":88,"line":346},[86,6824,1475],{"class":327},[86,6826,6827],{"class":331}," item ",[86,6829,1666],{"class":327},[86,6831,6832],{"class":331}," detail\n",[86,6834,6835],{"class":88,"line":382},[86,6836,1387],{"class":360},[86,6838,6839,6841],{"class":88,"line":405},[86,6840,1393],{"class":327},[86,6842,6843],{"class":360}," (\n",[86,6845,6846,6848,6851,6853],{"class":88,"line":410},[86,6847,2156],{"class":138},[86,6849,6850],{"class":96},"入力エラーで受け付けられませんでした。",[86,6852,6635],{"class":103},[86,6854,145],{"class":138},[86,6856,6857,6860,6862,6864,6866,6868,6870,6872,6875],{"class":88,"line":417},[86,6858,6859],{"class":779},"        +",[86,6861,139],{"class":138},[86,6863,6635],{"class":103},[86,6865,484],{"class":138},[86,6867,823],{"class":360},[86,6869,1022],{"class":331},[86,6871,787],{"class":360},[86,6873,6874],{"class":331},"lines",[86,6876,891],{"class":360},[86,6878,6879,6881,6883,6885,6887,6890,6893],{"class":88,"line":433},[86,6880,6859],{"class":779},[86,6882,3932],{"class":779},[86,6884,484],{"class":96},[86,6886,6635],{"class":103},[86,6888,6889],{"class":96},"使える勘定科目: ",[86,6891,6892],{"class":103},"{ACCOUNTS}",[86,6894,6895],{"class":96},"。日付は YYYY-MM-DD、金額は正の整数（円）です。\"\n",[86,6897,6898],{"class":88,"line":438},[86,6899,4470],{"class":360},[14,6901,6902,6905,6906,6909,6910,6912,6913,6916],{},[262,6903,6904],{},"部品3: API呼び出しの共通経路","。httpxでキーを付けて呼び、401と422をガイダンス付きの ",[51,6907,6908],{},"ToolError"," に変換する。",[51,6911,6908],{}," を投げると、MCPクライアントには ",[51,6914,6915],{},"isError: true"," のツール実行失敗として届き、成功と明確に区別される。",[77,6918,6920],{"className":282,"code":6919,"filename":6022,"language":284,"meta":82,"style":82},"def call_api(\n    tool: str,\n    method: str,\n    path: str,\n    *,\n    params: dict | None = None,\n    json_body: dict | None = None,\n) -> Any:\n    \"\"\"APIを呼び、エラーをエージェント向けのガイダンス文に整形する共通経路。\n\n    ToolErrorを投げると、MCPクライアントには isError: true のツール実行失敗として返る\n    （成功と区別されるので、エージェントが「失敗した」と認識してリカバリーに動ける）。\n    \"\"\"\n    args = {k: v for k, v in {\"params\": params, \"body\": json_body}.items() if v}\n    try:\n        res = httpx.request(\n            method,\n            BASE_URL + path,\n            headers={\"X-API-Key\": API_KEY},\n            params=params,\n            json=json_body,\n            timeout=10.0,\n        )\n    except httpx.ConnectError as e:\n        write_log(tool, args, \"connect_error\")\n        raise ToolError(\n            f\"APIに接続できません（{BASE_URL}）。\"\n            \"`uv run uvicorn api:app` でミニ仕訳帳APIが起動しているか確認してください。\"\n        ) from e\n    if res.status_code == 401:\n        write_log(tool, args, \"401\")\n        raise ToolError(\n            \"APIキーが違います。MCPサーバーの環境変数 JOURNAL_API_KEY を確認してください。\"\n        )\n    if res.status_code == 422:\n        write_log(tool, args, \"422\")\n        raise ToolError(format_422(res.json().get(\"detail\", [])))\n    res.raise_for_status()  # 予期しないステータスはそのままツール実行失敗として上げる\n    write_log(tool, args, str(res.status_code))\n    return res.json()\n",[51,6921,6922,6931,6942,6953,6964,6971,6990,7009,7019,7026,7030,7035,7040,7044,7110,7117,7133,7140,7152,7171,7182,7194,7206,7210,7228,7252,7261,7275,7284,7295,7312,7334,7342,7351,7355,7372,7395,7432,7447,7476],{"__ignoreMap":82},[86,6923,6924,6926,6929],{"class":88,"line":89},[86,6925,1129],{"class":779},[86,6927,6928],{"class":92}," call_api",[86,6930,1404],{"class":360},[86,6932,6933,6936,6938,6940],{"class":88,"line":111},[86,6934,6935],{"class":331},"    tool",[86,6937,450],{"class":360},[86,6939,464],{"class":114},[86,6941,496],{"class":360},[86,6943,6944,6947,6949,6951],{"class":88,"line":121},[86,6945,6946],{"class":331},"    method",[86,6948,450],{"class":360},[86,6950,464],{"class":114},[86,6952,496],{"class":360},[86,6954,6955,6958,6960,6962],{"class":88,"line":148},[86,6956,6957],{"class":331},"    path",[86,6959,450],{"class":360},[86,6961,464],{"class":114},[86,6963,496],{"class":360},[86,6965,6966,6969],{"class":88,"line":313},[86,6967,6968],{"class":779},"    *",[86,6970,496],{"class":331},[86,6972,6973,6976,6978,6980,6982,6984,6986,6988],{"class":88,"line":319},[86,6974,6975],{"class":331},"    params",[86,6977,450],{"class":360},[86,6979,453],{"class":114},[86,6981,2277],{"class":779},[86,6983,2050],{"class":327},[86,6985,423],{"class":360},[86,6987,2050],{"class":327},[86,6989,496],{"class":360},[86,6991,6992,6995,6997,6999,7001,7003,7005,7007],{"class":88,"line":324},[86,6993,6994],{"class":331},"    json_body",[86,6996,450],{"class":360},[86,6998,453],{"class":114},[86,7000,2277],{"class":779},[86,7002,2050],{"class":327},[86,7004,423],{"class":360},[86,7006,2050],{"class":327},[86,7008,496],{"class":360},[86,7010,7011,7013,7015,7017],{"class":88,"line":341},[86,7012,974],{"class":360},[86,7014,977],{"class":360},[86,7016,6397],{"class":331},[86,7018,982],{"class":360},[86,7020,7021,7023],{"class":88,"line":346},[86,7022,799],{"class":138},[86,7024,7025],{"class":96},"APIを呼び、エラーをエージェント向けのガイダンス文に整形する共通経路。\n",[86,7027,7028],{"class":88,"line":382},[86,7029,300],{"emptyLinePlaceholder":299},[86,7031,7032],{"class":88,"line":405},[86,7033,7034],{"class":96},"    ToolErrorを投げると、MCPクライアントには isError: true のツール実行失敗として返る\n",[86,7036,7037],{"class":88,"line":410},[86,7038,7039],{"class":96},"    （成功と区別されるので、エージェントが「失敗した」と認識してリカバリーに動ける）。\n",[86,7041,7042],{"class":88,"line":417},[86,7043,1638],{"class":138},[86,7045,7046,7049,7051,7053,7056,7058,7060,7062,7065,7067,7069,7071,7073,7075,7078,7080,7082,7084,7086,7088,7090,7092,7094,7097,7100,7102,7104,7106,7108],{"class":88,"line":433},[86,7047,7048],{"class":331},"    args ",[86,7050,871],{"class":360},[86,7052,3148],{"class":360},[86,7054,7055],{"class":331},"k",[86,7057,450],{"class":360},[86,7059,991],{"class":331},[86,7061,1700],{"class":327},[86,7063,7064],{"class":331}," k",[86,7066,361],{"class":360},[86,7068,991],{"class":331},[86,7070,1666],{"class":327},[86,7072,3148],{"class":360},[86,7074,484],{"class":138},[86,7076,7077],{"class":96},"params",[86,7079,484],{"class":138},[86,7081,450],{"class":360},[86,7083,4900],{"class":331},[86,7085,361],{"class":360},[86,7087,139],{"class":138},[86,7089,5414],{"class":96},[86,7091,484],{"class":138},[86,7093,450],{"class":360},[86,7095,7096],{"class":331}," json_body",[86,7098,7099],{"class":360},"}.",[86,7101,1673],{"class":331},[86,7103,1135],{"class":360},[86,7105,1834],{"class":327},[86,7107,967],{"class":331},[86,7109,626],{"class":360},[86,7111,7112,7115],{"class":88,"line":438},[86,7113,7114],{"class":327},"    try",[86,7116,982],{"class":360},[86,7118,7119,7122,7124,7126,7128,7131],{"class":88,"line":444},[86,7120,7121],{"class":331},"        res ",[86,7123,871],{"class":360},[86,7125,135],{"class":331},[86,7127,823],{"class":360},[86,7129,7130],{"class":331},"request",[86,7132,1404],{"class":360},[86,7134,7135,7138],{"class":88,"line":475},[86,7136,7137],{"class":331},"            method",[86,7139,496],{"class":360},[86,7141,7142,7145,7147,7150],{"class":88,"line":499},[86,7143,7144],{"class":103},"            BASE_URL",[86,7146,2782],{"class":779},[86,7148,7149],{"class":331}," path",[86,7151,496],{"class":360},[86,7153,7154,7157,7159,7161,7163,7165,7167,7169],{"class":88,"line":519},[86,7155,7156],{"class":867},"            headers",[86,7158,4903],{"class":360},[86,7160,484],{"class":138},[86,7162,256],{"class":96},[86,7164,484],{"class":138},[86,7166,450],{"class":360},[86,7168,2316],{"class":103},[86,7170,3333],{"class":360},[86,7172,7173,7176,7178,7180],{"class":88,"line":540},[86,7174,7175],{"class":867},"            params",[86,7177,871],{"class":360},[86,7179,7077],{"class":331},[86,7181,496],{"class":360},[86,7183,7184,7187,7189,7192],{"class":88,"line":561},[86,7185,7186],{"class":867},"            json",[86,7188,871],{"class":360},[86,7190,7191],{"class":331},"json_body",[86,7193,496],{"class":360},[86,7195,7196,7199,7201,7204],{"class":88,"line":582},[86,7197,7198],{"class":867},"            timeout",[86,7200,871],{"class":360},[86,7202,7203],{"class":107},"10.0",[86,7205,496],{"class":360},[86,7207,7208],{"class":88,"line":603},[86,7209,1469],{"class":360},[86,7211,7212,7215,7217,7219,7222,7224,7226],{"class":88,"line":623},[86,7213,7214],{"class":327},"    except",[86,7216,135],{"class":331},[86,7218,823],{"class":360},[86,7220,7221],{"class":331},"ConnectError ",[86,7223,335],{"class":327},[86,7225,1714],{"class":331},[86,7227,982],{"class":360},[86,7229,7230,7233,7235,7237,7239,7241,7243,7245,7248,7250],{"class":88,"line":629},[86,7231,7232],{"class":331},"        write_log",[86,7234,787],{"class":360},[86,7236,6375],{"class":331},[86,7238,361],{"class":360},[86,7240,6384],{"class":331},[86,7242,361],{"class":360},[86,7244,139],{"class":138},[86,7246,7247],{"class":96},"connect_error",[86,7249,484],{"class":138},[86,7251,891],{"class":360},[86,7253,7254,7256,7259],{"class":88,"line":634},[86,7255,2324],{"class":327},[86,7257,7258],{"class":331}," ToolError",[86,7260,1404],{"class":360},[86,7262,7263,7266,7269,7272],{"class":88,"line":640},[86,7264,7265],{"class":779},"            f",[86,7267,7268],{"class":96},"\"APIに接続できません（",[86,7270,7271],{"class":103},"{BASE_URL}",[86,7273,7274],{"class":96},"）。\"\n",[86,7276,7277,7279,7282],{"class":88,"line":664},[86,7278,2187],{"class":138},[86,7280,7281],{"class":96},"`uv run uvicorn api:app` でミニ仕訳帳APIが起動しているか確認してください。",[86,7283,145],{"class":138},[86,7285,7286,7289,7292],{"class":88,"line":684},[86,7287,7288],{"class":360},"        )",[86,7290,7291],{"class":327}," from",[86,7293,7294],{"class":331}," e\n",[86,7296,7297,7299,7301,7303,7305,7307,7310],{"class":88,"line":703},[86,7298,2308],{"class":327},[86,7300,3720],{"class":331},[86,7302,823],{"class":360},[86,7304,3725],{"class":331},[86,7306,1722],{"class":779},[86,7308,7309],{"class":107}," 401",[86,7311,982],{"class":360},[86,7313,7314,7316,7318,7320,7322,7324,7326,7328,7330,7332],{"class":88,"line":723},[86,7315,7232],{"class":331},[86,7317,787],{"class":360},[86,7319,6375],{"class":331},[86,7321,361],{"class":360},[86,7323,6384],{"class":331},[86,7325,361],{"class":360},[86,7327,139],{"class":138},[86,7329,2339],{"class":96},[86,7331,484],{"class":138},[86,7333,891],{"class":360},[86,7335,7336,7338,7340],{"class":88,"line":742},[86,7337,2324],{"class":327},[86,7339,7258],{"class":331},[86,7341,1404],{"class":360},[86,7343,7344,7346,7349],{"class":88,"line":761},[86,7345,2187],{"class":138},[86,7347,7348],{"class":96},"APIキーが違います。MCPサーバーの環境変数 JOURNAL_API_KEY を確認してください。",[86,7350,145],{"class":138},[86,7352,7353],{"class":88,"line":766},[86,7354,1469],{"class":360},[86,7356,7357,7359,7361,7363,7365,7367,7370],{"class":88,"line":771},[86,7358,2308],{"class":327},[86,7360,3720],{"class":331},[86,7362,823],{"class":360},[86,7364,3725],{"class":331},[86,7366,1722],{"class":779},[86,7368,7369],{"class":107}," 422",[86,7371,982],{"class":360},[86,7373,7374,7376,7378,7380,7382,7384,7386,7388,7391,7393],{"class":88,"line":776},[86,7375,7232],{"class":331},[86,7377,787],{"class":360},[86,7379,6375],{"class":331},[86,7381,361],{"class":360},[86,7383,6384],{"class":331},[86,7385,361],{"class":360},[86,7387,139],{"class":138},[86,7389,7390],{"class":96},"422",[86,7392,484],{"class":138},[86,7394,891],{"class":360},[86,7396,7397,7399,7401,7403,7406,7408,7411,7413,7415,7417,7419,7421,7423,7425,7427,7429],{"class":88,"line":796},[86,7398,2324],{"class":327},[86,7400,7258],{"class":331},[86,7402,787],{"class":360},[86,7404,7405],{"class":331},"format_422",[86,7407,787],{"class":360},[86,7409,7410],{"class":331},"res",[86,7412,823],{"class":360},[86,7414,3741],{"class":331},[86,7416,6480],{"class":360},[86,7418,2479],{"class":331},[86,7420,787],{"class":360},[86,7422,484],{"class":138},[86,7424,5629],{"class":96},[86,7426,484],{"class":138},[86,7428,361],{"class":360},[86,7430,7431],{"class":360}," [])))\n",[86,7433,7434,7437,7439,7442,7444],{"class":88,"line":807},[86,7435,7436],{"class":331},"    res",[86,7438,823],{"class":360},[86,7440,7441],{"class":331},"raise_for_status",[86,7443,1135],{"class":360},[86,7445,7446],{"class":413},"  # 予期しないステータスはそのままツール実行失敗として上げる\n",[86,7448,7449,7452,7454,7456,7458,7460,7462,7464,7466,7468,7470,7473],{"class":88,"line":812},[86,7450,7451],{"class":331},"    write_log",[86,7453,787],{"class":360},[86,7455,6375],{"class":331},[86,7457,361],{"class":360},[86,7459,6384],{"class":331},[86,7461,361],{"class":360},[86,7463,464],{"class":114},[86,7465,787],{"class":360},[86,7467,7410],{"class":331},[86,7469,823],{"class":360},[86,7471,7472],{"class":331},"status_code",[86,7474,7475],{"class":360},"))\n",[86,7477,7478,7480,7482,7484,7486],{"class":88,"line":829},[86,7479,1393],{"class":327},[86,7481,3720],{"class":331},[86,7483,823],{"class":360},[86,7485,3741],{"class":331},[86,7487,1567],{"class":360},[14,7489,7490],{},"エラー文面の設計は、freee-mcpから学んだ「読み手はLLMである」という前提をそのまま持ち込んだ。認証切れなら確認すべき環境変数の名前を、入力エラーなら使える科目の一覧を、失敗の報告と同じ文面に埋め込む。エージェントに「次に何をすべきか」を推測させない。",[14,7492,7493,7496],{},[262,7494,7495],{},"部品4: ツール3本の宣言","。docstringがそのままツールのdescriptionになる。",[77,7498,7500],{"className":282,"code":7499,"filename":6022,"language":284,"meta":82,"style":82},"@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))\ndef list_journal_entries(month: str | None = None) -> list[dict]:\n    \"\"\"仕訳の一覧を取得する。\n\n    month に \"YYYY-MM\"（例: \"2026-07\"）を渡すと、その月の仕訳だけに絞り込む。\n    省略するとすべての仕訳を返す。各仕訳は id・date・debit_account（借方科目）・\n    credit_account（貸方科目）・amount（金額・円）・description（摘要）を持つ。\n    \"\"\"\n    params = {\"month\": month} if month else None\n    return call_api(\"list_journal_entries\", \"GET\", \"/journal-entries\", params=params)\n\n\n@mcp.tool(\n    # 仕訳の新規登録は「加算的」で、既存データを書き換えも削除もしないので\n    # destructiveHint は付けない。freee-mcp対応: http-method-annotations.ts は\n    # POSTを一律 destructiveHint: true にする（HTTPメソッドから機械導出する保守的設計）。\n    # ツールを手で書くなら、操作の意味に即して申告できる。\n    # なお annotations は認可を強制しない「クライアント向けのヒント」にすぎない（MCP仕様）。\n    annotations=ToolAnnotations(readOnlyHint=False, destructiveHint=False),\n)\ndef register_journal_entry(\n    date: str,\n    debit_account: str,\n    credit_account: str,\n    amount: int,\n    description: str = \"\",\n) -> dict:\n    \"\"\"仕訳を1件登録する（1行仕訳のみ。借方1科目・貸方1科目）。\n\n    date は \"YYYY-MM-DD\" 形式、amount は正の整数（円）。\n    勘定科目はホワイトリスト制で、使えるのは次の7科目だけ:\n    現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費。\n    この一覧にない科目（例: 雑費）を渡すと入力エラーになる。\n    \"\"\"\n    body = {\n        \"date\": date,\n        \"debit_account\": debit_account,\n        \"credit_account\": credit_account,\n        \"amount\": amount,\n        \"description\": description,\n    }\n    return call_api(\"register_journal_entry\", \"POST\", \"/journal-entries\", json_body=body)\n\n\n@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))\ndef get_trial_balance() -> dict:\n    \"\"\"勘定科目別の残高試算表を取得する。\n\n    科目ごとに借方合計（debit_total）・貸方合計（credit_total）・残高（balance）・\n    残高の側（balance_side）・区分から決まる正常残高側（normal_side）を返す。\n    両者が食い違う科目には is_abnormal: true が立つ（例: 現金なのに貸方残）。\n    末尾の total で借方合計と貸方合計の一致（貸借一致）を確認できる。\n    \"\"\"\n    return call_api(\"get_trial_balance\", \"GET\", \"/trial-balance\")\n\n\nif __name__ == \"__main__\":\n    mcp.run()  # デフォルトはstdioトランスポート\n",[51,7501,7502,7534,7568,7575,7579,7584,7589,7594,7598,7628,7670,7674,7678,7690,7695,7700,7705,7710,7715,7743,7747,7755,7765,7775,7785,7795,7809,7819,7826,7830,7835,7840,7845,7850,7854,7862,7876,7890,7904,7918,7932,7936,7978,7982,7986,8014,8028,8035,8039,8044,8049,8054,8059,8063,8096,8100,8104,8122],{"__ignoreMap":82},[86,7503,7504,7506,7509,7511,7513,7515,7518,7520,7523,7525,7528,7530,7532],{"class":88,"line":89},[86,7505,2471],{"class":360},[86,7507,7508],{"class":92},"mcp",[86,7510,823],{"class":360},[86,7512,6375],{"class":92},[86,7514,787],{"class":360},[86,7516,7517],{"class":867},"annotations",[86,7519,871],{"class":360},[86,7521,7522],{"class":331},"ToolAnnotations",[86,7524,787],{"class":360},[86,7526,7527],{"class":867},"readOnlyHint",[86,7529,871],{"class":360},[86,7531,3195],{"class":327},[86,7533,7475],{"class":360},[86,7535,7536,7538,7540,7542,7544,7546,7548,7550,7552,7554,7556,7558,7560,7562,7564,7566],{"class":88,"line":111},[86,7537,1129],{"class":779},[86,7539,2498],{"class":92},[86,7541,787],{"class":360},[86,7543,4908],{"class":331},[86,7545,450],{"class":360},[86,7547,464],{"class":114},[86,7549,2277],{"class":779},[86,7551,2050],{"class":327},[86,7553,423],{"class":360},[86,7555,2050],{"class":327},[86,7557,974],{"class":360},[86,7559,977],{"class":360},[86,7561,1140],{"class":331},[86,7563,456],{"class":360},[86,7565,6683],{"class":114},[86,7567,1148],{"class":360},[86,7569,7570,7572],{"class":88,"line":121},[86,7571,799],{"class":138},[86,7573,7574],{"class":96},"仕訳の一覧を取得する。\n",[86,7576,7577],{"class":88,"line":148},[86,7578,300],{"emptyLinePlaceholder":299},[86,7580,7581],{"class":88,"line":313},[86,7582,7583],{"class":96},"    month に \"YYYY-MM\"（例: \"2026-07\"）を渡すと、その月の仕訳だけに絞り込む。\n",[86,7585,7586],{"class":88,"line":319},[86,7587,7588],{"class":96},"    省略するとすべての仕訳を返す。各仕訳は id・date・debit_account（借方科目）・\n",[86,7590,7591],{"class":88,"line":324},[86,7592,7593],{"class":96},"    credit_account（貸方科目）・amount（金額・円）・description（摘要）を持つ。\n",[86,7595,7596],{"class":88,"line":341},[86,7597,1638],{"class":138},[86,7599,7600,7603,7605,7607,7609,7611,7613,7615,7617,7619,7621,7623,7626],{"class":88,"line":346},[86,7601,7602],{"class":331},"    params ",[86,7604,871],{"class":360},[86,7606,3148],{"class":360},[86,7608,484],{"class":138},[86,7610,4908],{"class":96},[86,7612,484],{"class":138},[86,7614,450],{"class":360},[86,7616,2659],{"class":331},[86,7618,1054],{"class":360},[86,7620,1834],{"class":327},[86,7622,2594],{"class":331},[86,7624,7625],{"class":327},"else",[86,7627,1865],{"class":327},[86,7629,7630,7632,7634,7636,7638,7641,7643,7645,7647,7650,7652,7654,7656,7658,7660,7662,7664,7666,7668],{"class":88,"line":382},[86,7631,1393],{"class":327},[86,7633,6928],{"class":331},[86,7635,787],{"class":360},[86,7637,484],{"class":138},[86,7639,7640],{"class":96},"list_journal_entries",[86,7642,484],{"class":138},[86,7644,361],{"class":360},[86,7646,139],{"class":138},[86,7648,7649],{"class":96},"GET",[86,7651,484],{"class":138},[86,7653,361],{"class":360},[86,7655,139],{"class":138},[86,7657,2486],{"class":96},[86,7659,484],{"class":138},[86,7661,361],{"class":360},[86,7663,4900],{"class":867},[86,7665,871],{"class":360},[86,7667,7077],{"class":331},[86,7669,891],{"class":360},[86,7671,7672],{"class":88,"line":405},[86,7673,300],{"emptyLinePlaceholder":299},[86,7675,7676],{"class":88,"line":410},[86,7677,300],{"emptyLinePlaceholder":299},[86,7679,7680,7682,7684,7686,7688],{"class":88,"line":417},[86,7681,2471],{"class":360},[86,7683,7508],{"class":92},[86,7685,823],{"class":360},[86,7687,6375],{"class":92},[86,7689,1404],{"class":360},[86,7691,7692],{"class":88,"line":433},[86,7693,7694],{"class":413},"    # 仕訳の新規登録は「加算的」で、既存データを書き換えも削除もしないので\n",[86,7696,7697],{"class":88,"line":438},[86,7698,7699],{"class":413},"    # destructiveHint は付けない。freee-mcp対応: http-method-annotations.ts は\n",[86,7701,7702],{"class":88,"line":444},[86,7703,7704],{"class":413},"    # POSTを一律 destructiveHint: true にする（HTTPメソッドから機械導出する保守的設計）。\n",[86,7706,7707],{"class":88,"line":475},[86,7708,7709],{"class":413},"    # ツールを手で書くなら、操作の意味に即して申告できる。\n",[86,7711,7712],{"class":88,"line":499},[86,7713,7714],{"class":413},"    # なお annotations は認可を強制しない「クライアント向けのヒント」にすぎない（MCP仕様）。\n",[86,7716,7717,7720,7722,7724,7726,7728,7730,7732,7734,7737,7739,7741],{"class":88,"line":519},[86,7718,7719],{"class":867},"    annotations",[86,7721,871],{"class":360},[86,7723,7522],{"class":331},[86,7725,787],{"class":360},[86,7727,7527],{"class":867},[86,7729,871],{"class":360},[86,7731,6626],{"class":327},[86,7733,361],{"class":360},[86,7735,7736],{"class":867}," destructiveHint",[86,7738,871],{"class":360},[86,7740,6626],{"class":327},[86,7742,1205],{"class":360},[86,7744,7745],{"class":88,"line":540},[86,7746,891],{"class":360},[86,7748,7749,7751,7753],{"class":88,"line":561},[86,7750,1129],{"class":779},[86,7752,2711],{"class":92},[86,7754,1404],{"class":360},[86,7756,7757,7759,7761,7763],{"class":88,"line":582},[86,7758,815],{"class":331},[86,7760,450],{"class":360},[86,7762,464],{"class":114},[86,7764,496],{"class":360},[86,7766,7767,7769,7771,7773],{"class":88,"line":603},[86,7768,832],{"class":331},[86,7770,450],{"class":360},[86,7772,464],{"class":114},[86,7774,496],{"class":360},[86,7776,7777,7779,7781,7783],{"class":88,"line":623},[86,7778,843],{"class":331},[86,7780,450],{"class":360},[86,7782,464],{"class":114},[86,7784,496],{"class":360},[86,7786,7787,7789,7791,7793],{"class":88,"line":629},[86,7788,853],{"class":331},[86,7790,450],{"class":360},[86,7792,858],{"class":114},[86,7794,496],{"class":360},[86,7796,7797,7799,7801,7803,7805,7807],{"class":88,"line":634},[86,7798,897],{"class":331},[86,7800,450],{"class":360},[86,7802,464],{"class":114},[86,7804,423],{"class":360},[86,7806,6230],{"class":138},[86,7808,496],{"class":360},[86,7810,7811,7813,7815,7817],{"class":88,"line":640},[86,7812,974],{"class":360},[86,7814,977],{"class":360},[86,7816,453],{"class":114},[86,7818,982],{"class":360},[86,7820,7821,7823],{"class":88,"line":664},[86,7822,799],{"class":138},[86,7824,7825],{"class":96},"仕訳を1件登録する（1行仕訳のみ。借方1科目・貸方1科目）。\n",[86,7827,7828],{"class":88,"line":684},[86,7829,300],{"emptyLinePlaceholder":299},[86,7831,7832],{"class":88,"line":703},[86,7833,7834],{"class":96},"    date は \"YYYY-MM-DD\" 形式、amount は正の整数（円）。\n",[86,7836,7837],{"class":88,"line":723},[86,7838,7839],{"class":96},"    勘定科目はホワイトリスト制で、使えるのは次の7科目だけ:\n",[86,7841,7842],{"class":88,"line":742},[86,7843,7844],{"class":96},"    現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費。\n",[86,7846,7847],{"class":88,"line":761},[86,7848,7849],{"class":96},"    この一覧にない科目（例: 雑費）を渡すと入力エラーになる。\n",[86,7851,7852],{"class":88,"line":766},[86,7853,1638],{"class":138},[86,7855,7856,7858,7860],{"class":88,"line":771},[86,7857,5274],{"class":331},[86,7859,871],{"class":360},[86,7861,472],{"class":360},[86,7863,7864,7866,7868,7870,7872,7874],{"class":88,"line":776},[86,7865,2156],{"class":138},[86,7867,2637],{"class":96},[86,7869,484],{"class":138},[86,7871,450],{"class":360},[86,7873,1420],{"class":331},[86,7875,496],{"class":360},[86,7877,7878,7880,7882,7884,7886,7888],{"class":88,"line":796},[86,7879,2156],{"class":138},[86,7881,927],{"class":96},[86,7883,484],{"class":138},[86,7885,450],{"class":360},[86,7887,1430],{"class":331},[86,7889,496],{"class":360},[86,7891,7892,7894,7896,7898,7900,7902],{"class":88,"line":807},[86,7893,2156],{"class":138},[86,7895,936],{"class":96},[86,7897,484],{"class":138},[86,7899,450],{"class":360},[86,7901,1440],{"class":331},[86,7903,496],{"class":360},[86,7905,7906,7908,7910,7912,7914,7916],{"class":88,"line":812},[86,7907,2156],{"class":138},[86,7909,4432],{"class":96},[86,7911,484],{"class":138},[86,7913,450],{"class":360},[86,7915,1450],{"class":331},[86,7917,496],{"class":360},[86,7919,7920,7922,7924,7926,7928,7930],{"class":88,"line":829},[86,7921,2156],{"class":138},[86,7923,4448],{"class":96},[86,7925,484],{"class":138},[86,7927,450],{"class":360},[86,7929,879],{"class":331},[86,7931,496],{"class":360},[86,7933,7934],{"class":88,"line":840},[86,7935,2247],{"class":360},[86,7937,7938,7940,7942,7944,7946,7949,7951,7953,7955,7958,7960,7962,7964,7966,7968,7970,7972,7974,7976],{"class":88,"line":850},[86,7939,1393],{"class":327},[86,7941,6928],{"class":331},[86,7943,787],{"class":360},[86,7945,484],{"class":138},[86,7947,7948],{"class":96},"register_journal_entry",[86,7950,484],{"class":138},[86,7952,361],{"class":360},[86,7954,139],{"class":138},[86,7956,7957],{"class":96},"POST",[86,7959,484],{"class":138},[86,7961,361],{"class":360},[86,7963,139],{"class":138},[86,7965,2486],{"class":96},[86,7967,484],{"class":138},[86,7969,361],{"class":360},[86,7971,7096],{"class":867},[86,7973,871],{"class":360},[86,7975,5414],{"class":331},[86,7977,891],{"class":360},[86,7979,7980],{"class":88,"line":894},[86,7981,300],{"emptyLinePlaceholder":299},[86,7983,7984],{"class":88,"line":909},[86,7985,300],{"emptyLinePlaceholder":299},[86,7987,7988,7990,7992,7994,7996,7998,8000,8002,8004,8006,8008,8010,8012],{"class":88,"line":914},[86,7989,2471],{"class":360},[86,7991,7508],{"class":92},[86,7993,823],{"class":360},[86,7995,6375],{"class":92},[86,7997,787],{"class":360},[86,7999,7517],{"class":867},[86,8001,871],{"class":360},[86,8003,7522],{"class":331},[86,8005,787],{"class":360},[86,8007,7527],{"class":867},[86,8009,871],{"class":360},[86,8011,3195],{"class":327},[86,8013,7475],{"class":360},[86,8015,8016,8018,8020,8022,8024,8026],{"class":88,"line":943},[86,8017,1129],{"class":779},[86,8019,2885],{"class":92},[86,8021,1135],{"class":360},[86,8023,977],{"class":360},[86,8025,453],{"class":114},[86,8027,982],{"class":360},[86,8029,8030,8032],{"class":88,"line":951},[86,8031,799],{"class":138},[86,8033,8034],{"class":96},"勘定科目別の残高試算表を取得する。\n",[86,8036,8037],{"class":88,"line":985},[86,8038,300],{"emptyLinePlaceholder":299},[86,8040,8041],{"class":88,"line":1005},[86,8042,8043],{"class":96},"    科目ごとに借方合計（debit_total）・貸方合計（credit_total）・残高（balance）・\n",[86,8045,8046],{"class":88,"line":1031},[86,8047,8048],{"class":96},"    残高の側（balance_side）・区分から決まる正常残高側（normal_side）を返す。\n",[86,8050,8051],{"class":88,"line":1071},[86,8052,8053],{"class":96},"    両者が食い違う科目には is_abnormal: true が立つ（例: 現金なのに貸方残）。\n",[86,8055,8056],{"class":88,"line":1080},[86,8057,8058],{"class":96},"    末尾の total で借方合計と貸方合計の一致（貸借一致）を確認できる。\n",[86,8060,8061],{"class":88,"line":1085},[86,8062,1638],{"class":138},[86,8064,8065,8067,8069,8071,8073,8076,8078,8080,8082,8084,8086,8088,8090,8092,8094],{"class":88,"line":1090},[86,8066,1393],{"class":327},[86,8068,6928],{"class":331},[86,8070,787],{"class":360},[86,8072,484],{"class":138},[86,8074,8075],{"class":96},"get_trial_balance",[86,8077,484],{"class":138},[86,8079,361],{"class":360},[86,8081,139],{"class":138},[86,8083,7649],{"class":96},[86,8085,484],{"class":138},[86,8087,361],{"class":360},[86,8089,139],{"class":138},[86,8091,2873],{"class":96},[86,8093,484],{"class":138},[86,8095,891],{"class":360},[86,8097,8098],{"class":88,"line":1105},[86,8099,300],{"emptyLinePlaceholder":299},[86,8101,8102],{"class":88,"line":1116},[86,8103,300],{"emptyLinePlaceholder":299},[86,8105,8106,8108,8111,8113,8115,8118,8120],{"class":88,"line":1121},[86,8107,1711],{"class":327},[86,8109,8110],{"class":114}," __name__",[86,8112,2656],{"class":779},[86,8114,139],{"class":138},[86,8116,8117],{"class":96},"__main__",[86,8119,484],{"class":138},[86,8121,982],{"class":360},[86,8123,8124,8127,8129,8132,8134],{"class":88,"line":1126},[86,8125,8126],{"class":331},"    mcp",[86,8128,823],{"class":360},[86,8130,8131],{"class":331},"run",[86,8133,1135],{"class":360},[86,8135,8136],{"class":413},"  # デフォルトはstdioトランスポート\n",[14,8138,8139],{},"descriptionは日本語で、使える科目の一覧まで書き込んだ。エージェントはこの文章を実行時に読んでツールの使い方を決めるので、宣言の書き込みの質が、そのままエージェントの動作精度になる。freee-mcpのツール宣言が素っ気ない固定文字列だったのは、仕様知識をAgent Skills側へ分離したからで、うちのように3本しかなければ宣言に直接書くのが早い。同じ問題への、規模に応じた別の解だ。",[14,8141,8142,8143,8145,8146,8149,8150,8153,8154,8157,8158,8163],{},"annotationsには2つ論点を仕込んだ。1つは ",[51,8144,7948],{}," の ",[51,8147,8148],{},"destructiveHint: false","。freee-mcpはHTTPメソッドから機械的に導出するので、POSTは一律 ",[51,8151,8152],{},"destructiveHint: true"," になる。既存データを知らずに壊す可能性を広めに申告する保守的な設計だ。一方、仕訳の新規登録は既存の仕訳を1件も書き換えない加算的な操作なので、手でツールを書くなら意味に即して ",[51,8155,8156],{},"false"," と申告できる。もう1つは、そもそもannotationsは認可を強制しない「クライアント向けのヒント」にすぎないことで、これは",[17,8159,8162],{"href":8160,"target":41,"rel":8161},"https://modelcontextprotocol.io/specification/2025-06-18/server/tools",[43,44],"→ MCP仕様のツールの節","に明記されている。ヒントを見て確認UIを出すかどうかは、クライアントの仕事。この分業は後の実験で実際に確かめる。",[196,8165,8167],{"id":8166},"step-4-宣言を覗いてからつなぐ","Step 4: 宣言を覗いてから、つなぐ",[14,8169,8170,8171,8174,8175,8178],{},"Claude Codeにつなぐ前に、エージェントが実際に何を見るのかを自分の目で確かめたい。MCPクライアントを名乗る50行ほどのスクリプトを書いて、",[51,8172,8173],{},"tools/list","（ツール宣言の一覧）と ",[51,8176,8177],{},"tools/call","（ツールの実行）を1回ずつ叩く。",[77,8180,8183],{"className":282,"code":8181,"filename":8182,"language":284,"meta":82,"style":82},"\"\"\"MCPクライアントとしてserver.pyを起動し、tools/listとtools/callを1回ずつ実行する。\n\nエージェントが実際に見ているツール宣言（生JSON）を自分の目で確かめるための採取スクリプト。\n実行: uv run inspect_tools.py（事前に環境変数 JOURNAL_API_KEY を設定し、APIを起動しておく）\n\"\"\"\n\nimport asyncio\nimport json\nimport os\nimport sys\n\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import get_default_environment, stdio_client\n\n\nasync def main() -> None:\n    key = os.environ.get(\"JOURNAL_API_KEY\")\n    if not key:\n        sys.exit(\"環境変数 JOURNAL_API_KEY を設定してから実行してください。\")\n\n    # server.py をサブプロセスとして起動する。環境変数はこの env 経由で明示的に渡す\n    server = StdioServerParameters(\n        command=sys.executable,\n        args=[\"server.py\"],\n        env={\n            **get_default_environment(),\n            \"JOURNAL_API_KEY\": key,\n            \"JOURNAL_API_BASE_URL\": os.environ.get(\n                \"JOURNAL_API_BASE_URL\", \"http://127.0.0.1:8000\"\n            ),\n        },\n    )\n    async with stdio_client(server) as (read, write):\n        async with ClientSession(read, write) as session:\n            await session.initialize()\n\n            tools = await session.list_tools()\n            print(\"=== tools/list ===\")\n            print(\n                json.dumps(\n                    [t.model_dump(exclude_none=True) for t in tools.tools],\n                    ensure_ascii=False,\n                    indent=2,\n                )\n            )\n\n            result = await session.call_tool(\"get_trial_balance\", {})\n            print(\"=== tools/call get_trial_balance ===\")\n            print(json.dumps(result.model_dump(exclude_none=True), ensure_ascii=False, indent=2))\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n","inspect_tools.py",[51,8184,8185,8192,8196,8201,8206,8210,8214,8221,8227,8233,8240,8244,8261,8287,8291,8295,8314,8341,8351,8372,8376,8381,8393,8410,8426,8433,8444,8458,8480,8496,8501,8505,8509,8540,8566,8580,8584,8603,8619,8625,8636,8676,8687,8699,8704,8709,8713,8742,8757,8805,8809,8813,8829],{"__ignoreMap":82},[86,8186,8187,8189],{"class":88,"line":89},[86,8188,291],{"class":138},[86,8190,8191],{"class":96},"MCPクライアントとしてserver.pyを起動し、tools/listとtools/callを1回ずつ実行する。\n",[86,8193,8194],{"class":88,"line":111},[86,8195,300],{"emptyLinePlaceholder":299},[86,8197,8198],{"class":88,"line":121},[86,8199,8200],{"class":96},"エージェントが実際に見ているツール宣言（生JSON）を自分の目で確かめるための採取スクリプト。\n",[86,8202,8203],{"class":88,"line":148},[86,8204,8205],{"class":96},"実行: uv run inspect_tools.py（事前に環境変数 JOURNAL_API_KEY を設定し、APIを起動しておく）\n",[86,8207,8208],{"class":88,"line":313},[86,8209,316],{"class":138},[86,8211,8212],{"class":88,"line":319},[86,8213,300],{"emptyLinePlaceholder":299},[86,8215,8216,8218],{"class":88,"line":324},[86,8217,328],{"class":327},[86,8219,8220],{"class":331}," asyncio\n",[86,8222,8223,8225],{"class":88,"line":341},[86,8224,328],{"class":327},[86,8226,6080],{"class":331},[86,8228,8229,8231],{"class":88,"line":346},[86,8230,328],{"class":327},[86,8232,6087],{"class":331},[86,8234,8235,8237],{"class":88,"line":382},[86,8236,328],{"class":327},[86,8238,8239],{"class":331}," sys\n",[86,8241,8242],{"class":88,"line":405},[86,8243,300],{"emptyLinePlaceholder":299},[86,8245,8246,8248,8251,8253,8256,8258],{"class":88,"line":410},[86,8247,349],{"class":327},[86,8249,8250],{"class":331}," mcp ",[86,8252,328],{"class":327},[86,8254,8255],{"class":331}," ClientSession",[86,8257,361],{"class":360},[86,8259,8260],{"class":331}," StdioServerParameters\n",[86,8262,8263,8265,8267,8269,8272,8274,8277,8279,8282,8284],{"class":88,"line":417},[86,8264,349],{"class":327},[86,8266,6129],{"class":331},[86,8268,823],{"class":360},[86,8270,8271],{"class":331},"client",[86,8273,823],{"class":360},[86,8275,8276],{"class":331},"stdio ",[86,8278,328],{"class":327},[86,8280,8281],{"class":331}," get_default_environment",[86,8283,361],{"class":360},[86,8285,8286],{"class":331}," stdio_client\n",[86,8288,8289],{"class":88,"line":433},[86,8290,300],{"emptyLinePlaceholder":299},[86,8292,8293],{"class":88,"line":438},[86,8294,300],{"emptyLinePlaceholder":299},[86,8296,8297,8300,8303,8306,8308,8310,8312],{"class":88,"line":444},[86,8298,8299],{"class":779},"async",[86,8301,8302],{"class":779}," def",[86,8304,8305],{"class":92}," main",[86,8307,1135],{"class":360},[86,8309,977],{"class":360},[86,8311,2050],{"class":327},[86,8313,982],{"class":360},[86,8315,8316,8319,8321,8323,8325,8327,8329,8331,8333,8335,8337,8339],{"class":88,"line":475},[86,8317,8318],{"class":331},"    key ",[86,8320,871],{"class":360},[86,8322,6208],{"class":331},[86,8324,823],{"class":360},[86,8326,6213],{"class":331},[86,8328,823],{"class":360},[86,8330,2479],{"class":331},[86,8332,787],{"class":360},[86,8334,484],{"class":138},[86,8336,5815],{"class":96},[86,8338,484],{"class":138},[86,8340,891],{"class":360},[86,8342,8343,8345,8347,8349],{"class":88,"line":499},[86,8344,2308],{"class":327},[86,8346,2047],{"class":779},[86,8348,3891],{"class":331},[86,8350,982],{"class":360},[86,8352,8353,8356,8358,8361,8363,8365,8368,8370],{"class":88,"line":519},[86,8354,8355],{"class":331},"        sys",[86,8357,823],{"class":360},[86,8359,8360],{"class":331},"exit",[86,8362,787],{"class":360},[86,8364,484],{"class":138},[86,8366,8367],{"class":96},"環境変数 JOURNAL_API_KEY を設定してから実行してください。",[86,8369,484],{"class":138},[86,8371,891],{"class":360},[86,8373,8374],{"class":88,"line":540},[86,8375,300],{"emptyLinePlaceholder":299},[86,8377,8378],{"class":88,"line":561},[86,8379,8380],{"class":413},"    # server.py をサブプロセスとして起動する。環境変数はこの env 経由で明示的に渡す\n",[86,8382,8383,8386,8388,8391],{"class":88,"line":582},[86,8384,8385],{"class":331},"    server ",[86,8387,871],{"class":360},[86,8389,8390],{"class":331}," StdioServerParameters",[86,8392,1404],{"class":360},[86,8394,8395,8398,8400,8403,8405,8408],{"class":88,"line":603},[86,8396,8397],{"class":867},"        command",[86,8399,871],{"class":360},[86,8401,8402],{"class":331},"sys",[86,8404,823],{"class":360},[86,8406,8407],{"class":331},"executable",[86,8409,496],{"class":360},[86,8411,8412,8415,8417,8419,8421,8423],{"class":88,"line":623},[86,8413,8414],{"class":867},"        args",[86,8416,2439],{"class":360},[86,8418,484],{"class":138},[86,8420,6022],{"class":96},[86,8422,484],{"class":138},[86,8424,8425],{"class":360},"],\n",[86,8427,8428,8431],{"class":88,"line":629},[86,8429,8430],{"class":867},"        env",[86,8432,4370],{"class":360},[86,8434,8435,8438,8441],{"class":88,"line":634},[86,8436,8437],{"class":779},"            **",[86,8439,8440],{"class":331},"get_default_environment",[86,8442,8443],{"class":360},"(),\n",[86,8445,8446,8448,8450,8452,8454,8456],{"class":88,"line":640},[86,8447,2187],{"class":138},[86,8449,5815],{"class":96},[86,8451,484],{"class":138},[86,8453,450],{"class":360},[86,8455,3891],{"class":331},[86,8457,496],{"class":360},[86,8459,8460,8462,8464,8466,8468,8470,8472,8474,8476,8478],{"class":88,"line":664},[86,8461,2187],{"class":138},[86,8463,6256],{"class":96},[86,8465,484],{"class":138},[86,8467,450],{"class":360},[86,8469,6208],{"class":331},[86,8471,823],{"class":360},[86,8473,6213],{"class":331},[86,8475,823],{"class":360},[86,8477,2479],{"class":331},[86,8479,1404],{"class":360},[86,8481,8482,8484,8486,8488,8490,8492,8494],{"class":88,"line":684},[86,8483,1909],{"class":138},[86,8485,6256],{"class":96},[86,8487,484],{"class":138},[86,8489,361],{"class":360},[86,8491,139],{"class":138},[86,8493,5915],{"class":96},[86,8495,145],{"class":138},[86,8497,8498],{"class":88,"line":703},[86,8499,8500],{"class":360},"            ),\n",[86,8502,8503],{"class":88,"line":723},[86,8504,2241],{"class":360},[86,8506,8507],{"class":88,"line":742},[86,8508,4470],{"class":360},[86,8510,8511,8514,8517,8520,8522,8524,8526,8528,8530,8533,8535,8538],{"class":88,"line":761},[86,8512,8513],{"class":327},"    async",[86,8515,8516],{"class":327}," with",[86,8518,8519],{"class":331}," stdio_client",[86,8521,787],{"class":360},[86,8523,6134],{"class":331},[86,8525,974],{"class":360},[86,8527,6588],{"class":327},[86,8529,1483],{"class":360},[86,8531,8532],{"class":331},"read",[86,8534,361],{"class":360},[86,8536,8537],{"class":331}," write",[86,8539,793],{"class":360},[86,8541,8542,8545,8547,8549,8551,8553,8555,8557,8559,8561,8564],{"class":88,"line":766},[86,8543,8544],{"class":327},"        async",[86,8546,8516],{"class":327},[86,8548,8255],{"class":331},[86,8550,787],{"class":360},[86,8552,8532],{"class":331},[86,8554,361],{"class":360},[86,8556,8537],{"class":331},[86,8558,974],{"class":360},[86,8560,6588],{"class":327},[86,8562,8563],{"class":331}," session",[86,8565,982],{"class":360},[86,8567,8568,8571,8573,8575,8578],{"class":88,"line":771},[86,8569,8570],{"class":327},"            await",[86,8572,8563],{"class":331},[86,8574,823],{"class":360},[86,8576,8577],{"class":331},"initialize",[86,8579,1567],{"class":360},[86,8581,8582],{"class":88,"line":776},[86,8583,300],{"emptyLinePlaceholder":299},[86,8585,8586,8589,8591,8594,8596,8598,8601],{"class":88,"line":796},[86,8587,8588],{"class":331},"            tools ",[86,8590,871],{"class":360},[86,8592,8593],{"class":327}," await",[86,8595,8563],{"class":331},[86,8597,823],{"class":360},[86,8599,8600],{"class":331},"list_tools",[86,8602,1567],{"class":360},[86,8604,8605,8608,8610,8612,8615,8617],{"class":88,"line":807},[86,8606,8607],{"class":114},"            print",[86,8609,787],{"class":360},[86,8611,484],{"class":138},[86,8613,8614],{"class":96},"=== tools/list ===",[86,8616,484],{"class":138},[86,8618,891],{"class":360},[86,8620,8621,8623],{"class":88,"line":812},[86,8622,8607],{"class":114},[86,8624,1404],{"class":360},[86,8626,8627,8630,8632,8634],{"class":88,"line":829},[86,8628,8629],{"class":331},"                json",[86,8631,823],{"class":360},[86,8633,6611],{"class":331},[86,8635,1404],{"class":360},[86,8637,8638,8641,8644,8646,8648,8650,8653,8655,8657,8659,8661,8664,8666,8669,8671,8674],{"class":88,"line":840},[86,8639,8640],{"class":360},"                    [",[86,8642,8643],{"class":331},"t",[86,8645,823],{"class":360},[86,8647,2817],{"class":331},[86,8649,787],{"class":360},[86,8651,8652],{"class":867},"exclude_none",[86,8654,871],{"class":360},[86,8656,3195],{"class":327},[86,8658,974],{"class":360},[86,8660,2099],{"class":327},[86,8662,8663],{"class":331}," t ",[86,8665,1666],{"class":327},[86,8667,8668],{"class":331}," tools",[86,8670,823],{"class":360},[86,8672,8673],{"class":331},"tools",[86,8675,8425],{"class":360},[86,8677,8678,8681,8683,8685],{"class":88,"line":850},[86,8679,8680],{"class":867},"                    ensure_ascii",[86,8682,871],{"class":360},[86,8684,6626],{"class":327},[86,8686,496],{"class":360},[86,8688,8689,8692,8694,8697],{"class":88,"line":894},[86,8690,8691],{"class":867},"                    indent",[86,8693,871],{"class":360},[86,8695,8696],{"class":107},"2",[86,8698,496],{"class":360},[86,8700,8701],{"class":88,"line":909},[86,8702,8703],{"class":360},"                )\n",[86,8705,8706],{"class":88,"line":914},[86,8707,8708],{"class":360},"            )\n",[86,8710,8711],{"class":88,"line":943},[86,8712,300],{"emptyLinePlaceholder":299},[86,8714,8715,8718,8720,8722,8724,8726,8729,8731,8733,8735,8737,8739],{"class":88,"line":951},[86,8716,8717],{"class":331},"            result ",[86,8719,871],{"class":360},[86,8721,8593],{"class":327},[86,8723,8563],{"class":331},[86,8725,823],{"class":360},[86,8727,8728],{"class":331},"call_tool",[86,8730,787],{"class":360},[86,8732,484],{"class":138},[86,8734,8075],{"class":96},[86,8736,484],{"class":138},[86,8738,361],{"class":360},[86,8740,8741],{"class":360}," {})\n",[86,8743,8744,8746,8748,8750,8753,8755],{"class":88,"line":985},[86,8745,8607],{"class":114},[86,8747,787],{"class":360},[86,8749,484],{"class":138},[86,8751,8752],{"class":96},"=== tools/call get_trial_balance ===",[86,8754,484],{"class":138},[86,8756,891],{"class":360},[86,8758,8759,8761,8763,8765,8767,8769,8771,8774,8776,8778,8780,8782,8784,8786,8788,8790,8792,8794,8796,8799,8801,8803],{"class":88,"line":1005},[86,8760,8607],{"class":114},[86,8762,787],{"class":360},[86,8764,3741],{"class":331},[86,8766,823],{"class":360},[86,8768,6611],{"class":331},[86,8770,787],{"class":360},[86,8772,8773],{"class":331},"result",[86,8775,823],{"class":360},[86,8777,2817],{"class":331},[86,8779,787],{"class":360},[86,8781,8652],{"class":867},[86,8783,871],{"class":360},[86,8785,3195],{"class":327},[86,8787,2770],{"class":360},[86,8789,6621],{"class":867},[86,8791,871],{"class":360},[86,8793,6626],{"class":327},[86,8795,361],{"class":360},[86,8797,8798],{"class":867}," indent",[86,8800,871],{"class":360},[86,8802,8696],{"class":107},[86,8804,7475],{"class":360},[86,8806,8807],{"class":88,"line":1031},[86,8808,300],{"emptyLinePlaceholder":299},[86,8810,8811],{"class":88,"line":1071},[86,8812,300],{"emptyLinePlaceholder":299},[86,8814,8815,8817,8819,8821,8823,8825,8827],{"class":88,"line":1080},[86,8816,1711],{"class":327},[86,8818,8110],{"class":114},[86,8820,2656],{"class":779},[86,8822,139],{"class":138},[86,8824,8117],{"class":96},[86,8826,484],{"class":138},[86,8828,982],{"class":360},[86,8830,8831,8834,8836,8838,8840,8843],{"class":88,"line":1085},[86,8832,8833],{"class":331},"    asyncio",[86,8835,823],{"class":360},[86,8837,8131],{"class":331},[86,8839,787],{"class":360},[86,8841,8842],{"class":331},"main",[86,8844,2820],{"class":360},[14,8846,8847],{},"APIを起動したまま、別のターミナルで実行する（Step 1のcurlで登録した仕訳が残っていると試算表の数値が変わる。シード状態の出力を再現したいときは、uvicornをいったん再起動してから実行する）。",[77,8849,8851],{"className":79,"code":8850,"language":81,"meta":82,"style":82},"export JOURNAL_API_KEY=\"sk-journal-tutorial-2026\"\nuv run inspect_tools.py\n",[51,8852,8853,8867],{"__ignoreMap":82},[86,8854,8855,8857,8859,8861,8863,8865],{"class":88,"line":89},[86,8856,53],{"class":779},[86,8858,5842],{"class":867},[86,8860,871],{"class":360},[86,8862,484],{"class":138},[86,8864,428],{"class":96},[86,8866,145],{"class":138},[86,8868,8869,8871,8873],{"class":88,"line":111},[86,8870,93],{"class":92},[86,8872,5709],{"class":96},[86,8874,8875],{"class":96}," inspect_tools.py\n",[14,8877,8878,8879,8881,8882,8884],{},"出てきた ",[51,8880,8173],{}," の生JSONがこれだ。エージェントが接続時に受け取るものと同じで、名前と説明文と入出力スキーマとannotations、それがすべてだ。",[51,8883,6022],{}," の実装コードも、APIキーも、この中には存在しない。",[77,8886,8889],{"className":8887,"code":8888,"language":3741,"meta":82,"style":82},"language-json shiki shiki-themes vitesse-light vitesse-light","[\n  {\n    \"name\": \"list_journal_entries\",\n    \"description\": \"仕訳の一覧を取得する。\\n\\n    month に \\\"YYYY-MM\\\"（例: \\\"2026-07\\\"）を渡すと、その月の仕訳だけに絞り込む。\\n    省略するとすべての仕訳を返す。各仕訳は id・date・debit_account（借方科目）・\\n    credit_account（貸方科目）・amount（金額・円）・description（摘要）を持つ。\\n    \",\n    \"inputSchema\": {\n      \"properties\": {\n        \"month\": {\n          \"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"null\" }],\n          \"default\": null,\n          \"title\": \"Month\"\n        }\n      },\n      \"title\": \"list_journal_entriesArguments\",\n      \"type\": \"object\"\n    },\n    \"outputSchema\": {\n      \"properties\": {\n        \"result\": {\n          \"items\": { \"additionalProperties\": true, \"type\": \"object\" },\n          \"title\": \"Result\",\n          \"type\": \"array\"\n        }\n      },\n      \"required\": [\"result\"],\n      \"title\": \"list_journal_entriesOutput\",\n      \"type\": \"object\"\n    },\n    \"annotations\": { \"readOnlyHint\": true }\n  },\n  {\n    \"name\": \"register_journal_entry\",\n    \"description\": \"仕訳を1件登録する（1行仕訳のみ。借方1科目・貸方1科目）。\\n\\n    date は \\\"YYYY-MM-DD\\\" 形式、amount は正の整数（円）。\\n    勘定科目はホワイトリスト制で、使えるのは次の7科目だけ:\\n    現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費。\\n    この一覧にない科目（例: 雑費）を渡すと入力エラーになる。\\n    \",\n    \"inputSchema\": {\n      \"properties\": {\n        \"date\": { \"title\": \"Date\", \"type\": \"string\" },\n        \"debit_account\": { \"title\": \"Debit Account\", \"type\": \"string\" },\n        \"credit_account\": { \"title\": \"Credit Account\", \"type\": \"string\" },\n        \"amount\": { \"title\": \"Amount\", \"type\": \"integer\" },\n        \"description\": { \"default\": \"\", \"title\": \"Description\", \"type\": \"string\" }\n      },\n      \"required\": [\"date\", \"debit_account\", \"credit_account\", \"amount\"],\n      \"title\": \"register_journal_entryArguments\",\n      \"type\": \"object\"\n    },\n    \"annotations\": { \"readOnlyHint\": false, \"destructiveHint\": false }\n  },\n  {\n    \"name\": \"get_trial_balance\",\n    \"description\": \"勘定科目別の残高試算表を取得する。\\n\\n    科目ごとに借方合計（debit_total）・貸方合計（credit_total）・残高（balance）・\\n    残高の側（balance_side）・区分から決まる正常残高側（normal_side）を返す。\\n    両者が食い違う科目には is_abnormal: true が立つ（例: 現金なのに貸方残）。\\n    末尾の total で借方合計と貸方合計の一致（貸借一致）を確認できる。\\n    \",\n    \"inputSchema\": {\n      \"properties\": {},\n      \"title\": \"get_trial_balanceArguments\",\n      \"type\": \"object\"\n    },\n    \"annotations\": { \"readOnlyHint\": true }\n  }\n]\n",[51,8890,8891,8896,8901,8921,8978,8991,9005,9017,9071,9086,9104,9109,9114,9133,9150,9155,9168,9180,9192,9235,9254,9271,9275,9279,9300,9319,9335,9339,9364,9369,9373,9391,9442,9454,9466,9511,9556,9601,9647,9704,9708,9752,9771,9787,9791,9829,9833,9837,9855,9896,9908,9921,9940,9956,9960,9984,9989],{"__ignoreMap":82},[86,8892,8893],{"class":88,"line":89},[86,8894,8895],{"class":360},"[\n",[86,8897,8898],{"class":88,"line":111},[86,8899,8900],{"class":360},"  {\n",[86,8902,8903,8906,8909,8911,8913,8915,8917,8919],{"class":88,"line":121},[86,8904,478],{"class":8905},"sqvqQ",[86,8907,8908],{"class":114},"name",[86,8910,484],{"class":8905},[86,8912,450],{"class":360},[86,8914,139],{"class":138},[86,8916,7640],{"class":96},[86,8918,484],{"class":138},[86,8920,496],{"class":360},[86,8922,8923,8925,8927,8929,8931,8933,8936,8939,8942,8945,8948,8950,8953,8955,8957,8959,8962,8964,8967,8969,8972,8974,8976],{"class":88,"line":148},[86,8924,478],{"class":8905},[86,8926,4448],{"class":114},[86,8928,484],{"class":8905},[86,8930,450],{"class":360},[86,8932,139],{"class":138},[86,8934,8935],{"class":96},"仕訳の一覧を取得する。",[86,8937,8938],{"class":103},"\\n\\n",[86,8940,8941],{"class":96},"    month に ",[86,8943,8944],{"class":103},"\\\"",[86,8946,8947],{"class":96},"YYYY-MM",[86,8949,8944],{"class":103},[86,8951,8952],{"class":96},"（例: ",[86,8954,8944],{"class":103},[86,8956,4917],{"class":96},[86,8958,8944],{"class":103},[86,8960,8961],{"class":96},"）を渡すと、その月の仕訳だけに絞り込む。",[86,8963,6635],{"class":103},[86,8965,8966],{"class":96},"    省略するとすべての仕訳を返す。各仕訳は id・date・debit_account（借方科目）・",[86,8968,6635],{"class":103},[86,8970,8971],{"class":96},"    credit_account（貸方科目）・amount（金額・円）・description（摘要）を持つ。",[86,8973,6635],{"class":103},[86,8975,478],{"class":138},[86,8977,496],{"class":360},[86,8979,8980,8982,8985,8987,8989],{"class":88,"line":313},[86,8981,478],{"class":8905},[86,8983,8984],{"class":114},"inputSchema",[86,8986,484],{"class":8905},[86,8988,450],{"class":360},[86,8990,472],{"class":360},[86,8992,8993,8996,8999,9001,9003],{"class":88,"line":319},[86,8994,8995],{"class":8905},"      \"",[86,8997,8998],{"class":114},"properties",[86,9000,484],{"class":8905},[86,9002,450],{"class":360},[86,9004,472],{"class":360},[86,9006,9007,9009,9011,9013,9015],{"class":88,"line":324},[86,9008,2156],{"class":8905},[86,9010,4908],{"class":114},[86,9012,484],{"class":8905},[86,9014,450],{"class":360},[86,9016,472],{"class":360},[86,9018,9019,9022,9025,9027,9029,9032,9034,9037,9039,9041,9043,9046,9048,9051,9053,9055,9057,9059,9061,9063,9066,9068],{"class":88,"line":341},[86,9020,9021],{"class":8905},"          \"",[86,9023,9024],{"class":114},"anyOf",[86,9026,484],{"class":8905},[86,9028,450],{"class":360},[86,9030,9031],{"class":360}," [{",[86,9033,139],{"class":8905},[86,9035,9036],{"class":114},"type",[86,9038,484],{"class":8905},[86,9040,450],{"class":360},[86,9042,139],{"class":138},[86,9044,9045],{"class":96},"string",[86,9047,484],{"class":138},[86,9049,9050],{"class":360}," },",[86,9052,3148],{"class":360},[86,9054,139],{"class":8905},[86,9056,9036],{"class":114},[86,9058,484],{"class":8905},[86,9060,450],{"class":360},[86,9062,139],{"class":138},[86,9064,9065],{"class":96},"null",[86,9067,484],{"class":138},[86,9069,9070],{"class":360}," }],\n",[86,9072,9073,9075,9077,9079,9081,9084],{"class":88,"line":346},[86,9074,9021],{"class":8905},[86,9076,2288],{"class":114},[86,9078,484],{"class":8905},[86,9080,450],{"class":360},[86,9082,9083],{"class":327}," null",[86,9085,496],{"class":360},[86,9087,9088,9090,9093,9095,9097,9099,9102],{"class":88,"line":382},[86,9089,9021],{"class":8905},[86,9091,9092],{"class":114},"title",[86,9094,484],{"class":8905},[86,9096,450],{"class":360},[86,9098,139],{"class":138},[86,9100,9101],{"class":96},"Month",[86,9103,145],{"class":138},[86,9105,9106],{"class":88,"line":405},[86,9107,9108],{"class":360},"        }\n",[86,9110,9111],{"class":88,"line":410},[86,9112,9113],{"class":360},"      },\n",[86,9115,9116,9118,9120,9122,9124,9126,9129,9131],{"class":88,"line":417},[86,9117,8995],{"class":8905},[86,9119,9092],{"class":114},[86,9121,484],{"class":8905},[86,9123,450],{"class":360},[86,9125,139],{"class":138},[86,9127,9128],{"class":96},"list_journal_entriesArguments",[86,9130,484],{"class":138},[86,9132,496],{"class":360},[86,9134,9135,9137,9139,9141,9143,9145,9148],{"class":88,"line":433},[86,9136,8995],{"class":8905},[86,9138,9036],{"class":114},[86,9140,484],{"class":8905},[86,9142,450],{"class":360},[86,9144,139],{"class":138},[86,9146,9147],{"class":96},"object",[86,9149,145],{"class":138},[86,9151,9152],{"class":88,"line":438},[86,9153,9154],{"class":360},"    },\n",[86,9156,9157,9159,9162,9164,9166],{"class":88,"line":444},[86,9158,478],{"class":8905},[86,9160,9161],{"class":114},"outputSchema",[86,9163,484],{"class":8905},[86,9165,450],{"class":360},[86,9167,472],{"class":360},[86,9169,9170,9172,9174,9176,9178],{"class":88,"line":475},[86,9171,8995],{"class":8905},[86,9173,8998],{"class":114},[86,9175,484],{"class":8905},[86,9177,450],{"class":360},[86,9179,472],{"class":360},[86,9181,9182,9184,9186,9188,9190],{"class":88,"line":499},[86,9183,2156],{"class":8905},[86,9185,8773],{"class":114},[86,9187,484],{"class":8905},[86,9189,450],{"class":360},[86,9191,472],{"class":360},[86,9193,9194,9196,9198,9200,9202,9204,9206,9209,9211,9213,9216,9218,9220,9222,9224,9226,9228,9230,9232],{"class":88,"line":519},[86,9195,9021],{"class":8905},[86,9197,1673],{"class":114},[86,9199,484],{"class":8905},[86,9201,450],{"class":360},[86,9203,3148],{"class":360},[86,9205,139],{"class":8905},[86,9207,9208],{"class":114},"additionalProperties",[86,9210,484],{"class":8905},[86,9212,450],{"class":360},[86,9214,9215],{"class":327}," true",[86,9217,361],{"class":360},[86,9219,139],{"class":8905},[86,9221,9036],{"class":114},[86,9223,484],{"class":8905},[86,9225,450],{"class":360},[86,9227,139],{"class":138},[86,9229,9147],{"class":96},[86,9231,484],{"class":138},[86,9233,9234],{"class":360}," },\n",[86,9236,9237,9239,9241,9243,9245,9247,9250,9252],{"class":88,"line":540},[86,9238,9021],{"class":8905},[86,9240,9092],{"class":114},[86,9242,484],{"class":8905},[86,9244,450],{"class":360},[86,9246,139],{"class":138},[86,9248,9249],{"class":96},"Result",[86,9251,484],{"class":138},[86,9253,496],{"class":360},[86,9255,9256,9258,9260,9262,9264,9266,9269],{"class":88,"line":561},[86,9257,9021],{"class":8905},[86,9259,9036],{"class":114},[86,9261,484],{"class":8905},[86,9263,450],{"class":360},[86,9265,139],{"class":138},[86,9267,9268],{"class":96},"array",[86,9270,145],{"class":138},[86,9272,9273],{"class":88,"line":582},[86,9274,9108],{"class":360},[86,9276,9277],{"class":88,"line":603},[86,9278,9113],{"class":360},[86,9280,9281,9283,9286,9288,9290,9292,9294,9296,9298],{"class":88,"line":623},[86,9282,8995],{"class":8905},[86,9284,9285],{"class":114},"required",[86,9287,484],{"class":8905},[86,9289,450],{"class":360},[86,9291,2616],{"class":360},[86,9293,484],{"class":138},[86,9295,8773],{"class":96},[86,9297,484],{"class":138},[86,9299,8425],{"class":360},[86,9301,9302,9304,9306,9308,9310,9312,9315,9317],{"class":88,"line":629},[86,9303,8995],{"class":8905},[86,9305,9092],{"class":114},[86,9307,484],{"class":8905},[86,9309,450],{"class":360},[86,9311,139],{"class":138},[86,9313,9314],{"class":96},"list_journal_entriesOutput",[86,9316,484],{"class":138},[86,9318,496],{"class":360},[86,9320,9321,9323,9325,9327,9329,9331,9333],{"class":88,"line":634},[86,9322,8995],{"class":8905},[86,9324,9036],{"class":114},[86,9326,484],{"class":8905},[86,9328,450],{"class":360},[86,9330,139],{"class":138},[86,9332,9147],{"class":96},[86,9334,145],{"class":138},[86,9336,9337],{"class":88,"line":640},[86,9338,9154],{"class":360},[86,9340,9341,9343,9345,9347,9349,9351,9353,9355,9357,9359,9361],{"class":88,"line":664},[86,9342,478],{"class":8905},[86,9344,7517],{"class":114},[86,9346,484],{"class":8905},[86,9348,450],{"class":360},[86,9350,3148],{"class":360},[86,9352,139],{"class":8905},[86,9354,7527],{"class":114},[86,9356,484],{"class":8905},[86,9358,450],{"class":360},[86,9360,9215],{"class":327},[86,9362,9363],{"class":360}," }\n",[86,9365,9366],{"class":88,"line":684},[86,9367,9368],{"class":360},"  },\n",[86,9370,9371],{"class":88,"line":703},[86,9372,8900],{"class":360},[86,9374,9375,9377,9379,9381,9383,9385,9387,9389],{"class":88,"line":723},[86,9376,478],{"class":8905},[86,9378,8908],{"class":114},[86,9380,484],{"class":8905},[86,9382,450],{"class":360},[86,9384,139],{"class":138},[86,9386,7948],{"class":96},[86,9388,484],{"class":138},[86,9390,496],{"class":360},[86,9392,9393,9395,9397,9399,9401,9403,9406,9408,9411,9413,9416,9418,9421,9423,9426,9428,9431,9433,9436,9438,9440],{"class":88,"line":742},[86,9394,478],{"class":8905},[86,9396,4448],{"class":114},[86,9398,484],{"class":8905},[86,9400,450],{"class":360},[86,9402,139],{"class":138},[86,9404,9405],{"class":96},"仕訳を1件登録する（1行仕訳のみ。借方1科目・貸方1科目）。",[86,9407,8938],{"class":103},[86,9409,9410],{"class":96},"    date は ",[86,9412,8944],{"class":103},[86,9414,9415],{"class":96},"YYYY-MM-DD",[86,9417,8944],{"class":103},[86,9419,9420],{"class":96}," 形式、amount は正の整数（円）。",[86,9422,6635],{"class":103},[86,9424,9425],{"class":96},"    勘定科目はホワイトリスト制で、使えるのは次の7科目だけ:",[86,9427,6635],{"class":103},[86,9429,9430],{"class":96},"    現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費。",[86,9432,6635],{"class":103},[86,9434,9435],{"class":96},"    この一覧にない科目（例: 雑費）を渡すと入力エラーになる。",[86,9437,6635],{"class":103},[86,9439,478],{"class":138},[86,9441,496],{"class":360},[86,9443,9444,9446,9448,9450,9452],{"class":88,"line":761},[86,9445,478],{"class":8905},[86,9447,8984],{"class":114},[86,9449,484],{"class":8905},[86,9451,450],{"class":360},[86,9453,472],{"class":360},[86,9455,9456,9458,9460,9462,9464],{"class":88,"line":766},[86,9457,8995],{"class":8905},[86,9459,8998],{"class":114},[86,9461,484],{"class":8905},[86,9463,450],{"class":360},[86,9465,472],{"class":360},[86,9467,9468,9470,9472,9474,9476,9478,9480,9482,9484,9486,9488,9491,9493,9495,9497,9499,9501,9503,9505,9507,9509],{"class":88,"line":771},[86,9469,2156],{"class":8905},[86,9471,2637],{"class":114},[86,9473,484],{"class":8905},[86,9475,450],{"class":360},[86,9477,3148],{"class":360},[86,9479,139],{"class":8905},[86,9481,9092],{"class":114},[86,9483,484],{"class":8905},[86,9485,450],{"class":360},[86,9487,139],{"class":138},[86,9489,9490],{"class":96},"Date",[86,9492,484],{"class":138},[86,9494,361],{"class":360},[86,9496,139],{"class":8905},[86,9498,9036],{"class":114},[86,9500,484],{"class":8905},[86,9502,450],{"class":360},[86,9504,139],{"class":138},[86,9506,9045],{"class":96},[86,9508,484],{"class":138},[86,9510,9234],{"class":360},[86,9512,9513,9515,9517,9519,9521,9523,9525,9527,9529,9531,9533,9536,9538,9540,9542,9544,9546,9548,9550,9552,9554],{"class":88,"line":776},[86,9514,2156],{"class":8905},[86,9516,927],{"class":114},[86,9518,484],{"class":8905},[86,9520,450],{"class":360},[86,9522,3148],{"class":360},[86,9524,139],{"class":8905},[86,9526,9092],{"class":114},[86,9528,484],{"class":8905},[86,9530,450],{"class":360},[86,9532,139],{"class":138},[86,9534,9535],{"class":96},"Debit Account",[86,9537,484],{"class":138},[86,9539,361],{"class":360},[86,9541,139],{"class":8905},[86,9543,9036],{"class":114},[86,9545,484],{"class":8905},[86,9547,450],{"class":360},[86,9549,139],{"class":138},[86,9551,9045],{"class":96},[86,9553,484],{"class":138},[86,9555,9234],{"class":360},[86,9557,9558,9560,9562,9564,9566,9568,9570,9572,9574,9576,9578,9581,9583,9585,9587,9589,9591,9593,9595,9597,9599],{"class":88,"line":796},[86,9559,2156],{"class":8905},[86,9561,936],{"class":114},[86,9563,484],{"class":8905},[86,9565,450],{"class":360},[86,9567,3148],{"class":360},[86,9569,139],{"class":8905},[86,9571,9092],{"class":114},[86,9573,484],{"class":8905},[86,9575,450],{"class":360},[86,9577,139],{"class":138},[86,9579,9580],{"class":96},"Credit Account",[86,9582,484],{"class":138},[86,9584,361],{"class":360},[86,9586,139],{"class":8905},[86,9588,9036],{"class":114},[86,9590,484],{"class":8905},[86,9592,450],{"class":360},[86,9594,139],{"class":138},[86,9596,9045],{"class":96},[86,9598,484],{"class":138},[86,9600,9234],{"class":360},[86,9602,9603,9605,9607,9609,9611,9613,9615,9617,9619,9621,9623,9626,9628,9630,9632,9634,9636,9638,9640,9643,9645],{"class":88,"line":807},[86,9604,2156],{"class":8905},[86,9606,4432],{"class":114},[86,9608,484],{"class":8905},[86,9610,450],{"class":360},[86,9612,3148],{"class":360},[86,9614,139],{"class":8905},[86,9616,9092],{"class":114},[86,9618,484],{"class":8905},[86,9620,450],{"class":360},[86,9622,139],{"class":138},[86,9624,9625],{"class":96},"Amount",[86,9627,484],{"class":138},[86,9629,361],{"class":360},[86,9631,139],{"class":8905},[86,9633,9036],{"class":114},[86,9635,484],{"class":8905},[86,9637,450],{"class":360},[86,9639,139],{"class":138},[86,9641,9642],{"class":96},"integer",[86,9644,484],{"class":138},[86,9646,9234],{"class":360},[86,9648,9649,9651,9653,9655,9657,9659,9661,9663,9665,9667,9669,9671,9673,9675,9677,9679,9681,9684,9686,9688,9690,9692,9694,9696,9698,9700,9702],{"class":88,"line":812},[86,9650,2156],{"class":8905},[86,9652,4448],{"class":114},[86,9654,484],{"class":8905},[86,9656,450],{"class":360},[86,9658,3148],{"class":360},[86,9660,139],{"class":8905},[86,9662,2288],{"class":114},[86,9664,484],{"class":8905},[86,9666,450],{"class":360},[86,9668,6230],{"class":138},[86,9670,361],{"class":360},[86,9672,139],{"class":8905},[86,9674,9092],{"class":114},[86,9676,484],{"class":8905},[86,9678,450],{"class":360},[86,9680,139],{"class":138},[86,9682,9683],{"class":96},"Description",[86,9685,484],{"class":138},[86,9687,361],{"class":360},[86,9689,139],{"class":8905},[86,9691,9036],{"class":114},[86,9693,484],{"class":8905},[86,9695,450],{"class":360},[86,9697,139],{"class":138},[86,9699,9045],{"class":96},[86,9701,484],{"class":138},[86,9703,9363],{"class":360},[86,9705,9706],{"class":88,"line":829},[86,9707,9113],{"class":360},[86,9709,9710,9712,9714,9716,9718,9720,9722,9724,9726,9728,9730,9732,9734,9736,9738,9740,9742,9744,9746,9748,9750],{"class":88,"line":840},[86,9711,8995],{"class":8905},[86,9713,9285],{"class":114},[86,9715,484],{"class":8905},[86,9717,450],{"class":360},[86,9719,2616],{"class":360},[86,9721,484],{"class":138},[86,9723,2637],{"class":96},[86,9725,484],{"class":138},[86,9727,361],{"class":360},[86,9729,139],{"class":138},[86,9731,927],{"class":96},[86,9733,484],{"class":138},[86,9735,361],{"class":360},[86,9737,139],{"class":138},[86,9739,936],{"class":96},[86,9741,484],{"class":138},[86,9743,361],{"class":360},[86,9745,139],{"class":138},[86,9747,4432],{"class":96},[86,9749,484],{"class":138},[86,9751,8425],{"class":360},[86,9753,9754,9756,9758,9760,9762,9764,9767,9769],{"class":88,"line":850},[86,9755,8995],{"class":8905},[86,9757,9092],{"class":114},[86,9759,484],{"class":8905},[86,9761,450],{"class":360},[86,9763,139],{"class":138},[86,9765,9766],{"class":96},"register_journal_entryArguments",[86,9768,484],{"class":138},[86,9770,496],{"class":360},[86,9772,9773,9775,9777,9779,9781,9783,9785],{"class":88,"line":894},[86,9774,8995],{"class":8905},[86,9776,9036],{"class":114},[86,9778,484],{"class":8905},[86,9780,450],{"class":360},[86,9782,139],{"class":138},[86,9784,9147],{"class":96},[86,9786,145],{"class":138},[86,9788,9789],{"class":88,"line":909},[86,9790,9154],{"class":360},[86,9792,9793,9795,9797,9799,9801,9803,9805,9807,9809,9811,9814,9816,9818,9821,9823,9825,9827],{"class":88,"line":914},[86,9794,478],{"class":8905},[86,9796,7517],{"class":114},[86,9798,484],{"class":8905},[86,9800,450],{"class":360},[86,9802,3148],{"class":360},[86,9804,139],{"class":8905},[86,9806,7527],{"class":114},[86,9808,484],{"class":8905},[86,9810,450],{"class":360},[86,9812,9813],{"class":327}," false",[86,9815,361],{"class":360},[86,9817,139],{"class":8905},[86,9819,9820],{"class":114},"destructiveHint",[86,9822,484],{"class":8905},[86,9824,450],{"class":360},[86,9826,9813],{"class":327},[86,9828,9363],{"class":360},[86,9830,9831],{"class":88,"line":943},[86,9832,9368],{"class":360},[86,9834,9835],{"class":88,"line":951},[86,9836,8900],{"class":360},[86,9838,9839,9841,9843,9845,9847,9849,9851,9853],{"class":88,"line":985},[86,9840,478],{"class":8905},[86,9842,8908],{"class":114},[86,9844,484],{"class":8905},[86,9846,450],{"class":360},[86,9848,139],{"class":138},[86,9850,8075],{"class":96},[86,9852,484],{"class":138},[86,9854,496],{"class":360},[86,9856,9857,9859,9861,9863,9865,9867,9870,9872,9875,9877,9880,9882,9885,9887,9890,9892,9894],{"class":88,"line":1005},[86,9858,478],{"class":8905},[86,9860,4448],{"class":114},[86,9862,484],{"class":8905},[86,9864,450],{"class":360},[86,9866,139],{"class":138},[86,9868,9869],{"class":96},"勘定科目別の残高試算表を取得する。",[86,9871,8938],{"class":103},[86,9873,9874],{"class":96},"    科目ごとに借方合計（debit_total）・貸方合計（credit_total）・残高（balance）・",[86,9876,6635],{"class":103},[86,9878,9879],{"class":96},"    残高の側（balance_side）・区分から決まる正常残高側（normal_side）を返す。",[86,9881,6635],{"class":103},[86,9883,9884],{"class":96},"    両者が食い違う科目には is_abnormal: true が立つ（例: 現金なのに貸方残）。",[86,9886,6635],{"class":103},[86,9888,9889],{"class":96},"    末尾の total で借方合計と貸方合計の一致（貸借一致）を確認できる。",[86,9891,6635],{"class":103},[86,9893,478],{"class":138},[86,9895,496],{"class":360},[86,9897,9898,9900,9902,9904,9906],{"class":88,"line":1031},[86,9899,478],{"class":8905},[86,9901,8984],{"class":114},[86,9903,484],{"class":8905},[86,9905,450],{"class":360},[86,9907,472],{"class":360},[86,9909,9910,9912,9914,9916,9918],{"class":88,"line":1071},[86,9911,8995],{"class":8905},[86,9913,8998],{"class":114},[86,9915,484],{"class":8905},[86,9917,450],{"class":360},[86,9919,9920],{"class":360}," {},\n",[86,9922,9923,9925,9927,9929,9931,9933,9936,9938],{"class":88,"line":1080},[86,9924,8995],{"class":8905},[86,9926,9092],{"class":114},[86,9928,484],{"class":8905},[86,9930,450],{"class":360},[86,9932,139],{"class":138},[86,9934,9935],{"class":96},"get_trial_balanceArguments",[86,9937,484],{"class":138},[86,9939,496],{"class":360},[86,9941,9942,9944,9946,9948,9950,9952,9954],{"class":88,"line":1085},[86,9943,8995],{"class":8905},[86,9945,9036],{"class":114},[86,9947,484],{"class":8905},[86,9949,450],{"class":360},[86,9951,139],{"class":138},[86,9953,9147],{"class":96},[86,9955,145],{"class":138},[86,9957,9958],{"class":88,"line":1090},[86,9959,9154],{"class":360},[86,9961,9962,9964,9966,9968,9970,9972,9974,9976,9978,9980,9982],{"class":88,"line":1105},[86,9963,478],{"class":8905},[86,9965,7517],{"class":114},[86,9967,484],{"class":8905},[86,9969,450],{"class":360},[86,9971,3148],{"class":360},[86,9973,139],{"class":8905},[86,9975,7527],{"class":114},[86,9977,484],{"class":8905},[86,9979,450],{"class":360},[86,9981,9215],{"class":327},[86,9983,9363],{"class":360},[86,9985,9986],{"class":88,"line":1116},[86,9987,9988],{"class":360},"  }\n",[86,9990,9991],{"class":88,"line":1121},[86,9992,1884],{"class":360},[14,9994,9995,9997,9998,10001],{},[51,9996,7948],{}," の引数を見てほしい。date、借方科目、貸方科目、金額、摘要。",[262,9999,10000],{},"キーというフィールドが存在しない","。エージェントが何をどう間違えても、ツール呼び出しの引数にキーを書く場所自体がない。Before体験で「エージェントの毎回の振る舞い」に頼っていた秘密の管理が、宣言の形そのものに置き換わっている。",[14,10003,10004,10005,10007],{},"続けて ",[51,10006,8177],{}," の結果（シード状態の残高試算表）も返ってきた。",[77,10009,10011],{"className":8887,"code":10010,"language":3741,"meta":82,"style":82},"{\n  \"content\": [\n    {\n      \"type\": \"text\",\n      \"text\": \"{\\n  \\\"accounts\\\": [\\n    {\\n      \\\"account\\\": \\\"現金\\\",\\n      \\\"category\\\": \\\"資産\\\",\\n      \\\"debit_total\\\": 180000,\\n      \\\"credit_total\\\": 85000,\\n      \\\"balance_side\\\": \\\"借方\\\",\\n      \\\"balance\\\": 95000,\\n      \\\"normal_side\\\": \\\"借方\\\",\\n      \\\"is_abnormal\\\": false\\n    },\\n    （中略: 期待値表と同じ6科目、total は 265000 / 265000 / in_balance: true）\\n  ]\\n}\"\n    }\n  ],\n  \"isError\": false\n}\n",[51,10012,10013,10018,10032,10037,10055,10224,10228,10233,10247],{"__ignoreMap":82},[86,10014,10015],{"class":88,"line":89},[86,10016,10017],{"class":360},"{\n",[86,10019,10020,10023,10026,10028,10030],{"class":88,"line":111},[86,10021,10022],{"class":8905},"  \"",[86,10024,10025],{"class":114},"content",[86,10027,484],{"class":8905},[86,10029,450],{"class":360},[86,10031,1159],{"class":360},[86,10033,10034],{"class":88,"line":121},[86,10035,10036],{"class":360},"    {\n",[86,10038,10039,10041,10043,10045,10047,10049,10051,10053],{"class":88,"line":148},[86,10040,8995],{"class":8905},[86,10042,9036],{"class":114},[86,10044,484],{"class":8905},[86,10046,450],{"class":360},[86,10048,139],{"class":138},[86,10050,174],{"class":96},[86,10052,484],{"class":138},[86,10054,496],{"class":360},[86,10056,10057,10059,10061,10063,10065,10067,10069,10071,10074,10076,10078,10081,10083,10086,10088,10091,10093,10095,10097,10099,10101,10103,10105,10107,10109,10111,10113,10115,10117,10119,10121,10123,10125,10127,10129,10131,10134,10136,10138,10140,10142,10145,10147,10149,10151,10153,10155,10157,10159,10161,10163,10165,10167,10169,10171,10174,10176,10178,10180,10182,10184,10186,10188,10190,10192,10194,10196,10198,10200,10203,10205,10208,10210,10213,10215,10218,10220,10222],{"class":88,"line":313},[86,10058,8995],{"class":8905},[86,10060,174],{"class":114},[86,10062,484],{"class":8905},[86,10064,450],{"class":360},[86,10066,139],{"class":138},[86,10068,1048],{"class":96},[86,10070,6635],{"class":103},[86,10072,10073],{"class":103},"  \\\"",[86,10075,2159],{"class":96},[86,10077,8944],{"class":103},[86,10079,10080],{"class":96},": [",[86,10082,6635],{"class":103},[86,10084,10085],{"class":96},"    {",[86,10087,6635],{"class":103},[86,10089,10090],{"class":103},"      \\\"",[86,10092,1912],{"class":96},[86,10094,8944],{"class":103},[86,10096,3951],{"class":96},[86,10098,8944],{"class":103},[86,10100,481],{"class":96},[86,10102,8944],{"class":103},[86,10104,361],{"class":96},[86,10106,6635],{"class":103},[86,10108,10090],{"class":103},[86,10110,1881],{"class":96},[86,10112,8944],{"class":103},[86,10114,3951],{"class":96},[86,10116,8944],{"class":103},[86,10118,491],{"class":96},[86,10120,8944],{"class":103},[86,10122,361],{"class":96},[86,10124,6635],{"class":103},[86,10126,10090],{"class":103},[86,10128,1944],{"class":96},[86,10130,8944],{"class":103},[86,10132,10133],{"class":96},": 180000,",[86,10135,6635],{"class":103},[86,10137,10090],{"class":103},[86,10139,1961],{"class":96},[86,10141,8944],{"class":103},[86,10143,10144],{"class":96},": 85000,",[86,10146,6635],{"class":103},[86,10148,10090],{"class":103},[86,10150,1978],{"class":96},[86,10152,8944],{"class":103},[86,10154,3951],{"class":96},[86,10156,8944],{"class":103},[86,10158,677],{"class":96},[86,10160,8944],{"class":103},[86,10162,361],{"class":96},[86,10164,6635],{"class":103},[86,10166,10090],{"class":103},[86,10168,1995],{"class":96},[86,10170,8944],{"class":103},[86,10172,10173],{"class":96},": 95000,",[86,10175,6635],{"class":103},[86,10177,10090],{"class":103},[86,10179,2017],{"class":96},[86,10181,8944],{"class":103},[86,10183,3951],{"class":96},[86,10185,8944],{"class":103},[86,10187,677],{"class":96},[86,10189,8944],{"class":103},[86,10191,361],{"class":96},[86,10193,6635],{"class":103},[86,10195,10090],{"class":103},[86,10197,2034],{"class":96},[86,10199,8944],{"class":103},[86,10201,10202],{"class":96},": false",[86,10204,6635],{"class":103},[86,10206,10207],{"class":96},"    },",[86,10209,6635],{"class":103},[86,10211,10212],{"class":96},"    （中略: 期待値表と同じ6科目、total は 265000 / 265000 / in_balance: true）",[86,10214,6635],{"class":103},[86,10216,10217],{"class":96},"  ]",[86,10219,6635],{"class":103},[86,10221,1054],{"class":96},[86,10223,145],{"class":138},[86,10225,10226],{"class":88,"line":319},[86,10227,2247],{"class":360},[86,10229,10230],{"class":88,"line":324},[86,10231,10232],{"class":360},"  ],\n",[86,10234,10235,10237,10240,10242,10244],{"class":88,"line":341},[86,10236,10022],{"class":8905},[86,10238,10239],{"class":114},"isError",[86,10241,484],{"class":8905},[86,10243,450],{"class":360},[86,10245,10246],{"class":327}," false\n",[86,10248,10249],{"class":88,"line":346},[86,10250,626],{"class":360},[5924,10252,10254],{"id":10253},"claude-codeにつなぎ同じ依頼文をもう一度投げるafter体験","Claude Codeにつなぎ、同じ依頼文をもう一度投げる（After体験）",[14,10256,10257,10258,10261,10262,10265],{},"接続はプロジェクト直下に ",[51,10259,10260],{},".mcp.json"," を置くだけだ。キーの値はファイルに書かず、",[51,10263,10264],{},"${JOURNAL_API_KEY}"," で環境変数から展開させる。",[77,10267,10269],{"className":8887,"code":10268,"filename":10260,"language":3741,"meta":82,"style":82},"{\n  \"mcpServers\": {\n    \"journal\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"server.py\"],\n      \"env\": {\n        \"JOURNAL_API_KEY\": \"${JOURNAL_API_KEY}\",\n        \"JOURNAL_API_BASE_URL\": \"http://127.0.0.1:8000\"\n      }\n    }\n  }\n}\n",[51,10270,10271,10275,10288,10300,10319,10347,10360,10378,10394,10399,10403,10407],{"__ignoreMap":82},[86,10272,10273],{"class":88,"line":89},[86,10274,10017],{"class":360},[86,10276,10277,10279,10282,10284,10286],{"class":88,"line":111},[86,10278,10022],{"class":8905},[86,10280,10281],{"class":114},"mcpServers",[86,10283,484],{"class":8905},[86,10285,450],{"class":360},[86,10287,472],{"class":360},[86,10289,10290,10292,10294,10296,10298],{"class":88,"line":121},[86,10291,478],{"class":8905},[86,10293,6351],{"class":114},[86,10295,484],{"class":8905},[86,10297,450],{"class":360},[86,10299,472],{"class":360},[86,10301,10302,10304,10307,10309,10311,10313,10315,10317],{"class":88,"line":148},[86,10303,8995],{"class":8905},[86,10305,10306],{"class":114},"command",[86,10308,484],{"class":8905},[86,10310,450],{"class":360},[86,10312,139],{"class":138},[86,10314,93],{"class":96},[86,10316,484],{"class":138},[86,10318,496],{"class":360},[86,10320,10321,10323,10325,10327,10329,10331,10333,10335,10337,10339,10341,10343,10345],{"class":88,"line":313},[86,10322,8995],{"class":8905},[86,10324,6521],{"class":114},[86,10326,484],{"class":8905},[86,10328,450],{"class":360},[86,10330,2616],{"class":360},[86,10332,484],{"class":138},[86,10334,8131],{"class":96},[86,10336,484],{"class":138},[86,10338,361],{"class":360},[86,10340,139],{"class":138},[86,10342,6022],{"class":96},[86,10344,484],{"class":138},[86,10346,8425],{"class":360},[86,10348,10349,10351,10354,10356,10358],{"class":88,"line":319},[86,10350,8995],{"class":8905},[86,10352,10353],{"class":114},"env",[86,10355,484],{"class":8905},[86,10357,450],{"class":360},[86,10359,472],{"class":360},[86,10361,10362,10364,10366,10368,10370,10372,10374,10376],{"class":88,"line":324},[86,10363,2156],{"class":8905},[86,10365,5815],{"class":114},[86,10367,484],{"class":8905},[86,10369,450],{"class":360},[86,10371,139],{"class":138},[86,10373,10264],{"class":96},[86,10375,484],{"class":138},[86,10377,496],{"class":360},[86,10379,10380,10382,10384,10386,10388,10390,10392],{"class":88,"line":341},[86,10381,2156],{"class":8905},[86,10383,6256],{"class":114},[86,10385,484],{"class":8905},[86,10387,450],{"class":360},[86,10389,139],{"class":138},[86,10391,5915],{"class":96},[86,10393,145],{"class":138},[86,10395,10396],{"class":88,"line":346},[86,10397,10398],{"class":360},"      }\n",[86,10400,10401],{"class":88,"line":382},[86,10402,2247],{"class":360},[86,10404,10405],{"class":88,"line":405},[86,10406,9988],{"class":360},[86,10408,10409],{"class":88,"line":410},[86,10410,626],{"class":360},[14,10412,10413,10414,10417,10418,10420,10421,10423],{},"2つ注意がある。対話モードのClaude Codeでこのプロジェクトを開くと、初回に「.mcp.jsonのサーバーを信頼するか」の確認が出るので承認する（接続状態は ",[51,10415,10416],{},"/mcp"," コマンドで確認できる）。そして ",[51,10419,10264],{}," はclaudeを起動したシェルの環境変数から展開されるので、",[51,10422,53],{}," とclaudeの起動は必ず同じターミナルで行う。",[14,10425,10426],{},"APIをシード状態で再起動し、Before体験と同じ依頼文を投げる。実測に使ったコマンドはこれだ（前置きは「ミニ仕訳帳のMCPツール（journal）が接続されている。仕訳の操作はそのツールを使って。」の1行だけ。URLも認証方式も伝えていない）。",[77,10428,10430],{"className":79,"code":10429,"language":81,"meta":82,"style":82},"export JOURNAL_API_KEY=\"sk-journal-tutorial-2026\"\nclaude -p '（前置き＋依頼文）' --mcp-config .mcp.json --strict-mcp-config \\\n  --allowedTools \"mcp__journal__list_journal_entries,mcp__journal__get_trial_balance,mcp__journal__register_journal_entry\" \\\n  --output-format stream-json --verbose\n",[51,10431,10432,10446,10469,10483],{"__ignoreMap":82},[86,10433,10434,10436,10438,10440,10442,10444],{"class":88,"line":89},[86,10435,53],{"class":779},[86,10437,5842],{"class":867},[86,10439,871],{"class":360},[86,10441,484],{"class":138},[86,10443,428],{"class":96},[86,10445,145],{"class":138},[86,10447,10448,10450,10452,10454,10456,10458,10461,10464,10466],{"class":88,"line":111},[86,10449,5855],{"class":92},[86,10451,5858],{"class":103},[86,10453,5861],{"class":138},[86,10455,5864],{"class":96},[86,10457,5867],{"class":138},[86,10459,10460],{"class":103}," --mcp-config",[86,10462,10463],{"class":96}," .mcp.json",[86,10465,5880],{"class":103},[86,10467,10468],{"class":103}," \\\n",[86,10470,10471,10474,10476,10479,10481],{"class":88,"line":121},[86,10472,10473],{"class":103},"  --allowedTools",[86,10475,139],{"class":138},[86,10477,10478],{"class":96},"mcp__journal__list_journal_entries,mcp__journal__get_trial_balance,mcp__journal__register_journal_entry",[86,10480,484],{"class":138},[86,10482,10468],{"class":103},[86,10484,10485,10488,10490],{"class":88,"line":148},[86,10486,10487],{"class":103},"  --output-format",[86,10489,5886],{"class":96},[86,10491,5889],{"class":103},[14,10493,10494],{},"正常系の実録。",[77,10496,10499],{"className":10497,"code":10498,"language":174},[172],"[1] ToolSearch query=\"journal 仕訳 登録\"\n    → journalサーバーのツール宣言をロード\n[2] mcp__journal__register_journal_entry\n    {\"date\":\"2026-07-25\",\"debit_account\":\"消耗品費\",\"credit_account\":\"現金\",\n     \"amount\":3300,\"description\":\"消耗品費の現金支払い\"}\n    → {\"date\":\"2026-07-25\",...,\"id\":6}\n",[51,10500,10498],{"__ignoreMap":82},[14,10502,10503],{},"一発で成功した。Before体験で6ターンだったものが3ターン。openapi.jsonの読解ステップが消え（仕様は宣言に書いてある）、Windowsのエンコーディング事故も消えた。事故が消えたのは偶然ではない。引数がシェルのコマンドライン文字列ではなく、MCPの構造化JSONとして流れるからで、「文字列の組み立て」という事故の発生場所そのものが経路からなくなっている。",[14,10505,10506,10508],{},[51,10507,6326],{}," には操作ログが1行残った。",[77,10510,10512],{"className":8887,"code":10511,"filename":6326,"language":3741,"meta":82,"style":82},"{\"time\": \"2026-07-14T11:07:02\", \"tool\": \"register_journal_entry\", \"args\": {\"body\": {\"date\": \"2026-07-25\", \"debit_account\": \"消耗品費\", \"credit_account\": \"現金\", \"amount\": 3300, \"description\": \"消耗品費の現金支払い\"}}, \"status\": \"201\"}\n",[51,10513,10514],{"__ignoreMap":82},[86,10515,10516,10518,10520,10522,10524,10526,10528,10531,10533,10535,10537,10539,10541,10543,10545,10547,10549,10551,10553,10555,10557,10559,10561,10563,10565,10567,10569,10571,10573,10575,10577,10579,10581,10583,10585,10587,10589,10591,10593,10595,10597,10599,10601,10603,10605,10607,10609,10611,10613,10615,10617,10619,10621,10623,10625,10627,10630,10632,10634,10636,10638,10640,10642,10645,10647,10650,10652,10654,10656,10658,10660,10662,10664],{"class":88,"line":89},[86,10517,1048],{"class":360},[86,10519,484],{"class":8905},[86,10521,6461],{"class":114},[86,10523,484],{"class":8905},[86,10525,450],{"class":360},[86,10527,139],{"class":138},[86,10529,10530],{"class":96},"2026-07-14T11:07:02",[86,10532,484],{"class":138},[86,10534,361],{"class":360},[86,10536,139],{"class":8905},[86,10538,6375],{"class":114},[86,10540,484],{"class":8905},[86,10542,450],{"class":360},[86,10544,139],{"class":138},[86,10546,7948],{"class":96},[86,10548,484],{"class":138},[86,10550,361],{"class":360},[86,10552,139],{"class":8905},[86,10554,6521],{"class":114},[86,10556,484],{"class":8905},[86,10558,450],{"class":360},[86,10560,3148],{"class":360},[86,10562,484],{"class":8905},[86,10564,5414],{"class":114},[86,10566,484],{"class":8905},[86,10568,450],{"class":360},[86,10570,3148],{"class":360},[86,10572,484],{"class":8905},[86,10574,2637],{"class":114},[86,10576,484],{"class":8905},[86,10578,450],{"class":360},[86,10580,139],{"class":138},[86,10582,5293],{"class":96},[86,10584,484],{"class":138},[86,10586,361],{"class":360},[86,10588,139],{"class":8905},[86,10590,927],{"class":114},[86,10592,484],{"class":8905},[86,10594,450],{"class":360},[86,10596,139],{"class":138},[86,10598,608],{"class":96},[86,10600,484],{"class":138},[86,10602,361],{"class":360},[86,10604,139],{"class":8905},[86,10606,936],{"class":114},[86,10608,484],{"class":8905},[86,10610,450],{"class":360},[86,10612,139],{"class":138},[86,10614,481],{"class":96},[86,10616,484],{"class":138},[86,10618,361],{"class":360},[86,10620,139],{"class":8905},[86,10622,4432],{"class":114},[86,10624,484],{"class":8905},[86,10626,450],{"class":360},[86,10628,10629],{"class":107}," 3300",[86,10631,361],{"class":360},[86,10633,139],{"class":8905},[86,10635,4448],{"class":114},[86,10637,484],{"class":8905},[86,10639,450],{"class":360},[86,10641,139],{"class":138},[86,10643,10644],{"class":96},"消耗品費の現金支払い",[86,10646,484],{"class":138},[86,10648,10649],{"class":360},"}},",[86,10651,139],{"class":8905},[86,10653,6536],{"class":114},[86,10655,484],{"class":8905},[86,10657,450],{"class":360},[86,10659,139],{"class":138},[86,10661,2701],{"class":96},[86,10663,484],{"class":138},[86,10665,626],{"class":360},[14,10667,10668,10669,10672],{},"ちなみにAPI側（uvicorn）のアクセスログは ",[51,10670,10671],{},"\"POST /journal-entries HTTP/1.1\" 201 Created"," という1行で、何をどんな引数で登録したかは残らない。ツール名と引数と結果が揃うのはMCPサーバーの層だけだ。だからこそ、この層のログ設計に価値があるし、freee-mcpがログに「何を残さないか」（ツール引数の中身、つまり会計データ）まで設計していたことの意味もわかる。うちの教材ログは引数を丸ごと残しているが、運用ログに顧客の会計データを書いてよいかは、実務なら立ち止まるべき論点だ。",[14,10674,10675],{},"エラー系（雑費）の実録。",[77,10677,10680],{"className":10678,"code":10679,"language":174},[172],"[1] ToolSearch query=\"+journal 仕訳 登録\"\n[2] mcp__journal__register_journal_entry {\"debit_account\":\"雑費\",...}\n    → isError: true\n      \"Error executing tool register_journal_entry: 入力エラーで受け付けられませんでした。\n       - debit_account: Value error, 勘定科目「雑費」は使えません。使える科目: 現金、普通預金、\n         買掛金、資本金、売上高、仕入高、消耗品費\n       使える勘定科目: 現金、普通預金、買掛金、資本金、売上高、仕入高、消耗品費。\n       日付は YYYY-MM-DD、金額は正の整数（円）です。\"\n[3] 登録せず停止。「消耗品費に変えて登録する／server.pyのホワイトリストに雑費を\n    追加する」の2択をユーザーに提示\n",[51,10681,10679],{"__ignoreMap":82},[14,10683,10684,10685,10687],{},"最終判断はBeforeと同じで、勝手に読み替えず人間に確認を求めた。違うのは途中経過だ。Beforeでは原因調査のためにソースコードをgrepし、その巻き添えでキーが会話に出た。Afterでは、整形エラー文が「何がだめで、何なら使えるか」を1回で伝えたので、ソースを漁る動機自体が発生していない。エラー文面の中に科目一覧が2回出ているのはご愛嬌で、FastAPIのバリデータ由来の文と、",[51,10686,7405],{}," が付け足した文が重なった結果だ（金額や日付のエラーでは付け足しの方だけが情報源になるので、重複を承知で残している）。",[14,10689,10690,10691,10694],{},"もう1つ、承認の粒度を確かめる実験をした。許可リストを読み取り系2ツールだけにして、",[51,10692,10693],{},"--permission-mode default"," で権限確認を有効にした状態で、同じ正常系の依頼を投げる。実測に使ったコマンドはこれだ。",[77,10696,10698],{"className":79,"code":10697,"language":81,"meta":82,"style":82},"claude -p '（前置き＋依頼文）' --mcp-config .mcp.json --strict-mcp-config \\\n  --permission-mode default \\\n  --allowedTools \"mcp__journal__list_journal_entries,mcp__journal__get_trial_balance\" \\\n  --output-format stream-json --verbose\n",[51,10699,10700,10720,10729,10742],{"__ignoreMap":82},[86,10701,10702,10704,10706,10708,10710,10712,10714,10716,10718],{"class":88,"line":89},[86,10703,5855],{"class":92},[86,10705,5858],{"class":103},[86,10707,5861],{"class":138},[86,10709,5864],{"class":96},[86,10711,5867],{"class":138},[86,10713,10460],{"class":103},[86,10715,10463],{"class":96},[86,10717,5880],{"class":103},[86,10719,10468],{"class":103},[86,10721,10722,10725,10727],{"class":88,"line":111},[86,10723,10724],{"class":103},"  --permission-mode",[86,10726,2773],{"class":96},[86,10728,10468],{"class":103},[86,10730,10731,10733,10735,10738,10740],{"class":88,"line":121},[86,10732,10473],{"class":103},[86,10734,139],{"class":138},[86,10736,10737],{"class":96},"mcp__journal__list_journal_entries,mcp__journal__get_trial_balance",[86,10739,484],{"class":138},[86,10741,10468],{"class":103},[86,10743,10744,10746,10748],{"class":88,"line":148},[86,10745,10487],{"class":103},[86,10747,5886],{"class":96},[86,10749,5889],{"class":103},[77,10751,10754],{"className":10752,"code":10753,"language":174},[172],"[2] mcp__journal__register_journal_entry {...}\n    → 拒否: \"Claude requested permissions to use mcp__journal__register_journal_entry,\n       but you haven't granted it yet.\"\n[3] エージェントは登録内容（日付・借方・貸方・金額・摘要）を提示して承認待ちで停止\n",[51,10755,10753],{"__ignoreMap":82},[14,10757,10758,10759,10762],{},"仕訳は登録されず、シードの5件のままだった。ヘッドレス実行では承認に答える手段がないのでここで止まるが、対話モードなら承認ダイアログが出て、許可すれば登録まで進む。読み取りは素通しにして、書き込みだけ止める。この制御が",[262,10760,10761],{},"ツール名の単位","で効いている。Before体験ではこうはいかない。エージェントに許可するのは「Bash（シェルコマンドの実行）」という単位で、読み取りのcurlも書き込みのcurlも同じコマンド実行として見える。HTTPメソッドの意味を許可ルールの層で見分ける標準の経路がないからだ。OpenAPI仕様にはGETとPOSTの区別がちゃんとある。ないのは、その区別をクライアントの確認UIまで運ぶ配線で、MCPのツール分割とannotationsはその配線として機能する。",[14,10764,10765],{},"ただし、正直に書いておくと、この実験は1回目に失敗している。私のClaude Codeは普段、権限確認を自動許可するモードで動いていて、その設定のままでは、許可リストに入れていない書き込みツールもそのまま通った。annotationsが「強制力のないヒント」であり、実際に止めるかどうかはクライアントの設定次第、という分業の実演を、意図せず自分でやってしまった格好だ。サーバーが正直に申告していても、クライアント側の統制がゆるければ素通りする。導入するときは、どちらの層で何を止めているかを両方確認した方がいい。",[5924,10767,10769],{"id":10768},"beforeafterの差分表","Before/Afterの差分表",[14,10771,10772],{},"測れた差だけを表にする。",[204,10774,10775,10788],{},[207,10776,10777],{},[210,10778,10779,10782,10785],{},[213,10780,10781],{},"観測点",[213,10783,10784],{},"Before（生API直叩き）",[213,10786,10787],{},"After（MCP経由）",[220,10789,10790,10801,10812,10823,10834,10845,10856],{},[210,10791,10792,10795,10798],{},[225,10793,10794],{},"仕様の伝達",[225,10796,10797],{},"前置きでURLと認証方式を説明し、エージェントがopenapi.jsonを毎回読解",[225,10799,10800],{},"前置き1行。仕様はツール宣言に載って自動で届く",[210,10802,10803,10806,10809],{},[225,10804,10805],{},"秘密の扱い",[225,10807,10808],{},"エージェントはキーをechoしなかったが、エラー原因調査のgrepの巻き添えでキー値が会話に出現",[225,10810,10811],{},"キー値は一度も出現せず。ツール引数にキーのフィールド自体が存在しない",[210,10813,10814,10817,10820],{},[225,10815,10816],{},"承認の粒度",[225,10818,10819],{},"「Bash実行」の単位。読み取りと書き込みのcurlを許可ルールで区別する標準経路がない",[225,10821,10822],{},"ツール単位。読み取り2本を許可し書き込みだけ拒否、を実測で確認",[210,10824,10825,10828,10831],{},[225,10826,10827],{},"エラー復旧",[225,10829,10830],{},"422の後、ソースコードをgrepして原因特定してから停止（2手余分）",[225,10832,10833],{},"整形エラー文だけで即停止、確認要求。ソース調査なし",[210,10835,10836,10839,10842],{},[225,10837,10838],{},"操作ログ",[225,10840,10841],{},"uvicornのアクセスログのみ（メソッドとパスとステータス）",[225,10843,10844],{},"ツール名と引数と結果が1呼び出し1行で残る",[210,10846,10847,10850,10853],{},[225,10848,10849],{},"Windows固有の事故",[225,10851,10852],{},"日本語JSONのシェル渡しで400が2回とも再現",[225,10854,10855],{},"構造化JSONで渡るため発生せず",[210,10857,10858,10861,10864],{},[225,10859,10860],{},"ターン数（参考）",[225,10862,10863],{},"正常系6、エラー系7",[225,10865,10866],{},"どちらも3",[14,10868,10869,10870,10873],{},"差が出なかった項目も書いておく。",[262,10871,10872],{},"最終的なガバナンス挙動は同じだった","。雑費のエラーに対して、どちらの経路でもエージェントは科目を勝手に読み替えず、選択肢を提示して停止した。モデルも依頼文も同じなのだから、判断が変わる理由はない。変わったのは、その判断に至るまでに事故が起きる場所と手数だ。MCPは、エージェントを賢くする規格ではなく、事故が起きる場所を経路ごと減らす規格だった。この表がその一覧になっている。",[196,10875,10876],{"id":10876},"もしエンドポイントが277本あったら",[14,10878,10879],{},"ここまで意図的に避けてきたコストの話を、最後にする。",[14,10881,10882,10884],{},[51,10883,8173],{}," が返した3ツール分の宣言は、圧縮したJSONで2,429バイト、1ツールあたり平均810バイトだった。これはMCPのプロトコル上でクライアントに渡る宣言のサイズであり、freeeの規模（一意パス277本）を1対1のツールにしたと仮定して外挿すると約219KB、メソッド単位の416操作なら約329KBになる。外挿であって実測ではないことは明記しておく。それでも、宣言だけで数百KBという量が「接続しただけで発生する荷物」になり得ることは、この計算で十分に見える。",[14,10886,10887],{},"ただし、この宣言サイズがそのままLLMのコンテキスト消費になるわけではない。宣言をいつ、どれだけモデルに渡すかはMCPクライアント（ホスト）の実装に任されている。実際、今回のAfter体験の実録には面白い痕跡が残っていた。セッション開始時点でjournalサーバーは「pending」で、エージェントは依頼を受けてから検索ツールで宣言をロードしている。Claude CodeはMCPツールの宣言を遅延ロードする実装になっていて、接続した瞬間に全宣言をコンテキストへ流し込んではいない（この見え方はClaude Codeのバージョンや設定に依存する。実録にToolSearchが現れず、最初からツールが見えていてもそれは正常だ）。",[14,10889,10890,10891,10893],{},"つまり、宣言の肥大化には2つの対処層がある。ホスト側の遅延ロード（Claude Codeがやっていること）と、サーバー側の設計（freee-mcpが汎用5ツール+Agent Skillsへ畳み込んだこと）だ。3本の教材では1対1ツールが素直で、277本のfreeeでは畳み込みが要る。",[17,10892,20],{"href":19},"で見た「API呼び出しは汎用5ツール、全体でも15個」という設計は、この外挿計算の先にある必然だった、というのが手を動かした後の実感になる。",[196,10895,10897],{"id":10896},"締め-アプリの次はエージェント同士がつながる","締め: アプリの次は、エージェント同士がつながる",[14,10899,10900],{},"作ったものは、APIが1本、それを包むMCPサーバーが1本、ツール宣言が3つ。この最小の部品で、アプリケーションとエージェントの間の規格が固まると何が起きるかを確かめた。",[14,10902,10903,10904,10909],{},"そして、アプリとエージェントの接続が規格で埋まった今、次に規格化が進んでいるのはエージェントとエージェントの間だ。",[17,10905,10908],{"href":10906,"target":41,"rel":10907},"https://github.com/a2aproject/A2A",[43,44],"→ A2A（Agent2Agent Protocol・GitHub）","のように、エージェント同士が能力を宣言し合い、タスクを依頼し合うプロトコルが既に動き始めている。今回の教材で言えば、仕訳を登録する側のエージェントと、試算表を検証する側のエージェントが、人間を介さずに突き合わせをする形だ。",[14,10911,10912],{},"会計事務所の文脈に置き直すと、こうなる。あなたの事務所のエージェントが、顧問先のエージェントに「7月分の売上仕訳を根拠資料付きで」と依頼し、受け取った仕訳を試算表と突き合わせ、異常残高だけを人間の机に上げる。今日それができると言いたいのではない。ただ、その世界の部品が何でできているかは、もう見えている。APIがあり、それを包む宣言があり、許可の単位があり、操作の記録がある。今回手元で作った3つのツールは、その世界の最小単位だった。",[14,10914,10915],{},"freee-mcpを読んで、模型を作って、実測した。次に「エージェント対応」と書かれたサービスを見たとき、その裏で何が宣言され、何が隠され、どこに記録が残るのか。それを具体的に想像できるようになったことが、このハンズオンの収穫だ。",[196,10917,10918],{"id":10918},"まとめ",[32,10920,10921,10924,10927,10930,10933,10936,10939,10942],{},[35,10922,10923],{},"ミニ仕訳帳API（FastAPIで3エンドポイント、約150行）を自作し、MCP公式SDKのFastMCPで包んだ（約170行）。コードは全文掲載、出力はすべて実測値",[35,10925,10926],{},"生のAPIをエージェントに使わせると、仕様の読解が毎回走り、Windowsのシェル経由で日本語JSONが壊れる事故を踏み、422の原因調査でソースを漁った巻き添えにAPIキーが会話へ流れ込んだ",[35,10928,10929],{},"MCP経由では同じ依頼が3ターンで完了。キーはツールの宣言にも引数にも存在せず、エンコーディング事故は経路ごと消え、整形エラーがソース調査の動機をなくした",[35,10931,10932],{},"承認はツール単位で制御でき、読み取りだけ許可して書き込みを止める動作を実測した。ただしannotationsは強制力のないヒントで、クライアント側が自動許可モードなら素通りする（実測済み）",[35,10934,10935],{},"エージェントの判断は両経路で同じだった。雑費のエラーに対し、どちらも科目を読み替えず人間に確認を求めた。変わったのは、そこへ至るまでに事故が起きる場所と手数",[35,10937,10938],{},"ツール宣言の肥大化には、ホスト側の遅延ロードとサーバー側のツール畳み込み（freee-mcpの汎用5ツール+Agent Skills）という2層の対処がある。宣言サイズの実測と277本への外挿は「もしエンドポイントが277本あったら」の節に書いた",[35,10940,10941],{},"操作ログ（JSONLで1呼び出し1行）は監査証跡ではない。実行者の識別、改ざん検知、API側記録との突合がない記録は、証跡と呼ぶには距離がある",[35,10943,10944],{},"アプリとエージェントの接続（MCP）の次は、エージェント同士の通信（A2A）の規格化が進んでいる。今回の3ツールは、エージェント同士が帳簿を突き合わせる世界の最小単位になる",[196,10946,10947],{"id":10947},"参考リンク",[32,10949,10950,10955,10961,10967,10973,10980,10987,10993],{},[35,10951,10952],{},[17,10953,10954],{"href":19},"前記事: freee公式MCPサーバーのコードを開く。「APIをラップする」の実体は、宣言ではなく門番と配管だった",[35,10956,10957],{},[17,10958,10960],{"href":10959},"/mcp-agent-app-connection","前々記事: MCPはAPIを「エージェントが読める形」に包む規格。アプリ間接続の4つの疑問を深掘りする",[35,10962,10963],{},[17,10964,10966],{"href":6010,"target":41,"rel":10965},[43,44],"→ MCP公式Python SDK（GitHub）",[35,10968,10969],{},[17,10970,10972],{"href":8160,"target":41,"rel":10971},[43,44],"→ MCP仕様: Tools（annotationsの位置づけ）",[35,10974,10975],{},[17,10976,10979],{"href":10977,"target":41,"rel":10978},"https://github.com/freee/freee-mcp",[43,44],"→ freee/freee-mcp（GitHub）",[35,10981,10982],{},[17,10983,10986],{"href":10984,"target":41,"rel":10985},"https://fastapi.tiangolo.com/ja/",[43,44],"→ FastAPI公式ドキュメント",[35,10988,10989],{},[17,10990,10992],{"href":40,"target":41,"rel":10991},[43,44],"→ uv公式ドキュメント",[35,10994,10995],{},[17,10996,10908],{"href":10906,"target":41,"rel":10997},[43,44],[10999,11000,11001],"style",{},"html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sSkh3, html code.shiki .sSkh3{--shiki-default:#2E8F82;--shiki-dark:#2E8F82}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sLkVR, html code.shiki .sLkVR{--shiki-default:#AB5E3F;--shiki-dark:#AB5E3F}html pre.shiki code .sqvqQ, html code.shiki .sqvqQ{--shiki-default:#99841877;--shiki-dark:#99841877}",{"title":82,"searchDepth":111,"depth":111,"links":11003},[11004,11005,11009,11010,11014,11015,11016,11017],{"id":198,"depth":111,"text":199},{"id":5788,"depth":111,"text":5789,"children":11006},[11007,11008],{"id":5926,"depth":121,"text":5927},{"id":5962,"depth":121,"text":5963},{"id":6003,"depth":111,"text":6004},{"id":8166,"depth":111,"text":8167,"children":11011},[11012,11013],{"id":10253,"depth":121,"text":10254},{"id":10768,"depth":121,"text":10769},{"id":10876,"depth":111,"text":10876},{"id":10896,"depth":111,"text":10897},{"id":10918,"depth":111,"text":10918},{"id":10947,"depth":111,"text":10947},null,"freee公式MCPサーバーの解剖記事の続編。FastAPI製のミニ仕訳帳API（3エンドポイント）を自作し、生のままエージェントに使わせる体験と、MCPサーバー（公式SDKのFastMCP）で包んでから使わせる体験を、同じ依頼文で実測して比べた。APIキーの居場所、承認の粒度、エラーからの復旧、操作ログの4点で何が変わるかをターミナルの実録で確かめ、宣言サイズの実測値から「もし277本あったら」を外挿する。コードは全文掲載、コマンドと出力はすべて実測値。","md",{},"/journal-api-mcp-tutorial",false,"2026-07-14T00:00:00.000Z",{"title":5,"description":11019},"make-diary","2026-07/2026-07-14/journal-api-mcp-tutorial",[11029,11030,11031,11032,11033,11034],"MCP","FastAPI","Python","AIエージェント","freee","ハンズオン","H_oMJBxnOE5gDRARxhqyrJiAFJXXuHVBC6jYBJg_aTw",[],[11038,11041,11043,11046,11048],{"title":11039,"path":11040,"publishedAt":11024},"自作APIをMCPサーバー化するハンズオン講座を作った日。FastAPIミニ仕訳帳APIの実装と検証セッションの記録","/journal-mcp-handson-build",{"title":11042,"path":19,"publishedAt":11024},"freee公式MCPサーバーのコードを開く。「APIをラップする」の実体は、宣言ではなく門番と配管だった",{"title":11044,"path":11045,"publishedAt":11024},"Claude Codeで他社モデルが動く非対称性からMCP解剖まで — AIベンダー戦略を対話で掘って記事5本を書いた日","/ai-vendor-strategy-writing",{"title":11047,"path":10959,"publishedAt":11024},"MCPはAPIを「エージェントが読める形」に包む規格。アプリ間接続の4つの疑問を深掘りする",{"title":11049,"path":11050,"publishedAt":11051},"2026年1月22日の開発日記 - tax-assistant大規模リファクタリングと機能実装","/2026-01-22-diary","2026-01-22T00:00:00.000Z","https://log.eurekapu.com/og/blog/journal-api-mcp-tutorial.png?v=2026-07-14T00%3A00%3A00.000Z&title=%E8%87%AA%E4%BD%9CAPI%E3%82%92MCP%E5%8C%96%E3%81%99%E3%82%8B%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3%E3%80%82%E3%83%9F%E3%83%8B%E4%BB%95%E8%A8%B3%E5%B8%B3API%E3%82%92%E4%BD%9C%E3%82%8A%E3%80%81%E7%94%9F%E3%81%AE%E3%81%BE%E3%81%BE%E4%BD%BF%E3%81%84%E3%80%81%E5%8C%85%E3%82%93%E3%81%A7%E3%81%8B%E3%82%89%E4%BD%BF%E3%81%A3%E3%81%A6%E6%AF%94%E3%81%B9%E3%82%8B&author=Kei%20Komatsu&sig=f6557ebe94323359",1785654971362]