mcp-filter 0.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +33 -0
- package/dist/cli.js.map +1 -0
- package/dist/filter.d.ts +9 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +14 -0
- package/dist/filter.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +16 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +72 -0
- package/dist/proxy.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-filter contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# mcp-filter
|
|
2
|
+
|
|
3
|
+
MCP server proxy to filter tools, resources, and prompts from upstream MCP servers.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g mcp-filter
|
|
9
|
+
# or use with npx
|
|
10
|
+
npx mcp-filter [options] -- <upstream-command>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Filter out playwright tools
|
|
17
|
+
npx mcp-filter --disable "playwright*" -- npx @playwright/mcp
|
|
18
|
+
|
|
19
|
+
# Filter multiple patterns
|
|
20
|
+
npx mcp-filter --disable "playwright*" --disable "unsafe_*" -- npx @playwright/mcp
|
|
21
|
+
|
|
22
|
+
# Use with any MCP server
|
|
23
|
+
npx mcp-filter --disable "debug*" -- node my-mcp-server.js
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Options
|
|
27
|
+
|
|
28
|
+
- `--disable <pattern>` - Glob pattern for tools/resources/prompts to disable (can be specified multiple times)
|
|
29
|
+
- `--` - Separates filter options from upstream server command
|
|
30
|
+
|
|
31
|
+
## Pattern Examples
|
|
32
|
+
|
|
33
|
+
- `playwright*` - Match all items starting with "playwright"
|
|
34
|
+
- `*_admin` - Match all items ending with "_admin"
|
|
35
|
+
- `test_*_debug` - Match items with pattern in middle
|
|
36
|
+
- `exact_name` - Match exact name
|
|
37
|
+
|
|
38
|
+
## How It Works
|
|
39
|
+
|
|
40
|
+
mcp-filter acts as a proxy between an MCP client and an upstream MCP server:
|
|
41
|
+
|
|
42
|
+
1. Spawns the upstream MCP server as a subprocess
|
|
43
|
+
2. Connects to it as an MCP client
|
|
44
|
+
3. Exposes a filtered MCP server interface
|
|
45
|
+
4. Filters `tools/list`, `resources/list`, and `prompts/list` responses
|
|
46
|
+
5. Blocks calls to filtered items with error responses
|
|
47
|
+
|
|
48
|
+
## Development
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Install dependencies
|
|
52
|
+
pnpm install
|
|
53
|
+
|
|
54
|
+
# Build
|
|
55
|
+
pnpm run build
|
|
56
|
+
|
|
57
|
+
# Test locally
|
|
58
|
+
./dist/index.js --disable "playwright*" -- npx tsx test-server.ts
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAuCtD"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function parseArgs(args) {
|
|
2
|
+
const disablePatterns = [];
|
|
3
|
+
const upstreamCommand = [];
|
|
4
|
+
let inUpstreamCommand = false;
|
|
5
|
+
for (let i = 0; i < args.length; i++) {
|
|
6
|
+
const arg = args[i];
|
|
7
|
+
if (inUpstreamCommand) {
|
|
8
|
+
upstreamCommand.push(arg);
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (arg === '--') {
|
|
12
|
+
inUpstreamCommand = true;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (arg === '--disable') {
|
|
16
|
+
const pattern = args[++i];
|
|
17
|
+
if (!pattern) {
|
|
18
|
+
throw new Error('--disable requires a pattern argument');
|
|
19
|
+
}
|
|
20
|
+
disablePatterns.push(pattern);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
24
|
+
}
|
|
25
|
+
if (upstreamCommand.length === 0) {
|
|
26
|
+
throw new Error('No upstream command specified. Use -- to separate filter args from upstream command');
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
disablePatterns,
|
|
30
|
+
upstreamCommand
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,eAAe,GAAa,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,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9B,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,CAAC,qFAAqF,CAAC,CAAC;IACzG,CAAC;IAED,OAAO;QACL,eAAe;QACf,eAAe;KAChB,CAAC;AACJ,CAAC"}
|
package/dist/filter.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAEA,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM,EAAE;IAEtC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC,UAAU,CAAC,CAAC,SAAS;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;CAGxD"}
|
package/dist/filter.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { minimatch } from 'minimatch';
|
|
2
|
+
export class Filter {
|
|
3
|
+
patterns;
|
|
4
|
+
constructor(patterns) {
|
|
5
|
+
this.patterns = patterns;
|
|
6
|
+
}
|
|
7
|
+
shouldDisable(name) {
|
|
8
|
+
return this.patterns.some(pattern => minimatch(name, pattern));
|
|
9
|
+
}
|
|
10
|
+
filterList(items) {
|
|
11
|
+
return items.filter(item => !this.shouldDisable(item.name));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../src/filter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,OAAO,MAAM;IACG;IAApB,YAAoB,QAAkB;QAAlB,aAAQ,GAAR,QAAQ,CAAU;IAAG,CAAC;IAE1C,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,UAAU,CAA6B,KAAU;QAC/C,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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
|
+
async function main() {
|
|
9
|
+
// Parse command line arguments
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
let config;
|
|
12
|
+
try {
|
|
13
|
+
config = parseArgs(args);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error(`Error: ${error.message}`);
|
|
17
|
+
console.error('Usage: mcp-filter [--disable <pattern>]... -- <upstream-command> [args...]');
|
|
18
|
+
console.error('Example: mcp-filter --disable "playwright*" -- npx @playwright/mcp');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
console.error(`Starting MCP filter with ${config.disablePatterns.length} pattern(s)`);
|
|
22
|
+
config.disablePatterns.forEach(p => console.error(` Disable: ${p}`));
|
|
23
|
+
// Spawn upstream server
|
|
24
|
+
const upstreamProcess = spawnUpstream(config.upstreamCommand);
|
|
25
|
+
// Create filter
|
|
26
|
+
const filter = new Filter(config.disablePatterns);
|
|
27
|
+
// Create proxy server
|
|
28
|
+
const proxy = new ProxyServer({
|
|
29
|
+
name: 'mcp-filter',
|
|
30
|
+
version: '0.1.0',
|
|
31
|
+
}, filter);
|
|
32
|
+
// Connect client to upstream server via subprocess stdio
|
|
33
|
+
const clientTransport = new StdioClientTransport({
|
|
34
|
+
command: config.upstreamCommand[0],
|
|
35
|
+
args: config.upstreamCommand.slice(1),
|
|
36
|
+
stderr: 'pipe',
|
|
37
|
+
});
|
|
38
|
+
await proxy.getClient().connect(clientTransport);
|
|
39
|
+
console.error('Connected to upstream server');
|
|
40
|
+
// Connect server to current process stdio (for the MCP client calling us)
|
|
41
|
+
const serverTransport = new StdioServerTransport();
|
|
42
|
+
await proxy.getServer().connect(serverTransport);
|
|
43
|
+
console.error('MCP filter proxy ready');
|
|
44
|
+
// Handle cleanup
|
|
45
|
+
const cleanup = () => {
|
|
46
|
+
console.error('Shutting down...');
|
|
47
|
+
upstreamProcess.kill();
|
|
48
|
+
process.exit(0);
|
|
49
|
+
};
|
|
50
|
+
process.on('SIGINT', cleanup);
|
|
51
|
+
process.on('SIGTERM', cleanup);
|
|
52
|
+
}
|
|
53
|
+
function spawnUpstream(command) {
|
|
54
|
+
const [cmd, ...args] = command;
|
|
55
|
+
const proc = spawn(cmd, args, {
|
|
56
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
+
});
|
|
58
|
+
// Forward stderr to our stderr
|
|
59
|
+
proc.stderr.on('data', (data) => {
|
|
60
|
+
process.stderr.write(data);
|
|
61
|
+
});
|
|
62
|
+
proc.on('error', (error) => {
|
|
63
|
+
console.error(`Failed to start upstream server: ${error.message}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
});
|
|
66
|
+
proc.on('exit', (code) => {
|
|
67
|
+
console.error(`Upstream server exited with code ${code}`);
|
|
68
|
+
process.exit(code || 0);
|
|
69
|
+
});
|
|
70
|
+
return proc;
|
|
71
|
+
}
|
|
72
|
+
main().catch((error) => {
|
|
73
|
+
console.error('Fatal error:', error);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
export declare class ProxyServer {
|
|
5
|
+
private server;
|
|
6
|
+
private client;
|
|
7
|
+
private filter;
|
|
8
|
+
constructor(serverInfo: {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
}, filter: Filter);
|
|
12
|
+
private setupHandlers;
|
|
13
|
+
getClient(): Client;
|
|
14
|
+
getServer(): Server;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +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;gBAGrB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAC7C,MAAM,EAAE,MAAM;IA2BhB,OAAO,CAAC,aAAa;IAmDrB,SAAS,IAAI,MAAM;IAInB,SAAS,IAAI,MAAM;CAGpB"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
export class ProxyServer {
|
|
5
|
+
server;
|
|
6
|
+
client;
|
|
7
|
+
filter;
|
|
8
|
+
constructor(serverInfo, filter) {
|
|
9
|
+
this.filter = filter;
|
|
10
|
+
this.client = new Client({
|
|
11
|
+
name: `${serverInfo.name}-client`,
|
|
12
|
+
version: serverInfo.version,
|
|
13
|
+
}, {
|
|
14
|
+
capabilities: {},
|
|
15
|
+
});
|
|
16
|
+
this.server = new Server(serverInfo, {
|
|
17
|
+
capabilities: {
|
|
18
|
+
tools: {},
|
|
19
|
+
resources: {},
|
|
20
|
+
prompts: {},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
this.setupHandlers();
|
|
24
|
+
}
|
|
25
|
+
setupHandlers() {
|
|
26
|
+
// Tools
|
|
27
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
+
const response = await this.client.listTools();
|
|
29
|
+
return {
|
|
30
|
+
tools: this.filter.filterList(response.tools),
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
34
|
+
if (this.filter.shouldDisable(request.params.name)) {
|
|
35
|
+
throw new Error(`Tool '${request.params.name}' is disabled by filter`);
|
|
36
|
+
}
|
|
37
|
+
return await this.client.callTool(request.params);
|
|
38
|
+
});
|
|
39
|
+
// Resources
|
|
40
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
41
|
+
const response = await this.client.listResources();
|
|
42
|
+
return {
|
|
43
|
+
resources: this.filter.filterList(response.resources),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
47
|
+
// Resources are identified by URI, not name, so we can't easily filter calls
|
|
48
|
+
// We'll allow reads but they won't be in the list if filtered
|
|
49
|
+
return await this.client.readResource(request.params);
|
|
50
|
+
});
|
|
51
|
+
// Prompts
|
|
52
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
53
|
+
const response = await this.client.listPrompts();
|
|
54
|
+
return {
|
|
55
|
+
prompts: this.filter.filterList(response.prompts),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
59
|
+
if (this.filter.shouldDisable(request.params.name)) {
|
|
60
|
+
throw new Error(`Prompt '${request.params.name}' is disabled by filter`);
|
|
61
|
+
}
|
|
62
|
+
return await this.client.getPrompt(request.params);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
getClient() {
|
|
66
|
+
return this.client;
|
|
67
|
+
}
|
|
68
|
+
getServer() {
|
|
69
|
+
return this.server;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-filter",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server proxy to filter tools, resources, and prompts from upstream MCP servers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-filter": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mcp",
|
|
16
|
+
"model-context-protocol",
|
|
17
|
+
"proxy",
|
|
18
|
+
"filter"
|
|
19
|
+
],
|
|
20
|
+
"author": "baranovxyz",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/baranovxyz/mcp-filter.git"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/baranovxyz/mcp-filter#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/baranovxyz/mcp-filter/issues"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"minimatch": "10.0.1"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "1.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "1.0.4",
|
|
38
|
+
"@types/node": "22.10.5",
|
|
39
|
+
"@vitest/coverage-v8": "2.1.8",
|
|
40
|
+
"typescript": "5.7.3",
|
|
41
|
+
"vitest": "2.1.8",
|
|
42
|
+
"zod": "3.24.1"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"dev": "tsc --watch",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:watch": "vitest --watch",
|
|
52
|
+
"test:coverage": "vitest --coverage"
|
|
53
|
+
}
|
|
54
|
+
}
|