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.
Files changed (2) hide show
  1. package/README.md +127 -107
  2. 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 from upstream MCP servers using glob patterns.
4
+ MCP proxy that filters tools, resources, and prompts using glob patterns.
5
5
  <br />
6
- Works with any MCP client. Supports local and remote servers.
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
- ## Why mcp-filter?
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 per request. A PR review agent needs maybe 10 of them. The other 69 (gists, stars, security advisories, dependabot, discussions...) are noise that costs tokens and confuses tool selection.
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
- `mcp-filter` sits between your MCP client and upstream server, filtering what gets through:
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
- - **Cost** 79 tools 10 tools = ~80% fewer tokens per request
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
- ## Quick Start
28
+ ## The Solution
32
29
 
33
- Add mcp-filter to your MCP client config. No install needed `npx` downloads it automatically.
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
- **Remote server**filter tools from an HTTP MCP server:
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
- **Remote server with authentication:**
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
- This JSON format works with Cursor (`.cursor/mcp.json`), VS Code (`.vscode/mcp.json`), Claude Desktop (`claude_desktop_config.json`), and any MCP client that supports stdio servers.
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
- ## Examples: GitHub MCP Server
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
- The [GitHub MCP Server](https://github.com/github/github-mcp-server) is a good example of a large server that benefits from filtering. All examples below work with any MCP client that supports the JSON config format.
141
+ <details>
142
+ <summary>Pattern syntax and default behavior</summary>
99
143
 
100
- **PR review agent** whitelist only what's needed (79 → ~10 tools):
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 `pull_request_*`, `issue_*`, and the explicitly listed tools are visible.
197
+ When GitHub adds new tools tomorrow, they won't leak through — only the patterns above are visible to the agent.
126
198
 
127
- **Read-only agent** — exclude all mutations, keep all reads:
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
- **PR tools without merge** rsync-style, first match wins:
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` matches `--exclude` first, so it's blocked. The remaining `pull_request_*` tools pass through.
262
+ `merge_pull_request` hits the `--exclude` first and gets blocked. The remaining PR tools match `--include` and pass through.
179
263
 
180
- ### Claude Code
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
- ## Filtering
214
-
215
- ### Pattern Syntax
278
+ Transport is auto-detected: `--upstream-url` selects HTTP, `-- <command>` selects stdio.
216
279
 
217
- Patterns use glob syntax via [minimatch](https://github.com/isaacs/minimatch):
280
+ <details>
281
+ <summary>Common mistakes</summary>
218
282
 
219
- | Pattern | Matches |
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
- ### Pattern order matters
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
- ```bash
281
- # CORRECT: exclude first, then include the rest
282
- --exclude "browser_close" --include "browser_*"
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
- ### Two `--` separators in Claude Code
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
- ## Transports
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
- ## Development
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-filter",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "MCP server proxy to filter tools, resources, and prompts from upstream MCP servers",
5
5
  "type": "module",
6
6
  "bin": {