mcp-filter 1.1.0 → 1.1.2
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 +127 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<h1 align="center">mcp-filter</h1>
|
|
3
3
|
<p align="center">
|
|
4
|
-
MCP proxy that filters tools, resources, and prompts
|
|
4
|
+
MCP proxy that filters tools, resources, and prompts using glob patterns.
|
|
5
5
|
<br />
|
|
6
|
-
|
|
6
|
+
Any MCP server. Any MCP client. Local or remote.
|
|
7
7
|
</p>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
@@ -17,22 +17,17 @@
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## The Problem
|
|
21
21
|
|
|
22
|
-
[GitHub MCP Server](https://github.com/github/github-mcp-server) exposes 79 tools — **~52,000 tokens** of context window
|
|
22
|
+
[GitHub MCP Server](https://github.com/github/github-mcp-server) exposes 79 tools — **~52,000 tokens** of context window on every request. A PR review agent needs about 10 of them. The other 69 (gists, stars, security advisories, dependabot, discussions...) consume tokens and make tool selection harder for the model.
|
|
23
23
|
|
|
24
|
-
`
|
|
24
|
+
Most MCP clients offer blacklists like `disabledTools` — you list what to block. This works until the upstream server adds a new tool. It silently appears in context because it's not in your blocklist. You find out when the agent calls a tool you didn't know existed.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
- **Focus** — Fewer tools means better tool selection by the model
|
|
28
|
-
- **Security** — Block destructive operations (`delete_*`, `push_*`) before they reach the agent
|
|
29
|
-
- **Future-proof** — `--include` whitelists are immune to upstream adding new tools
|
|
26
|
+
Blacklists describe what you *don't* want. Whitelists describe what you *do* want — and they're immune to upstream changes.
|
|
30
27
|
|
|
31
|
-
##
|
|
28
|
+
## The Solution
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
**Local server** — filter tools from a stdio MCP server:
|
|
30
|
+
`mcp-filter` is an MCP proxy that sits between your client and server. It intercepts tool/resource/prompt lists, applies glob patterns, and only passes through what matches. Add it to your MCP client's JSON config:
|
|
36
31
|
|
|
37
32
|
```json
|
|
38
33
|
{
|
|
@@ -52,7 +47,10 @@ Add mcp-filter to your MCP client config. No install needed — `npx` downloads
|
|
|
52
47
|
}
|
|
53
48
|
```
|
|
54
49
|
|
|
55
|
-
|
|
50
|
+
No install needed — `npx` downloads it automatically. This config format works with Cursor, VS Code, Claude Desktop, and any MCP client that supports stdio servers.
|
|
51
|
+
|
|
52
|
+
<details>
|
|
53
|
+
<summary>Remote server (HTTP)</summary>
|
|
56
54
|
|
|
57
55
|
```json
|
|
58
56
|
{
|
|
@@ -70,7 +68,10 @@ Add mcp-filter to your MCP client config. No install needed — `npx` downloads
|
|
|
70
68
|
}
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
</details>
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>Remote server with authentication</summary>
|
|
74
75
|
|
|
75
76
|
```json
|
|
76
77
|
{
|
|
@@ -91,13 +92,84 @@ Add mcp-filter to your MCP client config. No install needed — `npx` downloads
|
|
|
91
92
|
|
|
92
93
|
For additional headers, use `--header "Key: Value"` (repeatable).
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
<details>
|
|
98
|
+
<summary>Claude Code</summary>
|
|
99
|
+
|
|
100
|
+
Claude Code uses `claude mcp add` instead of JSON config:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Local server (two -- separators: first for Claude, second for mcp-filter)
|
|
104
|
+
claude mcp add playwright-safe -- \
|
|
105
|
+
npx mcp-filter \
|
|
106
|
+
--exclude "browser_close" \
|
|
107
|
+
--exclude "browser_evaluate" \
|
|
108
|
+
--include "browser_*" \
|
|
109
|
+
-- npx @playwright/mcp@latest
|
|
110
|
+
|
|
111
|
+
# Remote HTTP server (no second --)
|
|
112
|
+
claude mcp add stripe-safe -- \
|
|
113
|
+
npx mcp-filter \
|
|
114
|
+
--exclude "create_refund" \
|
|
115
|
+
--exclude "delete_*" \
|
|
116
|
+
--upstream-url https://mcp.stripe.com
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
First `--` separates Claude's options from mcp-filter. Second `--` separates mcp-filter's options from the upstream command.
|
|
120
|
+
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
## How Filtering Works
|
|
124
|
+
|
|
125
|
+
mcp-filter supports three filtering modes:
|
|
126
|
+
|
|
127
|
+
**Exclude mode** blocks specific tools and allows everything else. Use `--exclude` when you trust most tools but want to remove a few dangerous ones: `--exclude "delete_*"` blocks all delete operations.
|
|
128
|
+
|
|
129
|
+
**Include mode** (whitelist) allows only what you specify and blocks everything else. Use `--include` when you want a tight perimeter: `--include "pull_request_*"` passes through only PR tools. New tools added upstream are automatically blocked.
|
|
130
|
+
|
|
131
|
+
**Combined mode** uses rsync-style ordering — patterns are evaluated in the order you write them, and the first match wins. This lets you create exceptions within a category:
|
|
95
132
|
|
|
96
|
-
|
|
133
|
+
```
|
|
134
|
+
--exclude "merge_pull_request" --include "pull_request_*"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Here, `merge_pull_request` hits the exclude rule first, so it's blocked. Other `pull_request_*` tools match the include rule and pass through. Anything that doesn't match any pattern is excluded (because `--include` exists).
|
|
138
|
+
|
|
139
|
+
Reversing the order would break this: `--include "pull_request_*" --exclude "merge_pull_request"` — now `merge_pull_request` matches `pull_request_*` first and gets included.
|
|
97
140
|
|
|
98
|
-
|
|
141
|
+
<details>
|
|
142
|
+
<summary>Pattern syntax and default behavior</summary>
|
|
99
143
|
|
|
100
|
-
|
|
144
|
+
Patterns use glob syntax via [minimatch](https://github.com/isaacs/minimatch):
|
|
145
|
+
|
|
146
|
+
| Pattern | Matches |
|
|
147
|
+
|---------|---------|
|
|
148
|
+
| `browser_*` | All items starting with `browser_` |
|
|
149
|
+
| `*_admin` | All items ending with `_admin` |
|
|
150
|
+
| `test_*_debug` | Items like `test_foo_debug` |
|
|
151
|
+
| `exact_name` | Exact match only |
|
|
152
|
+
| `*` | Everything |
|
|
153
|
+
|
|
154
|
+
Default behavior for unmatched items:
|
|
155
|
+
|
|
156
|
+
| Configuration | Unmatched items are... |
|
|
157
|
+
|---------------|------------------------|
|
|
158
|
+
| No patterns | Allowed (passthrough) |
|
|
159
|
+
| `--exclude` only | Allowed |
|
|
160
|
+
| `--include` only | Excluded (whitelist mode) |
|
|
161
|
+
| Mixed | Excluded if any `--include` exists |
|
|
162
|
+
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
## Real-World Examples
|
|
166
|
+
|
|
167
|
+
The [GitHub MCP Server](https://github.com/github/github-mcp-server) exposes 79 tools across 19 toolsets. Here's how different agents can get exactly the slice they need.
|
|
168
|
+
|
|
169
|
+
<details>
|
|
170
|
+
<summary>PR review agent — whitelist (79 → ~10 tools)</summary>
|
|
171
|
+
|
|
172
|
+
A code review agent only needs PRs, issues, file contents, and search. Everything else — gists, stars, notifications, security advisories — is noise.
|
|
101
173
|
|
|
102
174
|
```json
|
|
103
175
|
{
|
|
@@ -122,9 +194,14 @@ The [GitHub MCP Server](https://github.com/github/github-mcp-server) is a good e
|
|
|
122
194
|
}
|
|
123
195
|
```
|
|
124
196
|
|
|
125
|
-
When GitHub adds new tools tomorrow, they won't leak through — only
|
|
197
|
+
When GitHub adds new tools tomorrow, they won't leak through — only the patterns above are visible to the agent.
|
|
126
198
|
|
|
127
|
-
|
|
199
|
+
</details>
|
|
200
|
+
|
|
201
|
+
<details>
|
|
202
|
+
<summary>Read-only agent — exclude mutations</summary>
|
|
203
|
+
|
|
204
|
+
An analytics agent that collects data for reports shouldn't be able to change anything. Exclude all write operations:
|
|
128
205
|
|
|
129
206
|
```json
|
|
130
207
|
{
|
|
@@ -151,7 +228,14 @@ When GitHub adds new tools tomorrow, they won't leak through — only `pull_requ
|
|
|
151
228
|
}
|
|
152
229
|
```
|
|
153
230
|
|
|
154
|
-
|
|
231
|
+
The agent can read anything but can't modify anything.
|
|
232
|
+
|
|
233
|
+
</details>
|
|
234
|
+
|
|
235
|
+
<details>
|
|
236
|
+
<summary>PR tools without merge — rsync-style exceptions</summary>
|
|
237
|
+
|
|
238
|
+
Allow all PR tools except the ability to merge. First match wins:
|
|
155
239
|
|
|
156
240
|
```json
|
|
157
241
|
{
|
|
@@ -175,28 +259,9 @@ When GitHub adds new tools tomorrow, they won't leak through — only `pull_requ
|
|
|
175
259
|
}
|
|
176
260
|
```
|
|
177
261
|
|
|
178
|
-
`merge_pull_request`
|
|
262
|
+
`merge_pull_request` hits the `--exclude` first and gets blocked. The remaining PR tools match `--include` and pass through.
|
|
179
263
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
Claude Code uses `claude mcp add` instead of JSON:
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
# Local server (two -- separators: first for Claude, second for mcp-filter)
|
|
186
|
-
claude mcp add playwright-safe -- \
|
|
187
|
-
npx mcp-filter \
|
|
188
|
-
--exclude "browser_close" \
|
|
189
|
-
--exclude "browser_evaluate" \
|
|
190
|
-
--include "browser_*" \
|
|
191
|
-
-- npx @playwright/mcp@latest
|
|
192
|
-
|
|
193
|
-
# Remote HTTP server (no second --)
|
|
194
|
-
claude mcp add stripe-safe -- \
|
|
195
|
-
npx mcp-filter \
|
|
196
|
-
--exclude "create_refund" \
|
|
197
|
-
--exclude "delete_*" \
|
|
198
|
-
--upstream-url https://mcp.stripe.com
|
|
199
|
-
```
|
|
264
|
+
</details>
|
|
200
265
|
|
|
201
266
|
## Options
|
|
202
267
|
|
|
@@ -210,58 +275,12 @@ claude mcp add stripe-safe -- \
|
|
|
210
275
|
| `--header <header>` | HTTP header as `"Key: Value"` (repeatable, HTTP/SSE only) |
|
|
211
276
|
| `--` | Separates mcp-filter options from upstream command (stdio only) |
|
|
212
277
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
### Pattern Syntax
|
|
278
|
+
Transport is auto-detected: `--upstream-url` selects HTTP, `-- <command>` selects stdio.
|
|
216
279
|
|
|
217
|
-
|
|
280
|
+
<details>
|
|
281
|
+
<summary>Common mistakes</summary>
|
|
218
282
|
|
|
219
|
-
|
|
220
|
-
|---------|---------|
|
|
221
|
-
| `browser_*` | All items starting with `browser_` |
|
|
222
|
-
| `*_admin` | All items ending with `_admin` |
|
|
223
|
-
| `test_*_debug` | Items like `test_foo_debug` |
|
|
224
|
-
| `exact_name` | Exact match only |
|
|
225
|
-
| `*` | Everything |
|
|
226
|
-
|
|
227
|
-
### Modes
|
|
228
|
-
|
|
229
|
-
| Configuration | Unmatched items are... |
|
|
230
|
-
|---------------|------------------------|
|
|
231
|
-
| No patterns | Allowed (passthrough) |
|
|
232
|
-
| `--exclude` only | Allowed |
|
|
233
|
-
| `--include` only | Excluded (whitelist mode) |
|
|
234
|
-
| Mixed | Excluded if any `--include` exists |
|
|
235
|
-
|
|
236
|
-
### Rsync-Style Ordering
|
|
237
|
-
|
|
238
|
-
Patterns are evaluated **in order** — first match wins. This lets you combine `--include` and `--exclude` for fine-grained control:
|
|
239
|
-
|
|
240
|
-
```json
|
|
241
|
-
"args": [
|
|
242
|
-
"mcp-filter",
|
|
243
|
-
"--exclude", "merge_pull_request",
|
|
244
|
-
"--include", "pull_request_*",
|
|
245
|
-
"--include", "list_pull_requests",
|
|
246
|
-
"--",
|
|
247
|
-
"github-mcp-server", "stdio"
|
|
248
|
-
]
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
```
|
|
252
|
-
merge_pull_request → matches --exclude → EXCLUDED
|
|
253
|
-
pull_request_read → matches --include → included
|
|
254
|
-
list_pull_requests → matches --include → included
|
|
255
|
-
create_gist → no match, --include exists → excluded (whitelist mode)
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
> **Order matters!** `--exclude "merge_pull_request" --include "pull_request_*"` blocks merge then includes the rest. Reversing the order would include `merge_pull_request` (it matches `pull_request_*` first).
|
|
259
|
-
|
|
260
|
-
## Common Mistakes
|
|
261
|
-
|
|
262
|
-
### JSON args must be separate strings
|
|
263
|
-
|
|
264
|
-
In JSON configs, each argument must be its own array element. The shell splits arguments for you — JSON doesn't.
|
|
283
|
+
**JSON args must be separate strings.** In JSON configs, each argument must be its own array element:
|
|
265
284
|
|
|
266
285
|
```jsonc
|
|
267
286
|
// WRONG
|
|
@@ -273,21 +292,14 @@ In JSON configs, each argument must be its own array element. The shell splits a
|
|
|
273
292
|
|
|
274
293
|
mcp-filter detects this mistake and shows a corrective error message.
|
|
275
294
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
Put `--exclude` patterns **before** `--include` to create exceptions. First match wins.
|
|
295
|
+
**Pattern order matters.** Put `--exclude` before `--include` to create exceptions. First match wins:
|
|
279
296
|
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
--
|
|
283
|
-
|
|
284
|
-
# WRONG: include matches first, exclude never fires
|
|
285
|
-
--include "browser_*" --exclude "browser_close"
|
|
297
|
+
```
|
|
298
|
+
--exclude "browser_close" --include "browser_*" (browser_close blocked)
|
|
299
|
+
--include "browser_*" --exclude "browser_close" (browser_close allowed!)
|
|
286
300
|
```
|
|
287
301
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
When using `claude mcp add`, the first `--` separates Claude's options from the mcp-filter command. The second `--` separates mcp-filter's options from the upstream server command:
|
|
302
|
+
**Two `--` in Claude Code.** First `--` separates Claude's options. Second `--` separates mcp-filter's options from the upstream command:
|
|
291
303
|
|
|
292
304
|
```bash
|
|
293
305
|
claude mcp add my-server -- npx mcp-filter --exclude "dangerous_*" -- npx upstream-server
|
|
@@ -295,7 +307,10 @@ claude mcp add my-server -- npx mcp-filter --exclude "dangerous_*" -- npx upstre
|
|
|
295
307
|
# Claude's -- mcp-filter's --
|
|
296
308
|
```
|
|
297
309
|
|
|
298
|
-
|
|
310
|
+
</details>
|
|
311
|
+
|
|
312
|
+
<details>
|
|
313
|
+
<summary>Transports</summary>
|
|
299
314
|
|
|
300
315
|
| Transport | Flag | Use Case | Status |
|
|
301
316
|
|-----------|------|----------|--------|
|
|
@@ -303,7 +318,10 @@ claude mcp add my-server -- npx mcp-filter --exclude "dangerous_*" -- npx upstre
|
|
|
303
318
|
| **HTTP** | `--upstream-url <url>` | Remote servers via Streamable HTTP | Stable |
|
|
304
319
|
| **SSE** | `--transport sse --upstream-url <url>` | Legacy remote servers via Server-Sent Events | Deprecated |
|
|
305
320
|
|
|
306
|
-
|
|
321
|
+
</details>
|
|
322
|
+
|
|
323
|
+
<details>
|
|
324
|
+
<summary>Development</summary>
|
|
307
325
|
|
|
308
326
|
```bash
|
|
309
327
|
git clone https://github.com/baranovxyz/mcp-filter.git
|
|
@@ -315,6 +333,8 @@ pnpm test
|
|
|
315
333
|
|
|
316
334
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines and [TESTING.md](TESTING.md) for the testing guide.
|
|
317
335
|
|
|
336
|
+
</details>
|
|
337
|
+
|
|
318
338
|
## Links
|
|
319
339
|
|
|
320
340
|
- [npm package](https://www.npmjs.com/package/mcp-filter)
|