filter-mcp-tools
by mapix
README.md
# filter-mcp-tools
[](https://www.npmjs.com/package/filter-mcp-tools)
[](https://github.com/mapix/filter-mcp-tools/actions/workflows/ci.yml)
`filter-mcp-tools` is a deterministic MCP tool-list relay. It connects to one
HTTP, legacy SSE, or stdio MCP server, lets an operator inspect the complete
catalog, and exposes a filtered stdio MCP server to Claude Code, Codex, or any
other local MCP client.
## Behavior
- Exact, glob, and regular-expression include/exclude rules match full tool names.
- Include rules are ORed. When any include rule exists, unmatched tools are removed.
- Exclude rules are ORed and always win over include rules.
- `tools/list` returns only retained tools; direct `tools/call` attempts for hidden
tools are rejected before reaching the upstream server.
- A zero-tool result fails closed unless `--allow-empty` is explicit.
- Tool pagination and `notifications/tools/list_changed` are handled.
- Prompts, resources, subscriptions, and completion requests pass through unchanged
when the upstream advertises them.
This is deterministic name filtering, not semantic retrieval. It is designed for
auditable allowlists and denylists.
## Recommended workflow
First inspect the upstream catalog without a filter:
```bash
npx -y filter-mcp-tools@latest list \
--url https://mcp.example.com/mcp \
--names-only
```
Then preview both sides of a proposed rule before exposing the relay:
```bash
npx -y filter-mcp-tools@latest list \
--url https://mcp.example.com/mcp \
--include-glob 'docs_*' \
--exclude-regex '/delete|remove/i' \
--show kept
npx -y filter-mcp-tools@latest list \
--url https://mcp.example.com/mcp \
--include-glob 'docs_*' \
--exclude-regex '/delete|remove/i' \
--show removed
```
Move the accepted rules into a JSON config and use the same file for `list` and
`proxy`. This keeps review and runtime behavior identical.
## Install and test
```bash
npm install --global filter-mcp-tools
filter-mcp-tools --version
```
To develop locally:
```bash
git clone https://github.com/mapix/filter-mcp-tools.git
cd filter-mcp-tools
npm ci
npm run check
```
One-off use does not require a global install:
```bash
npx -y filter-mcp-tools@latest --help
```
## Inspect before filtering
List every tool from an HTTP MCP endpoint:
```bash
filter-mcp-tools list \
--url https://mcp.example.com/mcp \
--header-env Authorization=MCP_AUTHORIZATION
```
Preview a filter and include the match explanation and complete MCP schemas:
```bash
filter-mcp-tools list \
--url https://mcp.example.com/mcp \
--header-env Authorization=MCP_AUTHORIZATION \
--include-glob '*docs*' \
--exclude-regex '/delete|remove/i' \
--json
```
Useful output controls:
```bash
--show kept # all, kept, or removed
--names-only # one selected tool name per line
--json # schemas plus includedBy/excludedBy explanations
```
## Run as a relay
```bash
filter-mcp-tools proxy \
--url https://mcp.example.com/mcp \
--header-env Authorization=MCP_AUTHORIZATION \
--include-glob '*docs*' \
--exclude-regex '/delete|remove/i'
```
The relay speaks MCP over stdout/stdin, so stdout is reserved for protocol frames.
Diagnostics go to stderr and never include resolved header values.
Claude Code example (pin the version in long-lived configuration):
```bash
claude mcp add -s user filtered-docs -- \
npx -y filter-mcp-tools@0.1.0 proxy --config /absolute/path/filter.json
```
Codex uses the same stdio command:
```toml
[mcp_servers.filtered-docs]
command = "npx"
args = ["-y", "filter-mcp-tools@0.1.0", "proxy", "--config", "/absolute/path/filter.json"]
```
Clients with native per-server tool filtering can use that instead and avoid the
extra process.
## JSON configuration
Configuration avoids long client command lines and supports secret sources without
shell evaluation:
```json
{
"upstream": {
"transport": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": {
"env": "MCP_TOKEN",
"prefix": "Bearer "
},
"x-api-key": {
"command": [
"/usr/bin/security",
"find-generic-password",
"-s",
"my-mcp-token",
"-w"
]
}
}
},
"filter": {
"include": ["docs_read"],
"includeGlob": ["docs_*"],
"includeRegex": ["/^wiki_(read|search)$/"],
"exclude": [],
"excludeGlob": ["*_admin"],
"excludeRegex": ["/delete|remove/i"],
"ignoreCase": false
},
"allowEmpty": false
}
```
Run it with `filter-mcp-tools list --config filter.json` to preview, then change
`list` to `proxy`. Command secret sources use `execFile`, never a shell; only use
configuration files you trust.
[`examples/filter.example.json`](examples/filter.example.json) is a copyable
starting point.
Literal header values support `${ENV_VAR}` interpolation. Avoid putting secrets in
CLI arguments because process listings and shell history can expose them.
Use `--transport sse` only for a legacy HTTP+SSE upstream. Streamable HTTP is the
default for `--url`; the relay exposed to the local client remains stdio in both
cases.
## Stdio upstream
```bash
filter-mcp-tools list \
--transport stdio \
--stdio-command node \
--stdio-arg ./server.mjs \
--include-regex '/^docs_/'
```
The JSON equivalents are `upstream.command`, `args`, `cwd`, and `env`.
## Scope and security
This relay is a client-side visibility and invocation boundary. A user who controls
the relay configuration can change its filters, so it does not replace authorization
on the upstream MCP server. Enforce real access through server-, key-, team-, or
identity-bound policy, then use this package to narrow the already-authorized set.
See [SECURITY.md](SECURITY.md) for vulnerability reporting.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues