Houki e-Gov MCP Server
> [!CAUTION]
> 旧リポジトリ名 `houki-hub-mcp` / 旧 npm 名 `@shuji-bonji/houki-hub-mcp` は使っていません。
> 現行は `@shuji-bonji/houki-egov-mcp` です。
# Houki e-Gov MCP Server
[](https://github.com/shuji-bonji/houki-egov-mcp/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@shuji-bonji/houki-egov-mcp)
[](LICENSE)
[](https://nodejs.org/)
日本の法令(憲法・法律・政令・省令・規則)を **e-Gov 法令API v2** から、条・項・号の単位で、法令番号と URL を添えて返す MCP サーバーです。税法・労働法・会社法・民法など、分野を問わず条文を LLM から引けます。
通達・質疑応答事例・タックスアンサーは [`@shuji-bonji/houki-nta-mcp`](https://github.com/shuji-bonji/houki-nta-mcp) が担当します。2 つを分けているのは、「法律で決まっている」と「通達でそうなっている」を混ぜずに返すためです。
## できること
税務・労務・会社の手続きなどを調べるときに、根拠になる条文を一次情報のまま確かめるための機能です。
- e-Gov に収録されている法令の条文を、条・項・号の単位で返します。応答には法令番号と e-Gov の URL、取得日時が付きます
- 「消法」「労基法」「電帳法」のような略称でも引けます(略称辞書 174 エントリ・6 分野)
- 施行令・施行規則と、条文が「政令で定める」と委ねている先をたどれます
- 日付を指定して、その時点の条文を取れます。改正履歴(公布日・施行日)も引けます
- 民法の「契約」の章のように、章・節の単位でまとめて読めます
- LLM が書いた引用(「所得税法第 121 条第 1 項」など)が実在するかを、まとめて確かめられます
### 相談の形の問いでの使い方
「会社員で、副業の所得が 20 万円以下なら確定申告はしなくてよいか」と尋ねると、LLM が `get_law(law_name="所得税法", article="121", paragraph=1)` を呼び、「確定所得申告を要しない場合」の条文が返ります。
条文には、答えを分ける条件が並んでいます。給与の支払者が 1 か所か 2 か所以上か、給与の全部が源泉徴収または年末調整の対象か、給与等の金額が 2,000 万円以下か、給与所得と退職所得以外の所得の合計が 20 万円以下か、ただし書きの「政令で定める場合」に当たらないか、です。利用者は、自分の事実がどの条件に当たるかを条文で確かめられます。
国税庁の解説(タックスアンサー「給与所得者で確定申告が必要な人」など)もあわせて引くには、[`houki-nta-mcp`](https://github.com/shuji-bonji/houki-nta-mcp) を併用してください。個別の事案に条文を当てはめた結論(「あなたは申告が不要です」)は返しません。理由は[業法との関係](#業法との関係)に書いています。
## まず試す(ローカル DB なし)
登録するだけで、14 ツールのうち 13 はそのまま動きます。e-Gov 法令 API v2 をその場で呼ぶためで、事前の取り込みは要りません。
```json
// claude_desktop_config.json
{
"mcpServers": {
"houki-egov": {
"command": "npx",
"args": ["-y", "@shuji-bonji/houki-egov-mcp@latest"]
}
}
}
```
再起動して「消費税法第 30 条第 1 項を見せて」「インボイス制度の登録要件は」のように尋ねると、`search_law` → `get_law` の順に呼ばれ、法令番号と e-Gov の URL 付きで本文が返ります。
ローカル DB が要るのは `search_fulltext`(条文本文の横断検索)だけです。DB が無いときは `search_law`(法令名の検索)に切り替わり、応答の `source` が `"api-fallback"` になります。本文の全文検索が要ると分かったら、そのとき一度だけ下記の「CLI(ローカル DB の構築)」を実行してください。全法令 zip(約 290 MB)の取得と取り込みが走ります。
| | ローカル DB なし | ローカル DB あり |
|---|---|---|
| `search_law` `get_law` `get_toc` `get_law_range` `get_law_revisions` `resolve_abbreviation` `explain_law_type` `get_related_laws` `get_article_references` `verify_citations` `list_attachments` `get_attachment` `get_law_file` | 動く(e-Gov API をその場で呼ぶ) | 同じ |
| `search_fulltext` | `search_law` に切り替わる(`source: "api-fallback"`) | 条文本文を横断検索する(`freshness` 付き) |
## 提供ツール
| Tool | 用途 |
|---|---|
| `search_law` | 法令タイトルでキーワード検索(略称→正式名解決済み)。`total_count` は e-Gov で一致した総数で、0 件のときは `search_fulltext` と `resolve_abbreviation` を案内する(v0.18.0) |
| `get_law` | 条/項/号レベルで本文取得(Markdown / JSON / TOC)。条は本則から探し、附則の条は `suppl_index` で附則を指して取る(v0.18.0) |
| `get_toc` | 目次のみ取得(トークン節約)。本則と附則を分け、附則は改正法ごとにまとめる(v0.13.0) |
| `get_law_range` | 編・章・節・款・目のいずれか、または附則 1 本を範囲にして条を本文ごと取得。上限を超える範囲は条の単位で打ち切り、続きの条番号を返す(v0.14.0) |
| `get_law_revisions` | 改正履歴を取得(公布日・施行日・状態) |
| `search_fulltext` | 条文本文の横断全文検索(ローカル SQLite FTS5。bulk DB 未構築時は `search_law` にフォールバック)。通達などの管轄外の略称だけを渡すと `OUT_OF_SCOPE`(v0.18.0) |
| `resolve_abbreviation` | 略称→正式名解決の診断。全角英数字・全角空白は揃えて照合し、辞書のエントリはどの管轄でも返して `in_scope` と `hint` で管轄を示す(v0.16.0) |
| `explain_law_type` | 法令種別(憲法・法律・政令・省令・通達 等)の解説。e-Gov の法令種別コード(`Act`・`Constitution`・`Rule` など)でも引ける |
| `get_related_laws` | 法令名の規則で施行令・施行規則(施行令からは親の法律)を引き、e-Gov に実在するものだけを `law_id` 付きで返す(v0.10.0)。法律でも施行令・施行規則でもない法令からは候補を作らない(v0.18.0) |
| `get_article_references` | 本則の条の本文が引用している他法令の条(`law_id` 付き)・同一法令内の条項号・「附則第N条」・「政令で定める」の委任先を取り出し、`get_law`(条の無い他法令の参照は `get_toc`)の引数を `next_actions` で付ける(v0.10.0。附則と委任先の扱いは v0.18.0) |
| `verify_citations` | 引用のリストをまとめて実在確認し、件ごとに `found` / `not_found` / `ambiguous` を返す(v0.11.0)。条は本則で確かめ、附則の条は `suppl_index` で指す(v0.18.0) |
| `list_attachments` | 法令に付いた添付ファイル(別表・様式・別記の図。jpg / pdf)の一覧。各ファイルに認証なしで開ける URL と、法令の中の置き場所(「別表第一(第一条関係)」など。附則の別表・様式は v0.18.0 から)を付ける(v0.15.0) |
| `get_attachment` | 添付ファイル 1 件(または zip)。既定は URL とメタ情報だけ、`save: true` でサーバー側の保存先に書いて絶対パスを返す(v0.15.0) |
| `get_law_file` | 法令本文を xml / json / html / rtf / docx のファイルで。既定は URL だけ、`save: true` で保存(v0.15.0) |
`search_fulltext` は、2 文字の語(「相殺」「時効」)を渡されたときに何をして結果を出したかを `short_tokens` で返します(v0.12.0)。索引が trigram で 3 文字以上の語しか載せないため、既定では条の本文を引かず、法令名を添える形と `scan_body: true` で走査する形を `next_actions` で示します。詳しくは[2 文字の語の検索](#2-文字の語の検索v0120)をご覧ください。
`get_toc` は、本則を `toc`、附則を改正法ごとに `suppl_provisions` へ分けて返します(v0.13.0)。既定では附則は見出しと条数だけで、`suppl: "full"` で附則の中の条まで返します。詳しくは[本則と附則の分け方](#本則と附則の分け方v0130)をご覧ください。
`list_attachments` / `get_attachment` / `get_law_file` は、条文の文字列に入らないもの(別表・様式の図、Word や HTML の本文ファイル)を取る道です(v0.15.0)。ファイルの中身は応答に入れず、認証なしで開ける URL と、`save: true` のときだけ保存先の絶対パスを返します。詳しくは[添付ファイルと法令本文ファイル](#添付ファイルと法令本文ファイルv0150)をご覧ください。
`get_law_range` は、`get_law`(1 条ずつ)と `get_toc`(目次だけ)の間を埋めます(v0.14.0)。民法の「第三編第二章 契約」のように章・節を指定すると、その中の条を本文ごと返し、長い範囲は条の単位で打ち切って続きの条番号を返します。詳しくは[章・節単位の取得](#章節単位の取得v0140)をご覧ください。
略称辞書(174 エントリ・6 分野)は [`@shuji-bonji/houki-abbreviations`](https://github.com/shuji-bonji/houki-abbreviations) を内部で利用しています。
### 施行令・施行規則と条文内の参照(v0.10.0)
`get_related_laws` と `get_article_references` は、法令名の文字列規則と条文本文の正規表現で **決定論的に引ける参照だけ** を返します。同じ入力には同じ出力になり、LLM の判断は挟みません。
- `get_related_laws({ law_name: "所得税法" })` → `related[]` に所得税法施行令(`340CO0000000096`)と所得税法施行規則(`340M50000040011`)。名前の末尾に「施行令」「施行規則」を付けた候補を e-Gov に問い合わせ、`law_title` が完全一致した 1 件だけを採用します。無かった候補は `not_found[]` に残します
- `get_article_references({ law_name: "所得税法", article: "57の2", paragraph: 2 })` → `references[]` に「雇用保険法(昭和四十九年法律第百十六号)第十条第五項第一号」が `law_id` と条・項・号付きで入り、`delegations[]` に「政令で定める」×N と委任先(所得税法施行令)が入ります。「前項」「同法」は `kind: "relative"` で解決しません
- 確かでないときは推定しません(v0.18.0)。`get_article_references` は本則の条だけを対象にし、本文の「附則第N条」は `kind: "suppl"`・`resolved: false` で返します。省令・府令の委任先は、施行規則を定めた命令の名前(法令番号の `大蔵省令` など。省の改称は同じ省として扱います)が委任の文言と合うときだけ付け、合わないときと `主務省令` は `target_law: null` にします。施行規則の本文の「令第N条」は、兄弟の施行令が実在すれば `external` に解決します。`get_related_laws` は、法律でも施行令・施行規則でもない法令(省令・政令・規則など)からは候補を作らず、`related` を空にして `note` に理由を書きます
- どちらの応答にも `note` / `coverage.note` が付き、抽出できた範囲だけを返していること、網羅性を保証しないことを書いています。委任の趣旨の解釈や意味的に近い条の推薦は行いません(houki-hub#8 の法令グラフの担当)
## インストール
### Claude Desktop で使う
上の「まず試す」の `claude_desktop_config.json` の例をそのまま使います。ローカル DB は無くても動きます。
### Claude Code plugin で使う
リポジトリ同梱の [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) が MCP server として `npx -y @shuji-bonji/houki-egov-mcp@latest` を登録します。plugin として入れた場合も、下の「Claude Desktop で使う」も、起動されるのは npm に公開された同じパッケージです。
### ローカル開発
```bash
git clone git@github.com:shuji-bonji/houki-egov-mcp.git
cd houki-egov-mcp
npm install
npm run build
npm test
```
```json
// 開発中の動作確認 (.mcp.json)
{
"mcpServers": {
"houki-egov-local": {
"command": "node",
"args": ["/absolute/path/to/houki-egov-mcp/dist/index.js"]
}
}
}
```
手元のビルドも、`HOUKI_EGOV_DB_PATH` が無ければ plugin と同じ `~/.cache/houki-egov-mcp/laws.db` を開きます。古いコミットや DB の版を上げる変更を試すときは、別のファイルに向けてください([CONTRIBUTING.md の「ローカル DB を使う開発」](CONTRIBUTING.md#ローカル-db-を使う開発))。
## 使用例
```
# LLM への問いかけ → MCP ツール呼び出し
「消費税法30条1項を見せて」
→ get_law(law_name="消法", article="30", paragraph=1)
「消費税法第三十条第一項を見せて」(判決文や通達からの引き写し)
→ get_law(law_name="消法", article="第三十条", paragraph=1) # 漢数字は v0.7.0 から。項は数値で
「消費税法2条1項8号の2(特定資産の譲渡等)を見せて」
→ get_law(law_name="消法", article="2", paragraph=1, item="8の2")
「労働基準法の目次を取得」
→ get_toc(law_name="労基法")
「民法の契約の章をまとめて読みたい」
→ get_law_range(law_name="民法", part=3, chapter=2)
→ 第三編 債権 第二章 契約(198 条)を上限(既定 30,000 文字)まで返し、続きは from_article で取る
「会社法の設立の章を見せて」
→ get_law_range(law_name="会社法", path="Part2/Chapter1") # get_toc の toc[].path をそのまま渡せる
「個人情報保護法の改正履歴を最新5件」
→ get_law_revisions(law_name="個情法", latest=5)
「電帳法って正式名称なに?」
→ resolve_abbreviation(abbr="電帳法")
→ 電子計算機を使用して作成する国税関係帳簿書類の保存方法等の特例に関する法律
「政令と省令の違いは?」
→ explain_law_type(name="政令")
「民法で不法行為について定めている条文は?」(bulk DB 構築後)
→ search_fulltext(keyword="民法 不法行為")
→ law_scope=[民法] に絞って本文検索。724 条・719 条・509 条 などが snippet 付きで返る
「民法 第709条」(法令名 + 条番号だけ)
→ search_fulltext(keyword="民法 第709条")
→ 本文検索をせず、民法 709 条を直接返す
```
## CLI(ローカル DB の構築 — v0.3.1+)
ローカル DB が要るのは `search_fulltext` だけです。それ以外の 13 ツールは DB が無くても動くので、条文本文の横断検索が要ると分かってから作れば足ります(上の「まず試す」)。
全文検索用のローカル DB(SQLite FTS5)は、e-Gov の bulk ダウンロード zip から構築します。MCP server として常駐する通常起動とは別に、フラグ付きで起動すると CLI モードで動作します。
```bash
# 全法令 zip (約 290 MB) を DL して DB に取り込む (初回)
npx -y @shuji-bonji/houki-egov-mcp@latest --bulk-download-everything
# 最終同期日から今日までの日次差分を取り込む (2 回目以降。v0.8.0+)
npx -y @shuji-bonji/houki-egov-mcp@latest --sync
# DB の件数と鮮度 (freshness) を表示
npx -y @shuji-bonji/houki-egov-mcp@latest --status
```
コマンドは、どのフォルダーからでも動く `npx -y @shuji-bonji/houki-egov-mcp@latest <フラグ>` の形で書いています。
- `npm install -g @shuji-bonji/houki-egov-mcp` でグローバルにインストールしたときは、`houki-egov-mcp <フラグ>` でも動きます。インストールしていないと `command not found` になります
- `npx houki-egov-mcp <フラグ>` は、npm に `houki-egov-mcp` という名前のパッケージが無いので 404 になります(このリポジトリのフォルダーの中でだけ動きます)
- `@latest` を付けると、npx が以前に取得した古い版を使わずに、公開中の最新版で実行します。plugin と同じ版で DB を作り、更新するために付けています(0.18.x 以前の版で版 3 の DB を開くと全テーブルが消えるので、古い版を使わないことが大切です)
`search_fulltext` の応答(`next_actions` と `note`)と CLI の出力で案内するコマンドも、この `npx -y @shuji-bonji/houki-egov-mcp@latest <フラグ>` の形です(0.20.0 から)。`HOUKI_EGOV_DB_PATH` か `XDG_CACHE_HOME` で DB の場所を決めて起動・実行したときは、同じ変数を前に付けた形(例: `HOUKI_EGOV_DB_PATH="$HOME/.cache/houki-egov-mcp/laws.dev.db" npx -y @shuji-bonji/houki-egov-mcp@latest --bulk-download-everything`)になるので、そのまま実行すれば同じ DB を作り、更新します。`--help` の使い方だけは `houki-egov-mcp <フラグ>` の形で書いています。
`--sync` は、差分が無い日(土日など)を飛ばし、途中で失敗しても成功した日までを記録して終わります。最終同期から 90 日(`HOUKI_EGOV_INCREMENTAL_LIMIT_DAYS`)を超えて空いているときは、e-Gov の日次差分の公開範囲を超えるので、何もせずに `--bulk-download-everything` を促します。1 日分は数百 KB〜30 MB、13 日分でおよそ 1〜2 分です。
DB は既定で `~/.cache/houki-egov-mcp/laws.db` に作られます。場所を変えるときは、下の「DB の場所を変える(`HOUKI_EGOV_DB_PATH`)」を見てください。
`--status` は、1 行目に版、2 行目に `DB:`(開く DB のファイル)、3 行目に `DB の場所の設定:`(`HOUKI_EGOV_DB_PATH`・`XDG_CACHE_HOME`・`既定` のどれでその場所に決まったか)を出します(3 行目は 0.20.0 から)。同じフォルダーに、名前が `laws` で始まり `.db` で終わるファイルがほかにあるときは、その次の行の `[WARN] 同じフォルダーに、この DB のほかに laws*.db のファイルがあります: …` で、名前・大きさ・最終更新を挙げます。MCP サーバーと CLI が別のファイルを開いていないかを確かめるための行で、終了コードは変わりません。
MCP サーバー(plugin を含む)が開くファイルは、起動時のログ(標準エラー出力)の `[server] DB: <絶対パス>(DB の場所の設定: <名前>)` の行と、`search_fulltext` の応答の `freshness.db_path`(ホームディレクトリの部分は `~`)で確かめられます(0.20.0 から)。起動時のログは、MCP クライアントが保存する MCP サーバーのログに出ます。
`--bulk-download-by-date YYYYMMDD` は 1 日分の差分だけを取り込む確認用のコマンドです。同期の状態(`last_sync_date`)は変えないので、最新化には `--sync` を使ってください。差分の無い日を指定したときは `差分なし` を出して終了コード 0 で終わります。
引数を打ち間違えたとき(`houki-egov-mcp status` のような `-` の無い引数、`--sync --status` のようにフラグの後に続く引数)は、何もせずにエラーと使い方を出して終了コード 2 で終わります(0.19.0 から。それまでは MCP サーバーとして起動するか、最初のフラグだけを実行していました)。
### 日々の更新と作り直し
ふだんの更新は `--sync` だけで足ります。`--bulk-download-everything` を使うのは、表の 2〜5 行目の 4 つのときです。
| 場面 | 使うコマンド | すること |
|---|---|---|
| ふだんの更新(毎日・毎週など) | `--sync` | 最後に同期した日から今日までの日次差分を取り込みます。差分の無い日は `差分なし` で飛ばします |
| 初めて DB を作るとき | `--bulk-download-everything` | 全件の zip(約 290 MB)を取得して DB を作ります |
| 最後の同期から 90 日(`HOUKI_EGOV_INCREMENTAL_LIMIT_DAYS`)を超えたとき | `--bulk-download-everything` | `--sync` は何もせずに、このコマンドを促して終了コード 1 で終わります |
| houki-egov-mcp を上げて DB の版が変わったとき(0.19.0 で版 2 → 3) | `--bulk-download-everything` | 版の古い DB を作り直して取り込みます(取り込んだ中身は消えます) |
| `--sync`・`--status` が `[WARN] 施行日が last_sync_date …` を出したとき(0.19.1 から) | `--bulk-download-everything` | 施行日を過ぎても未施行のまま残った版の状態を直します(条の本文は入れ直しません) |
版が同じ DB に `--bulk-download-everything` を実行しても、作り直しはしません。全件の zip を取り直して、中身の変わった法令と、施行されて状態が変わった版だけを書き換えます。ふだんの更新に使う必要はありません。
### 0.19.0 で 2026-10-04 以降に `--sync` した DB は、0.19.1 で 1 回取り込み直してください
e-Gov は、改正の施行日の当日の差分に、それまで未施行として配っていた版を同じ中身のまま「施行済み」としてもう一度入れます。0.19.0 はこの版を「中身が同じ」として飛ばしていたので、施行日を過ぎても版が未施行のまま残り、`search_fulltext` が改正前の条文を返し続けることがありました(#107)。0.19.1 は、中身が同じでも状態だけを書き換えます。
0.19.0 で 2026-10-04 以降に `--sync` した DB は、0.19.1 に上げた後に次のコマンドを 1 回実行してください。施行日を過ぎても未施行のまま残った版の状態を直します(条の本文は入れ直しません。全件の zip 約 290 MB を取得します)。0.19.1 の `--sync` や `--status` が `[WARN] 施行日が last_sync_date …` を出したときも同じです。
```bash
npx -y @shuji-bonji/houki-egov-mcp@latest --bulk-download-everything
```
- 取り込みで状態だけを書き換えた版があると、` ingest 完了: …` の行の後に ` 状態の更新: <件数> 件 (…)` の行が出ます
- このコマンドが要る DB の正確な範囲(`--sync` だけで直る場合)は [docs/NOTES.md](docs/NOTES.md) の「施行日の当日に配り直される版(0.19.1)」にあります
### 0.19.0 に上げたら DB を作り直してください
0.19.0 で DB のスキーマの版を 2 から 3 に上げました。0.18.x 以前に作った DB は 0.19.0 では使えないので、次のコマンドで作り直してください。全件の zip(約 290 MB)を取得し直し、取り込み直します。
```bash
npx -y @shuji-bonji/houki-egov-mcp@0.19.0 --bulk-download-everything
```
- 作り直すまで、`search_fulltext` は条文本文を検索せずに `search_law`(法令名のタイトル一致)の結果を返し、`note` で作り直しを案内します。`--sync`・`--status`・`--bulk-download-by-date` は DB に触れずにエラー(終了コード 1)で終わります
- 作り直すのは、zip の取得に成功した後です。取得に失敗したときは古い DB がそのまま残ります
- 作り直した後に 0.18.x 以前の houki-egov-mcp でこの DB を開くと、版が違うため全テーブルが消えます(0.18.x 以前の動きで、0.19.0 からは直せません)。0.19.0 で作り直した後は 0.18.x に戻さないでください。plugin などで版を固定している場合は、CLI と同じ版にそろえてください
- 0.18.x の plugin を使い続けたまま 0.19.0 を試すときは、0.19.0 の側だけ `HOUKI_EGOV_DB_PATH` で別のファイルを指定してください(下の「DB の場所を変える」)。2 つの版が別々の DB を使うので、どちらの DB も消えません
### 環境変数
| 環境変数 | 内容 | 既定 |
|---|---|---|
| `HOUKI_EGOV_DB_PATH` | DB ファイルのパス(フォルダーではなく、ファイル名まで書く)。CLI と MCP サーバーの両方に同じ値を設定します(下の「DB の場所を変える」) | `$XDG_CACHE_HOME/houki-egov-mcp/laws.db`(`XDG_CACHE_HOME` が無ければ `~/.cache/houki-egov-mcp/laws.db`) |
| `HOUKI_EGOV_BULK_RETRY` | 一括ダウンロードの zip の取得に失敗したときに試す回数 | 3 |
| `HOUKI_EGOV_INCREMENTAL_LIMIT_DAYS` | `--sync` が差分で追える日数の上限。`--status` と `search_fulltext` の警告の日数にも使います | 90 |
| `HOUKI_EGOV_CONCURRENCY` | e-Gov 法令 API への同時リクエスト数の上限 | 4 |
| `HOUKI_EGOV_FILES_DIR` | `get_attachment` / `get_law_file` の `save: true` の保存先 | `${XDG_CACHE_HOME:-~/.cache}/houki-egov-mcp/files` |
数値の 3 つ(`HOUKI_EGOV_BULK_RETRY`・`HOUKI_EGOV_INCREMENTAL_LIMIT_DAYS`・`HOUKI_EGOV_CONCURRENCY`)は 1 以上の整数で指定します。`0`・負の数・小数・数字以外を指定すると、CLI(取り込み・同期・状態の表示)は何もせずに終了コード 2 で終わり、MCP サーバーは警告を出して既定値で起動します(0.19.0 から。それまでは `0` や数字以外は黙って既定値になり、負の数はそのまま使っていました)。
### DB の場所を変える(`HOUKI_EGOV_DB_PATH`)
DB の場所は、次の順で決まります。
1. 環境変数 `HOUKI_EGOV_DB_PATH` があれば、その値のファイル
2. 無ければ、環境変数 `XDG_CACHE_HOME` の下の `houki-egov-mcp/laws.db`
3. どちらも無ければ、`~/.cache/houki-egov-mcp/laws.db`
起動のしかたによって、環境変数が渡るかどうかが違います。どのファイルを開くかは次のとおりです。
| 起動のしかた | 環境変数 | 開く DB |
|---|---|---|
| Claude Code plugin(`.claude-plugin/plugin.json`) | plugin は `env` を持たず、Claude Desktop のような GUI アプリはシェルの環境変数を受け継がない | `~/.cache/houki-egov-mcp/laws.db` |
| MCP の設定ファイル(`claude_desktop_config.json`・`.mcp.json`)に書いたサーバー | 設定の `env` だけ | `env` に `HOUKI_EGOV_DB_PATH` があればそのファイル。無ければ `~/.cache/houki-egov-mcp/laws.db` |
| ターミナルの CLI(`--bulk-download-everything`・`--sync`・`--status`) | そのシェルの環境変数 | `HOUKI_EGOV_DB_PATH` があればそのファイル。無ければ `${XDG_CACHE_HOME:-~/.cache}/houki-egov-mcp/laws.db` |
**環境変数を付けずに CLI を実行すると、plugin が使う `laws.db` を作り、更新します。** plugin で使う DB は、環境変数を付けずに CLI で作り、`--sync` で更新してください。逆に、plugin と別の DB を試したいときは、CLI にだけ `HOUKI_EGOV_DB_PATH` を付けます。そのときに作った DB を plugin は読みません。シェルの設定(`~/.zshrc` など)で `HOUKI_EGOV_DB_PATH` を `export` しているときは、plugin と同じ DB を扱う CLI の前に `env -u HOUKI_EGOV_DB_PATH` を付けます(例: `env -u HOUKI_EGOV_DB_PATH npx -y @shuji-bonji/houki-egov-mcp@latest --sync`)。
`HOUKI_EGOV_DB_PATH` を使うのは、DB を別のディスクに置きたいとき、版の違う houki-egov-mcp を並べて使うとき(0.18.x の plugin と 0.19.0 など)、試しに別の DB を作りたいときです。設定するときは、次の 3 点に気を付けてください。
- **CLI と MCP サーバーの両方に、同じ値を設定します。** DB を作る CLI(`--bulk-download-everything` など)と、DB を読む MCP サーバー(`search_fulltext`)は別々に起動するので、片方だけに設定すると、CLI が作った DB を MCP サーバーが見つけられません(`search_fulltext` が `ローカル DB (<パス>) が無いため` か `HOUKI_EGOV_DB_PATH が指すファイル (<パス>) が無いため` で `search_law` に切り替わります)
- **フォルダーではなく、ファイル名まで書きます。** 例: `/Users/you/data/houki-egov/laws.db`。途中のフォルダーが無ければ、`--bulk-download-everything` が作ります
- **MCP の設定ファイル(JSON)では、`~` を使わずに絶対パスで書きます。** JSON の `env` の値はシェルを通らないので、`~/…` は展開されません。ターミナルで `export` するときは `~` が使えます
CLI での指定(ターミナル):
```bash
export HOUKI_EGOV_DB_PATH=~/data/houki-egov/laws.db
npx -y @shuji-bonji/houki-egov-mcp@latest --bulk-download-everything
npx -y @shuji-bonji/houki-egov-mcp@latest --status # 2 行目の「DB:」に使っている場所、3 行目に DB の場所の設定が出ます
```
MCP サーバーでの指定(`claude_desktop_config.json` や `.mcp.json`):
```json
{
"mcpServers": {
"houki-egov": {
"command": "npx",
"args": ["-y", "@shuji-bonji/houki-egov-mcp@latest"],
"env": {
"HOUKI_EGOV_DB_PATH": "/Users/you/data/houki-egov/laws.db"
}
}
}
}
```
設定を変えたら、MCP クライアント(Claude Desktop など)を起動し直してください。MCP サーバーが使っている場所は、起動時のログの `[server] DB: …` の行か、`search_fulltext` の応答の `freshness.db_path` で確かめられます。CLI では、同じ値を付けて `--status` を実行し、2 行目の `DB:`、3 行目の `DB の場所の設定:`、`laws:` の件数で確かめてください。
### `search_fulltext` が `api-fallback` になるとき
ローカル DB を作ったはずなのに `search_fulltext` が `source: "api-fallback"` を返すときは、`note` の先頭で原因を見分けます。
| `note` の先頭 | 考えられる原因 | 確かめ方・直し方 |
|---|---|---|
| `ローカル DB (<パス>) が無いため` | `<パス>` に DB をまだ作っていない(`HOUKI_EGOV_DB_PATH` を設定していないサーバー) | `<パス>` に DB を作ります。plugin なら環境変数を付けずに `--bulk-download-everything` を実行します(上の `env -u`)。別のファイルに作った DB があるなら、下の手順で `<パス>` に移します |
| `HOUKI_EGOV_DB_PATH が指すファイル (<パス>) が無いため` | MCP サーバーの `HOUKI_EGOV_DB_PATH` が、無いファイルを指している(ファイルの名前を変えた・消した、CLI と違う値を設定した、など) | `HOUKI_EGOV_DB_PATH` を作ってある DB のファイルに直すか、そのパスに作ります。`note` と `next_actions` のコマンドは同じ変数を付けた形なので、そのまま実行すればそのパスに作ります |
| `ローカル DB (<パス>) にまだ法令が取り込まれていないため` | ファイルはあるが、法令が取り込まれていない(0 バイトのファイル、取り込みを途中で止めた DB、houki-egov-mcp で作っていない SQLite のファイル) | `--bulk-download-everything` を実行します |
| `ローカル DB (<パス>) の版 (<n>) がこの houki-egov-mcp (3) より古いため` | 開いた DB が、前の版の houki-egov-mcp で作ったもの | `--bulk-download-everything` で作り直します。新しい版の DB が別のファイルにあるなら、下の手順で移すと取り込み直さずに済みます |
| `ローカル DB (<パス>) の版 (<n>) がこの houki-egov-mcp (3) より新しいため` | 開いた DB が、新しい版の houki-egov-mcp で作ったもの(plugin の版が CLI より古い、など) | plugin と CLI の版をそろえます |
| `ローカル DB (<パス>) の版を読めないため (schema_version: <値>)` | DB の版の記録が、整数でない値になっている | `<パス>` のファイルを消してから `--bulk-download-everything` を実行します |
| `ローカル DB (<パス>) を開けなかったため` | パスがフォルダーを指している、途中が普通のファイル、権限が無い | `HOUKI_EGOV_DB_PATH` の値を直します。この場面では `--bulk-download-everything` を案内しません(同じパスでは、取り込みも取得の前に止まるためです) |
`<パス>` は MCP サーバーが開こうとしたファイルで、ホームディレクトリの部分を `~` にして書きます(0.20.0 から。0.19.x までは `bulk DL 未実行のため` などの文で、開こうとしたファイルが分かりませんでした)。CLI の側は、MCP サーバーと同じ環境変数で `--status` を実行し、2 行目の `DB:` と 3 行目の `DB の場所の設定:` で、開くファイルとその場所に決まった理由を確かめます。plugin なら `HOUKI_EGOV_DB_PATH` を付けずに実行します(上の `env -u`)。同じフォルダーに別の `laws*.db` が残っていれば、`--status` が `[WARN]` の行で挙げます。
### 別のファイルで作った DB を `laws.db` に移す
`HOUKI_EGOV_DB_PATH` で別のファイル(例: `laws.v3.db`)に作った DB は、名前を `laws.db` に変えれば、取り込み直さずに plugin から使えます。
1. その DB を開いている MCP サーバーを止めます(Claude Desktop などを終了し、`--sync` などの CLI も動いていないことを確かめます)
2. WAL の中身を DB ファイルに書き戻します: `sqlite3 ~/.cache/houki-egov-mcp/laws.v3.db 'PRAGMA wal_checkpoint(TRUNCATE);'`
3. 今の `laws.db` を退避します: `mv ~/.cache/houki-egov-mcp/laws.db ~/.cache/houki-egov-mcp/laws.v2.bak.db`(`laws.db-wal`・`laws.db-shm` があれば、同じように名前を変えるか消します)
4. 名前を変えます: `mv ~/.cache/houki-egov-mcp/laws.v3.db ~/.cache/houki-egov-mcp/laws.db`(2 で空になった `laws.v3.db-wal`・`laws.v3.db-shm` は、`laws.db` の名前に付け替えずに消すか別の名前にします)
5. 環境変数を付けずに `npx -y @shuji-bonji/houki-egov-mcp@latest --status` を実行し、`DB:` が `laws.db` で `laws:` の件数が入っていることを確かめます
6. `HOUKI_EGOV_DB_PATH` で古いファイル名を指している設定(MCP の設定ファイルの `env`、シェルの `export`)があれば、消すか `laws.db` に直します。古い名前を指したままのサーバーは、ファイルが無いので `HOUKI_EGOV_DB_PATH が指すファイル (…) が無いため` を返します
退避した古い DB は、確かめた後に消してかまいません。
### SQLite と DB の置き場所(npx / plugin 経由で使う場合)
SQLite は本パッケージが依存する `better-sqlite3` に同梱されています(SQLite 3.53 系の amalgamation。OS の sqlite3 は使いません)。`npx` や plugin で初めて起動したときに npm が `better-sqlite3` を取り込み、実行中の Node.js と OS に合ったビルド済みバイナリ(`prebuild-install`)を GitHub Releases から取得します。対応する prebuilt がない Node.js の場合は `node-gyp` でその場でコンパイルするため、Python と C++ ビルドツール(macOS なら Xcode Command Line Tools)が必要になります。Node 22 / 24 の LTS では prebuilt が用意されているので、通常はコンパイルは走りません。
DB ファイルはパッケージの中ではなく、上記のユーザーのキャッシュディレクトリに置かれます。したがって次の 3 つは **同じ 1 つの DB** を読み書きします。
| 起動方法 | 実行されるコード | 読む DB |
|---|---|---|
| `npx -y @shuji-bonji/houki-egov-mcp@latest --bulk-download-everything`(CLI) | npx のキャッシュ内のパッケージ | `~/.cache/houki-egov-mcp/laws.db` |
| Claude Desktop / Claude Code plugin(`npx -y …@latest`) | 同上(`@latest` 指定なら起動ごとにレジストリを確認) | 同上 |
| ローカル開発(`node dist/index.js`) | リポジトリの `dist` | 同上。古いコミットや DB の版を上げる変更を試すときは、`HOUKI_EGOV_DB_PATH` で別のファイルに向けてください([CONTRIBUTING.md](CONTRIBUTING.md#ローカル-db-を使う開発)) |
どれも環境変数が無いときの場所です。`HOUKI_EGOV_DB_PATH` を設定した起動だけが別のファイルを開きます(上の「DB の場所を変える」)。
このため、DB の構築は一度 CLI で行えば、plugin 経由の `search_fulltext` からもそのまま使えます。`--bulk-download-everything` のあとに MCP server を再起動する必要はありません(`search_fulltext` は呼び出しごとに DB を開いて閉じます)。書き込みは CLI だけが行い、MCP server は読むだけです(journal は WAL なので、取り込み中に検索しても壊れません)。DB を作るのは `--bulk-download-everything` だけで、`search_fulltext` と `--status` は DB が無くてもファイルやフォルダーを作りません(0.19.0 から)。
DB が存在しない、または条が 1 件も入っていないときは、`search_fulltext` は `source: "api-fallback"` で `search_law` の結果を返し、`next_actions` に `--bulk-download-everything` の実行を案内します。パッケージを更新しても DB は消えません。版が古い DB は `--bulk-download-everything` を実行したときだけ作り直します。新しい版の DB は触りません。
DB の版(DB に記録したスキーマの版)ごとの扱いは次のとおりです(0.19.0 から)。
| DB の状態 | `--bulk-download-everything` | `--sync`・`--bulk-download-by-date` | `--status` | `search_fulltext` |
|---|---|---|---|---|
| ファイルが無い | 作って取り込む | 作らない。全件の取り込みを促して終了コード 1 | 作らない。DB が無いことを出して終了コード 0 | 作らない。`search_law` に切り替える |
| 版が同じ(3) | 取り込む | 取り込む | 表示する | 検索する |
| 版が古い(1・2) | 取得に成功してから作り直して取り込む | 書き込まずに終了コード 1 | 書き込まずに終了コード 1 | 使わずに `search_law` に切り替え、作り直しを案内する |
| 版が新しい・版を読めない | 取得せずに終了コード 1 | 書き込まずに終了コード 1 | 書き込まずに終了コード 1 | 使わずに `search_law` に切り替える |
全データを消すコマンドはありません。中身を消したいときは DB のファイルを消してください(場所は `--status` の `DB:` の行に出ます)。
DB を構築すると `search_fulltext` が条文本文を SQLite FTS5 で検索します(v0.5.0〜)。略称は正式名称にも展開され(`労基法` → `労基法` または `労働基準法`)、通称(`インボイス` など)は元の語で条が当たらないときだけ正式名称で探し直します(v0.18.0)。「民法 不法行為」「労基法 時間外」のように法令名と語を並べるとその法令の条に絞って本文を検索します。各ヒットに条番号・snippet・score・DB の鮮度(`freshness`)が付きます。DB が未構築のときは従来どおり `search_law`(法令名のタイトル一致)にフォールバックし、`note` でその旨を返します。
> **v0.5.0 以前に構築した DB について**: v0.5.0 で本文の正規化を投入時に行うようになり(スキーマバージョン 2)、v0.5.1 で編(Part)を持つ法令の本則が取り込まれていなかった不具合を直しました。0.19.0 からはスキーマの版 3 の DB だけを使うので、どの版で作った DB も `--bulk-download-everything` で作り直してください。
>
> **検索語の制約**: 索引が trigram のため、条文本文は 3 文字以上の語で索引から引きます。2 文字の語(「相殺」「時効」等)の扱いは v0.12.0 で変わりました(下記)。「第30条」のような条番号は本文検索には使わず、該当条を上位に寄せる加点にだけ使います(漢数字は未対応)。
### 添付ファイルと法令本文ファイル(v0.15.0)
法令には、条文の文字列に入らないものが付いています。別表・様式・別記の図(e-Gov では jpg か pdf)と、法令全体を 1 つのファイルにした本文(xml / json / html / rtf / docx)です。`get_law` の Markdown には図の中身は入らず、様式の図が要る作業(届書の書式、旗の寸法図)は条文だけでは済みません。v0.15.0 の 3 ツールはそのための道です。
```
「戸籍法施行規則の出生届の様式を見たい」
→ list_attachments(law_name="戸籍法施行規則")
attachments[] の location.title が「附録第十一号様式」の 1 件(pdf)の url を得る
→ pdf-reader-mcp の read_url(url=…) # URL は認証なしで開ける
(またはディスクに置くなら)
→ get_attachment(law_name="戸籍法施行規則", src="./pict/2FH00000076885.pdf", save=true)
→ saved.path を pdf-reader-mcp の read_text に渡す
「民法の全文を Word で」
→ get_law_file(law_name="民法", file_type="docx", save=true)
→ saved.path(182 KB)。saved.law_revision_id にどの履歴の本文かが入る
```
- **中身は返しません**。バイナリを base64 にして応答に入れることはせず、URL(`https://laws.e-gov.go.jp/api/2/attachment/<law_revision_id>?src=…`、`…/law_file/<file_type>/<law_id>`)を返します。URL は認証なしで開けるので、pdf-reader-mcp の `read_url` や、利用者のブラウザーにそのまま渡せます
- **保存先はサーバー側で決めます**。`save: true` のときだけファイルを取得し、`${XDG_CACHE_HOME:-~/.cache}/houki-egov-mcp/files/<law_revision_id>/<ファイル名>` に書いて `saved.path` を返します。保存先は環境変数 `HOUKI_EGOV_FILES_DIR` で変えられますが、ツールの引数にはありません(LLM が渡した文字列をパスに使わないため)。1 ファイル 50 MB を超えるときは保存せず `FILE_TOO_LARGE` を返します。e-Gov の応答の Content-Length で分かるときは本文を読みません(v0.16.0)
- **置き場所を付けます**。`list_attachments` は e-Gov の `attached_files_info`(src と更新日時)と本文の `Fig` 要素を `src` で突き合わせ、各ファイルに `location`(別表・様式の見出しと関係条文、条の中なら条番号、附則の中なら改正法番号)を付けます。一覧にだけあって本文に無いファイルは `location: null` です
- 添付ファイルは法令履歴ごとに付くので、`at` で時点を変えると一覧も変わります。添付が無い法令は `list_attachments` では `count: 0` の成功応答、`get_attachment` では `ATTACHMENT_NOT_FOUND` です
- `get_law_file` の `xml` / `json` は法令全体(民法で 1.6 MB)なので、条文を読むだけなら `get_law` / `get_law_range` を使ってください。`docx` / `html` / `rtf` は人が開く版です
### 章・節単位の取得(v0.14.0)
`get_law_range` は、編・章・節・款・目のいずれか、または附則 1 本を範囲にして、その中の条を本文ごと返します。`get_law` で 1 条ずつ引くと手数がかかり、法令全体を返すには長すぎる法令(民法・会社法・消費税法)のためのツールです。
範囲の指定は次の 3 通りで、同時に指定できるのは 1 つだけです。
| 指定 | 書き方 |
|---|---|
| 編・章・節・款・目の番号 | `part=3, chapter=2`(`"三"`・`"第三編"`・枝番号の `"2の2"` も可) |
| 範囲のパス | `path="Part3/Chapter2"`(`get_toc` の `toc[].path` をそのまま渡せます) |
| 附則 | `suppl_index=12`(`get_toc` の `suppl_provisions[].index`。`search_fulltext` が「附則(12) 1」と表示する番号と同じ) |
章番号は編ごとに振り直されます(民法には第一章が 5 つ、第一節が 19 あります)。`chapter` だけを指定して複数の範囲に当たったときは、候補のパスを `hint` と `next_actions` に入れた `INVALID_ARGUMENT` を返します。
大きい範囲は `max_chars`(既定 30,000 文字)で条の単位で打ち切ります。条の途中では切らないため、1 条目だけは上限を超えても返します。2026-09-20 に測った条本文のサイズは次のとおりです(UTF-8 の日本語は 1 文字 3 バイト)。
| 法令 | 章の条本文(中央値 / 最大) | 既定の上限での回数 |
|---|---|---|
| 民法 | 6.2 KB / 98.2 KB | ほとんどの章は 1 回。第三編第一章(183 条)は 2 回 |
| 会社法 | 17.9 KB / 207.6 KB | 大きい章は 2〜3 回 |
| 所得税法 | 10.8 KB / 229.1 KB | 大きい章は 2〜3 回 |
| 消費税法 | 59.5 KB / 102.4 KB | 章は 2〜4 回(編が無く章が大きい) |
打ち切ったときの応答の `range` は次の形です。
```jsonc
{
"path": "Part3/Chapter2",
"titles": ["第三編 債権", "第二章 契約"],
"tag": "Chapter",
"article_count": 198, // 範囲が持つ条の数
"returned_count": 186, // 本文を返した条の数
"skipped_count": 0, // from_article より前で返さなかった条の数
"first_article": "第521条",
"last_article": "第684条",
"truncated": true,
"body_chars": 29911,
"max_chars": 30000,
"next_from_article": "685",
"note": "範囲の条 198 件のうち 186 件を返しました(第521条〜第684条)。本文 29,911 文字(上限 30,000 文字)。上限で打ち切りました。続きは from_article: \"685\" を付けて同じ範囲を呼び直してください。"
}
```
`from_article` に `next_from_article` の値を渡すと、同じ範囲の続きから返します。条を立てず項だけで書かれた附則(「1 この法律は、公布の日から施行する。」の形)は、範囲の本文をそのまま返します。
削除された条は、e-Gov の法令データでは複数の条をまとめた範囲表記になっています(民法第534条は `Article Num="534:535"`、見出しは「第五百三十四条及び第五百三十五条」、本文は「削除」)。応答ではこれを `第534条及び第535条`(3 条以上なら `第170条から第174条まで`)と表示し、`next_from_article` にも `"534:535"` の形を返すので、そのまま `from_article` に渡せます(v0.14.1)。なお `get_law` に `article: "534"` を渡してこの条を引くことは、まだできません。
### 本則と附則の分け方(v0.13.0)
附則は改正法ごとに 1 本ずつ積み上がります(所得税法は 352 本・条 983 件)。v0.12.1 までの `get_toc` は、この附則の条を本則の章の後ろにそのまま並べていたため、いま効いている規定と、ある改正法の施行日・経過措置の区別が目次から付きませんでした。
v0.13.0 からは、本則を `toc`、附則を `suppl_provisions` に分けて返します。附則 1 本は次の形です。
```jsonc
{
"index": 2, // LawBody の中での並び順。ローカル DB の Suppl2_1 と同じ番号
"label": "附則",
"amend_law_num": "平成元年六月二八日法律第三九号", // どの改正法の附則か。制定時の附則には付かない
"extract": true, // 抄(改正法の附則のうち一部だけを載せた形)
"article_count": 1,
"paragraph_only": false, // 条を立てず項だけで書かれた附則か
"children": [] // suppl: "full" のときだけ中の目次が入る
}
```
`suppl` で附則をどこまで返すかを選びます。
| `suppl` | 返すもの | 所得税法の Markdown |
|---|---|---|
| `"list"`(既定) | 改正法ごとの見出しと条数だけ | 752 行 / 54.5 KB |
| `"full"` | 附則の中の条まで | 1,735 行 / 114.4 KB |
| `"none"` | 附則を返さない(本数と条数は `suppl.count` / `suppl.article_count` に入る) | 395 行 / 24.6 KB |
既定を `"list"` にしているのは、附則の条が目次の大半を占めるためです(所得税法は本則 388 ノードに対し附則の条 983 件)。何を返したかは `suppl.note` に書きます。
`with_amend_titles: true` を付けると、改正法の題名も付けます。附則の属性には法令番号しか無いため、改正履歴(`get_law_revisions` と同じ e-Gov の応答)を 1 回引き、法令番号で照合します。2 つの表記は違うので(附則は `令和七年六月二〇日法律第七四号`、改正履歴は `令和七年法律第七十四号`)、公布の月日と漢数字の書き方を落とした「元号 + 年 + 種別 + 号数」で突き合わせます。e-Gov の改正履歴は近年の改正が中心なので、それより古い改正法には題名が付きません(消費税法は附則 167 本のうち 28 本に付き、改正履歴は 65 件)。付いた本数と付かなかった本数は `suppl.amend_law_titles` に入ります。
`get_law` の `format: "toc"` でも本則と附則を分け、附則は見出しだけを返します。
### 2 文字の語の検索(v0.12.0)
「相殺」「時効」「善意」のような 2 文字の法律用語は、条本文の索引 `articles_fts`(trigram)に載りません。v0.12.0 からは、そのときに何をして結果を出したかを応答の `short_tokens` で返します。
| クエリ | `body_search` | 何をするか |
|---|---|---|
| `適格請求書 保存` | `fts_then_filter` | 3 文字以上の語で索引を引き、その条の本文に 2 文字語が含まれるかで絞る |
| `労基法 協定` | `like_in_law_scope` | 法令名で対象法令を絞り、その範囲の条の本文を引く |
| `相殺` | `not_searched` | 条の本文は引かず、法令名・略称・番号の照合だけを返す(既定) |
| `相殺` + `scan_body: true` | `like_all_articles` | 索引を使わず、全法令の条の本文を端から照合する |
`short_tokens.hits_by_match_type` に `article`(条本文由来)と `law_meta`(法令名・略称・番号由来)の件数が入ります。v0.11.0 までは「相殺」で「相殺関税に関する政令」だけが返り、条の本文が引かれなかったことが応答から分かりませんでした。
既定で `not_searched` にしているのは、全法令の走査に時間がかかるためです。2026-09-20 に実データ(条 1,434,710 件・本文 587,926,852 バイト)で測ったところ、ヒットが多く上限 150 件で打ち切れる語で 5.4 秒、該当が少なく全表を走り切る語で 22 秒かかりました。`LIKE` を `instr` や `GLOB` に変えても、JOIN を外しても同じ時間です。588 MB を読んで照合する分そのものなので、書き方では縮みません。
そのため `not_searched` の `next_actions` は 2 つの道を示します。
1. 「`<法令名> 相殺`」の形(例: `民法 相殺`)— 法令名を添えると、その法令の条に絞って索引で引けます(速く、並び順も関連度順)。語から法令名は決まらないので、この案内には `example` を付けず、`reason` に形を書きます(v0.18.0)
2. `{ keyword: "相殺", scan_body: true }` — 法令名が分からないときの最後の手段です。5〜20 秒かかり、並び順は関連度順になりません。上限(150 件)で打ち切ったときは `truncated: true` になります
3 文字以上の語を含むクエリでは索引を引くので、`scan_body` は効きません。
### 引用の実在確認(v0.11.0)
`verify_citations` は、回答に添える引用のリストを送り出す前に、**その条(指定があれば項・号)が e-Gov の法令にあるか** を 1 回の呼び出しでまとめて確かめます。存在しない引用が混ざっていてもツール全体はエラーにならず、件ごとに判定が返ります。
```jsonc
{
"citations": [
{ "law_name": "所法", "article": "9", "paragraph": 1, "item": 1, "label": "所法9①一" },
{ "law_name": "電子帳簿保存法", "article": "7" },
{ "law_name": "所得税法", "article": "9999" }
]
}
```
- 上の 3 件は順に `found`(条見出し「(非課税所得)」付き)、`found`(`resolved_by: "exact_title"` で `410AC0000000025`)、`not_found`(`code: "ARTICLE_NOT_FOUND"`)になります
- `summary` に件数の内訳と `all_found` が入るので、「全部実在した」と書いてよいかを 1 つの値で判断できます
- 法令名が e-Gov の法令名と完全一致しなければ `ambiguous` にし、部分一致の候補を `candidates[]` に最大 5 件返します(例: 「所得税法施行」→ 所得税法施行令・所得税法施行規則)。項が複数ある条で項を書かずに号だけを指定した件も `ambiguous` です
- 通達など houki-egov の管轄外の引用は `OUT_OF_SCOPE` にし、`next_actions` で `houki-nta` を指します
- 条は本則の中で確かめます。本則に無く附則にだけある条番号は `ARTICLE_NOT_FOUND` にし、附則の番号を案内します。附則の条は `suppl_index`(`get_toc` の `suppl_provisions[].index`)で附則を指して確かめます(v0.18.0)
- 確かめるのは条文が実在するかどうかだけです。引用した条文が主張を支えるかどうかは判定しません
- e-Gov に問い合わせられなかったときは、件ごとの判定を返さずツール全体を `SOURCE_*` エラーにします。「聞けなかった」を「存在しない」と書かないためです
## 状態
**v0.15.0 (2026-09-20)**
- [x] e-Gov 法令API v2 クライアント(`searchLaws` / `getLawData` / `getLawRevisions` / `getAttachment` / `getLawFile`)
- [x] 法令ツリー走査(条/項/号、目次抽出)+ LRU cache
- [x] 14 ツール本実装
- [x] 略称辞書を [`@shuji-bonji/houki-abbreviations`](https://github.com/shuji-bonji/houki-abbreviations) に分離(v0.15.4 から ^0.6.1)
- [x] 法令階層ナレッジ(憲法・法律・政令・省令・規則・条例・告示・訓令・通達・通知 の10種別)
- [x] houki-hub family 共通の error contract(`SOURCE_*` / `OUT_OF_SCOPE`)に準拠
- [x] Phase 2 基盤:bulk DL → SQLite FTS5 の取り込みパイプライン(schema / CSV・XML parser / zip fetcher / ingester / freshness / CLI)
- [x] Phase 2-7: `search_fulltext` の FTS5 本実装(略称 OR 展開 / revision 重複排除 / relevance scoring / freshness)
- [x] MCP SDK v2(`@modelcontextprotocol/server`)/ Node 22・24 / TypeScript 7 / Biome
- [x] Trusted Publisher (OIDC) で publish
- [x] `get_law` の `item` で枝番号の号(`"8の2"`・`"第8号の2"`)を指定(v0.6.0)
- [x] ツールの引数の型を inputSchema から導き(json-schema-to-ts の `FromSchema`)、未知の引数は `INVALID_ARGUMENT`(v0.6.0)
- [x] `get_law` の `article` / `item` で漢数字(`"第三十条の二"`・`"八の二"`)と全角数字を受け付ける(v0.7.0)
- [x] `--sync` で最終同期日から今日までの日次差分を取り込む。差分が無い日は飛ばし、途中で失敗しても成功した日までを記録(v0.8.0)
- [x] `get_related_laws` / `get_article_references`: 施行令・施行規則の関連付けと条文内の参照抽出(v0.10.0、Issue #20)
- [x] `verify_citations`: 引用リストの実在確認(v0.11.0、Issue #18)
- [x] `search_fulltext` の 2 文字語(「相殺」「時効」)の扱いを `short_tokens` で明示し、`scan_body` で全走査を選べるようにした(v0.12.0、Issue #23)
- [x] `get_toc` で本則と附則を分け、附則を改正法ごとにまとめた(v0.13.0、Issue #24)
- [x] `get_law_range`: 編・章・節(または附則 1 本)を範囲にした条文の取得(v0.14.0、Issue #22)
- [x] `list_attachments` / `get_attachment` / `get_law_file`: 添付ファイル(別表・様式の図)と xml / html / rtf / docx の本文ファイル(v0.15.0、Issue #19)
- [x] テストスイート(**456 tests**)
### 計画中
- [x] Phase 2-8: 差分同期(`--sync`)— v0.8.0
- [ ] Phase 2-13: API enrichment(`category` / 改正履歴 / 廃止ステータスの精緻化)
- [x] 漢数字対応(「第三十条」を 30 に変換)— v0.7.0 で `get_law` の `article` / `item` に対応。`search_fulltext` のキーワード中の「第三十条」は未対応
- [x] 大規模法令の応答サイズ対策(民法・会社法)— v0.14.0 の `get_law_range` で章・節単位の取得に対応
## houki-hub MCP family
houki-egov-mcp は **単体で利用可能**ですが、houki-hub MCP family の一員でもあります。同じ family 内の他 MCP と組み合わせると、通達・判例等まで横断的に扱えます。
| パッケージ | 役割 | 状態 |
|---|---|---|
| [`@shuji-bonji/houki-abbreviations`](https://github.com/shuji-bonji/houki-abbreviations) | 略称辞書・正規化・freshness 判定(共有ライブラリ) | ✅ v0.5.0 |
| **`@shuji-bonji/houki-egov-mcp`** | **e-Gov 法令API クライアント + ローカル全文検索(このリポジトリ)** | ✅ v0.5.1 |
| [`@shuji-bonji/houki-nta-mcp`](https://github.com/shuji-bonji/houki-nta-mcp) | 国税庁通達・Q&A・タックスアンサー・文書回答事例 | ✅ v0.9.5 |
| [`houki-research-skill`](https://github.com/shuji-bonji/houki-research-skill) | family を横断する Claude Skill(error contract の正典) | ✅ |
| `@shuji-bonji/houki-mhlw-mcp` | 厚労省通達・通知 | 計画中 |
| `@shuji-bonji/houki-court-mcp` | 判例(裁判所サイト) | 構想中 |
| `@shuji-bonji/houki-saiketsu-mcp` | 国税不服審判所裁決 | 構想中 |
family 全体の設計思想・想定利用シーン・業法との関係は [`docs/DESIGN.md`](docs/DESIGN.md) を参照。
## エラー応答 (houki-hub family contract)
**v0.3.0** より、本 MCP のエラー応答は **houki-hub family 共通契約**に完全準拠します。`code` 文字列は family 全体で統一された語彙を使用するため、複数の MCP を併用しても LLM・Skill 層は一貫したロジックで解釈できます。
- [`docs/ERROR-CODES.md`](https://github.com/shuji-bonji/houki-research-skill/blob/main/docs/ERROR-CODES.md) — 共通エラーコード語彙の正典 (houki-research-skill)
- [`docs/ERROR-HANDLING.md`](https://github.com/shuji-bonji/houki-research-skill/blob/main/docs/ERROR-HANDLING.md) — 解釈ポリシー / next_actions テンプレ
houki-egov-mcp の [`src/errors.ts`](src/errors.ts) は family 全体の **リファレンス実装**として位置付けられています。他 MCP は同じ `code` 語彙を共有しつつ、共通パッケージへの依存は持たずに独立実装します。
```json
{
"error": "法令『消費税法』第3000条は存在しません",
"code": "ARTICLE_NOT_FOUND",
"hint": "条番号を get_toc で確認してください",
"next_actions": [
{ "action": "get_toc", "reason": "目次で正しい条番号を特定", "example": { "law_name": "消費税法" } }
],
"retryable": false
}
```
### 本 MCP で使用するコード
| code | 用途 | retryable |
|---|---|---|
| `INVALID_ARGUMENT` | 引数が `tools/list` の `inputSchema` に合わない(型・必須・enum・範囲・形式・inputSchema に無い引数。`detail.issues[]` に違反 1 件ごとの引数名と日本語の文、`tool` に呼んだツール名)、必須の文字列が空白だけ、`at` が暦に無い日付、`get_law` で項が複数ある条に `paragraph` なしで `item` を指定した、`get_law_range` で範囲の指定が無い・2 通り同時・複数の章に当たった、e-Gov が時点 `at` を受け付けないと答えた(2017-04-01 より前。`detail.issues[0].path: "at"`、`hint` に e-Gov の文。v0.18.0) 等 | `false` |
| `INVALID_ARTICLE_NUM` | 条番号・号番号のフォーマットが不正 (例: "30-2"、位ごとに並べた "三〇") | `false` |
| `OUT_OF_SCOPE` | 通達名で `get_law` を呼んだ、`search_fulltext` に通達の略称だけを渡した(v0.18.0)等、別 MCP の管轄リソースが要求された | `false` |
| `LAW_NOT_FOUND` | 略称辞書に無く、e-Gov の法令名の検索で題名の完全一致が無かった(0 件、または部分一致だけ。部分一致のときは候補を `hint` と `next_actions` に入れる。v0.18.0)。law_id を決めた後に e-Gov が「その法令が無い」と答えたときも(404・`404004` / 改正履歴は `404001`。v0.18.0)。検索が通信の失敗で終わったときは `SOURCE_*`(v0.16.0) | `false` |
| `ARTICLE_NOT_FOUND` | 指定された条/項/号が見つからない(`get_law_range` の `from_article` がその範囲に無い場合を含む)。本則に無く附則にだけある条番号も含み、そのときは附則の番号を案内する(v0.18.0) | `false` |
| `RANGE_NOT_FOUND` | `get_law_range` で指定された編・章・節(または附則の番号)が見つからない | `false` |
| `ATTACHMENT_NOT_FOUND` | `get_attachment` で指定された `src` がその法令履歴の添付に無い、添付が 1 件も無い、または e-Gov の `/attachment` が「存在しない」(code 404003)を返した | `false` |
| `SOURCE_API_ERROR` | e-Gov API がエラー応答(5xx は再試行できる、429 以外の 4xx は再試行できない。`LAW_NOT_FOUND`・`INVALID_ARGUMENT` にする 404・400 を除く)。法令名の検索の失敗も含む | 状況による |
| `SOURCE_TIMEOUT` | e-Gov API がタイムアウト | `true` |
| `SOURCE_RATE_LIMITED` | e-Gov API がレート制限 (HTTP 429) | `true` |
| `SOURCE_UNAVAILABLE` | e-Gov に接続できない(`ENOTFOUND` / `EAI_AGAIN` / `ECONNREFUSED` / `ECONNRESET` / `ETIMEDOUT`。`detail.cause` にその code。v0.16.0 から `fetch failed` の `cause.code` も見る) | `true` |
| `FILE_TOO_LARGE` | `get_attachment` / `get_law_file` の `save: true` で、ファイルが上限(50 MB)を超えている(`detail.bytes` に大きさ。v0.16.0。pdf-reader-mcp と同じ code) | `false` |
| `INTERNAL_ERROR` | 内部エラー (バグ・予期せぬ例外)。`search_fulltext` でローカル DB の同期の記録の日付を読めないときも(v0.16.0。全件の取り込みを案内) | `false` |
| `UNKNOWN_TOOL` | 存在しない tool 名が呼ばれた | `false` |
### `verify_citations` の code は件ごとに付きます(v0.11.0)
`verify_citations` は、存在しない引用が混ざっていてもツール全体を `isError` にしません。上の表の `code` は `results[]` の 1 件ごとに付き、`LAW_NOT_FOUND` / `ARTICLE_NOT_FOUND` / `INVALID_ARTICLE_NUM` / `OUT_OF_SCOPE` / `INVALID_ARGUMENT` のいずれかです。法令名が完全一致せず候補が複数あった件は `status: "ambiguous"` と `candidates[]` だけを返し、`code` は付きません。
ツール全体がエラーになるのは、引数の形が壊れているとき(`INVALID_ARGUMENT`)と、e-Gov が時点 `at` を受け付けないとき(`INVALID_ARGUMENT`。`at` は全件に共通のため。v0.18.0)と、e-Gov に問い合わせられなかったとき(`SOURCE_*`)と、e-Gov との通信と関係の無い処理中の例外(`INTERNAL_ERROR`。v0.16.0)だけです。e-Gov に問い合わせられなかったときに件ごとの判定を返さないのは、「聞けなかった」を「存在しない」と書かないためです。
### Migration (v0.2.x → v0.3.0)
- v0.2.x までは `EGOV_API_ERROR` / `EGOV_TIMEOUT` / `EGOV_RATE_LIMITED` を返していました。v0.3.0 からは family 共通の `SOURCE_API_ERROR` / `SOURCE_TIMEOUT` / `SOURCE_RATE_LIMITED` に切替。
- `EGOV_*` は v0.15.x まで `LawErrorCode` の型に残していましたが、v0.16.0 で型からも外しました(返さない `ABBREVIATION_NOT_FOUND` も同じ)。
- 構造化エラーの形 (`{ error, code, tool?, hint?, next_actions?, retryable?, detail? }`) は不変(`tool` は v0.16.0 で引数の検査の `INVALID_ARGUMENT` に足した)。クライアント側で `code` 文字列の比較をしている場合は `SOURCE_*` を受け付けるよう更新してください。
- `OUT_OF_SCOPE` を新たに受け取る可能性があります。例えば「消基通」(消費税法基本通達 / 国税庁の通達) を `get_law` の `law_name` に渡すと、`next_actions[0].example.mcp = "houki-nta"` を含む `OUT_OF_SCOPE` が返されるので、Skill 層は houki-nta-mcp に切り替えてください。
## ドキュメント
- [`docs/LAW-HIERARCHY.md`](docs/LAW-HIERARCHY.md) — 法令種別の階層リファレンス(専門家でない利用者向け)
- [`docs/USE-CASES.md`](docs/USE-CASES.md) — プロダクト開発の典型ユースケース(電帳法・電子契約・個情法・e-KYC)
- [`docs/DESIGN.md`](docs/DESIGN.md) — 設計原則・houki-hub family のロードマップ・業法との関係
- [`docs/NOTES.md`](docs/NOTES.md) — README の注意書きの詳細(施行日の当日に配り直される版と 0.19.1 の DB の直し方)
- [`DISCLAIMER.md`](DISCLAIMER.md) — 利用上の注意(業法との関係)
- [`CONTRIBUTING.md`](CONTRIBUTING.md) — 貢献方法
- [`CHANGELOG.md`](CHANGELOG.md) — リリースノート
## 業法との関係
本MCPは **一次情報の取得・提示のみ** を担います。分析は LLM、判断は利用者(または有資格者)の責任です。**業としての法律事務・税務業務への利用は想定外**です — 詳細は [DISCLAIMER.md](DISCLAIMER.md) 参照。
## デジタル庁公式 MCP との関係
デジタル庁は 2025年12月〜2026年3月の「法令×デジタル」ハッカソンで法令API / MCP のプロトタイプを試行提供した。将来一般公開された場合は、本 MCP のコアを公式 MCP に委譲し、houki-hub family 全体は **公式が手を出さないレイヤ(通達・裁決・判例の横断インデックス、業法対応 Skill 等)** に注力する方針。
## ライセンス
MIT — 個人利用・学習用途のフォーク・改変・再配布を自由に許可します。
ただし、**業としての使用(弁護士法72条・税理士法52条・社労士法27条が定める独占業務)** については想定外であり、作者は一切の責任を負いません。[DISCLAIMER.md](DISCLAIMER.md) を必ずご確認ください。
TDQS
Scored across 7 tools
Each tool serves a clear, non-overlapping purpose: searching by keyword, retrieving specific text, getting TOC, full-text search, abbreviation resolution, revision history, and educational explanation. No ambiguity.
All tools use the consistent verb_noun pattern in snake_case (e.g., search_law, get_law, get_toc, search_fulltext, resolve_abbreviation, get_law_revisions, explain_law_type). Perfectly uniform.
Seven tools is well-scoped for a specialized legal information server. Each tool earns its place covering search, retrieval, navigation, history, and education without redundancy.
The tool set covers all core activities: finding laws (search_law, search_fulltext), retrieving content (get_law, get_toc), resolving abbreviations, checking revisions, and understanding law types. No obvious gaps.