building-standards-act-mcp 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +97 -74
  2. package/dist/data/kokuji-term-aliases.d.ts +2 -0
  3. package/dist/data/kokuji-term-aliases.js +21 -0
  4. package/dist/data/kokuji-term-aliases.js.map +1 -0
  5. package/dist/lib/article-analyzer.js +3 -4
  6. package/dist/lib/article-analyzer.js.map +1 -1
  7. package/dist/lib/article-fetcher.d.ts +12 -0
  8. package/dist/lib/article-fetcher.js +65 -0
  9. package/dist/lib/article-fetcher.js.map +1 -0
  10. package/dist/lib/article-ref.d.ts +14 -0
  11. package/dist/lib/article-ref.js +52 -0
  12. package/dist/lib/article-ref.js.map +1 -0
  13. package/dist/lib/article-schemas.d.ts +51 -0
  14. package/dist/lib/article-schemas.js +47 -0
  15. package/dist/lib/article-schemas.js.map +1 -0
  16. package/dist/lib/citation-verifier.js +5 -6
  17. package/dist/lib/citation-verifier.js.map +1 -1
  18. package/dist/lib/egov-client.d.ts +13 -1
  19. package/dist/lib/egov-client.js +59 -1
  20. package/dist/lib/egov-client.js.map +1 -1
  21. package/dist/lib/egov-parser.d.ts +38 -0
  22. package/dist/lib/egov-parser.js +14 -3
  23. package/dist/lib/egov-parser.js.map +1 -1
  24. package/dist/lib/errors.d.ts +3 -2
  25. package/dist/lib/errors.js +5 -3
  26. package/dist/lib/errors.js.map +1 -1
  27. package/dist/lib/kokuji-amendment.d.ts +2 -0
  28. package/dist/lib/kokuji-amendment.js +26 -0
  29. package/dist/lib/kokuji-amendment.js.map +1 -0
  30. package/dist/lib/kokuji-registry.d.ts +2 -3
  31. package/dist/lib/kokuji-registry.js +9 -91
  32. package/dist/lib/kokuji-registry.js.map +1 -1
  33. package/dist/lib/mlit-client.d.ts +10 -7
  34. package/dist/lib/mlit-client.js +136 -16
  35. package/dist/lib/mlit-client.js.map +1 -1
  36. package/dist/lib/openapi-spec.js +2 -1
  37. package/dist/lib/openapi-spec.js.map +1 -1
  38. package/dist/lib/pdf-extractor.d.ts +7 -1
  39. package/dist/lib/pdf-extractor.js +20 -9
  40. package/dist/lib/pdf-extractor.js.map +1 -1
  41. package/dist/lib/related-law-finder.js +3 -4
  42. package/dist/lib/related-law-finder.js.map +1 -1
  43. package/dist/lib/resilience.js +3 -1
  44. package/dist/lib/resilience.js.map +1 -1
  45. package/dist/lib/revision-tracker.d.ts +5 -5
  46. package/dist/lib/revision-tracker.js +16 -8
  47. package/dist/lib/revision-tracker.js.map +1 -1
  48. package/dist/lib/tool-helpers.d.ts +15 -0
  49. package/dist/lib/tool-helpers.js +37 -0
  50. package/dist/lib/tool-helpers.js.map +1 -1
  51. package/dist/lib/tool-invoker.d.ts +4 -0
  52. package/dist/lib/tool-invoker.js +2 -1
  53. package/dist/lib/tool-invoker.js.map +1 -1
  54. package/dist/lib/types.d.ts +17 -0
  55. package/dist/lib/version.d.ts +2 -0
  56. package/dist/lib/version.js +3 -0
  57. package/dist/lib/version.js.map +1 -0
  58. package/dist/server.js +8 -5
  59. package/dist/server.js.map +1 -1
  60. package/dist/tools/analyze-article.js +37 -2
  61. package/dist/tools/analyze-article.js.map +1 -1
  62. package/dist/tools/check-law-updates.js +31 -9
  63. package/dist/tools/check-law-updates.js.map +1 -1
  64. package/dist/tools/get-full-law.js +23 -3
  65. package/dist/tools/get-full-law.js.map +1 -1
  66. package/dist/tools/get-kokuji.js +107 -28
  67. package/dist/tools/get-kokuji.js.map +1 -1
  68. package/dist/tools/get-law.js +52 -8
  69. package/dist/tools/get-law.js.map +1 -1
  70. package/dist/tools/get-laws-batch.js +44 -41
  71. package/dist/tools/get-laws-batch.js.map +1 -1
  72. package/dist/tools/get-metrics.js +28 -2
  73. package/dist/tools/get-metrics.js.map +1 -1
  74. package/dist/tools/search-articles.d.ts +2 -0
  75. package/dist/tools/search-articles.js +86 -0
  76. package/dist/tools/search-articles.js.map +1 -0
  77. package/dist/tools/search-law.js +7 -2
  78. package/dist/tools/search-law.js.map +1 -1
  79. package/dist/tools/suggest-related.js +7 -2
  80. package/dist/tools/suggest-related.js.map +1 -1
  81. package/dist/tools/verify-citation.js +41 -3
  82. package/dist/tools/verify-citation.js.map +1 -1
  83. package/package.json +14 -6
package/README.md CHANGED
@@ -11,12 +11,13 @@ AI の建築法規回答に含まれるハルシネーションを、条文原
11
11
 
12
12
  ## 特徴
13
13
 
14
- - **法令取得** — e-Gov 法令 API v2 から条文を Markdown 形式で取得
15
- - **法令検索** — キーワードで法令を横断検索
14
+ - **法令取得** — e-Gov 法令 API v2 から条文を条単位(`elm` 指定)で取得。1 条あたり数 KB で済み、全文 1 MB 超を読まない
15
+ - **法令検索** — 法令名で建築関連法令を横断検索
16
+ - **条文本文検索** — e-Gov のキーワード検索 API で条文本文を全文検索(`search_articles`)
16
17
  - **法令全文取得** — 法令全体のテキストを取得
17
18
  - **告示取得** — 建築基準法が技術基準を委任している告示を国土交通省の告示データベース(PDF)から取得
18
19
  - **検索ファースト** — e-Gov API 検索による動的な法令解決。プリセットに限らず、e-Gov 収録の全法令を取得可能
19
- - **略称マップ** — 建築基準法・消防法・都市計画法ほか 112 法令の略称を登録済み。「建基法」「都計法」「消防法」等の略称で指定可能
20
+ - **略称マップ** — 建築基準法・消防法・都市計画法ほか 116 法令の略称を登録済み。「建基法」「都計法」「消防法」等の略称で指定可能
20
21
  - **キャッシュ** — 検索 30 分・法令データ 24 時間の TTL キャッシュ(永続化オプションあり)
21
22
  - **API 耐障害性** — 自動リトライ(exponential backoff)+ サーキットブレーカー
22
23
  - **運用可視化** — 構造化 JSON ログ + 使用量メトリクス(`get_metrics` ツール)
@@ -25,27 +26,29 @@ AI の建築法規回答に含まれるハルシネーションを、条文原
25
26
 
26
27
  Vercel にデプロイすると、Claude.ai からすぐに使えます。環境変数の設定は不要です(e-Gov API は公開 API)。
27
28
 
29
+ 公開インスタンス: `https://building-standards-act-mcp.vercel.app/api/mcp`(自分でデプロイしなくても、この URL をそのまま Custom Connector に登録できます)
30
+
28
31
  [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FSora-bluesky%2Fbuilding-standards-act-mcp)
29
32
 
30
33
  ### Claude.ai でのセットアップ(Free/Pro/Max/Team/Enterprise)
31
34
 
32
- > **注意**: Custom Connectors はベータ版のため、接続が不安定な場合があります。安定してご利用いただくには [npx(ローカル)でのセットアップ](#npx推奨)もご検討ください。
35
+ > Custom Connectors は Free / Pro / Max / Team / Enterprise の各プランで利用できます(Free プランは 1 件まで)。ローカルで動かしたい場合は [npx(ローカル)でのセットアップ](#npx推奨) を参照してください。
33
36
 
34
- 1. 上の「Deploy with Vercel」ボタンでデプロイ(ワンクリック)
35
- 2. [claude.ai](https://claude.ai) → プロフィールアイコン → Settings → Connectors
36
- 3. 「Add custom connector」をクリック
37
- 4. URL に `https://your-app.vercel.app/api/mcp`(your-app をデプロイ先に置換)を入力
37
+ 1. 公開インスタンスを使う場合はこの手順を飛ばす。自分でホストする場合は上の「Deploy with Vercel」ボタンでデプロイ(ワンクリック)
38
+ 2. [claude.ai](https://claude.ai) → Customize → Connectors
39
+ 3. 「+ Add」→「Add custom connector」をクリック
40
+ 4. URL に `https://building-standards-act-mcp.vercel.app/api/mcp`(自分でデプロイした場合はその URL)を入力し、認証は「No sign in」を選択
38
41
  5. チャットで「+」→「Connectors」→ building-standards-act を有効化
39
42
  6. 「建築基準法第20条を教えて」と質問
40
43
 
41
44
  > 参考: [Get started with custom connectors using remote MCP](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp)
42
45
 
43
- ### Vercel Free tier の制限事項
46
+ ### Vercel での実行時間
44
47
 
45
- - 関数の実行時間が **10 秒** に制限されます(Pro プランでは 60 秒)
46
- - `get_kokuji`(告示取得)は PDF ダウンロード + パースが重いため、タイムアウトする場合があります
47
- - `check_law_updates` の大規模グループ(9章: 53法令)は Free tier ではタイムアウトする場合があります(Pro プランでは並行実行により対応可能)
48
- - `BUILDING_LAW_REQUEST_TIMEOUT=8000` を設定してタイムアウトを短縮できます
48
+ - Vercel Functions の実行時間は Hobby プランでも既定 300 秒です(Fluid compute)。本リポの `vercel.json` は `maxDuration` を 60 秒に設定しています
49
+ - `get_kokuji`(告示取得)は PDF ダウンロード + パースが重いため、60 秒を超える場合は `vercel.json` の `maxDuration` を引き上げてください
50
+ - `check_law_updates` の大規模グループ(9章: 53法令)は最大 5 並行で実行します(`BUILDING_LAW_CONCURRENCY` で調整可能)
51
+ - `BUILDING_LAW_REQUEST_TIMEOUT=8000` を設定して e-Gov API 呼び出しのタイムアウトを短縮できます
49
52
 
50
53
  ---
51
54
 
@@ -56,9 +59,11 @@ Vercel にデプロイすると、Claude.ai からすぐに使えます。環境
56
59
  インストール不要で実行できます。
57
60
 
58
61
  ```bash
59
- npx -y building-standards-act-mcp
62
+ npx -y building-standards-act-mcp@latest
60
63
  ```
61
64
 
65
+ `@latest` を付けると、npx のキャッシュに古い版が残っていても最新版で起動します。
66
+
62
67
  ### Claude Desktop
63
68
 
64
69
  `claude_desktop_config.json` に以下を追加してください。
@@ -68,7 +73,7 @@ npx -y building-standards-act-mcp
68
73
  "mcpServers": {
69
74
  "building-standards-act": {
70
75
  "command": "npx",
71
- "args": ["-y", "building-standards-act-mcp"]
76
+ "args": ["-y", "building-standards-act-mcp@latest"]
72
77
  }
73
78
  }
74
79
  }
@@ -77,43 +82,37 @@ npx -y building-standards-act-mcp
77
82
  ### Claude Code
78
83
 
79
84
  ```bash
80
- claude mcp add building-standards-act -- npx -y building-standards-act-mcp
85
+ claude mcp add building-standards-act -- npx -y building-standards-act-mcp@latest
81
86
  ```
82
87
 
83
88
  #### Windows + VS Code 拡張機能の場合
84
89
 
85
- VS Code 拡張機能では `npx` 経由の起動が `Connection closed` エラーになる場合があります。
86
- プロジェクトルートに `.mcp.json` を作成してください。
87
-
88
- **Step 1: グローバルインストール**
89
-
90
- ```bash
91
- npm install -g building-standards-act-mcp
92
- ```
93
-
94
- **Step 2: パスの確認**
90
+ VS Code 拡張機能では `npx` 経由の起動が `Connection closed` エラーになる場合があります。その場合は、公開中の Vercel 版に HTTP で接続するのが確実です。
95
91
 
96
92
  ```bash
97
- where node # → node.exe のフルパス(例: C:\Program Files\nodejs\node.exe)
98
- npm root -g # → グローバル node_modules のパス
93
+ claude mcp add --transport http building-standards-act https://building-standards-act-mcp.vercel.app/api/mcp
99
94
  ```
100
95
 
101
- **Step 3: `.mcp.json` を作成**
102
-
103
- 取得したパスで置き換えてください(パス区切りは `/` を使用):
96
+ プロジェクト単位で設定するなら、プロジェクトルートの `.mcp.json` に次を書きます。
104
97
 
105
98
  ```json
106
99
  {
107
100
  "mcpServers": {
108
101
  "building-standards-act": {
109
- "command": "<where node の出力>",
110
- "args": ["<npm root -g の出力>/building-standards-act-mcp/dist/index.js"]
102
+ "type": "http",
103
+ "url": "https://building-standards-act-mcp.vercel.app/api/mcp"
111
104
  }
112
105
  }
113
106
  }
114
107
  ```
115
108
 
116
- > **注意**: `.mcp.json` にはマシン固有のパスが含まれるため、`.gitignore` に追加してください。
109
+ ローカルの stdio で動かしたい場合は、`npx` を `cmd /c` で包みます。
110
+
111
+ ```bash
112
+ claude mcp add building-standards-act -- cmd /c npx -y building-standards-act-mcp@latest
113
+ ```
114
+
115
+ > **注意**: グローバルインストールした `dist/index.js` のパスを `.mcp.json` に直接書く方法は使わないでください。パッケージの更新・削除やフォルダの移動で、エラーを出さずに接続できなくなります。
117
116
 
118
117
  ### ローカル(ソースから)
119
118
 
@@ -137,18 +136,19 @@ npm run build
137
136
 
138
137
  ## MCP ツール
139
138
 
140
- | ツール | 説明 |
141
- | ------------------- | --------------------------------------------------------------------------------------------- |
142
- | `get_law` | 条番号を指定して法令の条文を取得する。略称・正式名称のいずれでも指定可能 |
143
- | `get_full_law` | 法令の全文を取得する。条番号を指定せず法令全体のテキストを返す |
144
- | `search_law` | キーワードで建築関連法令を横断検索する。略称マップと e-Gov API の両方を検索 |
145
- | `get_kokuji` | 建築基準法が技術基準を委任している告示の全文を取得する(省エネ告示は国交省 PDF から直接取得) |
146
- | `check_law_updates` | 法令の改正状況を e-Gov API で確認する(単体/バッチ/改正履歴表示に対応) |
147
- | `get_laws_batch` | 複数の法令・条文を一括取得する(最大20件、同一法令は1回のAPI呼び出しで効率処理) |
148
- | `verify_citation` | AIの回答に含まれる法令引用を検証する(条文存在確認・テキスト照合、最大10件) |
149
- | `suggest_related` | 指定した条文の関連法令・委任先・同法令内参照を自動抽出して提案する |
150
- | `analyze_article` | 条文の構造解析メタデータ(項数・号数・参照統計・プレビュー)をJSON形式で返す |
151
- | `get_metrics` | サーバーの使用量メトリクスを返す(ツール呼び出し回数・APIリクエスト数・キャッシュヒット率) |
139
+ | ツール | 説明 |
140
+ | ------------------- | --------------------------------------------------------------------------------------------------------------- |
141
+ | `get_law` | 条番号を指定して法令の条文を取得する。略称・正式名称のいずれでも指定可能 |
142
+ | `get_full_law` | 法令の全文を取得する。`max_chars`(既定 100,000)で区切り、続きは `offset` で取る |
143
+ | `search_law` | 法令名(タイトル)で建築関連法令を検索する。略称マップと e-Gov API の両方を検索。条文本文の検索は `search_articles` |
144
+ | `search_articles` | 条文本文をキーワードで全文検索する(e-Gov `/keyword`)。法令名で絞り込み可。条番号は返らないので `get_law` で確定する |
145
+ | `get_kokuji` | 建築基準法が技術基準を委任している告示の全文を取得する(省エネ告示は国交省 PDF から直接取得) |
146
+ | `check_law_updates` | 法令の改正状況を e-Gov API で確認する。`since`(既定は 12 か月前)より後の改正だけを「改正あり」にする |
147
+ | `get_laws_batch` | 複数の法令・条文を一括取得する(最大20件、1 条ごとに条単位で取得) |
148
+ | `verify_citation` | AIの回答に含まれる法令引用を検証する(条文存在確認・テキスト照合、最大10件) |
149
+ | `suggest_related` | 指定した条文の関連法令・委任先・同法令内参照を自動抽出して提案する |
150
+ | `analyze_article` | 条文の構造解析メタデータ(項数・号数・参照統計・プレビュー)をJSON形式で返す |
151
+ | `get_metrics` | サーバーの使用量メトリクスを返す(ツール呼び出し回数・APIリクエスト数・キャッシュヒット率) |
152
152
 
153
153
  ### パラメータ
154
154
 
@@ -162,21 +162,34 @@ npm run build
162
162
 
163
163
  #### `get_full_law`
164
164
 
165
- | パラメータ | 説明 | 例 |
166
- | ---------- | ---------------------------- | ---------------------------- |
167
- | `law_name` | 法令名(正式名称または略称) | `建築基準法施行令`, `建基令` |
165
+ | パラメータ | 説明 | 例 |
166
+ | ----------- | --------------------------------------------- | ---------------------------- |
167
+ | `law_name` | 法令名(正式名称または略称) | `建築基準法施行令`, `建基令` |
168
+ | `max_chars` | 1 回に返す最大文字数(既定 100,000) | `50000` |
169
+ | `offset` | 続きを取るときの開始位置(末尾の案内に出る値) | `100000` |
168
170
 
169
171
  #### `search_law`
170
172
 
171
- | パラメータ | 説明 | 例 |
172
- | ---------- | -------------- | ---------------------- |
173
- | `keyword` | 検索キーワード | `耐火構造`, `用途変更` |
173
+ | パラメータ | 説明 | 例 |
174
+ | ---------- | ---------------------- | ---------------------- |
175
+ | `keyword` | 法令名に含まれる語 | `建築`, `都市計画` |
176
+
177
+ #### `search_articles`
178
+
179
+ | パラメータ | 説明 | 例 |
180
+ | ----------- | ------------------------------------------------------------ | ---------------------- |
181
+ | `keyword` | 条文本文に含まれる語。AND / OR / NOT と `*` `?` が使える | `耐火構造`, `壁量` |
182
+ | `law_title` | 法令名または略称で絞り込み(省略時は e-Gov の全法令) | `建築基準法` |
183
+ | `limit` | 返す該当文の数(既定 10、最大 50) | `20` |
184
+ | `offset` | 続きを取るときの開始位置(応答の `next_offset` を渡す) | `10` |
174
185
 
175
186
  #### `get_kokuji`
176
187
 
177
- | パラメータ | 説明 | 例 |
178
- | ------------- | ------ | ------------------------------ |
179
- | `kokuji_name` | 告示名 | `耐火構造の構造方法を定める件` |
188
+ | パラメータ | 説明 | 例 |
189
+ | ------------- | ------------------------------------- | ------------------------------ |
190
+ | `kokuji_name` | 告示名 | `耐火構造の構造方法を定める件` |
191
+ | `max_chars` | 1 回に返す最大文字数(既定 100,000) | `50000` |
192
+ | `offset` | 続きを取るときの開始位置 | `100000` |
180
193
 
181
194
  #### `check_law_updates`
182
195
 
@@ -185,6 +198,7 @@ npm run build
185
198
  | `law_name` | 法令名または略称(単体チェック) | `建築基準法` |
186
199
  | `group` | 章グループ(バッチチェック、省略時は全章) | `1章` |
187
200
  | `show_history` | 改正履歴の詳細を表示(`law_name` 指定時) | `true` |
201
+ | `since` | 基準日。これより後の改正だけを報告(省略時は 12 か月前) | `2026-01-01` |
188
202
 
189
203
  #### `get_laws_batch`
190
204
 
@@ -235,8 +249,16 @@ npm run build
235
249
  ### 法令検索
236
250
 
237
251
  ```
238
- 耐火構造に関する法令を検索して
239
- → search_law(keyword="耐火構造")
252
+ 都市計画に関する法令を検索して
253
+ → search_law(keyword="都市計画")
254
+ ```
255
+
256
+ ### 条文本文検索
257
+
258
+ ```
259
+ 建築基準法で「耐火構造」が出てくる条文を探して
260
+ → search_articles(keyword="耐火構造", law_title="建築基準法")
261
+ → 該当文と区分(本則 / 附則)が返るので、条番号は get_law で確定する
240
262
  ```
241
263
 
242
264
  ### 全文取得
@@ -261,6 +283,9 @@ npm run build
261
283
 
262
284
  建築基準法施行令の附則第1条を取得して
263
285
  → get_law(law_name="建築基準法施行令", article_number="附則第1条")
286
+
287
+ 未施行の改正附則(現行データに無いときは改正履歴から未施行版を取る)
288
+ → get_law(law_name="建築基準法施行令", article_number="附則(令和8年政令第284号)")
264
289
  ```
265
290
 
266
291
  ### 別表取得
@@ -315,9 +340,9 @@ AI が建築法規について回答する際、条文の引用ミスや存在
315
340
  → 「第20条第1項第三号の記載に誤りがあります。正しくは…」
316
341
  ```
317
342
 
318
- ## 対応法令一覧(112 法令 + e-Gov 全法令)
343
+ ## 対応法令一覧(116 法令 + e-Gov 全法令)
319
344
 
320
- > 以下の 112 法令は略称マップに登録済みです。略称マップに含まれない法令も、正式名称を指定すれば e-Gov API 検索で動的に取得できます。
345
+ > 以下の 116 法令は略称マップに登録済みです。略称マップに含まれない法令も、正式名称を指定すれば e-Gov API 検索で動的に取得できます。
321
346
 
322
347
  ### 総則(4 法令)
323
348
 
@@ -495,21 +520,19 @@ AI が建築法規について回答する際、条文の引用ミスや存在
495
520
  | 被災市街地復興特別措置法 | 被災市街地復興法 |
496
521
  | 被災区分所有建物の再建等に関する特別措置法 | 被災マンション法 |
497
522
 
498
- ## 対応告示(9 件)
523
+ ## 告示の取得
499
524
 
500
- e-Gov API は告示を収録していないため、`get_kokuji` は国土交通省の告示・通達データベース(Excel → PDF)から取得します。省エネ関連の告示第265号・第266号は国交省 PDF から直接取得します。見つからない場合は e-Gov API のキーワード検索にフォールバックします。
525
+ e-Gov API は告示を収録していないため、`get_kokuji` は国土交通省の告示・通達データベース(Excel → PDF)から正式名称で動的に取得します。見つからない場合は e-Gov API のキーワード検索にフォールバックします。
501
526
 
502
- | 告示名 | 分野 |
503
- | -------------------------------------------------------------------------------------------- | ------------------------ |
504
- | 耐火構造の構造方法を定める件 | 防火・耐火 |
505
- | 準耐火構造の構造方法を定める件 | 防火・耐火 |
506
- | 防火構造の構造方法を定める件 | 防火・耐火 |
507
- | 不燃材料を定める件 | 防火・耐火 |
508
- | 採光に有効な部分の面積の算定方法を定める件 | 採光 |
509
- | 避難安全検証法に関する算出方法等を定める件 | 避難 |
510
- | 許容応力度計算等の方法を定める件 | 構造 |
511
- | 建築物エネルギー消費性能基準等を定める省令における算出方法等に係る事項 | 省エネ(UA値) |
512
- | 住宅部分の外壁、窓等を通しての熱の損失の防止に関する基準及び一次エネルギー消費量に関する基準 | 省エネ(断熱等性能等級) |
527
+ ハードコードされたプリセットは持たず、常に最新の告示データベースから取得するため、改正後も陳腐化しません。
528
+
529
+ ```
530
+ 耐火構造の構造方法を定める件を取得して
531
+ → get_kokuji(kokuji_name="耐火構造の構造方法を定める件")
532
+
533
+ 木造建築物の軸組の設置の基準を定める件を取得して
534
+ → get_kokuji(kokuji_name="木造建築物の軸組の設置の基準を定める件")
535
+ ```
513
536
 
514
537
  ## 法令解決の仕組み
515
538
 
@@ -539,7 +562,7 @@ e-Gov API は告示を収録していないため、`get_kokuji` は国土交通
539
562
  "mcpServers": {
540
563
  "building-standards-act": {
541
564
  "command": "npx",
542
- "args": ["-y", "building-standards-act-mcp"],
565
+ "args": ["-y", "building-standards-act-mcp@latest"],
543
566
  "env": {
544
567
  "BUILDING_LAW_CACHE": "file"
545
568
  }
@@ -563,7 +586,7 @@ e-Gov API は告示を収録していないため、`get_kokuji` は国土交通
563
586
  | API 並行呼び出し | 最大 5 並行(200ms 間隔) |
564
587
  | Vercel デプロイ | 対応(MCP-over-HTTP + REST API) |
565
588
  | Vercel 関数タイムアウト | 60 秒(maxDuration) |
566
- | Node.js | >= 20.0.0 |
589
+ | Node.js | >= 22.12.0 |
567
590
 
568
591
  ## セキュリティ
569
592
 
@@ -0,0 +1,2 @@
1
+ /** Append distinct provision aliases while preserving the user's original text. */
2
+ export declare function expandKokujiAliases(text: string): string;
@@ -0,0 +1,21 @@
1
+ /** Terms absent from the legacy MLIT titles; keep aliases tied to provisions. */
2
+ const KOKUJI_TERM_ALIASES = {
3
+ // Reiwa 6 MLIT Notice 447 moved wall-quantity rules to Showa 56 Notice 1100, titled with Order Article 46(4).
4
+ 壁量: "令46条4項",
5
+ // Required wall quantity is governed by the same Order Article 46(4) rule in Showa 56 Notice 1100.
6
+ 必要壁量: "令46条4項",
7
+ // Wall-quantity calculations use Order Article 46(4), named in the legacy title of Showa 56 Notice 1100.
8
+ 壁量計算: "令46条4項",
9
+ // Wall-quantity standards moved under Showa 56 Notice 1100 through Reiwa 6 MLIT Notice 447.
10
+ 壁量基準: "令46条4項",
11
+ // Existing wall quantity is assessed against the Order Article 46(4) wall-quantity rule.
12
+ 存在壁量: "令46条4項",
13
+ };
14
+ /** Append distinct provision aliases while preserving the user's original text. */
15
+ export function expandKokujiAliases(text) {
16
+ const targets = new Set(Object.entries(KOKUJI_TERM_ALIASES)
17
+ .filter(([term]) => text.includes(term))
18
+ .map(([, target]) => target));
19
+ return [text, ...targets].join(" ");
20
+ }
21
+ //# sourceMappingURL=kokuji-term-aliases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kokuji-term-aliases.js","sourceRoot":"","sources":["../../src/data/kokuji-term-aliases.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,mBAAmB,GAAqC;IAC5D,8GAA8G;IAC9G,EAAE,EAAE,QAAQ;IACZ,mGAAmG;IACnG,IAAI,EAAE,QAAQ;IACd,yGAAyG;IACzG,IAAI,EAAE,QAAQ;IACd,4FAA4F;IAC5F,IAAI,EAAE,QAAQ;IACd,yFAAyF;IACzF,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SACvC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAC/B,CAAC;IACF,OAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC"}
@@ -1,5 +1,4 @@
1
- import { getLawData } from "./egov-client.js";
2
- import { parseArticleStructured } from "./egov-parser.js";
1
+ import { fetchParsedArticle } from "./article-fetcher.js";
3
2
  import { formatArticleRef } from "./errors.js";
4
3
  import { resolveLawId } from "./law-resolver.js";
5
4
  const PREVIEW_LENGTH = 100;
@@ -60,8 +59,8 @@ export async function analyzeArticle(lawName, articleNumber) {
60
59
  if (!resolved) {
61
60
  throw new Error(`法令「${lawName}」が見つかりませんでした。`);
62
61
  }
63
- const lawData = await getLawData(resolved.law_id);
64
- const article = parseArticleStructured(lawData.law_full_text, articleNumber);
62
+ const fetched = await fetchParsedArticle(resolved.law_id, articleNumber, "structured");
63
+ const article = fetched?.article;
65
64
  if (!article) {
66
65
  throw new Error(`${resolved.title}に${formatArticleRef(articleNumber)}が見つかりませんでした。`);
67
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"article-analyzer.js","sourceRoot":"","sources":["../../src/lib/article-analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"article-analyzer.js","sourceRoot":"","sources":["../../src/lib/article-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { EgovLawDataResponse, EgovRevisionInfo, ParsedArticle, StructuredArticle } from "./types.js";
2
+ export interface FetchedArticle<T> {
3
+ article: T;
4
+ revision?: Pick<EgovRevisionInfo, "law_revision_id" | "amendment_enforcement_date" | "current_revision_status">;
5
+ revisionNote?: string;
6
+ }
7
+ /** Choose the smallest API response that can satisfy the request. */
8
+ export declare function fetchArticleData(lawId: string, articleNumber: string): Promise<EgovLawDataResponse | null>;
9
+ /** Resolve amendment supplements against a matching revision only after a miss. */
10
+ export declare function fetchParsedArticle(lawId: string, articleNumber: string, format?: "text"): Promise<FetchedArticle<ParsedArticle> | null>;
11
+ export declare function fetchParsedArticle(lawId: string, articleNumber: string, format: "structured"): Promise<FetchedArticle<StructuredArticle> | null>;
12
+ export declare function fetchParsedArticle(lawId: string, articleNumber: string, format: "text" | "structured"): Promise<FetchedArticle<ParsedArticle | StructuredArticle> | null>;
@@ -0,0 +1,65 @@
1
+ import { getLawArticle, getLawData, getLawDataByRevision, getLawRevisions, } from "./egov-client.js";
2
+ import { detectSpecialSection, findAmendmentSupplProvision, getSupplProvisionArticleNumbers, matchAmendLawNum, parseArticle, parseArticleStructured, toArticleElm, } from "./egov-parser.js";
3
+ import { ArticleNotFoundError } from "./errors.js";
4
+ /** Choose the smallest API response that can satisfy the request. */
5
+ export async function fetchArticleData(lawId, articleNumber) {
6
+ const elm = toArticleElm(articleNumber);
7
+ return elm !== null ? await getLawArticle(lawId, elm) : await getLawData(lawId);
8
+ }
9
+ export async function fetchParsedArticle(lawId, articleNumber, format = "text") {
10
+ const data = await fetchArticleData(lawId, articleNumber);
11
+ if (!data)
12
+ return null;
13
+ const parse = format === "structured" ? parseArticleStructured : parseArticle;
14
+ const article = parse(data.law_full_text, articleNumber);
15
+ if (article)
16
+ return { article };
17
+ const special = detectSpecialSection(articleNumber);
18
+ if (special?.type !== "suppl_amendment" &&
19
+ special?.type !== "suppl_amendment_article") {
20
+ return null;
21
+ }
22
+ const revisions = await getLawRevisions(lawId);
23
+ const revision = revisions.revisions.find((entry) => entry.law_revision_id !== data.revision_info.law_revision_id &&
24
+ matchAmendLawNum(special.amendLawNum, entry.amendment_law_num));
25
+ let missingData = data;
26
+ if (revision) {
27
+ const revisionData = await getLawDataByRevision(revision.law_revision_id);
28
+ const revisedArticle = parse(revisionData.law_full_text, articleNumber);
29
+ if (revisedArticle) {
30
+ const metadata = {
31
+ law_revision_id: revision.law_revision_id,
32
+ amendment_enforcement_date: revision.amendment_enforcement_date,
33
+ current_revision_status: revision.current_revision_status,
34
+ };
35
+ const label = revision.current_revision_status === "UnEnforced"
36
+ ? "未施行の改正"
37
+ : "別の改正";
38
+ return {
39
+ article: revisedArticle,
40
+ revision: metadata,
41
+ revisionNote: `※ この附則は${label}(施行日 ${revision.amendment_enforcement_date})の法令データから取得しました。`,
42
+ };
43
+ }
44
+ if (findAmendmentSupplProvision(revisionData.law_full_text, special.amendLawNum)) {
45
+ missingData = revisionData;
46
+ }
47
+ }
48
+ if (special.type === "suppl_amendment_article") {
49
+ const suppl = findAmendmentSupplProvision(missingData.law_full_text, special.amendLawNum);
50
+ if (suppl) {
51
+ const numbers = getSupplProvisionArticleNumbers(suppl).map((num) => {
52
+ const [main, ...branches] = num.split("_");
53
+ return `第${main}条${branches.map((branch) => `の${branch}`).join("")}`;
54
+ });
55
+ const title = missingData.revision_info.law_title;
56
+ const qualifier = suppl.attr?.["Extract"] === "true" ? "は抄録で、" : "には";
57
+ const contents = numbers.length > 0
58
+ ? `${numbers.join("・")}のみ収録されています。`
59
+ : "条番号付きの条文は収録されていません。";
60
+ throw new ArticleNotFoundError(articleNumber, title, `${title}の附則(${special.amendLawNum})${qualifier}${contents}`);
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+ //# sourceMappingURL=article-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"article-fetcher.js","sourceRoot":"","sources":["../../src/lib/article-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** A reference and its source span; numeral strings retain kanji spelling. */
2
+ export interface ArticleRef {
3
+ law?: string;
4
+ article: string;
5
+ branches: string[];
6
+ paragraph?: string;
7
+ item?: string;
8
+ start: number;
9
+ end: number;
10
+ }
11
+ /** Parse bare references and explicit law names without assuming a law context. */
12
+ export declare function parseArticleRefs(text: string): ArticleRef[];
13
+ /** Render the kanji reference form used in notice titles, without the law name. */
14
+ export declare function formatArticleRef(ref: ArticleRef): string;
@@ -0,0 +1,52 @@
1
+ const NUMERAL = "[0-90-9〇零一二三四五六七八九十百千万億兆]+";
2
+ const LAW = "[\\u4E00-\\u9FFF]+(?:法(?:施行令|施行規則)?|施行令|規則)|施行令|規則|法|令";
3
+ /** Parse bare references and explicit law names without assuming a law context. */
4
+ export function parseArticleRefs(text) {
5
+ const pattern = new RegExp(`(?:(${LAW})\\s*)?第?(${NUMERAL})条((?:の第?${NUMERAL})*)(?:第?(${NUMERAL})項)?(?:第?(${NUMERAL})号)?`, "g");
6
+ return [...text.matchAll(pattern)].map((match) => {
7
+ const prefix = match[1];
8
+ const law = prefix === "法"
9
+ ? "建築基準法"
10
+ : prefix === "令" || prefix === "施行令"
11
+ ? "建築基準法施行令"
12
+ : prefix;
13
+ return {
14
+ law,
15
+ article: match[2],
16
+ branches: match[3] ? match[3].split("の").slice(1) : [],
17
+ paragraph: match[4],
18
+ item: match[5],
19
+ start: match.index,
20
+ end: match.index + match[0].length,
21
+ };
22
+ });
23
+ }
24
+ function integerToKanji(value) {
25
+ const digits = "〇一二三四五六七八九";
26
+ for (const [unit, label] of [
27
+ [1_0000_0000_0000, "兆"], [1_0000_0000, "億"], [1_0000, "万"],
28
+ [1000, "千"], [100, "百"], [10, "十"],
29
+ ]) {
30
+ if (value < unit)
31
+ continue;
32
+ const count = Math.floor(value / unit);
33
+ const prefix = count === 1 && unit <= 1000 ? "" : integerToKanji(count);
34
+ const remainder = value % unit;
35
+ return prefix + label + (remainder ? integerToKanji(remainder) : "");
36
+ }
37
+ return digits[value];
38
+ }
39
+ function formatNumeral(value) {
40
+ const normalized = value.replace(/^第/, "").replace(/[0-9]/g, (digit) => String(digit.charCodeAt(0) - "0".charCodeAt(0)));
41
+ return /^\d+$/.test(normalized)
42
+ ? integerToKanji(Number(normalized))
43
+ : normalized;
44
+ }
45
+ /** Render the kanji reference form used in notice titles, without the law name. */
46
+ export function formatArticleRef(ref) {
47
+ return `第${formatNumeral(ref.article)}条`
48
+ + ref.branches.map((branch) => `の${formatNumeral(branch)}`).join("")
49
+ + (ref.paragraph ? `第${formatNumeral(ref.paragraph)}項` : "")
50
+ + (ref.item ? `第${formatNumeral(ref.item)}号` : "");
51
+ }
52
+ //# sourceMappingURL=article-ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"article-ref.js","sourceRoot":"","sources":["../../src/lib/article-ref.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { z } from "zod";
2
+ import type { StructuredSubitem } from "./types.js";
3
+ export declare const parsedArticleSchema: z.ZodObject<{
4
+ article_num: z.ZodString;
5
+ article_caption: z.ZodString;
6
+ article_title: z.ZodString;
7
+ text: z.ZodString;
8
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
9
+ raw_text: z.ZodString;
10
+ ref_type: z.ZodEnum<{
11
+ same_law: "same_law";
12
+ cross_law: "cross_law";
13
+ relative: "relative";
14
+ delegation: "delegation";
15
+ unknown: "unknown";
16
+ }>;
17
+ target_law: z.ZodOptional<z.ZodString>;
18
+ target_article: z.ZodOptional<z.ZodString>;
19
+ target_paragraph: z.ZodOptional<z.ZodString>;
20
+ target_item: z.ZodOptional<z.ZodString>;
21
+ }, z.core.$strip>>>;
22
+ }, z.core.$strip>;
23
+ export declare const structuredArticleSchema: z.ZodObject<{
24
+ article_num: z.ZodString;
25
+ article_caption: z.ZodString;
26
+ article_title: z.ZodString;
27
+ paragraphs: z.ZodArray<z.ZodObject<{
28
+ paragraph_num: z.ZodString;
29
+ paragraph_sentence: z.ZodString;
30
+ items: z.ZodArray<z.ZodObject<{
31
+ item_num: z.ZodString;
32
+ item_title: z.ZodString;
33
+ item_sentence: z.ZodString;
34
+ subitems: z.ZodArray<z.ZodType<StructuredSubitem, unknown, z.core.$ZodTypeInternals<StructuredSubitem, unknown>>>;
35
+ }, z.core.$strip>>;
36
+ }, z.core.$strip>>;
37
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
38
+ raw_text: z.ZodString;
39
+ ref_type: z.ZodEnum<{
40
+ same_law: "same_law";
41
+ cross_law: "cross_law";
42
+ relative: "relative";
43
+ delegation: "delegation";
44
+ unknown: "unknown";
45
+ }>;
46
+ target_law: z.ZodOptional<z.ZodString>;
47
+ target_article: z.ZodOptional<z.ZodString>;
48
+ target_paragraph: z.ZodOptional<z.ZodString>;
49
+ target_item: z.ZodOptional<z.ZodString>;
50
+ }, z.core.$strip>>>;
51
+ }, z.core.$strip>;