rulesync 0.34.0 → 0.37.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/README.ja.md CHANGED
@@ -60,10 +60,7 @@ yarn global add rulesync
60
60
 
61
61
  1. **既存設定をインポート:**
62
62
  ```bash
63
- # 複数のツールから一度にインポート
64
- npx rulesync import --claudecode --cursor --copilot
65
-
66
- # または特定のツールからインポート
63
+ # 特定のツールからインポート(一度に1つのツールのみ指定可能)
67
64
  npx rulesync import --claudecode # CLAUDE.mdと.claude/memories/*.mdから
68
65
  npx rulesync import --cursor # .cursorrulesと.cursor/rules/*.mdcから
69
66
  npx rulesync import --copilot # .github/copilot-instructions.mdから
@@ -226,8 +223,10 @@ npx rulesync import --cline # .cline/instructions.mdからインポート
226
223
  npx rulesync import --roo # .roo/instructions.mdからインポート
227
224
  npx rulesync import --geminicli # GEMINI.mdと.gemini/memories/*.mdからインポート
228
225
 
229
- # 複数のツールからインポート
230
- npx rulesync import --claudecode --cursor --copilot
226
+ # 各ツールを個別にインポート
227
+ npx rulesync import --claudecode
228
+ npx rulesync import --cursor
229
+ npx rulesync import --copilot
231
230
 
232
231
  # インポート時の詳細出力
233
232
  npx rulesync import --claudecode --verbose
@@ -278,6 +277,33 @@ npx rulesync gitignore
278
277
  └── custom.md # プロジェクト固有ルール (root: false)
279
278
  ```
280
279
 
280
+ ### .rulesyncignoreでファイルを除外
281
+
282
+ プロジェクトルートに`.rulesyncignore`ファイルを作成することで、特定のルールファイルを処理から除外できます。このファイルはgitignoreスタイルのパターンを使用します。
283
+
284
+ `.rulesyncignore`の例:
285
+ ```
286
+ # テスト用ルールファイルを無視
287
+ **/*.test.md
288
+
289
+ # 一時ファイルを無視
290
+ tmp/**/*
291
+
292
+ # ドラフトルールを無視
293
+ draft-*.md
294
+ *-draft.md
295
+ ```
296
+
297
+ `.rulesyncignore`が存在する場合、rulesyncは:
298
+ 1. 処理時にマッチするファイルをスキップ
299
+ 2. ツール固有のignoreファイルを生成:
300
+ - Cursor用の`.cursorignore`
301
+ - Cline用の`.clineignore`
302
+ - Roo Code用の`.rooignore`
303
+ - GitHub Copilot用の`.copilotignore`(コミュニティツール用)
304
+ - Gemini CLI用の`.aiexclude`
305
+ - Claude Code用に`.claude/settings.json`のpermissions.denyに`Read()`ルールを追加
306
+
281
307
  ### フロントマタースキーマ
282
308
 
283
309
  各ルールファイルには以下のフィールドを含むフロントマターが必要です:
@@ -348,6 +374,69 @@ npx rulesync validate
348
374
  - ファイルパターン(globs)が有効な構文を使用
349
375
  - ターゲットツールが認識される値である
350
376
 
377
+ ## MCP(Model Context Protocol)サポート
378
+
379
+ rulesyncは、対応するAIツール用のMCPサーバー設定も管理できます。これにより、言語サーバーやその他のMCP互換サービスを一度設定すれば、複数のAIコーディングアシスタントにデプロイできます。
380
+
381
+ ### MCPをサポートするツール
382
+
383
+ - **Claude Code** (`.mcp.json`)
384
+ - **GitHub Copilot** (`.vscode/mcp.json`)
385
+ - **Cursor** (`.cursor/mcp.json`)
386
+ - **Cline** (`.cline/mcp.json`)
387
+ - **Gemini CLI** (`.gemini/settings.json`)
388
+ - **Roo Code** (`.roo/mcp.json`)
389
+
390
+ ### MCP設定
391
+
392
+ プロジェクトに`.rulesync/.mcp.json`ファイルを作成:
393
+
394
+ ```json
395
+ {
396
+ "mcpServers": {
397
+ "github": {
398
+ "command": "docker",
399
+ "args": [
400
+ "run", "-i", "--rm",
401
+ "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
402
+ "ghcr.io/github/github-mcp-server"
403
+ ],
404
+ "env": {},
405
+ "rulesyncTargets": ["*"]
406
+ }
407
+ }
408
+ }
409
+ ```
410
+
411
+ ### MCP設定フィールド
412
+
413
+ - **`mcpServers`**: MCPサーバー設定を含むオブジェクト
414
+ - **`command`**: stdioベースのサーバー用の実行可能コマンド
415
+ - **`args`**: コマンド引数
416
+ - **`url`**: HTTP/SSEベースのサーバー用URL
417
+ - **`env`**: サーバーに渡す環境変数
418
+ - **`rulesyncTargets`**: このサーバーをデプロイするツール名の配列
419
+ - 特定のツール名を使用: `["claude", "cursor", "copilot"]`
420
+ - すべてのサポートツールにデプロイするには`["*"]`を使用
421
+ - 省略した場合、デフォルトですべてのツールにデプロイ
422
+
423
+ ### MCP設定の生成
424
+
425
+ MCP設定はルールファイルと一緒に生成されます:
426
+
427
+ ```bash
428
+ # ルールとMCP設定の両方を生成
429
+ npx rulesync generate
430
+
431
+ # 特定のツールのみ生成
432
+ npx rulesync generate --claudecode --cursor
433
+
434
+ # 特定のディレクトリに生成(monorepo)
435
+ npx rulesync generate --base-dir ./packages/frontend
436
+ ```
437
+
438
+ MCP設定は各ツールの適切な場所に生成され、ツールは起動時に自動的にそれらを読み込みます。
439
+
351
440
  ## ライセンス
352
441
 
353
442
  MIT License
package/README.md CHANGED
@@ -60,10 +60,7 @@ If you already have AI tool configurations, you can import them into rulesync fo
60
60
 
61
61
  1. **Import existing configurations:**
62
62
  ```bash
63
- # Import from multiple tools at once
64
- npx rulesync import --claudecode --cursor --copilot
65
-
66
- # Or import from specific tools
63
+ # Import from specific tools (only one tool can be specified at a time)
67
64
  npx rulesync import --claudecode # From CLAUDE.md and .claude/memories/*.md
68
65
  npx rulesync import --cursor # From .cursorrules and .cursor/rules/*.mdc
69
66
  npx rulesync import --copilot # From .github/copilot-instructions.md
@@ -226,8 +223,10 @@ npx rulesync import --cline # Import from .cline/instructions.md
226
223
  npx rulesync import --roo # Import from .roo/instructions.md
227
224
  npx rulesync import --geminicli # Import from GEMINI.md and .gemini/memories/*.md
228
225
 
229
- # Import from multiple tools
230
- npx rulesync import --claudecode --cursor --copilot
226
+ # Import each tool individually
227
+ npx rulesync import --claudecode
228
+ npx rulesync import --cursor
229
+ npx rulesync import --copilot
231
230
 
232
231
  # Verbose output during import
233
232
  npx rulesync import --claudecode --verbose
@@ -278,6 +277,33 @@ npx rulesync gitignore
278
277
  └── custom.md # Project-specific rules (root: false)
279
278
  ```
280
279
 
280
+ ### Excluding Files with .rulesyncignore
281
+
282
+ You can exclude specific rule files from being processed by creating a `.rulesyncignore` file in your project root. This file uses gitignore-style patterns.
283
+
284
+ Example `.rulesyncignore`:
285
+ ```
286
+ # Ignore test rule files
287
+ **/*.test.md
288
+
289
+ # Ignore temporary files
290
+ tmp/**/*
291
+
292
+ # Ignore draft rules
293
+ draft-*.md
294
+ *-draft.md
295
+ ```
296
+
297
+ When `.rulesyncignore` exists, rulesync will:
298
+ 1. Skip matching files during rule processing
299
+ 2. Generate tool-specific ignore files:
300
+ - `.cursorignore` for Cursor
301
+ - `.clineignore` for Cline
302
+ - `.rooignore` for Roo Code
303
+ - `.copilotignore` for GitHub Copilot (community tools)
304
+ - `.aiexclude` for Gemini CLI
305
+ - Update `.claude/settings.json` permissions.deny with `Read()` rules for Claude Code
306
+
281
307
  ### Frontmatter Schema
282
308
 
283
309
  Each rule file must include frontmatter with the following fields:
@@ -348,6 +374,69 @@ Common validation rules:
348
374
  - File patterns (globs) use valid syntax
349
375
  - Target tools are recognized values
350
376
 
377
+ ## MCP (Model Context Protocol) Support
378
+
379
+ rulesync can also manage MCP server configurations for supported AI tools. This allows you to configure language servers and other MCP-compatible services once and deploy them across multiple AI coding assistants.
380
+
381
+ ### Supported MCP Tools
382
+
383
+ - **Claude Code** (`.mcp.json`)
384
+ - **GitHub Copilot** (`.vscode/mcp.json`)
385
+ - **Cursor** (`.cursor/mcp.json`)
386
+ - **Cline** (`.cline/mcp.json`)
387
+ - **Gemini CLI** (`.gemini/settings.json`)
388
+ - **Roo Code** (`.roo/mcp.json`)
389
+
390
+ ### MCP Configuration
391
+
392
+ Create a `.rulesync/.mcp.json` file in your project:
393
+
394
+ ```json
395
+ {
396
+ "mcpServers": {
397
+ "github": {
398
+ "command": "docker",
399
+ "args": [
400
+ "run", "-i", "--rm",
401
+ "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
402
+ "ghcr.io/github/github-mcp-server"
403
+ ],
404
+ "env": {},
405
+ "rulesyncTargets": ["*"]
406
+ }
407
+ }
408
+ }
409
+ ```
410
+
411
+ ### MCP Configuration Fields
412
+
413
+ - **`mcpServers`**: Object containing MCP server configurations
414
+ - **`command`**: Executable command for stdio-based servers
415
+ - **`args`**: Command arguments
416
+ - **`url`**: URL for HTTP/SSE-based servers
417
+ - **`env`**: Environment variables to pass to the server
418
+ - **`rulesyncTargets`**: Array of tool names to deploy this server to
419
+ - Use specific tool names: `["claude", "cursor", "copilot"]`
420
+ - Use `["*"]` to deploy to all supported tools
421
+ - If omitted, server is deployed to all tools by default
422
+
423
+ ### Generating MCP Configurations
424
+
425
+ MCP configurations are generated alongside rule files:
426
+
427
+ ```bash
428
+ # Generate both rules and MCP configurations
429
+ npx rulesync generate
430
+
431
+ # Generate only for specific tools
432
+ npx rulesync generate --claudecode --cursor
433
+
434
+ # Generate in specific directories (monorepo)
435
+ npx rulesync generate --base-dir ./packages/frontend
436
+ ```
437
+
438
+ The MCP configurations will be generated in the appropriate locations for each tool, and the tools will automatically load them when started.
439
+
351
440
  ## License
352
441
 
353
442
  MIT License
@@ -0,0 +1,67 @@
1
+ import {
2
+ shouldIncludeServer
3
+ } from "./chunk-QQN5GTOV.mjs";
4
+
5
+ // src/generators/mcp/claude.ts
6
+ function generateClaudeMcp(config, _target) {
7
+ const claudeSettings = {
8
+ mcpServers: {}
9
+ };
10
+ const shouldInclude = (server) => {
11
+ return shouldIncludeServer(server, "claude");
12
+ };
13
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
14
+ if (!shouldInclude(server)) continue;
15
+ const claudeServer = {};
16
+ if (server.command) {
17
+ claudeServer.command = server.command;
18
+ if (server.args) claudeServer.args = server.args;
19
+ } else if (server.url || server.httpUrl) {
20
+ const url = server.httpUrl || server.url;
21
+ if (url) {
22
+ claudeServer.url = url;
23
+ }
24
+ if (server.httpUrl) {
25
+ claudeServer.transport = "http";
26
+ } else if (server.transport === "sse") {
27
+ claudeServer.transport = "sse";
28
+ }
29
+ }
30
+ if (server.env) {
31
+ claudeServer.env = server.env;
32
+ }
33
+ claudeSettings.mcpServers[serverName] = claudeServer;
34
+ }
35
+ return JSON.stringify(claudeSettings, null, 2);
36
+ }
37
+ function generateClaudeMcpConfiguration(mcpServers, baseDir = "") {
38
+ const filepath = baseDir ? `${baseDir}/.claude/settings.json` : ".claude/settings.json";
39
+ const settings = {
40
+ mcpServers: {}
41
+ };
42
+ for (const [serverName, server] of Object.entries(mcpServers)) {
43
+ if (!shouldIncludeServer(server, "claudecode")) {
44
+ continue;
45
+ }
46
+ const { rulesyncTargets: _, transport, ...serverConfig } = server;
47
+ const claudeServer = {
48
+ ...serverConfig
49
+ };
50
+ if (transport && transport !== "stdio") {
51
+ claudeServer.transport = transport;
52
+ }
53
+ settings.mcpServers[serverName] = claudeServer;
54
+ }
55
+ return [
56
+ {
57
+ filepath,
58
+ content: `${JSON.stringify(settings, null, 2)}
59
+ `
60
+ }
61
+ ];
62
+ }
63
+
64
+ export {
65
+ generateClaudeMcp,
66
+ generateClaudeMcpConfiguration
67
+ };
@@ -0,0 +1,62 @@
1
+ import {
2
+ shouldIncludeServer
3
+ } from "./chunk-QQN5GTOV.mjs";
4
+
5
+ // src/generators/mcp/cline.ts
6
+ function generateClineMcp(config, _target) {
7
+ const clineConfig = {
8
+ mcpServers: {}
9
+ };
10
+ const shouldInclude = (server) => {
11
+ return shouldIncludeServer(server, "cline");
12
+ };
13
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
14
+ if (!shouldInclude(server)) continue;
15
+ const clineServer = {};
16
+ if (server.command) {
17
+ clineServer.command = server.command;
18
+ if (server.args) clineServer.args = server.args;
19
+ } else if (server.url) {
20
+ clineServer.url = server.url;
21
+ }
22
+ if (server.env) {
23
+ clineServer.env = server.env;
24
+ }
25
+ if (server.disabled !== void 0) {
26
+ clineServer.disabled = server.disabled;
27
+ }
28
+ if (server.alwaysAllow) {
29
+ clineServer.alwaysAllow = server.alwaysAllow;
30
+ }
31
+ if (server.networkTimeout !== void 0) {
32
+ clineServer.networkTimeout = server.networkTimeout;
33
+ }
34
+ clineConfig.mcpServers[serverName] = clineServer;
35
+ }
36
+ return JSON.stringify(clineConfig, null, 2);
37
+ }
38
+ function generateClineMcpConfiguration(mcpServers, baseDir = "") {
39
+ const filepath = baseDir ? `${baseDir}/.cline/mcp.json` : ".cline/mcp.json";
40
+ const config = {
41
+ mcpServers: {}
42
+ };
43
+ for (const [serverName, server] of Object.entries(mcpServers)) {
44
+ if (!shouldIncludeServer(server, "cline")) {
45
+ continue;
46
+ }
47
+ const { rulesyncTargets: _, ...serverConfig } = server;
48
+ config.mcpServers[serverName] = serverConfig;
49
+ }
50
+ return [
51
+ {
52
+ filepath,
53
+ content: `${JSON.stringify(config, null, 2)}
54
+ `
55
+ }
56
+ ];
57
+ }
58
+
59
+ export {
60
+ generateClineMcp,
61
+ generateClineMcpConfiguration
62
+ };
@@ -0,0 +1,78 @@
1
+ import {
2
+ shouldIncludeServer
3
+ } from "./chunk-QQN5GTOV.mjs";
4
+
5
+ // src/generators/mcp/roo.ts
6
+ function generateRooMcp(config, _target) {
7
+ const rooConfig = {
8
+ mcpServers: {}
9
+ };
10
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
11
+ if (!shouldIncludeServer(server, "roo")) continue;
12
+ const rooServer = {};
13
+ if (server.command) {
14
+ rooServer.command = server.command;
15
+ if (server.args) rooServer.args = server.args;
16
+ } else if (server.url || server.httpUrl) {
17
+ const url = server.httpUrl || server.url;
18
+ if (url) {
19
+ rooServer.url = url;
20
+ }
21
+ if (server.httpUrl || server.transport === "http") {
22
+ rooServer.type = "streamable-http";
23
+ } else if (server.transport === "sse" || server.type === "sse") {
24
+ rooServer.type = "sse";
25
+ }
26
+ }
27
+ if (server.env) {
28
+ rooServer.env = {};
29
+ for (const [key, value] of Object.entries(server.env)) {
30
+ if (value.startsWith("${env:") && value.endsWith("}")) {
31
+ rooServer.env[key] = value;
32
+ } else {
33
+ rooServer.env[key] = `\${env:${value}}`;
34
+ }
35
+ }
36
+ }
37
+ if (server.disabled !== void 0) {
38
+ rooServer.disabled = server.disabled;
39
+ }
40
+ if (server.alwaysAllow) {
41
+ rooServer.alwaysAllow = server.alwaysAllow;
42
+ }
43
+ if (server.networkTimeout !== void 0) {
44
+ rooServer.networkTimeout = Math.max(3e4, Math.min(3e5, server.networkTimeout));
45
+ }
46
+ rooConfig.mcpServers[serverName] = rooServer;
47
+ }
48
+ return JSON.stringify(rooConfig, null, 2);
49
+ }
50
+ function generateRooMcpConfiguration(mcpServers, baseDir = "") {
51
+ const filepath = baseDir ? `${baseDir}/.roo/mcp.json` : ".roo/mcp.json";
52
+ const config = {
53
+ mcpServers: {}
54
+ };
55
+ for (const [serverName, server] of Object.entries(mcpServers)) {
56
+ if (!server || typeof server !== "object") {
57
+ continue;
58
+ }
59
+ const serverObj = server;
60
+ if (!shouldIncludeServer(serverObj, "roo")) {
61
+ continue;
62
+ }
63
+ const { rulesyncTargets: _rulesyncTargets, ...serverConfig } = serverObj;
64
+ config.mcpServers[serverName] = serverConfig;
65
+ }
66
+ return [
67
+ {
68
+ filepath,
69
+ content: `${JSON.stringify(config, null, 2)}
70
+ `
71
+ }
72
+ ];
73
+ }
74
+
75
+ export {
76
+ generateRooMcp,
77
+ generateRooMcpConfiguration
78
+ };
@@ -0,0 +1,65 @@
1
+ import {
2
+ shouldIncludeServer
3
+ } from "./chunk-QQN5GTOV.mjs";
4
+
5
+ // src/generators/mcp/cursor.ts
6
+ function generateCursorMcp(config, _target) {
7
+ const cursorConfig = {
8
+ mcpServers: {}
9
+ };
10
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
11
+ if (!shouldIncludeServer(server, "cursor")) continue;
12
+ const cursorServer = {};
13
+ if (server.command) {
14
+ cursorServer.command = server.command;
15
+ if (server.args) cursorServer.args = server.args;
16
+ } else if (server.url || server.httpUrl) {
17
+ const url = server.httpUrl || server.url;
18
+ if (url) {
19
+ cursorServer.url = url;
20
+ }
21
+ if (server.httpUrl || server.transport === "http") {
22
+ cursorServer.type = "streamable-http";
23
+ } else if (server.transport === "sse" || server.type === "sse") {
24
+ cursorServer.type = "sse";
25
+ }
26
+ }
27
+ if (server.env) {
28
+ cursorServer.env = server.env;
29
+ }
30
+ if (server.cwd) {
31
+ cursorServer.cwd = server.cwd;
32
+ }
33
+ cursorConfig.mcpServers[serverName] = cursorServer;
34
+ }
35
+ return JSON.stringify(cursorConfig, null, 2);
36
+ }
37
+ function generateCursorMcpConfiguration(mcpServers, baseDir = "") {
38
+ const filepath = baseDir ? `${baseDir}/.cursor/mcp.json` : ".cursor/mcp.json";
39
+ const config = {
40
+ mcpServers: {}
41
+ };
42
+ for (const [serverName, server] of Object.entries(mcpServers)) {
43
+ if (!server || typeof server !== "object") {
44
+ continue;
45
+ }
46
+ const serverObj = server;
47
+ if (!shouldIncludeServer(serverObj, "cursor")) {
48
+ continue;
49
+ }
50
+ const { rulesyncTargets: _rulesyncTargets, ...serverConfig } = serverObj;
51
+ config.mcpServers[serverName] = serverConfig;
52
+ }
53
+ return [
54
+ {
55
+ filepath,
56
+ content: `${JSON.stringify(config, null, 2)}
57
+ `
58
+ }
59
+ ];
60
+ }
61
+
62
+ export {
63
+ generateCursorMcp,
64
+ generateCursorMcpConfiguration
65
+ };
@@ -0,0 +1,67 @@
1
+ import {
2
+ shouldIncludeServer
3
+ } from "./chunk-QQN5GTOV.mjs";
4
+
5
+ // src/generators/mcp/geminicli.ts
6
+ function generateGeminiCliMcp(config, _target) {
7
+ const geminiSettings = {
8
+ mcpServers: {}
9
+ };
10
+ for (const [serverName, server] of Object.entries(config.mcpServers)) {
11
+ if (!shouldIncludeServer(server, "geminicli")) continue;
12
+ const geminiServer = {};
13
+ if (server.command) {
14
+ geminiServer.command = server.command;
15
+ if (server.args) geminiServer.args = server.args;
16
+ } else if (server.url || server.httpUrl) {
17
+ if (server.httpUrl) {
18
+ geminiServer.httpUrl = server.httpUrl;
19
+ } else if (server.url) {
20
+ geminiServer.url = server.url;
21
+ }
22
+ }
23
+ if (server.env) {
24
+ geminiServer.env = {};
25
+ for (const [key, value] of Object.entries(server.env)) {
26
+ if (value.startsWith("${") && value.endsWith("}")) {
27
+ geminiServer.env[key] = value;
28
+ } else {
29
+ geminiServer.env[key] = `\${${value}}`;
30
+ }
31
+ }
32
+ }
33
+ if (server.timeout !== void 0) {
34
+ geminiServer.timeout = server.timeout;
35
+ }
36
+ if (server.trust !== void 0) {
37
+ geminiServer.trust = server.trust;
38
+ }
39
+ geminiSettings.mcpServers[serverName] = geminiServer;
40
+ }
41
+ return JSON.stringify(geminiSettings, null, 2);
42
+ }
43
+ function generateGeminiCliMcpConfiguration(mcpServers, baseDir = "") {
44
+ const filepath = baseDir ? `${baseDir}/.gemini/settings.json` : ".gemini/settings.json";
45
+ const config = {
46
+ mcpServers: {}
47
+ };
48
+ for (const [serverName, server] of Object.entries(mcpServers)) {
49
+ if (!shouldIncludeServer(server, "geminicli")) {
50
+ continue;
51
+ }
52
+ const { rulesyncTargets: _, ...serverConfig } = server;
53
+ config.mcpServers[serverName] = serverConfig;
54
+ }
55
+ return [
56
+ {
57
+ filepath,
58
+ content: `${JSON.stringify(config, null, 2)}
59
+ `
60
+ }
61
+ ];
62
+ }
63
+
64
+ export {
65
+ generateGeminiCliMcp,
66
+ generateGeminiCliMcpConfiguration
67
+ };
@@ -0,0 +1,56 @@
1
+ // src/schemas/mcp.ts
2
+ import { z } from "zod";
3
+ var ToolTargetSchema = z.enum([
4
+ "copilot",
5
+ "cursor",
6
+ "cline",
7
+ "claudecode",
8
+ "claude",
9
+ "roo",
10
+ "geminicli"
11
+ ]);
12
+ var WildcardTargetSchema = z.tuple([z.literal("*")]);
13
+ var SpecificTargetsSchema = z.array(ToolTargetSchema);
14
+ var RulesyncTargetsSchema = z.union([SpecificTargetsSchema, WildcardTargetSchema]);
15
+ var McpTransportTypeSchema = z.enum(["stdio", "sse", "http"]);
16
+ var McpServerBaseSchema = z.object({
17
+ command: z.string().optional(),
18
+ args: z.array(z.string()).optional(),
19
+ url: z.string().optional(),
20
+ httpUrl: z.string().optional(),
21
+ env: z.record(z.string()).optional(),
22
+ disabled: z.boolean().optional(),
23
+ networkTimeout: z.number().optional(),
24
+ timeout: z.number().optional(),
25
+ trust: z.boolean().optional(),
26
+ cwd: z.string().optional(),
27
+ transport: McpTransportTypeSchema.optional(),
28
+ type: z.enum(["sse", "streamable-http"]).optional(),
29
+ alwaysAllow: z.array(z.string()).optional(),
30
+ tools: z.array(z.string()).optional()
31
+ });
32
+ var RulesyncMcpServerSchema = McpServerBaseSchema.extend({
33
+ rulesyncTargets: RulesyncTargetsSchema.optional()
34
+ });
35
+
36
+ // src/utils/mcp-helpers.ts
37
+ function shouldIncludeServer(server, targetTool) {
38
+ if (!server.rulesyncTargets || server.rulesyncTargets.length === 0) {
39
+ return true;
40
+ }
41
+ const parsedTargets = RulesyncTargetsSchema.parse(server.rulesyncTargets);
42
+ if (parsedTargets.length === 1 && parsedTargets[0] === "*") {
43
+ return true;
44
+ }
45
+ const validatedTool = ToolTargetSchema.parse(targetTool);
46
+ for (const target of parsedTargets) {
47
+ if (target === validatedTool) {
48
+ return true;
49
+ }
50
+ }
51
+ return false;
52
+ }
53
+
54
+ export {
55
+ shouldIncludeServer
56
+ };