mcp-filter 0.0.1 → 0.2.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.md +186 -8
- package/dist/cli.d.ts +5 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -8
- package/dist/cli.js.map +1 -1
- package/dist/filter.d.ts +4 -2
- package/dist/filter.d.ts.map +1 -1
- package/dist/filter.js +16 -4
- package/dist/filter.js.map +1 -1
- package/dist/index.js +32 -24
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +3 -3
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +7 -7
- package/dist/proxy.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# mcp-filter
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/mcp-filter)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
3
6
|
MCP server proxy to filter tools, resources, and prompts from upstream MCP servers.
|
|
4
7
|
|
|
5
8
|
## Installation
|
|
@@ -12,28 +15,195 @@ npx mcp-filter [options] -- <upstream-command>
|
|
|
12
15
|
|
|
13
16
|
## Usage
|
|
14
17
|
|
|
18
|
+
### Basic Usage
|
|
19
|
+
|
|
15
20
|
```bash
|
|
16
|
-
#
|
|
17
|
-
npx mcp-filter --
|
|
21
|
+
# Exclude mode: filter out specific tools
|
|
22
|
+
npx mcp-filter --exclude "playwright*" -- npx @playwright/mcp
|
|
23
|
+
|
|
24
|
+
# Include mode: only allow specific tools
|
|
25
|
+
npx mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp
|
|
18
26
|
|
|
19
|
-
#
|
|
20
|
-
npx mcp-filter --
|
|
27
|
+
# Combination: include with exceptions
|
|
28
|
+
npx mcp-filter --include "browser_*" --exclude "browser_close" -- npx @playwright/mcp
|
|
29
|
+
|
|
30
|
+
# Multiple patterns
|
|
31
|
+
npx mcp-filter --exclude "playwright*" --exclude "unsafe_*" -- npx @playwright/mcp
|
|
21
32
|
|
|
22
33
|
# Use with any MCP server
|
|
23
|
-
npx mcp-filter --
|
|
34
|
+
npx mcp-filter --exclude "debug*" -- node my-mcp-server.js
|
|
24
35
|
```
|
|
25
36
|
|
|
26
37
|
## Options
|
|
27
38
|
|
|
28
|
-
- `--
|
|
39
|
+
- `--exclude <pattern>` - Exclude tools/resources/prompts matching this pattern
|
|
40
|
+
- `--include <pattern>` - Include ONLY tools/resources/prompts matching this pattern (whitelist mode)
|
|
29
41
|
- `--` - Separates filter options from upstream server command
|
|
30
42
|
|
|
43
|
+
Both options can be specified multiple times and combined together.
|
|
44
|
+
|
|
45
|
+
**Filtering style:** rsync-style evaluation where patterns are evaluated in the order specified, and first match wins.
|
|
46
|
+
|
|
47
|
+
## Filtering Modes
|
|
48
|
+
|
|
49
|
+
### Exclude Mode (--exclude only)
|
|
50
|
+
|
|
51
|
+
Blocks specific items, allows everything else:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Block browser_close and browser_evaluate tools
|
|
55
|
+
npx mcp-filter --exclude "browser_close" --exclude "browser_evaluate" -- npx @playwright/mcp
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Include Mode (--include only)
|
|
59
|
+
|
|
60
|
+
Allows ONLY specified items, blocks everything else:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Only allow safe, read-only browser tools
|
|
64
|
+
npx mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Combination Mode (--include + --exclude)
|
|
68
|
+
|
|
69
|
+
**Rsync-style filtering**: patterns evaluated in order, first match wins.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Example 1: Include first, then exclude
|
|
73
|
+
npx mcp-filter --include "browser_*" --exclude "browser_close" -- npx @playwright/mcp
|
|
74
|
+
# Result: All browser_* tools are INCLUDED (browser_* matched first)
|
|
75
|
+
# browser_close is also included because it matches browser_* first
|
|
76
|
+
|
|
77
|
+
# Example 2: Exclude first, then include (different result!)
|
|
78
|
+
npx mcp-filter --exclude "browser_close" --include "browser_*" -- npx @playwright/mcp
|
|
79
|
+
# Result: browser_close is EXCLUDED (matched exclude first)
|
|
80
|
+
# Other browser_* tools are included
|
|
81
|
+
|
|
82
|
+
# Example 3: More specific patterns first
|
|
83
|
+
npx mcp-filter --exclude "browser_close" --exclude "browser_evaluate" --include "browser_*" -- npx @playwright/mcp
|
|
84
|
+
# Result: browser_close and browser_evaluate excluded (matched first)
|
|
85
|
+
# All other browser_* tools included
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Key principle**: Order matters! The first pattern that matches determines if the item is included or excluded.
|
|
89
|
+
|
|
31
90
|
## Pattern Examples
|
|
32
91
|
|
|
92
|
+
Patterns use glob syntax (via minimatch):
|
|
93
|
+
|
|
33
94
|
- `playwright*` - Match all items starting with "playwright"
|
|
34
|
-
- `*_admin` - Match all items ending with "_admin"
|
|
95
|
+
- `*_admin` - Match all items ending with "\_admin"
|
|
35
96
|
- `test_*_debug` - Match items with pattern in middle
|
|
36
97
|
- `exact_name` - Match exact name
|
|
98
|
+
- `browser_*` - Match all browser-related tools
|
|
99
|
+
- `*` - Match everything
|
|
100
|
+
|
|
101
|
+
## Rsync-Style Filtering
|
|
102
|
+
|
|
103
|
+
mcp-filter uses rsync-style pattern evaluation:
|
|
104
|
+
|
|
105
|
+
1. **Order matters**: Patterns are evaluated in the order you specify them
|
|
106
|
+
2. **First match wins**: Once a pattern matches, that determines the outcome
|
|
107
|
+
3. **Default behavior**:
|
|
108
|
+
- If no patterns specified: allow everything (passthrough)
|
|
109
|
+
- If only `--include`: items not matching any include are excluded (whitelist mode)
|
|
110
|
+
- If only `--exclude`: items not matching any exclude are included
|
|
111
|
+
- If mixed: items not matching any pattern use whitelist mode if includes exist
|
|
112
|
+
|
|
113
|
+
**Example workflow**:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Put more specific patterns first
|
|
117
|
+
npx mcp-filter \
|
|
118
|
+
--exclude "browser_close" \
|
|
119
|
+
--exclude "browser_evaluate" \
|
|
120
|
+
--include "browser_*" \
|
|
121
|
+
-- npx @playwright/mcp
|
|
122
|
+
|
|
123
|
+
# This works because:
|
|
124
|
+
# 1. browser_close matches --exclude "browser_close" first → excluded
|
|
125
|
+
# 2. browser_evaluate matches --exclude "browser_evaluate" first → excluded
|
|
126
|
+
# 3. browser_navigate matches --include "browser_*" → included
|
|
127
|
+
# 4. other_tool doesn't match any pattern, but --include exists → excluded (whitelist mode)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Using with Cursor IDE
|
|
131
|
+
|
|
132
|
+
Add to your `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
133
|
+
|
|
134
|
+
### Example 1: Exclude specific dangerous tools
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"mcpServers": {
|
|
139
|
+
"playwright": {
|
|
140
|
+
"command": "npx",
|
|
141
|
+
"args": [
|
|
142
|
+
"mcp-filter",
|
|
143
|
+
"--exclude",
|
|
144
|
+
"browser_close",
|
|
145
|
+
"--exclude",
|
|
146
|
+
"browser_evaluate",
|
|
147
|
+
"--",
|
|
148
|
+
"npx",
|
|
149
|
+
"@playwright/mcp@latest"
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Example 2: Include safe tools only
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"mcpServers": {
|
|
161
|
+
"playwright-safe": {
|
|
162
|
+
"command": "npx",
|
|
163
|
+
"args": [
|
|
164
|
+
"mcp-filter",
|
|
165
|
+
"--include",
|
|
166
|
+
"browser_navigate",
|
|
167
|
+
"--include",
|
|
168
|
+
"browser_screenshot",
|
|
169
|
+
"--include",
|
|
170
|
+
"browser_snapshot",
|
|
171
|
+
"--",
|
|
172
|
+
"npx",
|
|
173
|
+
"@playwright/mcp@latest"
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Example 3: Include category with exceptions (rsync-style)
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"mcpServers": {
|
|
185
|
+
"playwright-filtered": {
|
|
186
|
+
"command": "npx",
|
|
187
|
+
"args": [
|
|
188
|
+
"mcp-filter",
|
|
189
|
+
"--exclude",
|
|
190
|
+
"browser_close",
|
|
191
|
+
"--exclude",
|
|
192
|
+
"browser_evaluate",
|
|
193
|
+
"--include",
|
|
194
|
+
"browser_*",
|
|
195
|
+
"--",
|
|
196
|
+
"npx",
|
|
197
|
+
"@playwright/mcp@latest"
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Note: Exclude patterns come first to match before the broader include pattern.
|
|
205
|
+
|
|
206
|
+
After adding the configuration, restart Cursor completely to apply the changes.
|
|
37
207
|
|
|
38
208
|
## How It Works
|
|
39
209
|
|
|
@@ -54,10 +224,18 @@ pnpm install
|
|
|
54
224
|
# Build
|
|
55
225
|
pnpm run build
|
|
56
226
|
|
|
227
|
+
# Run tests
|
|
228
|
+
pnpm test
|
|
229
|
+
|
|
57
230
|
# Test locally
|
|
58
|
-
./dist/index.js --
|
|
231
|
+
./dist/index.js --exclude "playwright*" -- npx tsx test-server.ts
|
|
59
232
|
```
|
|
60
233
|
|
|
234
|
+
## Links
|
|
235
|
+
|
|
236
|
+
- [npm package](https://www.npmjs.com/package/mcp-filter)
|
|
237
|
+
- [GitHub repository](https://github.com/baranovxyz/mcp-filter)
|
|
238
|
+
|
|
61
239
|
## License
|
|
62
240
|
|
|
63
241
|
MIT
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
export interface FilterPattern {
|
|
2
|
+
type: "include" | "exclude";
|
|
3
|
+
pattern: string;
|
|
4
|
+
}
|
|
1
5
|
export interface FilterConfig {
|
|
2
|
-
|
|
6
|
+
patterns: FilterPattern[];
|
|
3
7
|
upstreamCommand: string[];
|
|
4
8
|
}
|
|
5
9
|
export declare function parseArgs(args: string[]): FilterConfig;
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAkDtD"}
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function parseArgs(args) {
|
|
2
|
-
const
|
|
2
|
+
const patterns = [];
|
|
3
3
|
const upstreamCommand = [];
|
|
4
4
|
let inUpstreamCommand = false;
|
|
5
5
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -8,26 +8,34 @@ export function parseArgs(args) {
|
|
|
8
8
|
upstreamCommand.push(arg);
|
|
9
9
|
continue;
|
|
10
10
|
}
|
|
11
|
-
if (arg ===
|
|
11
|
+
if (arg === "--") {
|
|
12
12
|
inUpstreamCommand = true;
|
|
13
13
|
continue;
|
|
14
14
|
}
|
|
15
|
-
if (arg ===
|
|
15
|
+
if (arg === "--exclude") {
|
|
16
16
|
const pattern = args[++i];
|
|
17
17
|
if (!pattern) {
|
|
18
|
-
throw new Error(
|
|
18
|
+
throw new Error("--exclude requires a pattern argument");
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
patterns.push({ type: "exclude", pattern });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (arg === "--include") {
|
|
24
|
+
const pattern = args[++i];
|
|
25
|
+
if (!pattern) {
|
|
26
|
+
throw new Error("--include requires a pattern argument");
|
|
27
|
+
}
|
|
28
|
+
patterns.push({ type: "include", pattern });
|
|
21
29
|
continue;
|
|
22
30
|
}
|
|
23
31
|
throw new Error(`Unknown argument: ${arg}`);
|
|
24
32
|
}
|
|
25
33
|
if (upstreamCommand.length === 0) {
|
|
26
|
-
throw new Error(
|
|
34
|
+
throw new Error("No upstream command specified. Use -- to separate filter args from upstream command");
|
|
27
35
|
}
|
|
28
36
|
return {
|
|
29
|
-
|
|
30
|
-
upstreamCommand
|
|
37
|
+
patterns,
|
|
38
|
+
upstreamCommand,
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
41
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpB,IAAI,iBAAiB,EAAE,CAAC;YACtB,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,iBAAiB,GAAG,IAAI,CAAC;YACzB,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC3D,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ;QACR,eAAe;KAChB,CAAC;AACJ,CAAC"}
|
package/dist/filter.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { FilterPattern } from "./cli.js";
|
|
1
2
|
export declare class Filter {
|
|
2
3
|
private patterns;
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
private hasIncludePatterns;
|
|
5
|
+
constructor(patterns: FilterPattern[]);
|
|
6
|
+
shouldExclude(name: string): boolean;
|
|
5
7
|
filterList<T extends {
|
|
6
8
|
name: string;
|
|
7
9
|
}>(items: T[]): T[];
|
package/dist/filter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,qBAAa,MAAM;IAGL,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,kBAAkB,CAAU;gBAEhB,QAAQ,EAAE,aAAa,EAAE;IAI7C,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAepC,UAAU,CAAC,CAAC,SAAS;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;CAGxD"}
|
package/dist/filter.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import { minimatch } from
|
|
1
|
+
import { minimatch } from "minimatch";
|
|
2
2
|
export class Filter {
|
|
3
3
|
patterns;
|
|
4
|
+
hasIncludePatterns;
|
|
4
5
|
constructor(patterns) {
|
|
5
6
|
this.patterns = patterns;
|
|
7
|
+
this.hasIncludePatterns = patterns.some((p) => p.type === "include");
|
|
6
8
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
shouldExclude(name) {
|
|
10
|
+
// Evaluate patterns in order - first match wins (rsync-style)
|
|
11
|
+
for (const pattern of this.patterns) {
|
|
12
|
+
if (minimatch(name, pattern.pattern)) {
|
|
13
|
+
// First pattern that matches determines the outcome
|
|
14
|
+
return pattern.type === "exclude";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// No pattern matched - determine default behavior
|
|
18
|
+
// If there are include patterns, default is exclude (whitelist mode)
|
|
19
|
+
// Otherwise, default is include (allow all)
|
|
20
|
+
return this.hasIncludePatterns;
|
|
9
21
|
}
|
|
10
22
|
filterList(items) {
|
|
11
|
-
return items.filter(item => !this.
|
|
23
|
+
return items.filter((item) => !this.shouldExclude(item.name));
|
|
12
24
|
}
|
|
13
25
|
}
|
|
14
26
|
//# sourceMappingURL=filter.js.map
|
package/dist/filter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,OAAO,MAAM;IAGG;IAFZ,kBAAkB,CAAU;IAEpC,YAAoB,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;QAC3C,IAAI,CAAC,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACvE,CAAC;IAED,aAAa,CAAC,IAAY;QACxB,8DAA8D;QAC9D,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrC,oDAAoD;gBACpD,OAAO,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC;YACpC,CAAC;QACH,CAAC;QAED,kDAAkD;QAClD,qEAAqE;QACrE,4CAA4C;QAC5C,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IAED,UAAU,CAA6B,KAAU;QAC/C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;CACF"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from
|
|
3
|
-
import { StdioServerTransport } from
|
|
4
|
-
import { StdioClientTransport } from
|
|
5
|
-
import { parseArgs } from
|
|
6
|
-
import { Filter } from
|
|
7
|
-
import { ProxyServer } from
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
5
|
+
import { parseArgs } from "./cli.js";
|
|
6
|
+
import { Filter } from "./filter.js";
|
|
7
|
+
import { ProxyServer } from "./proxy.js";
|
|
8
8
|
async function main() {
|
|
9
9
|
// Parse command line arguments
|
|
10
10
|
const args = process.argv.slice(2);
|
|
@@ -14,63 +14,71 @@ async function main() {
|
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
|
16
16
|
console.error(`Error: ${error.message}`);
|
|
17
|
-
console.error(
|
|
18
|
-
console.error(
|
|
17
|
+
console.error("Usage: mcp-filter [--exclude <pattern>]... [--include <pattern>]... -- <upstream-command> [args...]");
|
|
18
|
+
console.error("Examples:");
|
|
19
|
+
console.error(' mcp-filter --exclude "playwright*" -- npx @playwright/mcp');
|
|
20
|
+
console.error(' mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp');
|
|
21
|
+
console.error(' mcp-filter --include "browser_*" --exclude "browser_close" -- npx @playwright/mcp');
|
|
19
22
|
process.exit(1);
|
|
20
23
|
}
|
|
21
|
-
console.error(`Starting MCP filter with ${config.
|
|
22
|
-
config.
|
|
24
|
+
console.error(`Starting MCP filter with ${config.patterns.length} pattern(s)`);
|
|
25
|
+
config.patterns.forEach((p) => console.error(` ${p.type === "include" ? "Include" : "Exclude"}: ${p.pattern}`));
|
|
26
|
+
const hasInclude = config.patterns.some((p) => p.type === "include");
|
|
27
|
+
const hasExclude = config.patterns.some((p) => p.type === "exclude");
|
|
28
|
+
if (hasInclude && hasExclude) {
|
|
29
|
+
console.error("Note: Using rsync-style filtering - patterns evaluated in order, first match wins.");
|
|
30
|
+
}
|
|
23
31
|
// Spawn upstream server
|
|
24
32
|
const upstreamProcess = spawnUpstream(config.upstreamCommand);
|
|
25
33
|
// Create filter
|
|
26
|
-
const filter = new Filter(config.
|
|
34
|
+
const filter = new Filter(config.patterns);
|
|
27
35
|
// Create proxy server
|
|
28
36
|
const proxy = new ProxyServer({
|
|
29
|
-
name:
|
|
30
|
-
version:
|
|
37
|
+
name: "mcp-filter",
|
|
38
|
+
version: "0.2.0",
|
|
31
39
|
}, filter);
|
|
32
40
|
// Connect client to upstream server via subprocess stdio
|
|
33
41
|
const clientTransport = new StdioClientTransport({
|
|
34
42
|
command: config.upstreamCommand[0],
|
|
35
43
|
args: config.upstreamCommand.slice(1),
|
|
36
|
-
stderr:
|
|
44
|
+
stderr: "pipe",
|
|
37
45
|
});
|
|
38
46
|
await proxy.getClient().connect(clientTransport);
|
|
39
|
-
console.error(
|
|
47
|
+
console.error("Connected to upstream server");
|
|
40
48
|
// Connect server to current process stdio (for the MCP client calling us)
|
|
41
49
|
const serverTransport = new StdioServerTransport();
|
|
42
50
|
await proxy.getServer().connect(serverTransport);
|
|
43
|
-
console.error(
|
|
51
|
+
console.error("MCP filter proxy ready");
|
|
44
52
|
// Handle cleanup
|
|
45
53
|
const cleanup = () => {
|
|
46
|
-
console.error(
|
|
54
|
+
console.error("Shutting down...");
|
|
47
55
|
upstreamProcess.kill();
|
|
48
56
|
process.exit(0);
|
|
49
57
|
};
|
|
50
|
-
process.on(
|
|
51
|
-
process.on(
|
|
58
|
+
process.on("SIGINT", cleanup);
|
|
59
|
+
process.on("SIGTERM", cleanup);
|
|
52
60
|
}
|
|
53
61
|
function spawnUpstream(command) {
|
|
54
62
|
const [cmd, ...args] = command;
|
|
55
63
|
const proc = spawn(cmd, args, {
|
|
56
|
-
stdio: [
|
|
64
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
57
65
|
});
|
|
58
66
|
// Forward stderr to our stderr
|
|
59
|
-
proc.stderr.on(
|
|
67
|
+
proc.stderr.on("data", (data) => {
|
|
60
68
|
process.stderr.write(data);
|
|
61
69
|
});
|
|
62
|
-
proc.on(
|
|
70
|
+
proc.on("error", (error) => {
|
|
63
71
|
console.error(`Failed to start upstream server: ${error.message}`);
|
|
64
72
|
process.exit(1);
|
|
65
73
|
});
|
|
66
|
-
proc.on(
|
|
74
|
+
proc.on("exit", (code) => {
|
|
67
75
|
console.error(`Upstream server exited with code ${code}`);
|
|
68
76
|
process.exit(code || 0);
|
|
69
77
|
});
|
|
70
78
|
return proc;
|
|
71
79
|
}
|
|
72
80
|
main().catch((error) => {
|
|
73
|
-
console.error(
|
|
81
|
+
console.error("Fatal error:", error);
|
|
74
82
|
process.exit(1);
|
|
75
83
|
});
|
|
76
84
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAkC,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,KAAK,UAAU,IAAI;IACjB,+BAA+B;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,UAAW,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAkC,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,KAAK,UAAU,IAAI;IACjB,+BAA+B;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,UAAW,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CACX,qGAAqG,CACtG,CAAC;QACF,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC3B,OAAO,CAAC,KAAK,CACX,6DAA6D,CAC9D,CAAC;QACF,OAAO,CAAC,KAAK,CACX,iGAAiG,CAClG,CAAC;QACF,OAAO,CAAC,KAAK,CACX,qFAAqF,CACtF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,KAAK,CACX,4BAA4B,MAAM,CAAC,QAAQ,CAAC,MAAM,aAAa,CAChE,CAAC;IACF,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5B,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,OAAO,EAAE,CAClE,CACF,CAAC;IAEF,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAErE,IAAI,UAAU,IAAI,UAAU,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CACX,oFAAoF,CACrF,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAE9D,gBAAgB;IAChB,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE3C,sBAAsB;IACtB,MAAM,KAAK,GAAG,IAAI,WAAW,CAC3B;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,EACD,MAAM,CACP,CAAC;IAEF,yDAAyD;IACzD,MAAM,eAAe,GAAG,IAAI,oBAAoB,CAAC;QAC/C,OAAO,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;QACrC,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE9C,0EAA0E;IAC1E,MAAM,eAAe,GAAG,IAAI,oBAAoB,EAAE,CAAC;IACnD,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAExC,iBAAiB;IACjB,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAClC,eAAe,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,OAAiB;IACtC,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC;IAE/B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;QAC5B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAC;IAEH,+BAA+B;IAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QACzB,OAAO,CAAC,KAAK,CAAC,oCAAoC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,OAAO,CAAC,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,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"}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Client } from
|
|
2
|
-
import { Server } from
|
|
3
|
-
import { Filter } from
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { Filter } from "./filter.js";
|
|
4
4
|
export declare class ProxyServer {
|
|
5
5
|
private server;
|
|
6
6
|
private client;
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AASnE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AASnE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,MAAM,EAAE,MAAM;IAuBzE,OAAO,CAAC,aAAa;IAwDrB,SAAS,IAAI,MAAM;IAInB,SAAS,IAAI,MAAM;CAGpB"}
|
package/dist/proxy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Client } from
|
|
2
|
-
import { Server } from
|
|
3
|
-
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
export class ProxyServer {
|
|
5
5
|
server;
|
|
6
6
|
client;
|
|
@@ -31,8 +31,8 @@ export class ProxyServer {
|
|
|
31
31
|
};
|
|
32
32
|
});
|
|
33
33
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
34
|
-
if (this.filter.
|
|
35
|
-
throw new Error(`Tool '${request.params.name}' is
|
|
34
|
+
if (this.filter.shouldExclude(request.params.name)) {
|
|
35
|
+
throw new Error(`Tool '${request.params.name}' is excluded by filter`);
|
|
36
36
|
}
|
|
37
37
|
return await this.client.callTool(request.params);
|
|
38
38
|
});
|
|
@@ -56,8 +56,8 @@ export class ProxyServer {
|
|
|
56
56
|
};
|
|
57
57
|
});
|
|
58
58
|
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
59
|
-
if (this.filter.
|
|
60
|
-
throw new Error(`Prompt '${request.params.name}' is
|
|
59
|
+
if (this.filter.shouldExclude(request.params.name)) {
|
|
60
|
+
throw new Error(`Prompt '${request.params.name}' is excluded by filter`);
|
|
61
61
|
}
|
|
62
62
|
return await this.client.getPrompt(request.params);
|
|
63
63
|
});
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAG5C,MAAM,OAAO,WAAW;IACd,MAAM,CAAS;IACf,MAAM,CAAS;IACf,MAAM,CAAS;IAEvB,
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|