@shuji-bonji/rfcxml-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.
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025 shuji-bonji
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # RFCXML MCP Server
2
+
3
+ RFC 文書を **構造的に理解** するための MCP サーバー。
4
+
5
+ ## 目的
6
+
7
+ 既存の RFC MCP サーバー(テキストベース)と異なり、RFCXML の意味構造を活用して:
8
+
9
+ - **規範性要件(MUST/SHOULD/MAY)** の抽出・構造化
10
+ - **RFC 間依存関係グラフ** の構築
11
+ - **定義語のスコープ管理**
12
+ - **実装チェックリストの自動生成**
13
+
14
+ を可能にする。
15
+
16
+ ## レイヤー構造
17
+
18
+ ```
19
+ ┌─────────────────────────┐
20
+ │ Markdown / PDF │ 表示・共有
21
+ ├─────────────────────────┤
22
+ │ 翻訳 │ 説明・検証・普及
23
+ ├─────────────────────────┤
24
+ │ RFCXML MCP │ AI と人の共通理解基盤
25
+ ├─────────────────────────┤
26
+ │ RFCXML │ 唯一の真実(Single Source of Truth)
27
+ └─────────────────────────┘
28
+ ```
29
+
30
+ ## 既存 MCP との違い
31
+
32
+ | 機能 | 既存 mcp-rfc | RFCXML MCP |
33
+ |------|-------------|------------|
34
+ | RFC テキスト取得 | ✅ | ✅ |
35
+ | セクション抽出 | ✅ (テキストベース) | ✅ (構造ベース) |
36
+ | MUST/SHOULD/MAY 抽出 | ❌ | ✅ |
37
+ | 条件・例外の構造化 | ❌ | ✅ |
38
+ | RFC 間依存グラフ | ❌ | ✅ |
39
+ | 定義スコープ管理 | ❌ | ✅ |
40
+ | 実装チェックリスト | ❌ | ✅ |
41
+
42
+ ## インストール
43
+
44
+ ```bash
45
+ npm install @shuji-bonji/rfcxml-mcp
46
+ ```
47
+
48
+ ## MCP 設定
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "rfcxml": {
54
+ "command": "npx",
55
+ "args": ["-y", "@shuji-bonji/rfcxml-mcp"]
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## 利用可能なツール
62
+
63
+ ### Phase 1: 基本構造
64
+
65
+ - `get_rfc_structure` - セクション階層とメタデータ取得
66
+ - `get_requirements` - 規範性要件(MUST/SHOULD/MAY)の構造化抽出
67
+ - `get_definitions` - 用語定義とスコープ
68
+
69
+ ### Phase 2: 関係性
70
+
71
+ - `get_rfc_dependencies` - 参照 RFC(normative/informative)
72
+ - `get_related_sections` - 関連セクション(同一 RFC 内)
73
+
74
+ ### Phase 3: 検証支援
75
+
76
+ - `validate_statement` - 主張が RFC に準拠しているか検証
77
+ - `generate_checklist` - 実装チェックリスト生成
78
+
79
+ ## 古い RFC のサポート
80
+
81
+ RFC 8650 (2019年12月) 以降は公式 RFCXML v3 形式で提供されていますが、それ以前の RFC は XML が利用できない場合があります。
82
+
83
+ このサーバーは **自動フォールバック機能** を備えており、XML が取得できない場合はテキスト形式から解析を行います。
84
+
85
+ ### ソース情報
86
+
87
+ すべてのレスポンスには解析ソース情報が含まれます:
88
+
89
+ ```json
90
+ {
91
+ "rfc": 6455,
92
+ "sections": [...],
93
+ "_source": "text",
94
+ "_sourceNote": "⚠️ テキストからの解析結果です。精度が低い可能性があります。"
95
+ }
96
+ ```
97
+
98
+ | `_source` | 説明 |
99
+ |-----------|------|
100
+ | `xml` | RFCXML から解析(高精度) |
101
+ | `text` | テキストから解析(中精度) |
102
+
103
+ ### 対応状況
104
+
105
+ | RFC | 形式 | 備考 |
106
+ |-----|------|------|
107
+ | RFC 8650 以降 | XML | RFCXML v3 公式対応 |
108
+ | RFC 8650 未満 | テキスト | 自動フォールバック |
109
+
110
+ ## 使用例
111
+
112
+ ### 規範性要件の抽出
113
+
114
+ ```typescript
115
+ // ツール呼び出し
116
+ {
117
+ "tool": "get_requirements",
118
+ "arguments": {
119
+ "rfc": 6455,
120
+ "section": "5.5.1"
121
+ }
122
+ }
123
+
124
+ // 結果
125
+ {
126
+ "section": "5.5.1",
127
+ "title": "Close",
128
+ "requirements": [
129
+ {
130
+ "id": "R-5.5.1-1",
131
+ "level": "MUST",
132
+ "text": "endpoint MUST send a Close frame",
133
+ "subject": "endpoint",
134
+ "action": "send Close frame",
135
+ "condition": "when closing connection",
136
+ "fullContext": "After sending a control frame indicating..."
137
+ }
138
+ ]
139
+ }
140
+ ```
141
+
142
+ ### 実装チェックリスト生成
143
+
144
+ ```typescript
145
+ // ツール呼び出し
146
+ {
147
+ "tool": "generate_checklist",
148
+ "arguments": {
149
+ "rfc": 6455,
150
+ "role": "client"
151
+ }
152
+ }
153
+
154
+ // 結果(Markdown)
155
+ ## RFC 6455 WebSocket Client 実装チェックリスト
156
+
157
+ ### 必須要件 (MUST)
158
+ - [ ] Opening Handshake で Sec-WebSocket-Key を含める (Section 4.1)
159
+ - [ ] Close フレーム受信後、TCP 接続を閉じる (Section 5.5.1)
160
+ - [ ] マスクキーは予測不可能である必要がある (Section 5.3)
161
+
162
+ ### 推奨要件 (SHOULD)
163
+ - [ ] Close フレームには理由を含める (Section 7.1.6)
164
+ ```
165
+
166
+ ## 開発
167
+
168
+ ```bash
169
+ # 依存関係インストール
170
+ npm install
171
+
172
+ # 開発モード
173
+ npm run dev
174
+
175
+ # ビルド
176
+ npm run build
177
+
178
+ # テスト
179
+ npm test
180
+ ```
181
+
182
+ ## ライセンス
183
+
184
+ MIT
185
+
186
+ ## 関連プロジェクト
187
+
188
+ - [mjpitz/mcp-rfc](https://github.com/mjpitz/mcp-rfc) - テキストベースの RFC MCP
189
+ - [ietf-tools/RFCXML](https://github.com/ietf-tools/RFCXML) - RFCXML スキーマ
190
+ - [xml2rfc](https://xml2rfc.ietf.org/) - IETF 公式ツール
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * RFCXML MCP Server
4
+ * RFC 文書を構造的に理解するための MCP サーバー
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * RFCXML MCP Server
4
+ * RFC 文書を構造的に理解するための MCP サーバー
5
+ */
6
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
9
+ import { tools } from './tools/definitions.js';
10
+ import { handleGetRFCStructure, handleGetRequirements, handleGetDefinitions, handleGetDependencies, handleGetRelatedSections, handleGenerateChecklist, handleValidateStatement, } from './tools/handlers.js';
11
+ // サーバーインスタンス
12
+ const server = new Server({
13
+ name: 'rfcxml-mcp',
14
+ version: '0.1.0',
15
+ }, {
16
+ capabilities: {
17
+ tools: {},
18
+ resources: {},
19
+ },
20
+ });
21
+ // ツール一覧
22
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
23
+ return { tools };
24
+ });
25
+ // ツール実行
26
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
27
+ const { name, arguments: args } = request.params;
28
+ try {
29
+ let result;
30
+ switch (name) {
31
+ case 'get_rfc_structure':
32
+ result = await handleGetRFCStructure(args);
33
+ break;
34
+ case 'get_requirements':
35
+ result = await handleGetRequirements(args);
36
+ break;
37
+ case 'get_definitions':
38
+ result = await handleGetDefinitions(args);
39
+ break;
40
+ case 'get_rfc_dependencies':
41
+ result = await handleGetDependencies(args);
42
+ break;
43
+ case 'get_related_sections':
44
+ result = await handleGetRelatedSections(args);
45
+ break;
46
+ case 'generate_checklist':
47
+ result = await handleGenerateChecklist(args);
48
+ break;
49
+ case 'validate_statement':
50
+ result = await handleValidateStatement(args);
51
+ break;
52
+ default:
53
+ throw new Error(`Unknown tool: ${name}`);
54
+ }
55
+ return {
56
+ content: [
57
+ {
58
+ type: 'text',
59
+ text: JSON.stringify(result, null, 2),
60
+ },
61
+ ],
62
+ };
63
+ }
64
+ catch (error) {
65
+ const message = error instanceof Error ? error.message : String(error);
66
+ return {
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: JSON.stringify({ error: message }, null, 2),
71
+ },
72
+ ],
73
+ isError: true,
74
+ };
75
+ }
76
+ });
77
+ // リソース一覧(RFC スキーマ)
78
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
79
+ return {
80
+ resources: [
81
+ {
82
+ uri: 'rfcxml://schema',
83
+ name: 'RFCXML Schema Information',
84
+ description: 'RFCXML v3 の構造とスキーマ情報',
85
+ mimeType: 'application/json',
86
+ },
87
+ ],
88
+ };
89
+ });
90
+ // リソース読み取り
91
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
92
+ const { uri } = request.params;
93
+ if (uri === 'rfcxml://schema') {
94
+ return {
95
+ contents: [
96
+ {
97
+ uri,
98
+ mimeType: 'application/json',
99
+ text: JSON.stringify({
100
+ version: 'v3',
101
+ spec: 'RFC 7991 (superseded by rfc7991bis)',
102
+ documentation: 'https://authors.ietf.org/rfcxml-vocabulary',
103
+ keyElements: {
104
+ bcp14: 'RFC 2119 キーワード(MUST, SHOULD, MAY 等)をマークアップ',
105
+ xref: '内部・外部参照',
106
+ reference: '参考文献',
107
+ section: 'セクション構造',
108
+ t: 'テキストパラグラフ',
109
+ dl: '定義リスト',
110
+ sourcecode: 'ソースコード',
111
+ },
112
+ }, null, 2),
113
+ },
114
+ ],
115
+ };
116
+ }
117
+ throw new Error(`Unknown resource: ${uri}`);
118
+ });
119
+ // サーバー起動
120
+ async function main() {
121
+ const transport = new StdioServerTransport();
122
+ await server.connect(transport);
123
+ console.error('RFCXML MCP Server started');
124
+ }
125
+ main().catch((error) => {
126
+ console.error('Server error:', error);
127
+ process.exit(1);
128
+ });
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,aAAa;AACb,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;CACjB,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;KACd;CACF,CACF,CAAC;AAEF,QAAQ;AACR,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IAC1D,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC,CAAC,CAAC;AAEH,QAAQ;AACR,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAEjD,IAAI,CAAC;QACH,IAAI,MAAe,CAAC;QAEpB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,mBAAmB;gBACtB,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAW,CAAC,CAAC;gBAClD,MAAM;YAER,KAAK,kBAAkB;gBACrB,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAW,CAAC,CAAC;gBAClD,MAAM;YAER,KAAK,iBAAiB;gBACpB,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAW,CAAC,CAAC;gBACjD,MAAM;YAER,KAAK,sBAAsB;gBACzB,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAW,CAAC,CAAC;gBAClD,MAAM;YAER,KAAK,sBAAsB;gBACzB,MAAM,GAAG,MAAM,wBAAwB,CAAC,IAAW,CAAC,CAAC;gBACrD,MAAM;YAER,KAAK,oBAAoB;gBACvB,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAW,CAAC,CAAC;gBACpD,MAAM;YAER,KAAK,oBAAoB;gBACvB,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAW,CAAC,CAAC;gBACpD,MAAM;YAER;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC;aACF;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;iBAClD;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mBAAmB;AACnB,MAAM,CAAC,iBAAiB,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;IAC9D,OAAO;QACL,SAAS,EAAE;YACT;gBACE,GAAG,EAAE,iBAAiB;gBACtB,IAAI,EAAE,2BAA2B;gBACjC,WAAW,EAAE,sBAAsB;gBACnC,QAAQ,EAAE,kBAAkB;aAC7B;SACF;KACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,WAAW;AACX,MAAM,CAAC,iBAAiB,CAAC,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IACpE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAE/B,IAAI,GAAG,KAAK,iBAAiB,EAAE,CAAC;QAC9B,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG;oBACH,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;wBACE,OAAO,EAAE,IAAI;wBACb,IAAI,EAAE,qCAAqC;wBAC3C,aAAa,EAAE,4CAA4C;wBAC3D,WAAW,EAAE;4BACX,KAAK,EAAE,4CAA4C;4BACnD,IAAI,EAAE,SAAS;4BACf,SAAS,EAAE,MAAM;4BACjB,OAAO,EAAE,SAAS;4BAClB,CAAC,EAAE,WAAW;4BACd,EAAE,EAAE,OAAO;4BACX,UAAU,EAAE,QAAQ;yBACrB;qBACF,EACD,IAAI,EACJ,CAAC,CACF;iBACF;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,SAAS;AACT,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,2BAA2B,CAAC,CAAC;AAC7C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * RFC 取得サービス
3
+ * RFCXML ソースの取得とキャッシュ管理
4
+ */
5
+ import type { RFCMetadata } from '../types/index.js';
6
+ /**
7
+ * RFCXML を取得
8
+ */
9
+ export declare function fetchRFCXML(rfcNumber: number): Promise<string>;
10
+ /**
11
+ * RFC メタデータを取得(IETF Datatracker API)
12
+ */
13
+ export declare function fetchRFCMetadata(rfcNumber: number): Promise<RFCMetadata>;
14
+ /**
15
+ * RFC テキストを取得
16
+ */
17
+ export declare function fetchRFCText(rfcNumber: number): Promise<string>;
18
+ /**
19
+ * RFC が XML 形式で利用可能か確認
20
+ * 注: RFC 8650 (2019年12月) 以降は公式に RFCXML v3
21
+ */
22
+ export declare function isRFCXMLAvailable(rfcNumber: number): boolean;
23
+ /**
24
+ * RFC XML 取得エラー
25
+ */
26
+ export declare class RFCXMLNotAvailableError extends Error {
27
+ readonly rfcNumber: number;
28
+ readonly isOldRFC: boolean;
29
+ readonly suggestion: string;
30
+ constructor(rfcNumber: number, originalErrors?: string[]);
31
+ }
32
+ /**
33
+ * キャッシュクリア
34
+ */
35
+ export declare function clearCache(): void;
36
+ //# sourceMappingURL=rfc-fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfc-fetcher.d.ts","sourceRoot":"","sources":["../../src/services/rfc-fetcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA6BrD;;GAEG;AACH,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCpE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoD9E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAI5D;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,QAAQ,EAAE,OAAO,CAAC;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,SAAS,EAAE,MAAM,EAAE,cAAc,GAAE,MAAM,EAAO;CAmB7D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * RFC 取得サービス
3
+ * RFCXML ソースの取得とキャッシュ管理
4
+ */
5
+ // キャッシュ(メモリ内)
6
+ const xmlCache = new Map();
7
+ const textCache = new Map();
8
+ const metadataCache = new Map();
9
+ /**
10
+ * RFC XML ソースの取得元
11
+ */
12
+ const RFC_XML_SOURCES = {
13
+ // RFC Editor 公式
14
+ rfcEditor: (num) => `https://www.rfc-editor.org/rfc/rfc${num}.xml`,
15
+ // IETF Tools
16
+ ietfTools: (num) => `https://xml2rfc.ietf.org/public/rfc/rfc${num}.xml`,
17
+ // Datatracker
18
+ datatracker: (num) => `https://datatracker.ietf.org/doc/rfc${num}/xml/`,
19
+ };
20
+ /**
21
+ * RFC テキストソースの取得元
22
+ */
23
+ const RFC_TEXT_SOURCES = {
24
+ // RFC Editor 公式(テキスト)
25
+ rfcEditor: (num) => `https://www.rfc-editor.org/rfc/rfc${num}.txt`,
26
+ // IETF Tools
27
+ ietfTools: (num) => `https://tools.ietf.org/rfc/rfc${num}.txt`,
28
+ };
29
+ /**
30
+ * RFCXML を取得
31
+ */
32
+ export async function fetchRFCXML(rfcNumber) {
33
+ // キャッシュチェック
34
+ const cached = xmlCache.get(rfcNumber);
35
+ if (cached) {
36
+ return cached;
37
+ }
38
+ // 複数ソースを試行
39
+ const errors = [];
40
+ for (const [sourceName, urlFn] of Object.entries(RFC_XML_SOURCES)) {
41
+ try {
42
+ const url = urlFn(rfcNumber);
43
+ const response = await fetch(url, {
44
+ headers: {
45
+ Accept: 'application/xml, text/xml',
46
+ 'User-Agent': 'rfcxml-mcp/0.1.0',
47
+ },
48
+ });
49
+ if (response.ok) {
50
+ const xml = await response.text();
51
+ // 基本的な XML 検証
52
+ if (xml.includes('<?xml') || xml.includes('<rfc')) {
53
+ xmlCache.set(rfcNumber, xml);
54
+ console.error(`[RFC ${rfcNumber}] Fetched from ${sourceName}`);
55
+ return xml;
56
+ }
57
+ }
58
+ }
59
+ catch (error) {
60
+ errors.push(error);
61
+ }
62
+ }
63
+ // すべて失敗した場合
64
+ throw new RFCXMLNotAvailableError(rfcNumber, errors.map((e) => e.message));
65
+ }
66
+ /**
67
+ * RFC メタデータを取得(IETF Datatracker API)
68
+ */
69
+ export async function fetchRFCMetadata(rfcNumber) {
70
+ // キャッシュチェック
71
+ const cached = metadataCache.get(rfcNumber);
72
+ if (cached) {
73
+ return cached;
74
+ }
75
+ const url = `https://datatracker.ietf.org/api/v1/doc/document/rfc${rfcNumber}/`;
76
+ try {
77
+ const response = await fetch(url, {
78
+ headers: {
79
+ Accept: 'application/json',
80
+ 'User-Agent': 'rfcxml-mcp/0.1.0',
81
+ },
82
+ });
83
+ if (!response.ok) {
84
+ throw new Error(`HTTP ${response.status}`);
85
+ }
86
+ const data = (await response.json());
87
+ const metadata = {
88
+ number: rfcNumber,
89
+ title: data.title || `RFC ${rfcNumber}`,
90
+ authors: [], // TODO: 別 API から取得
91
+ date: data.time || '',
92
+ category: mapCategory(data.std_level ?? null),
93
+ stream: mapStream(data.stream ?? null),
94
+ abstract: data.abstract || undefined,
95
+ };
96
+ metadataCache.set(rfcNumber, metadata);
97
+ return metadata;
98
+ }
99
+ catch (_error) {
100
+ // フォールバック: 最小限のメタデータ
101
+ return {
102
+ number: rfcNumber,
103
+ title: `RFC ${rfcNumber}`,
104
+ authors: [],
105
+ date: '',
106
+ category: 'info',
107
+ stream: 'IETF',
108
+ };
109
+ }
110
+ }
111
+ /**
112
+ * RFC テキストを取得
113
+ */
114
+ export async function fetchRFCText(rfcNumber) {
115
+ // キャッシュチェック
116
+ const cached = textCache.get(rfcNumber);
117
+ if (cached) {
118
+ return cached;
119
+ }
120
+ // 複数ソースを試行
121
+ const errors = [];
122
+ for (const [sourceName, urlFn] of Object.entries(RFC_TEXT_SOURCES)) {
123
+ try {
124
+ const url = urlFn(rfcNumber);
125
+ const response = await fetch(url, {
126
+ headers: {
127
+ Accept: 'text/plain',
128
+ 'User-Agent': 'rfcxml-mcp/0.1.0',
129
+ },
130
+ });
131
+ if (response.ok) {
132
+ const text = await response.text();
133
+ // 基本的な検証(RFCテキストの特徴を確認)
134
+ if (text.includes('Request for Comments') || text.includes('RFC ')) {
135
+ textCache.set(rfcNumber, text);
136
+ console.error(`[RFC ${rfcNumber}] Text fetched from ${sourceName}`);
137
+ return text;
138
+ }
139
+ }
140
+ }
141
+ catch (error) {
142
+ errors.push(error);
143
+ }
144
+ }
145
+ // すべて失敗
146
+ throw new Error(`Failed to fetch RFC ${rfcNumber} text from all sources. ` +
147
+ `Errors: ${errors.map((e) => e.message).join(', ')}`);
148
+ }
149
+ /**
150
+ * RFC が XML 形式で利用可能か確認
151
+ * 注: RFC 8650 (2019年12月) 以降は公式に RFCXML v3
152
+ */
153
+ export function isRFCXMLAvailable(rfcNumber) {
154
+ // RFC 8650 以降は確実に RFCXML v3 が利用可能
155
+ // それ以前は一部のみ利用可能
156
+ return rfcNumber >= 8650;
157
+ }
158
+ /**
159
+ * RFC XML 取得エラー
160
+ */
161
+ export class RFCXMLNotAvailableError extends Error {
162
+ rfcNumber;
163
+ isOldRFC;
164
+ suggestion;
165
+ constructor(rfcNumber, originalErrors = []) {
166
+ const isOldRFC = rfcNumber < 8650;
167
+ const suggestion = isOldRFC
168
+ ? `RFC ${rfcNumber} は RFCXML v3 より前の形式で公開されているため、XML が利用できない可能性があります。` +
169
+ `テキスト形式での取得を検討してください(ietf MCP の get_ietf_doc を使用)。`
170
+ : `RFC ${rfcNumber} の XML 取得に失敗しました。ネットワーク接続を確認してください。`;
171
+ super(`RFC ${rfcNumber} XML を取得できませんでした。\n` +
172
+ `理由: ${isOldRFC ? '古い RFC (< 8650) のため XML が利用できない可能性があります' : 'ネットワークエラー'}\n` +
173
+ `提案: ${suggestion}` +
174
+ (originalErrors.length > 0 ? `\n詳細: ${originalErrors.join(', ')}` : ''));
175
+ this.name = 'RFCXMLNotAvailableError';
176
+ this.rfcNumber = rfcNumber;
177
+ this.isOldRFC = isOldRFC;
178
+ this.suggestion = suggestion;
179
+ }
180
+ }
181
+ /**
182
+ * キャッシュクリア
183
+ */
184
+ export function clearCache() {
185
+ xmlCache.clear();
186
+ textCache.clear();
187
+ metadataCache.clear();
188
+ }
189
+ // ヘルパー関数
190
+ function mapCategory(stdLevel) {
191
+ switch (stdLevel?.toLowerCase()) {
192
+ case 'proposed standard':
193
+ case 'draft standard':
194
+ case 'internet standard':
195
+ return 'std';
196
+ case 'best current practice':
197
+ return 'bcp';
198
+ case 'experimental':
199
+ return 'exp';
200
+ case 'historic':
201
+ return 'historic';
202
+ default:
203
+ return 'info';
204
+ }
205
+ }
206
+ function mapStream(stream) {
207
+ switch (stream?.toLowerCase()) {
208
+ case 'ietf':
209
+ return 'IETF';
210
+ case 'iab':
211
+ return 'IAB';
212
+ case 'irtf':
213
+ return 'IRTF';
214
+ case 'ise':
215
+ return 'independent';
216
+ default:
217
+ return 'IETF';
218
+ }
219
+ }
220
+ //# sourceMappingURL=rfc-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfc-fetcher.js","sourceRoot":"","sources":["../../src/services/rfc-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * RFC テキストパーサー
3
+ * XMLが利用できない古いRFC用のフォールバック解析
4
+ */
5
+ import type { Section, Requirement, RequirementLevel } from '../types/index.js';
6
+ import type { ParsedRFC } from './rfcxml-parser.js';
7
+ /**
8
+ * RFC テキストをパースして構造化データに変換(中精度)
9
+ */
10
+ export declare function parseRFCText(text: string, rfcNumber: number): ParsedRFC;
11
+ /**
12
+ * テキストから要件を抽出
13
+ */
14
+ export declare function extractTextRequirements(sections: Section[], filter?: {
15
+ section?: string;
16
+ level?: RequirementLevel;
17
+ }): Requirement[];
18
+ //# sourceMappingURL=rfc-text-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfc-text-parser.d.ts","sourceRoot":"","sources":["../../src/services/rfc-text-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EACX,gBAAgB,EAIjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAmBpD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAYvE;AAyMD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,OAAO,EAAE,EACnB,MAAM,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;CAAE,GACtD,WAAW,EAAE,CA0Cf"}