@monoharada/wcf-mcp 0.9.1 → 0.11.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.1.0",
3
- "indexedAt": "2026-03-07T09:50:20.703Z",
3
+ "indexedAt": "2026-03-16T07:35:00.939Z",
4
4
  "documents": [
5
5
  {
6
6
  "id": ".claude/skills/css-writing-rules/references/core-principles.md",
@@ -4271,14 +4271,71 @@
4271
4271
  "カスタムツール定義の配列",
4272
4272
  "tools",
4273
4273
  "wcfmcpplugintool",
4274
- "データソース差し替え定義の配列",
4275
- "datasources",
4276
- "wcfmcpdatasourceconfig"
4274
+ "validate_",
4275
+ "系に差し込む",
4276
+ "validator",
4277
+ "hook"
4277
4278
  ],
4278
- "snippet": "```typescript\n/** プラグイン定義 */\ninterface WcfMcpPlugin {\n /** プラグイン名(必須。組み込みツール名と重複不可) */\n name: string;\n /** プラグインバージョン(必須。semver 推奨) */\n version: string;\n /** カスタムツール定義の配列 */\n tools?: WcfMcpPluginTool[];\n /** データソース差し替え定義の配列 */\n dataSources?: WcfMcpDataSourceConfig[];\n}\n```",
4279
+ "snippet": "```typescript\n/** プラグイン定義 */\ninterface WcfMcpPlugin {\n /** プラグイン名(必須。組み込みツール名と重複不可) */\n name: string;\n /** プラグインバージョン(必須。semver 推奨) */\n version: string;\n /** カスタムツール定義の配列 */\n tools?: WcfMcpPluginTool[];\n /** validate_* 系に差し込む validator hook */\n validators?: WcfMcpPluginValidator[];\n /** 追加 prompt */\n prompts?: WcfMcpPluginPrompt[];\n /** 追加 resource */\n resources?: WcfMcpPluginResource[];\n /** 追加 resource template */\n resourceTemplates?: WcfMcpPluginResourceTemplate[];\n /** データソース差",
4279
4280
  "body": "",
4280
4281
  "startLine": 9
4281
4282
  },
4283
+ {
4284
+ "heading": "Validator オブジェクト",
4285
+ "keywords": [
4286
+ "validator",
4287
+ "オブジェクト",
4288
+ "typescript",
4289
+ "interface",
4290
+ "wcfmcppluginvalidator",
4291
+ "plugin",
4292
+ "内で一意",
4293
+ "name",
4294
+ "string",
4295
+ "description",
4296
+ "診断配列または",
4297
+ "diagnostics",
4298
+ "を返す",
4299
+ "handler",
4300
+ "input",
4301
+ "filepath",
4302
+ "text",
4303
+ "prefix",
4304
+ "context",
4305
+ "wcfmcphandlercontext"
4306
+ ],
4307
+ "snippet": "```typescript\ninterface WcfMcpPluginValidator {\n /** validator 名(plugin 内で一意) */\n name: string;\n /** 説明 */\n description?: string;\n /** 診断配列または { diagnostics } を返す */\n handler: (\n input: { filePath: string; text: string; prefix: string },\n context: WcfMcpHandlerContext\n ) => Array<Record<string, unknown>> | { diagnostics: Array<Record<string, unknown>> } | Promise<Array<Record<string, unknown>> | { diagnostics: Array<Record<string, unknown>> }>;\n}\n```\n\n### validator hook\n\n- `validate",
4308
+ "body": "### validator hook - `validate_markup` - `validate_files` - `validate_project` 上記 3 tool 実行時に、各 plugin validator が追加診断を返せます。 - `severity` 未指定時は `warning` - `file` 未指定時は対象ファイルへ自動補完 - 失敗した validator は `pluginValidatorRuntimeError` warning として返却",
4309
+ "startLine": 33
4310
+ },
4311
+ {
4312
+ "heading": "Prompt / Resource オブジェクト",
4313
+ "keywords": [
4314
+ "prompt",
4315
+ "resource",
4316
+ "オブジェクト",
4317
+ "typescript",
4318
+ "interface",
4319
+ "wcfmcppluginprompt",
4320
+ "name",
4321
+ "string",
4322
+ "title",
4323
+ "description",
4324
+ "argsschema",
4325
+ "record",
4326
+ "unknown",
4327
+ "zod",
4328
+ "raw",
4329
+ "shape",
4330
+ "plain",
4331
+ "handler",
4332
+ "args",
4333
+ "context"
4334
+ ],
4335
+ "snippet": "```typescript\ninterface WcfMcpPluginPrompt {\n name: string;\n title?: string;\n description?: string;\n argsSchema?: Record<string, unknown>; // zod raw shape or plain shape\n handler?: (args: Record<string, unknown>, context: WcfMcpHandlerContext) => string | { messages: Array<Record<string, unknown>> } | Promise<string | { messages: Array<Record<string, unknown>> }>;\n text?: string;\n}\n\ninterface WcfMcpPluginResource {\n name: string;\n uri: string;\n title?: string;\n description?: string;\n ",
4336
+ "body": "- prompt は `handler` または `text` が必須 - resource は `handler` / `text` / `payload` のいずれかが必須 - resourceTemplate も `handler` / `text` / `payload` のいずれかが必須 - prompt 名は組み込み prompt と重複不可 - resource URI は組み込み resource URI と重複不可 - resource template URI は組み込み template URI と重複不可",
4337
+ "startLine": 61
4338
+ },
4282
4339
  {
4283
4340
  "heading": "Tool オブジェクト",
4284
4341
  "keywords": [
@@ -4305,7 +4362,7 @@
4305
4362
  ],
4306
4363
  "snippet": "```typescript\n/** カスタムツール定義 */\ninterface WcfMcpPluginTool {\n /** ツール名(必須。組み込みツール名と重複不可) */\n name: string;\n /** ツールの説明 */\n description?: string;\n /** 入力スキーマ(JSON Schema 形式) */\n inputSchema?: Record<string, unknown>;\n /** 動的ハンドラ関数。両方指定時は handler が優先される */\n handler?: (args: Record<string, unknown>, context: WcfMcpHandlerContext) => unknown | Promise<unknown>;\n /** 静的レスポンスペイロード。handler がある場合は無視される */\n staticPayload?: unknown;\n}\n```\n\n### handler vs staticPayload\n\n- `handler`: リクエストごとに実行される関",
4307
4364
  "body": "### handler vs staticPayload - `handler`: リクエストごとに実行される関数。動的な結果を返す場合に使用 - `staticPayload`: 固定のレスポンスを返す場合に使用 - **両方指定した場合**: `handler` が優先され、`staticPayload` は無視される - **どちらも未指定**: バリデーションエラー(少なくとも一方が必須) - `handler` は plain payload のほか raw MCP result(`{ content: [...] }`)を返してもよい - ただし最終返却サイズには 100KB 上限が適用され、上限を超える raw result は `TOOL_RESULT_TOO_LARGE` warning payload に置き換わる",
4308
- "startLine": 25
4365
+ "startLine": 108
4309
4366
  },
4310
4367
  {
4311
4368
  "heading": "Handler Context",
@@ -4333,7 +4390,7 @@
4333
4390
  ],
4334
4391
  "snippet": "```typescript\n/** handler 関数に渡されるコンテキスト */\ninterface WcfMcpHandlerContext {\n /** プラグイン自身の情報 */\n plugin: { name: string; version: string };\n /** 共通ヘルパー */\n helpers: {\n /** JSON データファイルを読み込む */\n loadJsonData: (fileName: string) => Promise<unknown>;\n /** テキストデータファイルを読み込む (v1.1+) */\n loadTextData: (fileName: string) => Promise<string>;\n /** ツール応答を MCP 形式の JSON テキストに変換する */\n buildJsonToolResponse: (payload: unknown) => { content: Array<{ type: string; text: string }> };\n /** ",
4335
4392
  "body": "",
4336
- "startLine": 52
4393
+ "startLine": 135
4337
4394
  },
4338
4395
  {
4339
4396
  "heading": "DataSource オブジェクト",
@@ -4359,9 +4416,9 @@
4359
4416
  "manifest",
4360
4417
  "install-registry"
4361
4418
  ],
4362
- "snippet": "```typescript\n/** データソース差し替え定義 */\ninterface WcfMcpDataSourceConfig {\n /** 差し替え対象のファイル名 */\n fileName: string;\n /** 差し替えファイルのパス */\n path: string;\n}\n```\n\n### 差し替え可能なファイル\n\n| fileName | 説明 |\n|----------|------|\n| `custom-elements.json` | Custom Elements Manifest |\n| `install-registry.json` | インストールレジストリ |\n| `pattern-registry.json` | パターンレジストリ |\n| `design-tokens.json` | デザイントークン |\n| `guidelines-index.json` | ガイドラインインデックス |",
4363
- "body": "### 差し替え可能なファイル | fileName | 説明 | |----------|------| | `custom-elements.json` | Custom Elements Manifest | | `install-registry.json` | インストールレジストリ | | `pattern-registry.json` | パターンレジストリ | | `design-tokens.json` | デザイントークン | | `guidelines-index.json` | ガイドラインインデックス |",
4364
- "startLine": 77
4419
+ "snippet": "```typescript\n/** データソース差し替え定義 */\ninterface WcfMcpDataSourceConfig {\n /** 差し替え対象のファイル名 */\n fileName: string;\n /** 差し替えファイルのパス */\n path: string;\n}\n```\n\n### 差し替え可能なファイル\n\n| fileName | 説明 |\n|----------|------|\n| `custom-elements.json` | Custom Elements Manifest |\n| `install-registry.json` | インストールレジストリ |\n| `pattern-registry.json` | パターンレジストリ |\n| `component-selector-guide.json` | コンポーネント選択ガイド |\n| `design-tokens.json` | デザイントークン |\n| `guidelines-index.json` | ガイドラインインデックス |\n| `skills-registry.json`",
4420
+ "body": "### 差し替え可能なファイル | fileName | 説明 | |----------|------| | `custom-elements.json` | Custom Elements Manifest | | `install-registry.json` | インストールレジストリ | | `pattern-registry.json` | パターンレジストリ | | `component-selector-guide.json` | コンポーネント選択ガイド | | `design-tokens.json` | デザイントークン | | `guidelines-index.json` | ガイドラインインデックス | | `skills-registry.json` | スキルレジストリ | | `llms-full.txt` | LLM 向け全文リファレンス |",
4421
+ "startLine": 160
4365
4422
  },
4366
4423
  {
4367
4424
  "heading": "バリデーションルール",
@@ -4373,12 +4430,12 @@
4373
4430
  "ツール名は組み込みツール名と重複不可",
4374
4431
  "複数プラグイン間でツール名の重複不可",
4375
4432
  "datasources",
4376
- "のファイル名は上記5種のみ",
4433
+ "のファイル名は上記8種のみ",
4377
4434
  "複数プラグイン間で同一ファイルの重複差し替え不可"
4378
4435
  ],
4379
- "snippet": "1. `name` と `version` は必須\n2. ツール名は組み込みツール名と重複不可\n3. 複数プラグイン間でツール名の重複不可\n4. `dataSources` のファイル名は上記5種のみ\n5. 複数プラグイン間で同一ファイルの重複差し替え不可",
4380
- "body": "1. `name` と `version` は必須 2. ツール名は組み込みツール名と重複不可 3. 複数プラグイン間でツール名の重複不可 4. `dataSources` のファイル名は上記5種のみ 5. 複数プラグイン間で同一ファイルの重複差し替え不可",
4381
- "startLine": 99
4436
+ "snippet": "1. `name` と `version` は必須\n2. ツール名は組み込みツール名と重複不可\n3. 複数プラグイン間でツール名の重複不可\n4. `dataSources` のファイル名は上記8種のみ\n5. 複数プラグイン間で同一ファイルの重複差し替え不可",
4437
+ "body": "1. `name` と `version` は必須 2. ツール名は組み込みツール名と重複不可 3. 複数プラグイン間でツール名の重複不可 4. `dataSources` のファイル名は上記8種のみ 5. 複数プラグイン間で同一ファイルの重複差し替え不可",
4438
+ "startLine": 185
4382
4439
  },
4383
4440
  {
4384
4441
  "heading": "互換性ポリシー",
@@ -4391,15 +4448,22 @@
4391
4448
  "loadtextdata",
4392
4449
  "テキストファイルの読み込み",
4393
4450
  "utf-8",
4394
- "破壊的変更なし",
4395
- "新フィールドは追加のみ",
4396
- "既存フィールドの削除・型変更なし",
4397
- "破壊的変更を含む可能性あり",
4398
- "メジャーバージョンアップで通知"
4451
+ "validators",
4452
+ "validate_",
4453
+ "tool",
4454
+ "へ差し込む",
4455
+ "validator",
4456
+ "hook",
4457
+ "prompts",
4458
+ "resources",
4459
+ "plugin",
4460
+ "mcp",
4461
+ "prompt",
4462
+ "resource"
4399
4463
  ],
4400
- "snippet": "- **契約バージョン**: `1.1.0`(`PLUGIN_CONTRACT_VERSION` 定数で公開)\n- **v1.1 追加**: `helpers.loadTextData` — テキストファイルの読み込み(UTF-8)\n- **v1.x 内**: 破壊的変更なし。新フィールドは追加のみ(既存フィールドの削除・型変更なし)\n- **v2.0**: 破壊的変更を含む可能性あり。メジャーバージョンアップで通知",
4401
- "body": "- **契約バージョン**: `1.1.0`(`PLUGIN_CONTRACT_VERSION` 定数で公開) - **v1.1 追加**: `helpers.loadTextData` — テキストファイルの読み込み(UTF-8) - **v1.x 内**: 破壊的変更なし。新フィールドは追加のみ(既存フィールドの削除・型変更なし) - **v2.0**: 破壊的変更を含む可能性あり。メジャーバージョンアップで通知",
4402
- "startLine": 107
4464
+ "snippet": "- **契約バージョン**: `1.4.0`(`PLUGIN_CONTRACT_VERSION` 定数で公開)\n- **v1.1 追加**: `helpers.loadTextData` — テキストファイルの読み込み(UTF-8)\n- **v1.2 追加**: `validators` — validate_* tool へ差し込む validator hook\n- **v1.3 追加**: `prompts`, `resources` — plugin から MCP prompt/resource を追加\n- **v1.4 追加**: `resourceTemplates`, prompt の richer `argsSchema` shape\n- **v1.x 内**: 破壊的変更なし。新フィールドは追加のみ(既存フィールドの削除・型変更なし)\n- **v2.0**: 破壊的変更を含む可能性あり。メジャーバージョンアップで通知",
4465
+ "body": "- **契約バージョン**: `1.4.0`(`PLUGIN_CONTRACT_VERSION` 定数で公開) - **v1.1 追加**: `helpers.loadTextData` — テキストファイルの読み込み(UTF-8) - **v1.2 追加**: `validators` — validate_* tool へ差し込む validator hook - **v1.3 追加**: `prompts`, `resources` — plugin から MCP prompt/resource を追加 - **v1.4 追加**: `resourceTemplates`, prompt の richer `argsSchema` shape - **v1.x 内**: 破壊的変更なし。新フィールドは追加のみ(既存フィールドの削除・型変更なし) - **v2.0**: 破壊的変更を含む可能性あり。メジャーバージョンアップで通知",
4466
+ "startLine": 193
4403
4467
  },
4404
4468
  {
4405
4469
  "heading": "@experimental 機能",
@@ -4414,7 +4478,7 @@
4414
4478
  ],
4415
4479
  "snippet": "以下は将来追加される可能性がありますが、まだ安定していません:\n\n- ライフサイクルフック(`onInit`, `onDestroy`)\n- プラグイン間依存の宣言",
4416
4480
  "body": "以下は将来追加される可能性がありますが、まだ安定していません: - ライフサイクルフック(`onInit`, `onDestroy`) - プラグイン間依存の宣言",
4417
- "startLine": 114
4481
+ "startLine": 203
4418
4482
  },
4419
4483
  {
4420
4484
  "heading": "設定ファイルからの利用",
@@ -4442,7 +4506,7 @@
4442
4506
  ],
4443
4507
  "snippet": "```json\n{\n \"plugins\": [\n {\n \"module\": \"./plugins/my-plugin.mjs\"\n },\n {\n \"name\": \"static-tools\",\n \"version\": \"1.0.0\",\n \"staticTools\": [\n { \"name\": \"my_tool\", \"payload\": { \"ok\": true } }\n ]\n }\n ]\n}\n```\n\n### module プラグイン\n\nESM ファイルが `default export` でプラグインオブジェクトを返す:\n\n```javascript\n// plugins/my-plugin.mjs\nexport default {\n name: 'my-plugin',\n version: '1.0.0',\n tools: [\n {\n name: 'my_custom_tool',\n description: 'Custom tool from plugin',\n",
4444
4508
  "body": "### module プラグイン ESM ファイルが `default export` でプラグインオブジェクトを返す:",
4445
- "startLine": 121
4509
+ "startLine": 210
4446
4510
  }
4447
4511
  ]
4448
4512
  },
@@ -2,6 +2,9 @@
2
2
  * Sample plugin for wcf-mcp (Plugin Contract v1).
3
3
  * Demonstrates:
4
4
  * - Custom tool with handler
5
+ * - Validator hook used by validate_markup / validate_files / validate_project
6
+ * - Static prompt and resource hooks
7
+ * - Resource template hook
5
8
  * - Custom tool using handler context (helpers.loadJsonData)
6
9
  * - dataSources override for guidelines-index.json
7
10
  */
@@ -33,6 +36,64 @@ export default {
33
36
  path: './custom-guidelines.json',
34
37
  },
35
38
  ],
39
+ validators: [
40
+ {
41
+ name: 'heading_structure',
42
+ description: 'Warn on skipped heading levels during validate_* flows.',
43
+ async handler({ text, filePath }) {
44
+ const diagnostics = detectSkippedHeadingLevel(text).map((item) => ({
45
+ file: filePath,
46
+ severity: 'warning',
47
+ code: item.code,
48
+ message: item.message,
49
+ hint: 'Use sequential heading levels (e.g. h2 -> h3).',
50
+ }));
51
+ return { diagnostics };
52
+ },
53
+ },
54
+ ],
55
+ prompts: [
56
+ {
57
+ name: 'custom_validation_workflow',
58
+ title: 'Custom Validation Workflow',
59
+ argsSchema: {
60
+ audience: {
61
+ type: 'string',
62
+ description: 'Optional audience label',
63
+ },
64
+ },
65
+ text: 'Run validate_markup, then validate_files for page-level issues, then inspect custom guidelines.',
66
+ },
67
+ ],
68
+ resources: [
69
+ {
70
+ name: 'custom_validation_notes',
71
+ uri: 'plugin://custom-validation/notes',
72
+ mimeType: 'text/plain',
73
+ text: 'Custom validation plugin loaded. Use validate_heading_structure for manual checks.',
74
+ },
75
+ ],
76
+ resourceTemplates: [
77
+ {
78
+ name: 'custom_guideline_template',
79
+ uriTemplate: 'plugin://custom-validation/guidelines/{slug}',
80
+ complete: {
81
+ slug: ['headings', 'forms'],
82
+ },
83
+ async handler({ uri, variables }) {
84
+ return {
85
+ contents: [{
86
+ uri,
87
+ mimeType: 'application/json',
88
+ text: JSON.stringify({
89
+ slug: variables?.slug ?? '',
90
+ note: 'Custom guideline template resource',
91
+ }, null, 2),
92
+ }],
93
+ };
94
+ },
95
+ },
96
+ ],
36
97
  tools: [
37
98
  {
38
99
  name: 'validate_heading_structure',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoharada/wcf-mcp",
3
- "version": "0.9.1",
3
+ "version": "0.11.0",
4
4
  "description": "MCP server for the web-components-factory design system. Provides component discovery, validation, and pattern-based UI composition without cloning the repository.",
5
5
  "type": "module",
6
6
  "bin": {
package/runtime-data.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
3
4
 
4
5
  export const RUNTIME_FILE_MAP = Object.freeze({
5
6
  'custom-elements.json': 'custom-elements.json',
@@ -31,6 +32,33 @@ async function readTextIfExists(targetPath) {
31
32
  }
32
33
  }
33
34
 
35
+ async function loadGeneratedJsonFallback(fileName, { repoRoot }) {
36
+ const generators = {
37
+ 'design-tokens.json': {
38
+ modulePath: path.join(repoRoot, 'scripts/mcp/extract-design-tokens.mjs'),
39
+ exportName: 'buildDesignTokensData',
40
+ },
41
+ 'guidelines-index.json': {
42
+ modulePath: path.join(repoRoot, 'scripts/mcp/index-guidelines.mjs'),
43
+ exportName: 'buildGuidelinesIndexData',
44
+ },
45
+ };
46
+
47
+ const generator = generators[fileName];
48
+ if (!generator) return null;
49
+
50
+ try {
51
+ await fs.access(generator.modulePath);
52
+ } catch {
53
+ return null;
54
+ }
55
+
56
+ const loaded = await import(pathToFileURL(generator.modulePath).href);
57
+ const build = loaded?.[generator.exportName];
58
+ if (typeof build !== 'function') return null;
59
+ return build();
60
+ }
61
+
34
62
  export async function loadTextDataWithFallback(fileName, { bundledDir, repoRoot = process.cwd() } = {}) {
35
63
  const bundled = resolveBundledDataPath(fileName, { bundledDir });
36
64
  const repo = resolveRuntimeDataPath(fileName, { repoRoot });
@@ -44,12 +72,20 @@ export async function loadTextDataWithFallback(fileName, { bundledDir, repoRoot
44
72
  }
45
73
 
46
74
  export async function loadJsonDataWithFallback(fileName, options = {}) {
47
- const text = await loadTextDataWithFallback(fileName, options);
48
75
  try {
49
- return JSON.parse(text);
76
+ const text = await loadTextDataWithFallback(fileName, options);
77
+ try {
78
+ return JSON.parse(text);
79
+ } catch (error) {
80
+ throw new Error(
81
+ `データファイルのJSON解析に失敗しました: ${fileName} (${error instanceof Error ? error.message : String(error)})`,
82
+ );
83
+ }
50
84
  } catch (error) {
51
- throw new Error(
52
- `データファイルのJSON解析に失敗しました: ${fileName} (${error instanceof Error ? error.message : String(error)})`,
53
- );
85
+ const generated = await loadGeneratedJsonFallback(fileName, {
86
+ repoRoot: options.repoRoot ?? process.cwd(),
87
+ });
88
+ if (generated !== null) return generated;
89
+ throw error;
54
90
  }
55
91
  }
package/server.mjs CHANGED
@@ -197,6 +197,10 @@ export async function loadJsonDataFromPath(sourcePath) {
197
197
  return JSON.parse(text);
198
198
  }
199
199
 
200
+ export async function loadTextDataFromPath(sourcePath) {
201
+ return fs.readFile(sourcePath, 'utf8');
202
+ }
203
+
200
204
  // ---------------------------------------------------------------------------
201
205
  // Public API
202
206
  // ---------------------------------------------------------------------------
@@ -211,6 +215,7 @@ export async function createServer(options = {}) {
211
215
  return createMcpServer(loadJsonData, loadValidator, {
212
216
  plugins: runtimeConfig.plugins,
213
217
  loadJsonDataFromPath,
218
+ loadTextDataFromPath,
214
219
  loadTextData,
215
220
  });
216
221
  }