mcp-filter 0.6.0 → 1.0.1
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/CHANGELOG.md +29 -3
- package/README.md +399 -97
- package/dist/core/config-loader.d.ts +22 -0
- package/dist/core/config-loader.d.ts.map +1 -0
- package/dist/core/config-loader.js +308 -0
- package/dist/core/config-loader.js.map +1 -0
- package/dist/core/config-schema.d.ts +1363 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +139 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/server-manager.d.ts +51 -0
- package/dist/core/server-manager.d.ts.map +1 -0
- package/dist/core/server-manager.js +149 -0
- package/dist/core/server-manager.js.map +1 -0
- package/dist/features/discovery/config-init.d.ts +37 -0
- package/dist/features/discovery/config-init.d.ts.map +1 -0
- package/dist/features/discovery/config-init.js +95 -0
- package/dist/features/discovery/config-init.js.map +1 -0
- package/dist/features/discovery/discovery-handler.d.ts +128 -0
- package/dist/features/discovery/discovery-handler.d.ts.map +1 -0
- package/dist/features/discovery/discovery-handler.js +629 -0
- package/dist/features/discovery/discovery-handler.js.map +1 -0
- package/dist/features/discovery/initialization.d.ts +126 -0
- package/dist/features/discovery/initialization.d.ts.map +1 -0
- package/dist/features/discovery/initialization.js +314 -0
- package/dist/features/discovery/initialization.js.map +1 -0
- package/dist/features/discovery/search-phase.d.ts +19 -0
- package/dist/features/discovery/search-phase.d.ts.map +1 -0
- package/dist/features/discovery/search-phase.js +76 -0
- package/dist/features/discovery/search-phase.js.map +1 -0
- package/dist/features/discovery/simple-rag.d.ts +30 -0
- package/dist/features/discovery/simple-rag.d.ts.map +1 -0
- package/dist/features/discovery/simple-rag.js +85 -0
- package/dist/features/discovery/simple-rag.js.map +1 -0
- package/dist/features/filtering/filter.d.ts +18 -0
- package/dist/features/filtering/filter.d.ts.map +1 -0
- package/dist/features/filtering/filter.js +43 -0
- package/dist/features/filtering/filter.js.map +1 -0
- package/dist/features/overrides/override-manager.d.ts +25 -0
- package/dist/features/overrides/override-manager.d.ts.map +1 -0
- package/dist/features/overrides/override-manager.js +67 -0
- package/dist/features/overrides/override-manager.js.map +1 -0
- package/dist/index.js +73 -34
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +3 -1
- package/dist/logger.js.map +1 -1
- package/dist/proxy.d.ts +21 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +250 -41
- package/dist/proxy.js.map +1 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +18 -1
- package/dist/transport.js.map +1 -1
- package/dist/utils/debug-logger.d.ts +2 -0
- package/dist/utils/debug-logger.d.ts.map +1 -0
- package/dist/utils/debug-logger.js +33 -0
- package/dist/utils/debug-logger.js.map +1 -0
- package/package.json +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.1] - 2026-03-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- Logger was writing info/success messages to stdout, corrupting MCP JSON-RPC stream and causing "not valid JSON" errors in clients like Cursor
|
|
12
|
+
|
|
13
|
+
## [1.0.0] - 2026-03-14
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- `--help` and `--version` CLI flags
|
|
17
|
+
- CI workflow (GitHub Actions, Node 20/22/24)
|
|
18
|
+
- CONTRIBUTING.md for OSS contributors
|
|
19
|
+
- Test for "all items filtered out" empty-list edge case
|
|
20
|
+
- Tests for `--help`, `--version`, and invalid CLI args
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Stable release**: Public API is now considered stable
|
|
24
|
+
- Version is now read from package.json at runtime (no longer hardcoded)
|
|
25
|
+
- List operations (`tools/list`, `resources/list`, `prompts/list`, `resources/templates/list`) now forward AbortSignal for cancellation support
|
|
26
|
+
- `fetchAllPages()` accepts AbortSignal and checks it between pages
|
|
27
|
+
- `resources/read` now forwards progress notifications (like `tools/call` and `prompts/get`)
|
|
28
|
+
- Reverse-direction handlers (`sampling/createMessage`, `roots/list`, `elicitation/create`) now forward cancellation signals
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- Cancellation not propagated during paginated list operations
|
|
32
|
+
- Missing signal forwarding in reverse-direction request handlers
|
|
33
|
+
|
|
8
34
|
## [0.6.0] - 2025-12-02
|
|
9
35
|
|
|
10
36
|
### Added
|
|
@@ -67,7 +93,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
67
93
|
- ADR-003 documenting subprocess delegation pattern
|
|
68
94
|
- Claude Code configuration with custom slash commands
|
|
69
95
|
|
|
70
|
-
## [0.3.0] - 2025-
|
|
96
|
+
## [0.3.0] - 2025-09-15
|
|
71
97
|
|
|
72
98
|
### Added
|
|
73
99
|
- Rsync-style pattern evaluation (first match wins)
|
|
@@ -76,13 +102,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
76
102
|
### Changed
|
|
77
103
|
- Pattern matching now evaluates in order with first-match-wins semantics
|
|
78
104
|
|
|
79
|
-
## [0.2.0] - 2025-01
|
|
105
|
+
## [0.2.0] - 2025-09-01
|
|
80
106
|
|
|
81
107
|
### Added
|
|
82
108
|
- Comprehensive documentation updates
|
|
83
109
|
- Testing infrastructure with Vitest
|
|
84
110
|
|
|
85
|
-
## [0.1.0] - 2025-
|
|
111
|
+
## [0.1.0] - 2025-08-15
|
|
86
112
|
|
|
87
113
|
### Added
|
|
88
114
|
- Initial release
|
package/README.md
CHANGED
|
@@ -1,119 +1,413 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">mcp-filter</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
MCP proxy that filters tools, resources, and prompts from upstream MCP servers using glob patterns.
|
|
5
|
+
<br />
|
|
6
|
+
Works with any MCP client. Supports local and remote servers.
|
|
7
|
+
</p>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/mcp-filter"><img src="https://img.shields.io/npm/v/mcp-filter.svg?style=flat-square" alt="npm version" /></a>
|
|
12
|
+
<a href="https://github.com/baranovxyz/mcp-filter/actions"><img src="https://img.shields.io/github/actions/workflow/status/baranovxyz/mcp-filter/ci.yml?branch=main&style=flat-square&label=tests" alt="CI" /></a>
|
|
13
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="License: MIT" /></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/mcp-filter"><img src="https://img.shields.io/node/v/mcp-filter?style=flat-square" alt="Node version" /></a>
|
|
15
|
+
<a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-spec%20conformant-green?style=flat-square" alt="MCP Spec" /></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Why mcp-filter?
|
|
21
|
+
|
|
22
|
+
MCP servers expose tools, resources, and prompts to AI agents — but you don't always want agents to have access to everything. `mcp-filter` sits between your MCP client and upstream server, filtering what gets through:
|
|
23
|
+
|
|
24
|
+
- **Security** — Block destructive operations (`delete_*`, `admin_*`) before they reach the agent
|
|
25
|
+
- **Focus** — Whitelist only the tools an agent needs for its specific task
|
|
26
|
+
- **Cost** — Fewer tools in context means fewer tokens consumed per request
|
|
27
|
+
- **Flexibility** — Works with any MCP server, any MCP client, any transport
|
|
2
28
|
|
|
3
|
-
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
29
|
+
## Quick Start
|
|
5
30
|
|
|
6
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g mcp-filter
|
|
33
|
+
# or use directly with npx (no install needed)
|
|
34
|
+
```
|
|
7
35
|
|
|
8
|
-
|
|
36
|
+
```bash
|
|
37
|
+
# Filter a local MCP server (stdio)
|
|
38
|
+
npx mcp-filter --exclude "browser_close" --exclude "browser_evaluate" -- npx @playwright/mcp
|
|
9
39
|
|
|
10
|
-
|
|
40
|
+
# Filter a remote MCP server (HTTP)
|
|
41
|
+
npx mcp-filter --exclude "delete_*" --upstream-url https://mcp.notion.com/mcp
|
|
11
42
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"mcpServers": {
|
|
15
|
-
"playwright-safe": {
|
|
16
|
-
"command": "npx",
|
|
17
|
-
"args": [
|
|
18
|
-
"mcp-filter",
|
|
19
|
-
"--exclude", "browser_close",
|
|
20
|
-
"--exclude", "browser_evaluate",
|
|
21
|
-
"--include", "browser_*",
|
|
22
|
-
"--",
|
|
23
|
-
"npx", "@playwright/mcp@latest"
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
43
|
+
# Whitelist mode — only allow specific tools
|
|
44
|
+
npx mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp
|
|
28
45
|
```
|
|
29
46
|
|
|
30
|
-
|
|
47
|
+
## Supported Transports
|
|
48
|
+
|
|
49
|
+
mcp-filter connects to upstream MCP servers via three transport types:
|
|
31
50
|
|
|
32
|
-
|
|
51
|
+
| Transport | Flag | Use Case | Status |
|
|
52
|
+
|-----------|------|----------|--------|
|
|
53
|
+
| **Stdio** | `-- <command>` | Local servers spawned as subprocesses | Stable |
|
|
54
|
+
| **HTTP** | `--upstream-url <url>` | Remote servers via Streamable HTTP | Stable |
|
|
55
|
+
| **SSE** | `--transport sse --upstream-url <url>` | Legacy remote servers via Server-Sent Events | Deprecated |
|
|
33
56
|
|
|
34
|
-
|
|
35
|
-
- **Control** - Whitelist only the tools your agent needs
|
|
36
|
-
- **Works everywhere** - Proxy any MCP server (local or remote)
|
|
57
|
+
Transport is auto-detected: `--upstream-url` selects HTTP by default, `-- <command>` selects stdio. Override with `--transport`.
|
|
37
58
|
|
|
38
|
-
##
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Local Servers (Stdio)
|
|
39
62
|
|
|
40
63
|
```bash
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
# Exclude specific tools
|
|
65
|
+
npx mcp-filter --exclude "playwright*" -- npx @playwright/mcp
|
|
66
|
+
|
|
67
|
+
# Include only specific tools (whitelist)
|
|
68
|
+
npx mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp
|
|
69
|
+
|
|
70
|
+
# Rsync-style: exclude exceptions, then include category
|
|
71
|
+
npx mcp-filter --exclude "browser_close" --include "browser_*" -- npx @playwright/mcp
|
|
72
|
+
|
|
73
|
+
# Works with any local MCP server
|
|
74
|
+
npx mcp-filter --exclude "debug*" -- node my-mcp-server.js
|
|
44
75
|
```
|
|
45
76
|
|
|
46
|
-
|
|
77
|
+
### Remote Servers (HTTP)
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Filter a remote HTTP MCP server
|
|
81
|
+
npx mcp-filter --exclude "delete_*" --upstream-url https://mcp.notion.com/mcp
|
|
82
|
+
|
|
83
|
+
# With authentication headers
|
|
84
|
+
npx mcp-filter --exclude "admin_*" \
|
|
85
|
+
--upstream-url https://api.example.com/mcp \
|
|
86
|
+
--header "Authorization: Bearer your-token-here"
|
|
87
|
+
|
|
88
|
+
# Multiple headers
|
|
89
|
+
npx mcp-filter --exclude "write_*" \
|
|
90
|
+
--upstream-url https://api.example.com/mcp \
|
|
91
|
+
--header "Authorization: Bearer token" \
|
|
92
|
+
--header "X-Team-Id: engineering"
|
|
93
|
+
```
|
|
47
94
|
|
|
48
|
-
|
|
95
|
+
### Legacy SSE Servers
|
|
49
96
|
|
|
50
97
|
```bash
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
--
|
|
98
|
+
# SSE transport (deprecated — prefer HTTP for new deployments)
|
|
99
|
+
npx mcp-filter --transport sse \
|
|
100
|
+
--upstream-url https://mcp.example.com/sse \
|
|
101
|
+
--exclude "dangerous_*"
|
|
54
102
|
```
|
|
55
103
|
|
|
56
|
-
|
|
104
|
+
## CLI Reference
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
mcp-filter [options] -- <upstream-command>
|
|
108
|
+
mcp-filter [options] --upstream-url <url>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Filtering Options
|
|
112
|
+
|
|
113
|
+
| Flag | Description |
|
|
114
|
+
|------|-------------|
|
|
115
|
+
| `--exclude <pattern>` | Exclude items matching glob pattern (repeatable) |
|
|
116
|
+
| `--include <pattern>` | Include only items matching glob pattern (repeatable) |
|
|
117
|
+
|
|
118
|
+
### Transport Options
|
|
119
|
+
|
|
120
|
+
| Flag | Description |
|
|
121
|
+
|------|-------------|
|
|
122
|
+
| `--upstream-url <url>` | Connect to remote HTTP/SSE server |
|
|
123
|
+
| `--transport <type>` | Transport type: `stdio`, `http`, `sse` (auto-detected) |
|
|
124
|
+
| `--header <header>` | HTTP header as `"Key: Value"` (repeatable, HTTP/SSE only) |
|
|
125
|
+
| `--` | Separates mcp-filter options from upstream command (stdio only) |
|
|
126
|
+
|
|
127
|
+
### Other Options
|
|
128
|
+
|
|
129
|
+
| Flag | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| `--help` | Show help message |
|
|
132
|
+
| `--version` | Show version number |
|
|
133
|
+
|
|
134
|
+
> **Note**: `--upstream-url` and `-- <command>` are mutually exclusive.
|
|
135
|
+
|
|
136
|
+
## Filtering Modes
|
|
137
|
+
|
|
138
|
+
### Exclude Mode
|
|
139
|
+
|
|
140
|
+
Block specific items, allow everything else:
|
|
57
141
|
|
|
58
142
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# Result: browser_close blocked, other browser_* allowed
|
|
143
|
+
npx mcp-filter --exclude "browser_close" --exclude "browser_evaluate" -- npx @playwright/mcp
|
|
144
|
+
```
|
|
62
145
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
146
|
+
### Include Mode (Whitelist)
|
|
147
|
+
|
|
148
|
+
Allow only specified items, block everything else:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npx mcp-filter --include "browser_navigate" --include "browser_screenshot" -- npx @playwright/mcp
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Rsync-Style Combination
|
|
155
|
+
|
|
156
|
+
Patterns are evaluated **in order** — first match wins. This lets you combine `--include` and `--exclude` for fine-grained control:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Exclude specific tools, then include the rest of the category
|
|
160
|
+
npx mcp-filter \
|
|
161
|
+
--exclude "browser_close" \
|
|
162
|
+
--exclude "browser_evaluate" \
|
|
163
|
+
--include "browser_*" \
|
|
164
|
+
-- npx @playwright/mcp
|
|
165
|
+
|
|
166
|
+
# Evaluation:
|
|
167
|
+
# browser_close → matches --exclude "browser_close" → EXCLUDED
|
|
168
|
+
# browser_evaluate → matches --exclude "browser_evaluate" → EXCLUDED
|
|
169
|
+
# browser_navigate → matches --include "browser_*" → included
|
|
170
|
+
# browser_screenshot → matches --include "browser_*" → included
|
|
171
|
+
# some_other_tool → no match, --include exists → excluded (whitelist mode)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
> **Order matters!** `--exclude "browser_close" --include "browser_*"` excludes `browser_close` then includes the rest. Reversing the order would include `browser_close` (it matches `browser_*` first).
|
|
175
|
+
|
|
176
|
+
### Pattern Syntax
|
|
177
|
+
|
|
178
|
+
Patterns use glob syntax via [minimatch](https://github.com/isaacs/minimatch):
|
|
179
|
+
|
|
180
|
+
| Pattern | Matches |
|
|
181
|
+
|---------|---------|
|
|
182
|
+
| `browser_*` | All items starting with `browser_` |
|
|
183
|
+
| `*_admin` | All items ending with `_admin` |
|
|
184
|
+
| `test_*_debug` | Items like `test_foo_debug` |
|
|
185
|
+
| `exact_name` | Exact match only |
|
|
186
|
+
| `*` | Everything |
|
|
187
|
+
|
|
188
|
+
### Default Behavior
|
|
189
|
+
|
|
190
|
+
| Configuration | Unmatched items are... |
|
|
191
|
+
|---------------|------------------------|
|
|
192
|
+
| No patterns | Allowed (passthrough) |
|
|
193
|
+
| `--exclude` only | Allowed |
|
|
194
|
+
| `--include` only | Excluded (whitelist mode) |
|
|
195
|
+
| Mixed | Excluded if any `--include` exists |
|
|
196
|
+
|
|
197
|
+
## MCP Spec Conformance
|
|
198
|
+
|
|
199
|
+
mcp-filter is a fully conformant MCP proxy. It transparently forwards all MCP protocol features while applying filters only to list/call operations.
|
|
200
|
+
|
|
201
|
+
### Filtered Operations
|
|
202
|
+
|
|
203
|
+
| Operation | Behavior |
|
|
204
|
+
|-----------|----------|
|
|
205
|
+
| `tools/list` | Drains all pages, filters by name, returns filtered list |
|
|
206
|
+
| `tools/call` | Blocks excluded tools with `-32602 InvalidParams` |
|
|
207
|
+
| `resources/list` | Drains all pages, filters by name |
|
|
208
|
+
| `resources/templates/list` | Drains all pages, filters by name |
|
|
209
|
+
| `resources/read` | Forwarded (filtered resources won't appear in list) |
|
|
210
|
+
| `resources/subscribe` | Forwarded to upstream |
|
|
211
|
+
| `resources/unsubscribe` | Forwarded to upstream |
|
|
212
|
+
| `prompts/list` | Drains all pages, filters by name |
|
|
213
|
+
| `prompts/get` | Blocks excluded prompts with `-32602 InvalidParams` |
|
|
214
|
+
| `completion/complete` | Blocks if referenced prompt is filtered; forwards resource completions |
|
|
215
|
+
| `logging/setLevel` | Forwarded to upstream |
|
|
216
|
+
|
|
217
|
+
### Forwarded Notifications
|
|
218
|
+
|
|
219
|
+
| Direction | Notification | Description |
|
|
220
|
+
|-----------|-------------|-------------|
|
|
221
|
+
| Upstream → Downstream | `notifications/tools/list_changed` | Tool list changed |
|
|
222
|
+
| Upstream → Downstream | `notifications/resources/list_changed` | Resource list changed |
|
|
223
|
+
| Upstream → Downstream | `notifications/prompts/list_changed` | Prompt list changed |
|
|
224
|
+
| Upstream → Downstream | `notifications/resources/updated` | Resource content updated |
|
|
225
|
+
| Upstream → Downstream | `notifications/message` | Log messages |
|
|
226
|
+
| Downstream → Upstream | `notifications/roots/list_changed` | Client roots changed |
|
|
227
|
+
|
|
228
|
+
### Reverse-Direction Requests (Server → Client)
|
|
229
|
+
|
|
230
|
+
| Request | Description |
|
|
231
|
+
|---------|-------------|
|
|
232
|
+
| `sampling/createMessage` | Forwarded from upstream to downstream client |
|
|
233
|
+
| `roots/list` | Forwarded from upstream to downstream client |
|
|
234
|
+
| `elicitation/create` | Forwarded from upstream to downstream client |
|
|
235
|
+
|
|
236
|
+
### Protocol Features
|
|
237
|
+
|
|
238
|
+
| Feature | Support |
|
|
239
|
+
|---------|---------|
|
|
240
|
+
| **Capability gating** | Only advertises capabilities the upstream server supports |
|
|
241
|
+
| **Instructions forwarding** | Upstream server instructions passed through to downstream |
|
|
242
|
+
| **Pagination** | Drains all pages before filtering (max 100 pages) |
|
|
243
|
+
| **Progress notifications** | Forwarded on `tools/call`, `prompts/get`, `resources/read` |
|
|
244
|
+
| **Cancellation propagation** | Downstream abort triggers upstream `notifications/cancelled` |
|
|
245
|
+
| **Graceful shutdown** | SIGINT/SIGTERM cleanly close both transports |
|
|
246
|
+
| **Connection timeout** | 30-second timeout prevents hang on unreachable servers |
|
|
247
|
+
|
|
248
|
+
## Architecture
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
┌─────────────┐ ┌──────────────────────────────────────┐ ┌──────────────┐
|
|
252
|
+
│ MCP Client │ stdio │ mcp-filter │ stdio/ │ Upstream │
|
|
253
|
+
│ (Claude, │◄───────►│ │ HTTP/ │ MCP Server │
|
|
254
|
+
│ Cursor, │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ SSE │ (Playwright, │
|
|
255
|
+
│ etc.) │ │ │ Server │→ │ Filter │→ │ Client │◄┼────────►│ Notion, │
|
|
256
|
+
│ │ │ └────────┘ └────────┘ └────────┘ │ │ etc.) │
|
|
257
|
+
└─────────────┘ └──────────────────────────────────────┘ └──────────────┘
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Four-layer design:**
|
|
261
|
+
|
|
262
|
+
1. **CLI** (`src/cli.ts`) — Parses arguments into a typed `FilterConfig`
|
|
263
|
+
2. **Transport Factory** (`src/transport.ts`) — Creates the appropriate client transport (stdio/HTTP/SSE)
|
|
264
|
+
3. **Filter Engine** (`src/filter.ts`) — Glob pattern matching via minimatch
|
|
265
|
+
4. **Proxy Server** (`src/proxy.ts`) — Dual-role MCP client + server with two-phase initialization
|
|
266
|
+
|
|
267
|
+
## Integration Guides
|
|
268
|
+
|
|
269
|
+
### Claude Code
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Add a filtered MCP server
|
|
273
|
+
claude mcp add playwright-safe -- \
|
|
274
|
+
npx mcp-filter \
|
|
275
|
+
--exclude "browser_close" \
|
|
276
|
+
--exclude "browser_evaluate" \
|
|
277
|
+
--include "browser_*" \
|
|
278
|
+
-- npx @playwright/mcp@latest
|
|
279
|
+
|
|
280
|
+
# Scopes: local (default), user (all projects), project (team-shared .mcp.json)
|
|
281
|
+
claude mcp add --scope user playwright-safe -- \
|
|
282
|
+
npx mcp-filter --include "browser_*" -- npx @playwright/mcp@latest
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Command structure:** first `--` separates Claude options from mcp-filter; second `--` separates mcp-filter options from the upstream command.
|
|
286
|
+
|
|
287
|
+
<details>
|
|
288
|
+
<summary>More Claude Code examples</summary>
|
|
289
|
+
|
|
290
|
+
**Read-only monitoring agent:**
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
claude mcp add browser-monitor -- \
|
|
294
|
+
npx mcp-filter \
|
|
295
|
+
--include "browser_navigate" \
|
|
296
|
+
--include "browser_snapshot" \
|
|
297
|
+
--include "browser_console_messages" \
|
|
298
|
+
--include "browser_network_requests" \
|
|
299
|
+
--include "browser_take_screenshot" \
|
|
300
|
+
-- npx @playwright/mcp@latest
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Testing agent (no destructive actions):**
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
claude mcp add browser-test -- \
|
|
307
|
+
npx mcp-filter \
|
|
308
|
+
--exclude "browser_close" \
|
|
309
|
+
--exclude "browser_tabs" \
|
|
310
|
+
--exclude "browser_evaluate" \
|
|
311
|
+
--include "browser_*" \
|
|
312
|
+
-- npx @playwright/mcp@latest
|
|
66
313
|
```
|
|
67
314
|
|
|
68
|
-
|
|
315
|
+
**Managing servers:**
|
|
69
316
|
|
|
70
|
-
|
|
317
|
+
```bash
|
|
318
|
+
claude mcp list # List all servers
|
|
319
|
+
claude mcp get playwright-safe # Show server details
|
|
320
|
+
claude mcp remove playwright-safe # Remove a server
|
|
321
|
+
```
|
|
71
322
|
|
|
72
|
-
|
|
323
|
+
</details>
|
|
324
|
+
|
|
325
|
+
### Cursor IDE
|
|
326
|
+
|
|
327
|
+
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
73
328
|
|
|
74
329
|
```json
|
|
75
330
|
{
|
|
76
331
|
"mcpServers": {
|
|
77
|
-
"
|
|
332
|
+
"playwright-safe": {
|
|
78
333
|
"command": "npx",
|
|
79
334
|
"args": [
|
|
80
335
|
"mcp-filter",
|
|
81
|
-
"--exclude", "
|
|
82
|
-
"--
|
|
336
|
+
"--exclude", "browser_close",
|
|
337
|
+
"--exclude", "browser_evaluate",
|
|
338
|
+
"--include", "browser_*",
|
|
83
339
|
"--",
|
|
84
|
-
"npx", "
|
|
340
|
+
"npx", "@playwright/mcp@latest"
|
|
85
341
|
]
|
|
86
342
|
}
|
|
87
343
|
}
|
|
88
344
|
}
|
|
89
345
|
```
|
|
90
346
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
- Cursor: `.cursor/mcp.json` or `~/.cursor/mcp.json`
|
|
347
|
+
<details>
|
|
348
|
+
<summary>More Cursor examples</summary>
|
|
94
349
|
|
|
95
|
-
|
|
350
|
+
**Whitelist mode:**
|
|
96
351
|
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"mcpServers": {
|
|
355
|
+
"playwright-readonly": {
|
|
356
|
+
"command": "npx",
|
|
357
|
+
"args": [
|
|
358
|
+
"mcp-filter",
|
|
359
|
+
"--include", "browser_navigate",
|
|
360
|
+
"--include", "browser_screenshot",
|
|
361
|
+
"--include", "browser_snapshot",
|
|
362
|
+
"--",
|
|
363
|
+
"npx", "@playwright/mcp@latest"
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
100
369
|
|
|
101
|
-
|
|
102
|
-
npx mcp-filter --exclude "delete_*" --upstream-url https://mcp.example.com/mcp
|
|
370
|
+
**Remote server with auth:**
|
|
103
371
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"mcpServers": {
|
|
375
|
+
"notion-safe": {
|
|
376
|
+
"command": "npx",
|
|
377
|
+
"args": [
|
|
378
|
+
"mcp-filter",
|
|
379
|
+
"--exclude", "delete_*",
|
|
380
|
+
"--exclude", "archive_*",
|
|
381
|
+
"--upstream-url", "https://mcp.notion.com/mcp",
|
|
382
|
+
"--header", "Authorization: Bearer your-token"
|
|
383
|
+
]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
</details>
|
|
390
|
+
|
|
391
|
+
### Any MCP Client
|
|
392
|
+
|
|
393
|
+
mcp-filter works with any MCP client that supports stdio servers. The upstream server can be local (stdio) or remote (HTTP/SSE):
|
|
394
|
+
|
|
395
|
+
```json
|
|
396
|
+
{
|
|
397
|
+
"command": "npx",
|
|
398
|
+
"args": ["mcp-filter", "--exclude", "pattern", "--", "npx", "your-mcp-server"]
|
|
399
|
+
}
|
|
108
400
|
```
|
|
109
401
|
|
|
110
402
|
## Common Mistakes
|
|
111
403
|
|
|
112
404
|
### JSON args must be separate strings
|
|
113
405
|
|
|
406
|
+
In JSON configs (Claude Desktop, Cursor, VS Code), each argument must be its own array element. The shell splits arguments for you — JSON doesn't.
|
|
407
|
+
|
|
114
408
|
**WRONG:**
|
|
115
409
|
```json
|
|
116
|
-
"args": ["mcp-filter", "--include browser_* --", "npx", "server"]
|
|
410
|
+
"args": ["mcp-filter", "--include browser_*", "--", "npx", "server"]
|
|
117
411
|
```
|
|
118
412
|
|
|
119
413
|
**CORRECT:**
|
|
@@ -121,68 +415,76 @@ npx mcp-filter --exclude "admin_*" \
|
|
|
121
415
|
"args": ["mcp-filter", "--include", "browser_*", "--", "npx", "server"]
|
|
122
416
|
```
|
|
123
417
|
|
|
124
|
-
|
|
418
|
+
mcp-filter detects this mistake and shows a corrective error message.
|
|
125
419
|
|
|
126
|
-
|
|
420
|
+
### Pattern order matters
|
|
127
421
|
|
|
128
|
-
|
|
129
|
-
Malformed argument: "--include browser_* --"
|
|
422
|
+
Put `--exclude` patterns **before** `--include` to create exceptions. First match wins.
|
|
130
423
|
|
|
131
|
-
|
|
132
|
-
|
|
424
|
+
```bash
|
|
425
|
+
# CORRECT: exclude first, then include the rest
|
|
426
|
+
--exclude "browser_close" --include "browser_*"
|
|
427
|
+
# Result: browser_close blocked, other browser_* allowed
|
|
133
428
|
|
|
134
|
-
|
|
135
|
-
|
|
429
|
+
# WRONG order: include matches first, exclude never fires
|
|
430
|
+
--include "browser_*" --exclude "browser_close"
|
|
431
|
+
# Result: ALL browser_* allowed including browser_close
|
|
136
432
|
```
|
|
137
433
|
|
|
138
|
-
###
|
|
434
|
+
### Two `--` separators in Claude Code
|
|
139
435
|
|
|
140
|
-
|
|
436
|
+
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:
|
|
141
437
|
|
|
142
438
|
```bash
|
|
143
|
-
|
|
144
|
-
|
|
439
|
+
claude mcp add my-server -- npx mcp-filter --exclude "dangerous_*" -- npx upstream-server
|
|
440
|
+
# ^^ ^^
|
|
441
|
+
# Claude's -- mcp-filter's --
|
|
145
442
|
```
|
|
146
443
|
|
|
147
|
-
##
|
|
444
|
+
## Programmatic API
|
|
148
445
|
|
|
149
|
-
|
|
150
|
-
|--------|-------------|
|
|
151
|
-
| `--include <pattern>` | Include items matching pattern (whitelist) |
|
|
152
|
-
| `--exclude <pattern>` | Exclude items matching pattern (blocklist) |
|
|
153
|
-
| `--upstream-url <url>` | Connect to remote HTTP/SSE server |
|
|
154
|
-
| `--transport <type>` | Transport: `stdio`, `http`, `sse` (auto-detected) |
|
|
155
|
-
| `--header <header>` | HTTP header (format: `"Key: Value"`) |
|
|
156
|
-
| `--help` | Show help |
|
|
446
|
+
mcp-filter exports its core modules for use in custom tooling:
|
|
157
447
|
|
|
158
|
-
|
|
448
|
+
```typescript
|
|
449
|
+
import { FilterEngine } from 'mcp-filter/filter';
|
|
450
|
+
import { ProxyServer } from 'mcp-filter/proxy';
|
|
451
|
+
import { createTransport } from 'mcp-filter/transport';
|
|
452
|
+
import type { FilterConfig, TransportConfig } from 'mcp-filter/types';
|
|
453
|
+
```
|
|
159
454
|
|
|
160
|
-
##
|
|
455
|
+
## Testing
|
|
161
456
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
457
|
+
187+ tests across 15 test suites covering unit tests, integration tests with real MCP servers, and full spec compliance validation.
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
pnpm test # Run all tests
|
|
461
|
+
pnpm test:coverage # With coverage report
|
|
462
|
+
pnpm test tests/unit/ # Unit tests only (fast)
|
|
167
463
|
```
|
|
168
464
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
465
|
+
Tests run on **Node 20, 22, and 24** via GitHub Actions CI.
|
|
466
|
+
|
|
467
|
+
See [TESTING.md](TESTING.md) for the full testing guide.
|
|
172
468
|
|
|
173
469
|
## Development
|
|
174
470
|
|
|
175
471
|
```bash
|
|
472
|
+
git clone https://github.com/baranovxyz/mcp-filter.git
|
|
473
|
+
cd mcp-filter
|
|
176
474
|
pnpm install
|
|
177
475
|
pnpm run build
|
|
178
476
|
pnpm test
|
|
179
477
|
```
|
|
180
478
|
|
|
479
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.
|
|
480
|
+
|
|
181
481
|
## Links
|
|
182
482
|
|
|
183
483
|
- [npm package](https://www.npmjs.com/package/mcp-filter)
|
|
184
|
-
- [GitHub](https://github.com/baranovxyz/mcp-filter)
|
|
484
|
+
- [GitHub repository](https://github.com/baranovxyz/mcp-filter)
|
|
485
|
+
- [Changelog](CHANGELOG.md)
|
|
486
|
+
- [MCP specification](https://modelcontextprotocol.io)
|
|
185
487
|
|
|
186
488
|
## License
|
|
187
489
|
|
|
188
|
-
MIT
|
|
490
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ConfigFile, ServerConfig, DiscoveryConfig, FilterConfig } from "../types.js";
|
|
2
|
+
import { ConfigValidationResult } from "./config-schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* Loads and validates the config file from project root
|
|
5
|
+
* Returns config even if validation fails (for graceful error reporting)
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadConfigFile(configPath?: string): ConfigFile | null;
|
|
8
|
+
/**
|
|
9
|
+
* Validates config file structure
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateConfigFile(config: ConfigFile): void;
|
|
12
|
+
/**
|
|
13
|
+
* Merges CLI config with config file
|
|
14
|
+
* CLI args take precedence over config file values
|
|
15
|
+
* Returns validation errors if config file is invalid
|
|
16
|
+
*/
|
|
17
|
+
export declare function mergeConfigs(cliConfig: FilterConfig | null, fileConfig: ConfigFile | null): {
|
|
18
|
+
servers: Map<string, ServerConfig>;
|
|
19
|
+
discovery: DiscoveryConfig;
|
|
20
|
+
validationErrors?: ConfigValidationResult;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAuC,MAAM,aAAa,CAAC;AAE3H,OAAO,EAAyB,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEnF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAwDrE;AA8CD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA0E3D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,YAAY,GAAG,IAAI,EAC9B,UAAU,EAAE,UAAU,GAAG,IAAI,GAC5B;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAAC,SAAS,EAAE,eAAe,CAAC;IAAC,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;CAAE,CAyJ/G"}
|