building-standards-act-mcp 0.1.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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +301 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +14 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/cache.d.ts +11 -0
  7. package/dist/lib/cache.js +44 -0
  8. package/dist/lib/cache.js.map +1 -0
  9. package/dist/lib/egov-client.d.ts +11 -0
  10. package/dist/lib/egov-client.js +67 -0
  11. package/dist/lib/egov-client.js.map +1 -0
  12. package/dist/lib/egov-parser.d.ts +35 -0
  13. package/dist/lib/egov-parser.js +498 -0
  14. package/dist/lib/egov-parser.js.map +1 -0
  15. package/dist/lib/errors.d.ts +18 -0
  16. package/dist/lib/errors.js +37 -0
  17. package/dist/lib/errors.js.map +1 -0
  18. package/dist/lib/kokuji-registry.d.ts +19 -0
  19. package/dist/lib/kokuji-registry.js +63 -0
  20. package/dist/lib/kokuji-registry.js.map +1 -0
  21. package/dist/lib/law-registry.d.ts +27 -0
  22. package/dist/lib/law-registry.js +623 -0
  23. package/dist/lib/law-registry.js.map +1 -0
  24. package/dist/lib/types.d.ts +70 -0
  25. package/dist/lib/types.js +3 -0
  26. package/dist/lib/types.js.map +1 -0
  27. package/dist/server.d.ts +2 -0
  28. package/dist/server.js +42 -0
  29. package/dist/server.js.map +1 -0
  30. package/dist/tools/get-full-law.d.ts +2 -0
  31. package/dist/tools/get-full-law.js +40 -0
  32. package/dist/tools/get-full-law.js.map +1 -0
  33. package/dist/tools/get-kokuji.d.ts +2 -0
  34. package/dist/tools/get-kokuji.js +79 -0
  35. package/dist/tools/get-kokuji.js.map +1 -0
  36. package/dist/tools/get-law.d.ts +2 -0
  37. package/dist/tools/get-law.js +46 -0
  38. package/dist/tools/get-law.js.map +1 -0
  39. package/dist/tools/search-law.d.ts +2 -0
  40. package/dist/tools/search-law.js +54 -0
  41. package/dist/tools/search-law.js.map +1 -0
  42. package/package.json +42 -0
@@ -0,0 +1,70 @@
1
+ export interface EgovLawSearchResponse {
2
+ total_count: number;
3
+ count: number;
4
+ laws: EgovLawEntry[];
5
+ }
6
+ export interface EgovLawEntry {
7
+ law_info: EgovLawInfo;
8
+ revision_info: EgovRevisionInfo;
9
+ current_revision_info: EgovRevisionInfo;
10
+ }
11
+ export interface EgovLawInfo {
12
+ law_type: string;
13
+ law_id: string;
14
+ law_num: string;
15
+ law_num_era: string;
16
+ law_num_year: number;
17
+ law_num_type: string;
18
+ law_num_num: string;
19
+ promulgation_date: string;
20
+ }
21
+ export interface EgovRevisionInfo {
22
+ law_revision_id: string;
23
+ law_type: string;
24
+ law_title: string;
25
+ law_title_kana: string;
26
+ abbrev: string | null;
27
+ category: string;
28
+ updated: string;
29
+ amendment_promulgate_date: string;
30
+ amendment_enforcement_date: string;
31
+ amendment_enforcement_comment: string | null;
32
+ amendment_law_id: string;
33
+ amendment_law_title: string;
34
+ amendment_law_num: string;
35
+ repeal_status: string;
36
+ remain_in_force: boolean;
37
+ current_revision_status: string;
38
+ }
39
+ export interface EgovLawDataResponse {
40
+ attached_files_info: unknown;
41
+ law_info: EgovLawInfo;
42
+ revision_info: EgovRevisionInfo;
43
+ law_full_text: LawNode;
44
+ }
45
+ export interface LawNode {
46
+ tag: string;
47
+ attr?: Record<string, string>;
48
+ children?: Array<LawNode | string>;
49
+ }
50
+ export interface ParsedArticle {
51
+ article_num: string;
52
+ article_caption: string;
53
+ article_title: string;
54
+ text: string;
55
+ }
56
+ export interface LawPreset {
57
+ law_id: string;
58
+ law_num: string;
59
+ title: string;
60
+ abbrev: string[];
61
+ group: string;
62
+ tier: "Act" | "CabinetOrder" | "MinisterialOrdinance" | "Other";
63
+ }
64
+ export interface KokujiPreset {
65
+ law_id: string;
66
+ law_num: string;
67
+ title: string;
68
+ abbrev: string[];
69
+ delegated_by: string;
70
+ }
@@ -0,0 +1,3 @@
1
+ // e-Gov API v2 response types
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,8BAA8B"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,42 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerGetLawTool } from "./tools/get-law.js";
3
+ import { registerGetFullLawTool } from "./tools/get-full-law.js";
4
+ import { registerSearchLawTool } from "./tools/search-law.js";
5
+ import { registerGetKokujiTool } from "./tools/get-kokuji.js";
6
+ const SERVER_NAME = "building-law-mcp";
7
+ const SERVER_VERSION = "0.1.0";
8
+ const INSTRUCTIONS = `あなたは建築確認申請の法規照合アシスタントです。
9
+
10
+ ## 利用可能なツール
11
+ - get_law: 条番号を指定して条文を取得(例: 建築基準法 第20条)
12
+ - get_full_law: 法令全文を取得(例: 建築基準法施行令)
13
+ - search_law: キーワードで法令を横断検索(例: 耐火構造)
14
+ - get_kokuji: 告示の全文を取得(例: 耐火構造の構造方法を定める件)
15
+
16
+ ## 回答ルール
17
+ 1. まず質問に対する仮回答を生成する
18
+ 2. 仮回答に含まれる条文・数値を get_law で取得して原文と照合する
19
+ 3. 相違があれば仮回答を修正する
20
+ 4. 2〜3 を収束まで繰り返す(最大 4 ラウンド)
21
+ 5. 最終回答には照合済みの条文番号・告示番号を引用元として明示する
22
+
23
+ ## 回答できない場合
24
+ - 該当法令が見つからない場合は「該当条文を確認できませんでした」と明示する
25
+ - API エラーの場合はエラー内容を報告する
26
+
27
+ ## 略称対応
28
+ 建基法=建築基準法、建基令=建築基準法施行令、都計法=都市計画法 等の略称が使用可能です。`;
29
+ export function createServer() {
30
+ const server = new McpServer({
31
+ name: SERVER_NAME,
32
+ version: SERVER_VERSION,
33
+ }, {
34
+ instructions: INSTRUCTIONS,
35
+ });
36
+ registerGetLawTool(server);
37
+ registerGetFullLawTool(server);
38
+ registerSearchLawTool(server);
39
+ registerGetKokujiTool(server);
40
+ return server;
41
+ }
42
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;8CAoByB,CAAC;AAE/C,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,EACD;QACE,YAAY,EAAE,YAAY;KAC3B,CACF,CAAC;IAEF,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAE9B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetFullLawTool(server: McpServer): void;
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { LawRegistry } from "../lib/law-registry.js";
3
+ import { getLawData } from "../lib/egov-client.js";
4
+ import { parseFullLaw } from "../lib/egov-parser.js";
5
+ import { LawNotFoundError } from "../lib/errors.js";
6
+ const registry = new LawRegistry();
7
+ const schema = {
8
+ law_name: z
9
+ .string()
10
+ .describe("法令名(正式名称、略称のいずれか。例: 建築基準法施行令、建基令)"),
11
+ };
12
+ export function registerGetFullLawTool(server) {
13
+ server.tool("get_full_law", "法令の全文を取得する。条番号を指定せず法令全体のテキストを返す。", schema, async ({ law_name }) => {
14
+ try {
15
+ const preset = registry.findByName(law_name);
16
+ if (!preset) {
17
+ throw new LawNotFoundError(law_name);
18
+ }
19
+ const lawData = await getLawData(preset.law_id);
20
+ const fullText = parseFullLaw(lawData.law_full_text);
21
+ const text = [
22
+ `【${preset.title}】全文`,
23
+ `法令番号: ${preset.law_num}`,
24
+ "",
25
+ fullText,
26
+ "",
27
+ `出典: e-Gov法令検索`,
28
+ ].join("\n");
29
+ return { content: [{ type: "text", text }] };
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ return {
34
+ content: [{ type: "text", text: `エラー: ${message}` }],
35
+ isError: true,
36
+ };
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=get-full-law.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-full-law.js","sourceRoot":"","sources":["../../src/tools/get-full-law.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;AAEnC,MAAM,MAAM,GAAG;IACb,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,CACP,mCAAmC,CACpC;CACJ,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,kCAAkC,EAClC,MAAM,EACN,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAErD,MAAM,IAAI,GAAG;gBACX,IAAI,MAAM,CAAC,KAAK,KAAK;gBACrB,SAAS,MAAM,CAAC,OAAO,EAAE;gBACzB,EAAE;gBACF,QAAQ;gBACR,EAAE;gBACF,eAAe;aAChB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEb,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,OAAO,EAAE,EAAE,CAAC;gBAC7D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetKokujiTool(server: McpServer): void;
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+ import { KokujiRegistry } from "../lib/kokuji-registry.js";
3
+ import { searchLaws, getLawData } from "../lib/egov-client.js";
4
+ import { parseFullLaw } from "../lib/egov-parser.js";
5
+ const registry = new KokujiRegistry();
6
+ const schema = {
7
+ kokuji_name: z
8
+ .string()
9
+ .describe("告示名(例: 耐火構造の構造方法を定める件、不燃材料を定める件)"),
10
+ };
11
+ export function registerGetKokujiTool(server) {
12
+ server.tool("get_kokuji", "建築基準法が技術基準を委任している告示の全文を取得する。e-Gov APIで検索を試みる。", schema, async ({ kokuji_name }) => {
13
+ try {
14
+ // First check preset registry
15
+ const preset = registry.findByName(kokuji_name);
16
+ if (preset) {
17
+ // If we have a preset with a law_id, fetch from API
18
+ const lawData = await getLawData(preset.law_id);
19
+ const fullText = parseFullLaw(lawData.law_full_text);
20
+ const text = [
21
+ `【告示】${preset.title}`,
22
+ `法令番号: ${preset.law_num}`,
23
+ `委任元: ${preset.delegated_by}`,
24
+ "",
25
+ fullText,
26
+ "",
27
+ "出典: e-Gov法令検索",
28
+ ].join("\n");
29
+ return { content: [{ type: "text", text }] };
30
+ }
31
+ // No preset found - try searching e-Gov API directly
32
+ const searchResult = await searchLaws(kokuji_name);
33
+ if (searchResult.count > 0) {
34
+ // Found something - try to get the first result
35
+ const firstLaw = searchResult.laws[0];
36
+ const title = firstLaw.revision_info?.law_title ??
37
+ firstLaw.current_revision_info?.law_title ??
38
+ kokuji_name;
39
+ const lawId = firstLaw.law_info.law_id;
40
+ const lawData = await getLawData(lawId);
41
+ const fullText = parseFullLaw(lawData.law_full_text);
42
+ const text = [
43
+ `【検索結果】${title}`,
44
+ `法令番号: ${firstLaw.law_info.law_num}`,
45
+ "",
46
+ fullText,
47
+ "",
48
+ "出典: e-Gov法令検索",
49
+ "",
50
+ "※ この告示はプリセットに含まれていないため、検索結果から取得しました。",
51
+ ].join("\n");
52
+ return { content: [{ type: "text", text }] };
53
+ }
54
+ // Nothing found
55
+ const allKokuji = registry.getAll();
56
+ const text = [
57
+ `該当する告示を確認できませんでした: ${kokuji_name}`,
58
+ "",
59
+ "告示は e-Gov 法令 API v2 の検索対象に含まれていない場合があります。",
60
+ "正式な告示名で再度お試しいただくか、関連する法令(建築基準法施行令等)の",
61
+ "該当条文を get_law ツールで確認してください。",
62
+ "",
63
+ "登録済みの告示一覧:",
64
+ ...(allKokuji.length > 0
65
+ ? allKokuji.map((k) => ` - ${k.title}`)
66
+ : [" (現在登録されている告示はありません)"]),
67
+ ].join("\n");
68
+ return { content: [{ type: "text", text }] };
69
+ }
70
+ catch (error) {
71
+ const message = error instanceof Error ? error.message : String(error);
72
+ return {
73
+ content: [{ type: "text", text: `エラー: ${message}` }],
74
+ isError: true,
75
+ };
76
+ }
77
+ });
78
+ }
79
+ //# sourceMappingURL=get-kokuji.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-kokuji.js","sourceRoot":"","sources":["../../src/tools/get-kokuji.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetLawTool(server: McpServer): void;
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import { LawRegistry } from "../lib/law-registry.js";
3
+ import { getLawData } from "../lib/egov-client.js";
4
+ import { parseArticle } from "../lib/egov-parser.js";
5
+ import { LawNotFoundError, ArticleNotFoundError } from "../lib/errors.js";
6
+ const registry = new LawRegistry();
7
+ const schema = {
8
+ law_name: z
9
+ .string()
10
+ .describe("法令名(正式名称、略称のいずれか。例: 建築基準法、建基法)"),
11
+ article_number: z.string().describe("条文番号(例: 第20条、20、第6条の2)"),
12
+ };
13
+ export function registerGetLawTool(server) {
14
+ server.tool("get_law", "条番号を指定して法令の条文を取得する。略称・正式名称のいずれでも指定可能。", schema, async ({ law_name, article_number }) => {
15
+ try {
16
+ const preset = registry.findByName(law_name);
17
+ if (!preset) {
18
+ throw new LawNotFoundError(law_name);
19
+ }
20
+ const lawData = await getLawData(preset.law_id);
21
+ const article = parseArticle(lawData.law_full_text, article_number);
22
+ if (!article) {
23
+ throw new ArticleNotFoundError(article_number, preset.title);
24
+ }
25
+ const text = [
26
+ `【${preset.title}】${article.article_title}`,
27
+ article.article_caption ? article.article_caption : "",
28
+ "",
29
+ article.text,
30
+ "",
31
+ `出典: e-Gov法令検索(法令番号: ${preset.law_num})`,
32
+ ]
33
+ .filter((line) => line !== undefined)
34
+ .join("\n");
35
+ return { content: [{ type: "text", text }] };
36
+ }
37
+ catch (error) {
38
+ const message = error instanceof Error ? error.message : String(error);
39
+ return {
40
+ content: [{ type: "text", text: `エラー: ${message}` }],
41
+ isError: true,
42
+ };
43
+ }
44
+ });
45
+ }
46
+ //# sourceMappingURL=get-law.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-law.js","sourceRoot":"","sources":["../../src/tools/get-law.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;AAEnC,MAAM,MAAM,GAAG;IACb,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,CAAC,gCAAgC,CAAC;IAC7C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;CAC9D,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,SAAS,EACT,uCAAuC,EACvC,MAAM,EACN,KAAK,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YACvC,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;YAEpE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,oBAAoB,CAAC,cAAc,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/D,CAAC;YAED,MAAM,IAAI,GAAG;gBACX,IAAI,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,aAAa,EAAE;gBAC3C,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE;gBACtD,EAAE;gBACF,OAAO,CAAC,IAAI;gBACZ,EAAE;gBACF,uBAAuB,MAAM,CAAC,OAAO,GAAG;aACzC;iBACE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC;iBACpC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,OAAO,EAAE,EAAE,CAAC;gBAC7D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchLawTool(server: McpServer): void;
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import { LawRegistry } from "../lib/law-registry.js";
3
+ import { searchLaws } from "../lib/egov-client.js";
4
+ const registry = new LawRegistry();
5
+ const schema = {
6
+ keyword: z
7
+ .string()
8
+ .describe("検索キーワード(例: 耐火構造、避難階段、建築確認)"),
9
+ };
10
+ export function registerSearchLawTool(server) {
11
+ server.tool("search_law", "キーワードで建築関連法令を横断検索する。プリセット法令とe-Gov APIの両方を検索する。", schema, async ({ keyword }) => {
12
+ try {
13
+ // Search presets first
14
+ const presetResults = registry.search(keyword);
15
+ // Also search e-Gov API
16
+ const apiResults = await searchLaws(keyword);
17
+ const lines = [];
18
+ if (presetResults.length > 0) {
19
+ lines.push("■ プリセット法令の検索結果:");
20
+ for (const p of presetResults) {
21
+ const abbrevStr = p.abbrev.length > 0 ? `(${p.abbrev.join("、")})` : "";
22
+ lines.push(` - ${p.title}${abbrevStr} [${p.group}]`);
23
+ }
24
+ lines.push("");
25
+ }
26
+ if (apiResults.count > 0) {
27
+ lines.push(`■ e-Gov API検索結果(${apiResults.count}件):`);
28
+ const maxShow = 20;
29
+ const lawsToShow = apiResults.laws.slice(0, maxShow);
30
+ for (const law of lawsToShow) {
31
+ const title = law.revision_info?.law_title ??
32
+ law.current_revision_info?.law_title ??
33
+ "(不明)";
34
+ lines.push(` - ${title}(${law.law_info.law_num})`);
35
+ }
36
+ if (apiResults.count > maxShow) {
37
+ lines.push(` ... 他 ${apiResults.count - maxShow} 件`);
38
+ }
39
+ }
40
+ if (lines.length === 0) {
41
+ lines.push(`「${keyword}」に該当する法令は見つかりませんでした。`);
42
+ }
43
+ return { content: [{ type: "text", text: lines.join("\n") }] };
44
+ }
45
+ catch (error) {
46
+ const message = error instanceof Error ? error.message : String(error);
47
+ return {
48
+ content: [{ type: "text", text: `エラー: ${message}` }],
49
+ isError: true,
50
+ };
51
+ }
52
+ });
53
+ }
54
+ //# sourceMappingURL=search-law.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-law.js","sourceRoot":"","sources":["../../src/tools/search-law.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "building-standards-act-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Japanese building regulations — fetches law text from e-Gov API v2 to prevent AI hallucination in building permit reviews",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "building-standards-act-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc && node -e \"try{require('fs').chmodSync('dist/index.js',0o755)}catch{}\"",
15
+ "start": "node dist/index.js",
16
+ "dev": "tsx src/index.ts",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "building-law",
23
+ "e-gov",
24
+ "japan",
25
+ "architecture",
26
+ "legal"
27
+ ],
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.26.0",
31
+ "zod": "^3.23.8"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.0.0",
35
+ "tsx": "^4.0.0",
36
+ "typescript": "^5.7.0",
37
+ "vitest": "^3.0.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ }
42
+ }