building-standards-act-mcp 0.2.0 → 0.4.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 (52) hide show
  1. package/README.md +82 -21
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/article-analyzer.d.ts +5 -0
  5. package/dist/lib/article-analyzer.js +106 -0
  6. package/dist/lib/article-analyzer.js.map +1 -0
  7. package/dist/lib/cache.d.ts +40 -1
  8. package/dist/lib/cache.js +127 -0
  9. package/dist/lib/cache.js.map +1 -1
  10. package/dist/lib/citation-verifier.d.ts +14 -0
  11. package/dist/lib/citation-verifier.js +139 -0
  12. package/dist/lib/citation-verifier.js.map +1 -0
  13. package/dist/lib/egov-client.d.ts +4 -0
  14. package/dist/lib/egov-client.js +48 -5
  15. package/dist/lib/egov-client.js.map +1 -1
  16. package/dist/lib/logger.d.ts +10 -0
  17. package/dist/lib/logger.js +41 -0
  18. package/dist/lib/logger.js.map +1 -0
  19. package/dist/lib/metrics.d.ts +14 -0
  20. package/dist/lib/metrics.js +100 -0
  21. package/dist/lib/metrics.js.map +1 -0
  22. package/dist/lib/mlit-client.js +3 -3
  23. package/dist/lib/mlit-client.js.map +1 -1
  24. package/dist/lib/pdf-extractor.js +2 -2
  25. package/dist/lib/pdf-extractor.js.map +1 -1
  26. package/dist/lib/related-law-finder.d.ts +5 -0
  27. package/dist/lib/related-law-finder.js +103 -0
  28. package/dist/lib/related-law-finder.js.map +1 -0
  29. package/dist/lib/resilience.d.ts +34 -0
  30. package/dist/lib/resilience.js +110 -0
  31. package/dist/lib/resilience.js.map +1 -0
  32. package/dist/lib/types.d.ts +72 -0
  33. package/dist/server.js +16 -1
  34. package/dist/server.js.map +1 -1
  35. package/dist/tools/analyze-article.d.ts +2 -0
  36. package/dist/tools/analyze-article.js +31 -0
  37. package/dist/tools/analyze-article.js.map +1 -0
  38. package/dist/tools/get-laws-batch.d.ts +2 -0
  39. package/dist/tools/get-laws-batch.js +165 -0
  40. package/dist/tools/get-laws-batch.js.map +1 -0
  41. package/dist/tools/get-metrics.d.ts +2 -0
  42. package/dist/tools/get-metrics.js +15 -0
  43. package/dist/tools/get-metrics.js.map +1 -0
  44. package/dist/tools/suggest-related.d.ts +2 -0
  45. package/dist/tools/suggest-related.js +62 -0
  46. package/dist/tools/suggest-related.js.map +1 -0
  47. package/dist/tools/validate-presets.js +2 -2
  48. package/dist/tools/validate-presets.js.map +1 -1
  49. package/dist/tools/verify-citation.d.ts +2 -0
  50. package/dist/tools/verify-citation.js +98 -0
  51. package/dist/tools/verify-citation.js.map +1 -0
  52. package/package.json +1 -1
package/README.md CHANGED
@@ -15,10 +15,12 @@ AI の建築法規回答に含まれるハルシネーションを、条文原
15
15
  - **法令検索** — キーワードで法令を横断検索
16
16
  - **法令全文取得** — 法令全体のテキストを取得
17
17
  - **告示取得** — 建築基準法が技術基準を委任している告示を国土交通省の告示データベース(PDF)から取得
18
- - **主要法令プリセット** — 建築基準法・消防法・都市計画法ほか 115 法令の law_id をプリセット(全 11 章カバー)
18
+ - **主要法令プリセット** — 建築基準法・消防法・都市計画法ほか 115 法令の law_id をプリセット登録済み
19
19
  - **プリセット検証** — `validate_presets` ツールでプリセットの有効性をランタイム検証
20
20
  - **略称対応** — 「建基法」「都計法」「消防法」等の略称で指定可能
21
- - **キャッシュ** — 検索 30 分・法令データ 24 時間の TTL キャッシュ
21
+ - **キャッシュ** — 検索 30 分・法令データ 24 時間の TTL キャッシュ(永続化オプションあり)
22
+ - **API 耐障害性** — 自動リトライ(exponential backoff)+ サーキットブレーカー
23
+ - **運用可視化** — 構造化 JSON ログ + 使用量メトリクス(`get_metrics` ツール)
22
24
 
23
25
  ## セットアップ
24
26
 
@@ -73,14 +75,19 @@ npm run build
73
75
 
74
76
  ## MCP ツール
75
77
 
76
- | ツール | 説明 |
77
- | ------------------- | ------------------------------------------------------------------------------- |
78
- | `get_law` | 条番号を指定して法令の条文を取得する。略称・正式名称のいずれでも指定可能 |
79
- | `get_full_law` | 法令の全文を取得する。条番号を指定せず法令全体のテキストを返す |
80
- | `search_law` | キーワードで建築関連法令を横断検索する。プリセット法令と e-Gov API の両方を検索 |
81
- | `get_kokuji` | 建築基準法が技術基準を委任している告示の全文を取得する |
82
- | `validate_presets` | プリセット法令の law_id が e-Gov API で有効かを一括検証する |
83
- | `check_law_updates` | 法令の改正状況を e-Gov API で確認する(単体/バッチ/改正履歴表示に対応) |
78
+ | ツール | 説明 |
79
+ | ------------------- | ------------------------------------------------------------------------------------------- |
80
+ | `get_law` | 条番号を指定して法令の条文を取得する。略称・正式名称のいずれでも指定可能 |
81
+ | `get_full_law` | 法令の全文を取得する。条番号を指定せず法令全体のテキストを返す |
82
+ | `search_law` | キーワードで建築関連法令を横断検索する。プリセット法令と e-Gov API の両方を検索 |
83
+ | `get_kokuji` | 建築基準法が技術基準を委任している告示の全文を取得する |
84
+ | `validate_presets` | プリセット法令の law_id が e-Gov API で有効かを一括検証する |
85
+ | `check_law_updates` | 法令の改正状況を e-Gov API で確認する(単体/バッチ/改正履歴表示に対応) |
86
+ | `get_laws_batch` | 複数の法令・条文を一括取得する(最大20件、同一法令は1回のAPI呼び出しで効率処理) |
87
+ | `verify_citation` | AIの回答に含まれる法令引用を検証する(条文存在確認・テキスト照合、最大10件) |
88
+ | `suggest_related` | 指定した条文の関連法令・委任先・同法令内参照を自動抽出して提案する |
89
+ | `analyze_article` | 条文の構造解析メタデータ(項数・号数・参照統計・プレビュー)をJSON形式で返す |
90
+ | `get_metrics` | サーバーの使用量メトリクスを返す(ツール呼び出し回数・APIリクエスト数・キャッシュヒット率) |
84
91
 
85
92
  ### パラメータ
86
93
 
@@ -124,6 +131,36 @@ npm run build
124
131
  | `group` | 章グループ(バッチチェック、省略時は全章) | `1章` |
125
132
  | `show_history` | 改正履歴の詳細を表示(`law_name` 指定時) | `true` |
126
133
 
134
+ #### `get_laws_batch`
135
+
136
+ | パラメータ | 説明 | 例 |
137
+ | ---------- | ---------------------------------------------------------------------- | --- |
138
+ | `requests` | 取得対象の配列。各要素に `law_name`, `article_number`, `format` を指定 | — |
139
+
140
+ #### `verify_citation`
141
+
142
+ | パラメータ | 説明 | 例 |
143
+ | ----------- | ------------------------------------------------------------------------------- | --- |
144
+ | `citations` | 検証対象の配列。各要素に `law_name`, `article_number`, `claimed_text`(省略可) | — |
145
+
146
+ #### `suggest_related`
147
+
148
+ | パラメータ | 説明 | 例 |
149
+ | ---------------- | ---------------------------- | ------------ |
150
+ | `law_name` | 法令名(正式名称または略称) | `建築基準法` |
151
+ | `article_number` | 条文番号 | `第20条` |
152
+
153
+ #### `analyze_article`
154
+
155
+ | パラメータ | 説明 | 例 |
156
+ | ---------------- | ---------------------------- | ------------ |
157
+ | `law_name` | 法令名(正式名称または略称) | `建築基準法` |
158
+ | `article_number` | 条文番号 | `第20条` |
159
+
160
+ #### `get_metrics`
161
+
162
+ パラメータなし。サーバー起動後の稼働時間・ツール呼び出し回数・API リクエスト数・キャッシュヒット率を返す。
163
+
127
164
  ## 使用例
128
165
 
129
166
  ### 条文取得
@@ -172,7 +209,7 @@ npm run build
172
209
 
173
210
  ## 対応法令一覧(115 法令)
174
211
 
175
- ### 第1章 総則(4 法令)
212
+ ### 総則(4 法令)
176
213
 
177
214
  | 法令名 | 略称 |
178
215
  | ------------------ | -------------------- |
@@ -181,7 +218,7 @@ npm run build
181
218
  | 建築基準法施行規則 | 建基規則 |
182
219
  | 民法 | — |
183
220
 
184
- ### 第2章 手続関連規定(6 法令)
221
+ ### 手続関連規定(6 法令)
185
222
 
186
223
  | 法令名 | 略称 |
187
224
  | ---------------- | ------------ |
@@ -192,7 +229,7 @@ npm run build
192
229
  | 建設業法施行令 | — |
193
230
  | 建設業法施行規則 | — |
194
231
 
195
- ### 第3章 集団規定・街づくり規定(13 法令)
232
+ ### 集団規定・街づくり(13 法令)
196
233
 
197
234
  | 法令名 | 略称 |
198
235
  | -------------------------------------------------- | ---------------------- |
@@ -210,7 +247,7 @@ npm run build
210
247
  | 国土利用計画法 | 国土利用計画法, 国土法 |
211
248
  | 都市計画法施行規則 | 都計規則 |
212
249
 
213
- ### 第4章 防火規定・耐火規定(4 法令)
250
+ ### 防火・耐火規定(4 法令)
214
251
 
215
252
  | 法令名 | 略称 |
216
253
  | ------------------------ | ---------- |
@@ -219,7 +256,7 @@ npm run build
219
256
  | 消防法施行規則 | 消防規則 |
220
257
  | 危険物の規制に関する規則 | 危険物規則 |
221
258
 
222
- ### 第5章 構造規定(7 法令)
259
+ ### 構造規定(7 法令)
223
260
 
224
261
  | 法令名 | 略称 |
225
262
  | ------------------------------------------ | ---------------------- |
@@ -231,7 +268,7 @@ npm run build
231
268
  | 建築物の耐震改修の促進に関する法律施行令 | 耐震改修促進法施行令 |
232
269
  | 建築物の耐震改修の促進に関する法律施行規則 | 耐震改修促進法施行規則 |
233
270
 
234
- ### 第6章 建築材料(3 法令)
271
+ ### 建築材料(3 法令)
235
272
 
236
273
  | 法令名 | 略称 |
237
274
  | ---------------- | ---------------------- |
@@ -239,7 +276,7 @@ npm run build
239
276
  | 製造物責任法 | PL法, 製造物責任法 |
240
277
  | 石綿障害予防規則 | 石綿則, アスベスト規則 |
241
278
 
242
- ### 第7章 設備関連規定(5 法令)
279
+ ### 設備関連規定(5 法令)
243
280
 
244
281
  | 法令名 | 略称 |
245
282
  | -------------------------- | ---------------- |
@@ -249,7 +286,7 @@ npm run build
249
286
  | 浄化槽法施行令 | — |
250
287
  | 環境省関係浄化槽法施行規則 | 浄化槽法施行規則 |
251
288
 
252
- ### 第8章 その他(5 法令)
289
+ ### その他(5 法令)
253
290
 
254
291
  | 法令名 | 略称 |
255
292
  | ---------------------------------------------- | ------------------ |
@@ -259,7 +296,7 @@ npm run build
259
296
  | 不動産の鑑定評価に関する法律 | 不動産鑑定法 |
260
297
  | 住宅宿泊事業法 | 民泊新法 |
261
298
 
262
- ### 第9章 建築基準関係規定・建築関連法令(52 法令)
299
+ ### 建築基準関係規定・建築関連法令(52 法令)
263
300
 
264
301
  <details>
265
302
  <summary>法令一覧を表示</summary>
@@ -321,7 +358,7 @@ npm run build
321
358
 
322
359
  </details>
323
360
 
324
- ### 第10章 省エネ法・住宅関連法(13 法令)
361
+ ### 省エネ・住宅関連法(13 法令)
325
362
 
326
363
  | 法令名 | 略称 |
327
364
  | ------------------------------------------------------------------ | ---------------------- |
@@ -339,7 +376,7 @@ npm run build
339
376
  | 長期優良住宅の普及の促進に関する法律施行規則 | 長期優良住宅法施行規則 |
340
377
  | 建築物のエネルギー消費性能の向上等に関する法律施行規則 | 建築物省エネ法施行規則 |
341
378
 
342
- ### 第11章 既存建築物関連(3 法令)
379
+ ### 既存建築物関連(3 法令)
343
380
 
344
381
  | 法令名 | 略称 |
345
382
  | ------------------------------------------ | ---------------- |
@@ -368,6 +405,30 @@ e-Gov API は告示を収録していないため、`get_kokuji` は国土交通
368
405
  - `check_law_updates` ツールで法令の改正状況を確認できます(e-Gov API のリビジョン履歴を参照)
369
406
  - 法令改正による `law_id` の無効化リスクは低い(`law_id` は法令番号ベースの固有識別子)
370
407
 
408
+ ## 環境変数
409
+
410
+ | 変数 | 説明 | デフォルト |
411
+ | ------------------------ | ------------------------------------------------- | ---------------------------- |
412
+ | `BUILDING_LAW_CACHE` | キャッシュモード(`memory` / `file`) | `memory` |
413
+ | `BUILDING_LAW_CACHE_DIR` | ファイルキャッシュの保存先ディレクトリ | `~/.cache/building-law-mcp/` |
414
+ | `BUILDING_LAW_LOG_LEVEL` | ログレベル(`debug` / `info` / `warn` / `error`) | `info` |
415
+
416
+ ### 永続キャッシュの有効化
417
+
418
+ ```json
419
+ {
420
+ "mcpServers": {
421
+ "building-law": {
422
+ "command": "npx",
423
+ "args": ["-y", "building-law-mcp"],
424
+ "env": {
425
+ "BUILDING_LAW_CACHE": "file"
426
+ }
427
+ }
428
+ }
429
+ }
430
+ ```
431
+
371
432
  ## 技術仕様
372
433
 
373
434
  | 項目 | 値 |
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { createServer } from "./server.js";
4
+ import { logger } from "./lib/logger.js";
4
5
  const server = createServer();
5
6
  async function main() {
6
7
  const transport = new StdioServerTransport();
7
8
  await server.connect(transport);
8
- console.error("building-law-mcp Server running on stdio");
9
+ logger.info("server started", { transport: "stdio" });
9
10
  }
10
11
  main().catch((error) => {
11
12
  console.error("Fatal error:", error);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAE9B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAE9B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ArticleAnalysis } from "./types.js";
2
+ /**
3
+ * Analyze a single article and return structured metadata.
4
+ */
5
+ export declare function analyzeArticle(lawName: string, articleNumber: string): Promise<ArticleAnalysis>;
@@ -0,0 +1,106 @@
1
+ import { getLawData } from "./egov-client.js";
2
+ import { parseArticleStructured } from "./egov-parser.js";
3
+ import { LawRegistry } from "./law-registry.js";
4
+ const registry = new LawRegistry();
5
+ const PREVIEW_LENGTH = 100;
6
+ /**
7
+ * Remove parentheses from caption text.
8
+ * "(構造耐力)" → "構造耐力"
9
+ */
10
+ function stripParentheses(caption) {
11
+ return caption.replace(/^[((]/, "").replace(/[))]$/, "");
12
+ }
13
+ /**
14
+ * Count total characters in a structured article.
15
+ */
16
+ function countCharacters(article) {
17
+ let count = 0;
18
+ for (const para of article.paragraphs) {
19
+ count += para.paragraph_sentence.length;
20
+ for (const item of para.items) {
21
+ count += item.item_sentence.length;
22
+ for (const sub of item.subitems) {
23
+ count += countSubitemChars(sub);
24
+ }
25
+ }
26
+ }
27
+ return count;
28
+ }
29
+ function countSubitemChars(sub) {
30
+ let count = sub.subitem_sentence.length;
31
+ for (const child of sub.subitems) {
32
+ count += countSubitemChars(child);
33
+ }
34
+ return count;
35
+ }
36
+ /**
37
+ * Count total subitems recursively.
38
+ */
39
+ function countSubitems(article) {
40
+ let count = 0;
41
+ for (const para of article.paragraphs) {
42
+ for (const item of para.items) {
43
+ count += countSubitemsRecursive(item.subitems);
44
+ }
45
+ }
46
+ return count;
47
+ }
48
+ function countSubitemsRecursive(subs) {
49
+ let count = subs.length;
50
+ for (const sub of subs) {
51
+ count += countSubitemsRecursive(sub.subitems);
52
+ }
53
+ return count;
54
+ }
55
+ /**
56
+ * Analyze a single article and return structured metadata.
57
+ */
58
+ export async function analyzeArticle(lawName, articleNumber) {
59
+ const preset = registry.findByName(lawName);
60
+ if (!preset) {
61
+ throw new Error(`法令「${lawName}」がプリセットに見つかりませんでした。`);
62
+ }
63
+ const lawData = await getLawData(preset.law_id);
64
+ const article = parseArticleStructured(lawData.law_full_text, articleNumber);
65
+ if (!article) {
66
+ throw new Error(`${preset.title}に第${articleNumber}条が見つかりませんでした。`);
67
+ }
68
+ const itemCount = article.paragraphs.reduce((sum, p) => sum + p.items.length, 0);
69
+ const refs = article.references ?? [];
70
+ const crossLawRefs = refs.filter((r) => r.ref_type === "cross_law");
71
+ const referencedLaws = [
72
+ ...new Set(crossLawRefs
73
+ .map((r) => r.target_law)
74
+ .filter((l) => l !== undefined)),
75
+ ];
76
+ return {
77
+ law_name: preset.title,
78
+ law_num: preset.law_num,
79
+ article_num: article.article_num,
80
+ article_title: article.article_title,
81
+ caption: stripParentheses(article.article_caption),
82
+ structure: {
83
+ paragraph_count: article.paragraphs.length,
84
+ item_count: itemCount,
85
+ subitem_count: countSubitems(article),
86
+ total_characters: countCharacters(article),
87
+ },
88
+ paragraph_summaries: article.paragraphs.map((p) => ({
89
+ paragraph_num: p.paragraph_num,
90
+ preview: p.paragraph_sentence.length > PREVIEW_LENGTH
91
+ ? p.paragraph_sentence.slice(0, PREVIEW_LENGTH) + "…"
92
+ : p.paragraph_sentence,
93
+ item_count: p.items.length,
94
+ })),
95
+ reference_summary: {
96
+ total: refs.length,
97
+ cross_law: crossLawRefs.length,
98
+ same_law: refs.filter((r) => r.ref_type === "same_law").length,
99
+ relative: refs.filter((r) => r.ref_type === "relative").length,
100
+ delegation: refs.filter((r) => r.ref_type === "delegation").length,
101
+ referenced_laws: referencedLaws,
102
+ },
103
+ structured_data: article,
104
+ };
105
+ }
106
+ //# sourceMappingURL=article-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"article-analyzer.js","sourceRoot":"","sources":["../../src/lib/article-analyzer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,18 @@
1
- export declare class TTLCache<T> {
1
+ /**
2
+ * Common cache interface shared by all cache implementations.
3
+ */
4
+ export interface ICache<T> {
5
+ get(key: string): T | undefined;
6
+ set(key: string, value: T, ttl_ms?: number): void;
7
+ has(key: string): boolean;
8
+ delete(key: string): boolean;
9
+ clear(): void;
10
+ readonly size: number;
11
+ }
12
+ /**
13
+ * In-memory TTL cache. Entries expire after a configurable duration.
14
+ */
15
+ export declare class TTLCache<T> implements ICache<T> {
2
16
  private readonly store;
3
17
  private readonly default_ttl_ms;
4
18
  constructor(default_ttl_ms?: number);
@@ -9,3 +23,28 @@ export declare class TTLCache<T> {
9
23
  clear(): void;
10
24
  get size(): number;
11
25
  }
26
+ /**
27
+ * File-based TTL cache. Entries persist across server restarts.
28
+ * Each key is stored as an individual JSON file under
29
+ * `~/.cache/building-law-mcp/{name}/{hash}.json`.
30
+ */
31
+ export declare class FileCache<T> implements ICache<T> {
32
+ private readonly dir;
33
+ private readonly default_ttl_ms;
34
+ constructor(name: string, default_ttl_ms?: number);
35
+ private keyToPath;
36
+ get(key: string): T | undefined;
37
+ set(key: string, value: T, ttl_ms?: number): void;
38
+ has(key: string): boolean;
39
+ delete(key: string): boolean;
40
+ clear(): void;
41
+ get size(): number;
42
+ }
43
+ /**
44
+ * Factory function to create a cache instance based on the
45
+ * `BUILDING_LAW_CACHE` environment variable.
46
+ *
47
+ * - `"memory"` (default): in-memory TTLCache
48
+ * - `"file"`: file-based FileCache that persists across restarts
49
+ */
50
+ export declare function createCache<T>(name: string, ttl_ms: number): ICache<T>;
package/dist/lib/cache.js CHANGED
@@ -1,3 +1,10 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ import * as crypto from "node:crypto";
5
+ /**
6
+ * In-memory TTL cache. Entries expire after a configurable duration.
7
+ */
1
8
  export class TTLCache {
2
9
  store = new Map();
3
10
  default_ttl_ms;
@@ -41,4 +48,124 @@ export class TTLCache {
41
48
  return this.store.size;
42
49
  }
43
50
  }
51
+ const DEFAULT_CACHE_DIR = path.join(os.homedir(), ".cache", "building-law-mcp");
52
+ /**
53
+ * File-based TTL cache. Entries persist across server restarts.
54
+ * Each key is stored as an individual JSON file under
55
+ * `~/.cache/building-law-mcp/{name}/{hash}.json`.
56
+ */
57
+ export class FileCache {
58
+ dir;
59
+ default_ttl_ms;
60
+ constructor(name, default_ttl_ms = 30 * 60 * 1000) {
61
+ this.default_ttl_ms = default_ttl_ms;
62
+ const cacheBase = process.env.BUILDING_LAW_CACHE_DIR ?? DEFAULT_CACHE_DIR;
63
+ this.dir = path.join(cacheBase, name);
64
+ fs.mkdirSync(this.dir, { recursive: true });
65
+ }
66
+ keyToPath(key) {
67
+ const hash = crypto.createHash("md5").update(key).digest("hex");
68
+ return path.join(this.dir, `${hash}.json`);
69
+ }
70
+ get(key) {
71
+ const filePath = this.keyToPath(key);
72
+ try {
73
+ const raw = fs.readFileSync(filePath, "utf-8");
74
+ const entry = JSON.parse(raw);
75
+ if (Date.now() > entry.expires_at) {
76
+ try {
77
+ fs.unlinkSync(filePath);
78
+ }
79
+ catch {
80
+ // ignore cleanup failure
81
+ }
82
+ return undefined;
83
+ }
84
+ return entry.value;
85
+ }
86
+ catch {
87
+ return undefined;
88
+ }
89
+ }
90
+ set(key, value, ttl_ms) {
91
+ const ttl = ttl_ms ?? this.default_ttl_ms;
92
+ const entry = { value, expires_at: Date.now() + ttl };
93
+ fs.writeFileSync(this.keyToPath(key), JSON.stringify(entry), "utf-8");
94
+ }
95
+ has(key) {
96
+ return this.get(key) !== undefined;
97
+ }
98
+ delete(key) {
99
+ try {
100
+ fs.unlinkSync(this.keyToPath(key));
101
+ return true;
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ }
107
+ clear() {
108
+ try {
109
+ const files = fs.readdirSync(this.dir);
110
+ for (const file of files) {
111
+ if (file.endsWith(".json")) {
112
+ try {
113
+ fs.unlinkSync(path.join(this.dir, file));
114
+ }
115
+ catch {
116
+ // ignore individual file cleanup failure
117
+ }
118
+ }
119
+ }
120
+ }
121
+ catch {
122
+ // directory might not exist
123
+ }
124
+ }
125
+ get size() {
126
+ try {
127
+ const files = fs.readdirSync(this.dir).filter((f) => f.endsWith(".json"));
128
+ let count = 0;
129
+ for (const file of files) {
130
+ const filePath = path.join(this.dir, file);
131
+ try {
132
+ const raw = fs.readFileSync(filePath, "utf-8");
133
+ const entry = JSON.parse(raw);
134
+ if (Date.now() <= entry.expires_at) {
135
+ count++;
136
+ }
137
+ else {
138
+ try {
139
+ fs.unlinkSync(filePath);
140
+ }
141
+ catch {
142
+ // ignore cleanup failure
143
+ }
144
+ }
145
+ }
146
+ catch {
147
+ // corrupted file, skip
148
+ }
149
+ }
150
+ return count;
151
+ }
152
+ catch {
153
+ return 0;
154
+ }
155
+ }
156
+ }
157
+ /**
158
+ * Factory function to create a cache instance based on the
159
+ * `BUILDING_LAW_CACHE` environment variable.
160
+ *
161
+ * - `"memory"` (default): in-memory TTLCache
162
+ * - `"file"`: file-based FileCache that persists across restarts
163
+ */
164
+ export function createCache(name, ttl_ms) {
165
+ const mode = process.env.BUILDING_LAW_CACHE ?? "memory";
166
+ if (mode === "file") {
167
+ return new FileCache(name, ttl_ms);
168
+ }
169
+ return new TTLCache(ttl_ms);
170
+ }
44
171
  //# sourceMappingURL=cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/lib/cache.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,QAAQ;IACF,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IACzC,cAAc,CAAS;IAExC,YAAY,iBAAyB,EAAE,GAAG,EAAE,GAAG,IAAI;QACjD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,MAAe;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,8BAA8B;QAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;gBAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/lib/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CitationVerification } from "./types.js";
2
+ /**
3
+ * Normalize text for comparison: collapse whitespace, remove formatting artifacts.
4
+ */
5
+ export declare function normalizeText(text: string): string;
6
+ /**
7
+ * Calculate match score between claimed text and actual text.
8
+ * Returns a value between 0.0 and 1.0.
9
+ */
10
+ export declare function calculateMatchScore(claimed: string, actual: string): number;
11
+ /**
12
+ * Verify a single citation against the actual law text.
13
+ */
14
+ export declare function verifyCitation(lawName: string, articleNumber: string, claimedText?: string): Promise<CitationVerification>;