A Model Context Protocol (MCP) proxy server that aggregates multiple MCP servers into a single interface, enabling you to use tools from multiple sources simultaneously through Claude Desktop or Claude Code CLI.
MCP Funnel addresses two critical limitations in the current MCP ecosystem:
- Single Server Limitation: Claude Desktop and Claude Code CLI can only connect to one MCP server at a time
- Context Bloat: Most MCP servers expose all their tools with no filtering options, consuming valuable context space
MCP Funnel enables you to:
- Connect to multiple MCP servers simultaneously (GitHub, Memory, Filesystem, etc.)
- Fine-grained tool filtering: Hide specific tools that you don't need
- Pattern-based filtering: Use wildcards to hide entire categories of tools
- Reduce context usage: Significantly decrease token consumption by exposing only necessary tools
- Avoid tool name conflicts through automatic prefixing
- Multi-Server Aggregation: Connect to any number of MCP servers
- Tool Namespacing: Automatic prefixing prevents naming conflicts (
github__create_issue,memory__store_memory) - Flexible Filtering: Show/hide tools using wildcard patterns
- Granular Control: Filter individual tools that servers don't allow you to disable
- Context Optimization: Reduce MCP tool context usage by 40-60% through selective filtering
- Custom Transports: Supports stdio-based MCP servers (Docker, NPX, local binaries)
- Server Log Prefixing: Clear identification of which server is logging what
- Dynamic Tool Discovery: Experimental feature for reducing initial context usage (see limitations)
- Node.js 18+ and npm/yarn
- tsx for running TypeScript directly
- MCP servers you want to proxy (installed separately)
# Clone the repository
git clone https://github.com/yourusername/mcp-funnel.git
cd mcp-funnel
# Install dependencies
yarn install
# Create your configuration
cp .mcp-funnel.example.json .mcp-funnel.json
# Edit .mcp-funnel.json with your serversMCP Funnel supports two ways to specify configuration:
-
Implicit (default): Looks for
.mcp-funnel.jsonin the current working directorynpx mcp-funnel # Uses ./.mcp-funnel.json -
Explicit: Specify a custom config file path
npx mcp-funnel /path/to/config.json
Create a .mcp-funnel.json file in your project directory:
{
"servers": [
{
"name": "github",
"command": "docker",
"args": [
"run",
"--env-file",
".env",
"-i",
"--rm",
"ghcr.io/github/github-mcp-server"
]
},
{
"name": "memory",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
{
"name": "filesystem",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/directory"
]
}
],
"hideTools": [
"github__list_workflow_runs",
"github__get_workflow_run_logs",
"memory__debug_*",
"memory__dashboard_*",
"github__get_team_members"
],
"enableDynamicDiscovery": false
}- servers: Array of MCP servers to connect to
name: Unique identifier (used as tool prefix)command: Command to executeargs: Command arguments (optional)env: Environment variables (optional)
- exposeTools: Whitelist patterns for tools to expose (optional)
- hideTools: Blacklist patterns for tools to hide (optional)
- enableDynamicDiscovery: Enable experimental dynamic tool discovery (default: false)
Patterns match against the prefixed tool names (serverName__toolName) and support wildcards (*):
Individual tools:
github__get_team_members- Hide specific tool from GitHub servermemory__check_database_health- Hide specific tool from Memory server
Wildcard patterns:
memory__dashboard_*- All dashboard tools from Memory servergithub__debug_*- All debug tools from GitHub server*__workflow_*- All workflow-related tools from any servermemory__ingest_*- All ingestion tools from Memory server*__list_*- All list tools from any server
Common filtering examples:
"hideTools": [
"memory__dashboard_*", // Hide all dashboard tools from Memory
"memory__debug_*", // Hide all debug tools from Memory
"memory__ingest_*", // Hide ingestion tools from Memory
"github__get_team_members", // Hide specific GitHub tool
"github__*_workflow_*", // Hide workflow tools from GitHub
"*__list_*_artifacts" // Hide artifact listing tools from all servers
]Note: Always use the server prefix (e.g., github__, memory__) to target specific servers' tools. Use *__ at the beginning to match tools from any server.
Add to your configuration (e.g. path/to/your/project/.mcp.json):
{
"mcpServers": {
"mcp-funnel": {
"command": "npx",
"args": [
"mcp-funnel"
]
}
}
}This will use .mcp-funnel.json from your current working directory. To use a custom config path:
{
"mcpServers": {
"mcp-funnel": {
"command": "npx",
"args": [
"mcp-funnel",
"/path/to/your/.mcp-funnel.json"
]
}
}
}Add to your configuration (e.g. path/to/your/project/.gemini/settings.json):
{
"mcpServers": {
"mcp-funnel": {
"command": "npx",
"args": [
"mcp-funnel"
]
}
}
}Add to your configuration (e.g. ~/.codex/config.toml):
[mcp_servers.mcp-funnel]
command = "npx"
args = ["mcp-funnel"]Once configured, you can use natural language to interact with your aggregated tools:
"Load PRs for https://github.com/chris-schra/mcp-funnel"
This works seamlessly because MCP Funnel aggregates your GitHub server's tools with proper namespacing!
# Run from source (uses .mcp-funnel.json from current directory)
yarn dev
# Or build and test locally
yarn build
node dist/cli.js # Uses .mcp-funnel.json from current directory
node dist/cli.js /path/to/custom-config.json # Explicit configMCP Funnel includes a discover_tools_by_words tool that allows searching for tools by keywords. However, this feature currently has limited utility:
Claude Code CLI does not support dynamic tool updates. Once a session starts, the tool list is fixed. This means:
- The
discover_tools_by_wordstool can find matching tools - It can "enable" them in MCP Funnel's internal state
- But Claude won't see newly enabled tools until you restart the session
We're eagerly waiting for these issues to be resolved:
- claude-code#7519 - Dynamic tool discovery support
- claude-code#4118 - Runtime tool updates
Once these features land, dynamic discovery will significantly reduce initial context usage by loading only the tools you need on-demand.
When dynamic updates are supported, you'll be able to:
User: "I need to work with GitHub issues"
Assistant: *discovers and enables only GitHub issue tools*
User: "Now let's store some information"
Assistant: *discovers and enables only memory storage tools*
This will dramatically reduce context usage compared to loading 100+ tools upfront.
A typical MCP setup might expose:
- GitHub MCP: ~130 tools
- Memory MCP: ~30 tools
- Filesystem MCP: ~15 tools
- Total: 175+ tools consuming 60-70k tokens
Many of these tools are rarely used:
- Workflow management tools
- Team/organization tools
- Debug and diagnostic tools
- Dashboard interfaces
- Advanced embedding operations
With MCP Funnel, you can:
- Connect multiple servers: Use GitHub + Memory + Filesystem simultaneously
- Filter out noise: Hide tools you never use
- Save context: Reduce tool context from 70k to 30-40k tokens
- Maintain control: Unlike server-side filtering (which most don't support), you control exactly what's exposed
ββββββββββββββββββββββββββ
β CLI (e.g. Claude Code) β
ββββββββ¬ββββββββββββββββββ
β MCP Protocol via stdio
ββββββββΌβββββββ
β MCP Funnel β β Filtering happens here
ββββββββ¬βββββββ
β
βββββ΄βββββββ¬ββββββββββ¬ββββββββββ
β β β β
ββββΌβββββ βββββΌββββ βββββΌββββ βββββΌββββ
βGitHub β βMemory β βFS β β ... β β Each exposes all tools
βββββββββ βββββββββ βββββββββ βββββββββ
MCP Funnel:
- Connects to multiple MCP servers as a client
- Receives all tools from each server
- Applies your filtering rules
- Exposes only the filtered tools to Claude
- Routes tool calls to the appropriate backend server
MCP Funnel prefixes each server's stderr output for debugging:
[github] Connecting to GitHub API...
[memory] Database initialized at ~/.mcp-memory
[filesystem] Watching directory: /Users/example
- Tool not found: Check that the tool isn't filtered by
hideToolspatterns - Server fails to start: Check the command and args in your config
- Permission denied: Ensure MCP Funnel has permission to execute server commands
- Environment variables: Use the
envfield in server config for API keys
- Never commit API keys: Use environment variables or
.envfiles (git-ignored) - Filesystem access: Be careful with filesystem server paths
- Docker permissions: Ensure proper Docker socket access if using containerized servers
- Network isolation: Consider running in isolated environments for sensitive operations
- Connection retry logic for resilient server management
- Health monitoring and status reporting
- Graceful degradation when servers fail
- Structured logging with configurable levels
- Metrics and performance monitoring
- WebSocket transport support
- Full dynamic tool discovery (blocked on Claude Code CLI support)
Contributions are welcome! Key areas needing work:
- Error handling: Make MCP Funnel resilient to server failures
- Testing: Add comprehensive test coverage
- Logging: Implement structured logging
- Build pipeline: Set up proper TypeScript compilation and packaging
MIT - See LICENSE file in the repository root
Built on top of the Model Context Protocol SDK by Anthropic.
Note: This is an experimental tool in active development. Production use should include proper error handling and monitoring.