# shiwake-mcp 仕訳データの一次スクリーニングを行う MCP サーバー。依存ライブラリはゼロ。 総勘定元帳から仕訳を受け取り、15個のルールを当てて、先に人間が目を通すべき順番に並べ替えて返します。監査の現場でいう仕訳テスト(Journal Entry Testing)を、AIエージェントから呼べる形にしたものです。 [English](README.en.md) ## 依存ライブラリを持たない理由 `npm install` で入るものが1つもありません。`package.json` の `dependencies` は空です。 会計データを扱う道具に外部依存を足すと、導入のたびに「このパッケージは何をしているのか」を説明する必要が出ます。監査法人や会計事務所のネットワークで動かすとき、その説明コストは実装の手間より高くつきます。依存がゼロなら、読むべきコードはこのリポジトリの中だけで閉じます。 MCP の stdio トランスポートは、行区切りの JSON-RPC 2.0 です。SDK を使わなくても 200 行ほどで書けます。 ## 動かす Node.js 20 以上が必要です。 ### npmの修正版0.3.1を使う 0.3.1にはJSON-RPC入力ガードを含めています。npmから取得した配布物が検査済みの候補と一致し、不正な入力3ケースの拒否と、その後の正常な初期化を確認しました。Node.js 20以上がある環境では、次のコマンドで同じ版を起動できます。 ```bash npx -y shiwake-mcp@0.3.1 ``` Claude Codeへの接続は`claude mcp add shiwake -- npx -y shiwake-mcp@0.3.1`です。Claude Desktopでは`"command": "npx"`、`"args": ["-y", "shiwake-mcp@0.3.1"]`を設定します。元帳ファイルを読む場合は、引数の末尾に`"--data-dir", "/path/to/ledgers"`を追加し、実際のフォルダーに置き換えてください。初回の取得には通信が必要です。固定ソースから試験を再現する方法は次に示します。 ### 入力ガードを含むGitHub版を使う npmの配布版0.3.0には、GitHubへ追加したJSON-RPC入力ガードが含まれていません。入力形式が不正な場合にエラーを返して処理を続ける修正版は、次の固定ソースから使えます。外部ライブラリのインストールは不要です。 ```bash git clone https://github.com/USHIKUNDESUYO/shiwake-mcp.git cd shiwake-mcp git checkout 3f053b2cff7d003069186fee071bce7cda1c5989 npm test ``` このcommitの公開ソースで119試験の成功を確認しています。下の接続例では、`/path/to/shiwake-mcp`をcloneしたフォルダーの絶対パスへ置き換えてください。Node.jsから直接起動するので、npm配布版は使いません。 ### MCP サーバーとして繋ぐ 上で取得したGitHub版をNode.jsから起動します。 Claude Code なら1行です。 ```bash claude mcp add shiwake -- node "/path/to/shiwake-mcp/src/server.js" ``` 名前の前に `--scope project` を付けると、プロジェクト直下の `.mcp.json` に書き込まれ、チームで共有できます。 Claude Desktop は設定ファイル(`claude_desktop_config.json`)に追記します。 ```json { "mcpServers": { "shiwake": { "command": "node", "args": ["/path/to/shiwake-mcp/src/server.js"] } } } ``` WindowsのJSON設定では、パスの区切りに`/`を使うか、バックスラッシュを`\\`と2つ書いてください。 ### 大きな元帳はファイルで渡す 数百件を超える元帳は、仕訳を会話に並べずに、ファイルのパスを渡します。仕訳を会話で渡すと、AI がそれを全部書き出すことになり、数万件では収まりません。 サーバーが読んでよいフォルダを、起動時に `--data-dir` で指定します(何度でも指定できます。環境変数 `SHIWAKE_DATA_DIR` でも指定できます)。 ```bash claude mcp add shiwake -- node "/path/to/shiwake-mcp/src/server.js" --data-dir "/path/to/ledgers" ``` Claude Desktop なら `"args": ["/path/to/shiwake-mcp/src/server.js", "--data-dir", "C:\\audit\\ledgers"]` です。 指定したフォルダの外にあるファイルは、AI からパスを渡されても開きません。シンボリックリンクやジャンクションで外を指している場合も、たどった先で判定して読みません。 あとは「2025年度_仕訳帳.csv を screen_journals で見て」のように頼めば、ツールに `file` が渡ります。相対パスは、最初に指定したフォルダを起点にします。読めるのは `.json` と `.csv`(UTF-8・Shift_JIS)で、上限は 256MB です。手元の計測では、38万件(CSV 76MB)で約9秒、応答は約8万字でした。 ### まず手元で試す リポジトリを clone すると、同梱のサンプルデータ(合成データ383件、既知の異常を混ぜてあります)で挙動を確かめられます。`npm install` は要りません。 ```bash git clone https://github.com/USHIKUNDESUYO/shiwake-mcp.git cd shiwake-mcp npm run demo ``` ``` 検査対象 383 件 検出 54 件 / 対象仕訳 25 件 重要度 high 13 / medium 16 / low 25 ベンフォード MAD 0.012241 → 許容の限界(n=383) ルール別: 営業時間外の入力 11 件 キリのよい金額 9 件 !! 承認限度額の直下 7 件 ! 重複仕訳 5 件 !! 起票者と承認者が同一 4 件 ! 期末直前の大口計上 4 件 ! 計上日と入力日の乖離 3 件 ! 稀な勘定科目の組み合わせ 3 件 休日の計上 3 件 !! 貸借不一致 2 件 摘要が空 2 件 ! 期末後の入力 1 件 確認の優先順位(上位 20 件): [ 23] JV-0382 2025-09-06 3000000 self_approval, rare_account_pair, weekend_or_holiday, after_hours, round_amount, missing_description [ 19] JV-0365 2026-03-30 8900000 self_approval, period_end_large, after_hours, round_amount 開発委託費 [ 17] JV-0362 2026-01-22 1200000 unbalanced, rare_account_pair, round_amount 業務委託費計上 (以下省略) ``` 383件が25件に絞られます。スコアは各ルールの重要度の合計で、複数のルールに同時に当たった仕訳ほど上に来ます。 ## ツール | ツール | 何を返すか | |---|---| | `screen_journals` | 全ルールを当て、リスクスコア順に並べ替えた一覧 | | `check_balance` | 貸借が一致しない仕訳と、その差額 | | `benford_analysis` | 金額の先頭桁の分布、MAD、χ² | | `detect_duplicates` | 完全に一致する仕訳のグループ | | `list_rules` | 実装されているルールの一覧と趣旨 | どのツールも、MCP のツール注釈で「読み取り専用(`readOnlyHint`)・外部に触れない(`openWorldHint: false`)」と宣言しています。何かを書き換えたり、外のサービスに送ったりはしません。 仕訳は `journals` に並べて渡すか、`file` でファイルのパスを渡します(前節)。 `screen_journals` が返す個々の検出(`findings`)は、上位 `top` 件(既定 50)の仕訳に関わるものだけです。件数の集計は常に全件です。全件が必要なら `allFindings: true` を渡します。`check_balance` と `detect_duplicates` の一覧も、既定で 200 件までです。 入力の仕訳は、簡易形と明細形のどちらでも受けます。 ```json { "id": "JV-0001", "date": "2026-03-31", "entered_at": "2026-04-02T23:41:00+09:00", "debit_account": "売掛金", "credit_account": "売上高", "amount": 12000000, "description": "3月度売上計上", "created_by": "acc01", "approved_by": "mgr01" } ``` 消費税や複合仕訳のように行数が増えるものは、明細形で渡します。 ```json { "id": "JV-0002", "date": "2026-03-31", "lines": [ { "account": "外注費", "debit": 1000000 }, { "account": "仮払消費税", "debit": 100000 }, { "account": "買掛金", "credit": 1100000 } ] } ``` 1件でも読めない仕訳があると、既定では全体を止めて、何件目のどこが読めないかを返します。読めない行を除外して続けたいときは `skipInvalid: true` を渡します。除外した行は、何件目か・伝票番号・理由を添えて `invalidRows` に返ります。 `entered_at` は日付だけでも受けます。その場合は「計上日と入力日の乖離」には使い、「営業時間外の入力」には使いません。 ### CSV の読み方 会計ソフトから書き出した CSV を、そのまま渡せます。列名は次の候補から自動で当てます。全角と半角、空白、「(税込)」のような括弧の注記の違いは無視します。 | 項目 | 列名の候補 | |---|---| | 伝票番号 | 伝票番号・伝票No・仕訳番号・取引番号・No など | | 日付 | 日付・取引日・計上日・伝票日付・仕訳日 など | | 入力日時 | 入力日時・登録日時・作成日時・入力日 など | | 借方科目・貸方科目 | 借方勘定科目・借方科目、貸方勘定科目・貸方科目 | | 金額 | 借方金額と貸方金額、または 金額 | | 摘要 | 摘要・内容 | | 起票者・承認者 | 入力者・起票者・作成者、承認者 | 当たらない列は `columns` で指定します(例: `{ "date": "伝票日付", "amount": "金額(税込)" }`)。どの列を使ったかは応答の `source.columnsUsed` に返るので、確かめてから結果を読んでください。 1行に借方と貸方を持つ形を前提に、伝票番号と日付が同じ行を1つの仕訳にまとめます。複合仕訳の相手に使われる「諸口」は、同じ伝票の中で借方と貸方が同額なら取り除きます。合わないときは、貸借のずれを隠さないよう残します。 日付は 2026/3/31・20260331・2026年3月31日・R8.3.31・令和8年3月31日 などを読みます。金額の桁区切りと円記号は落とし、△ と括弧は負の数として扱います(負の金額は、既定では止まります)。見出しの前に表題の行があっても、見出しの行を探して読みます。エラーと除外の位置は、CSV の何行目かで返します。 弥生会計の「弥生インポート形式」(見出しの行が無い25項目または27項目の CSV)は、1項目めの識別フラグで見分けて、列の位置で読みます。2000・2111 は1行で1仕訳、2110 から 2101 までの行を1つの仕訳にまとめます。取引日付は 20260331・2026/3/31・R08/03/31 のどれでも読みます。列の並びは、弥生会計サポート情報「仕訳データの項目と記述形式」の表に合わせています。この形式には入力日時の列が無いので、入力日時を使う3つのルール(計上日と入力日の乖離・期末後の入力・営業時間外の入力)は動きません。 ## ルール | ID | 内容 | 重要度 | 何を示すか | |---|---|---|---| | `unbalanced` | 貸借不一致 | high | 手入力、取込不良、改変のいずれか | | `self_approval` | 起票者と承認者が同一 | high | 職務分掌が効いていない | | `threshold_avoidance` | 承認限度額の直下 | high | 分割計上による承認回避 | | `duplicate` | 重複仕訳 | medium | 二重計上、または正当な定期計上 | | `reversal` | 取消・訂正仕訳 | medium | 誤りの取消・訂正。期末をまたぐ組は期間帰属の確認へ | | `backdated` | 計上日と入力日の乖離 | medium | 期間帰属の誤り、遡及計上 | | `post_period_entry` | 期末後の入力 | medium | 決算整理と締めたあとの修正。統制の無効化が現れやすい | | `period_end_large` | 期末直前の大口計上 | medium | 利益調整が現れるならこの窓 | | `rare_account_pair` | 稀な勘定科目の組み合わせ | medium | 通常の取引フローから外れた処理 | | `weekend_or_holiday` | 休日の計上 | low | 業務サイクルの外での処理 | | `after_hours` | 営業時間外の入力 | low | 単独では弱いが、重なると効く | | `round_amount` | キリのよい金額 | low | 見積、概算、付け替え | | `missing_description` | 摘要が空 | low | 監査証跡としての品質 | | `description_keyword` | 摘要のキーワード | low | 事後の手直し、内容の定まっていない計上 | | `voucher_gap` | 伝票番号の欠番 | low | 削除・取消された伝票、出力の漏れ | 前提条件はオプションで渡します。 ```json { "fiscalYearEnd": "03-31", "businessHours": [9, 18], "holidays": ["2026-01-01", "2026-01-12"], "approvalThresholds": [1000000, 5000000], "backdatedDaysThreshold": 30 } ``` `approvalThresholds` と `fiscalYearEnd` を渡さなければ、対応するルールは動きません。関係のないルールが空振りして偽陽性を増やすより、明示的に止まるほうがよいという判断です。 「休日の計上」は、月末日付の仕訳を既定で対象から外します。月次・期末の整理仕訳は、土日でも月末の日付で計上されることが多いためです。3月31日が日曜だった2024年3月期のような年は、外さないと期末の整理仕訳がすべて当たります。月末も含めて見る場合は `exemptMonthEnd: false` を渡します。 「休日の計上」は、土日に加えて日本の祝日(振替休日・国民の休日を含む、2000〜2099年)を自動で見ます。祝日は内閣府の一覧を取り込まず、祝日法の規定から計算しています。2000〜2027年の全日で、内閣府の一覧と一致することを確かめました。年末年始のような会社独自の休日は `holidays` で足します。日本以外の元帳に使う場合は `japaneseHolidays: false` を渡します。 「重複仕訳」と「稀な勘定科目の組み合わせ」は、借方・貸方それぞれの科目を並べ替えてから比べます。明細の行の順番は結果に影響しません。 「期末後の入力」は、期末日より後に入力された、期末日以前の日付の仕訳を拾います。決算整理と、締めたあとの修正がここに集まります。「計上日と入力日の乖離」は既定で30日を超えた遅れしか拾わないので、3月31日付を4月10日に入力したような短い遅れは、こちらで拾います。`fiscalYearEnd` と `entered_at` がそろっているときだけ動きます。 「取消・訂正仕訳」は、同じ金額で借方と貸方を入れ替えた仕訳が 30 日以内(`reversalWindowDays`)にある組を、両方に相手の伝票番号を添えて返します。1件は1組にしか入れません。期末をまたぐ組は理由にそう書き添えますが、重要度は上げません。期首の洗替仕訳も同じ形になるためです。 「摘要のキーワード」の既定の語は「修正」「訂正」「取消」「調整」「仮計上」「不明」です。`descriptionKeywords` で差し替えられ、空の配列を渡すと止まります。「仮」1文字は仮払金などを拾いすぎるので、既定には入れていません。 「伝票番号の欠番」は、伝票番号を頭の文字と末尾の数字に分け(JV-0382 なら JV- と 382)、頭の文字ごとに連番の飛びを探します。欠けているのは仕訳そのものなので、前後の仕訳のスコアには入れず、欠番の一覧として返します。範囲の半分以上が欠けている番号は、連番で振られていないとみなして見ません。伝票番号の無い仕訳も見ません。 ## ベンフォード分析について MAD の判定境界は Nigrini, M. J. *Benford's Law* (Wiley, 2012) Table 5.1 の値を使っています。実務で広く引かれている値ですが、法令や監査基準が定めたものではありません。 サンプルが300件を下回る場合、結果に注記が付きます。この判定境界は大標本を前提にしているためです。 そして、ベンフォードは母集団の性質を見る道具であって、個別の仕訳を判定するものではありません。分布が崩れていても、事業の性質(単価が固定の商売、規制価格、少額取引の多い業態)で説明がつくことが普通にあります。 ## この道具の限界 **検出は不正の証拠ではありません。** どのルールも、正当な処理を大量に拾います。重複仕訳の多くは毎月同額の定期計上ですし、期末の大口は期末に売上が立つ商売なら当たり前に出ます。 この道具がやるのは、**母集団のどこから見るかを決めること**だけです。検出された仕訳をどう評価するかは、依然として人の仕事として残ります。 以下は、この道具では**できません**。 - 監査手続そのものの代替(十分かつ適切な監査証拠は、これでは得られません) - 不正の有無の結論づけ - 勘定科目の内容的な妥当性の判断 - 税務上の取扱いの判定 監査意見の形成や、税務申告の根拠として使えるものではありません。 ## 実データの取り扱い `examples/` に入っているのは合成データです。固定シードで生成しているので、`node examples/generate.js` を何度実行しても同じファイルになります。 `.gitignore` で `*.csv` `*.xlsx` `journals.json` `/data/` を除外しています。実際の仕訳データをコミットしないための保険です。 サーバー自体はネットワークに出ません。読むのは stdin と、起動時に `--data-dir` で許可したフォルダの中の `.json` と `.csv` だけです。書くのは stdout だけで、ファイルには書きません。 ## テスト ```bash npm test ``` 119件のテストが走ります。MCP サーバーのテストは、子プロセスとして起こして実際に JSON-RPC を投げる経路で書いています。 CI は Node 20 / 22 / 24 で走ります。テストのほかに、依存が増えていないこと、`package-lock.json` が生まれていないこと、固定シードのサンプルデータが再生成しても一致することを検査しています。依存ゼロはこのリポジトリの前提なので、人の注意ではなく CI で守っています。 ## 解説記事 このサーバーを書いた経緯と設計の判断は、記事にしています。 - [会計士がMCPサーバーを書くと、依存ライブラリがゼロになる](https://zenn.dev/ushikundesu/articles/shiwake-mcp-zero-dependency) ## ライセンス MIT ## 作者 星野宇潮(公認会計士・税理士) 経歴と無料で公開した製品は、[公式プロフィール](https://invaders.co.jp/members/hoshino-ushio.html)にまとめています。