io.github.rupinder2/mcp-gateway
Aggregates tools from multiple MCP servers with unified BM25/regex search and deferred loading.
Open source Open in the app JSON README (API)
About
Aggregates tools from multiple MCP servers with unified BM25/regex search and deferred loading.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- rupinder2
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.1.1
- Stars
- 6
- Forks
- 3
- Last push
- 2026-02-26T01:47:08Z
- Repository state
- ativo
- Language
- Python
- License
- MIT
- Added
- 2026-08-29 04:01:19
- Updated
- 2026-08-29 04:01:19
- Origin id
io.github.rupinder2/mcp-gateway
README
# MCP Orchestrator
<!-- mcp-name: io.github.rupinder2/mcp-orchestrator -->
[](https://pypi.org/project/mcp-orchestrator/)
[](https://pypi.org/project/mcp-orchestrator/)
[](https://opensource.org/licenses/MIT)
[](https://github.com/rupinder2/mcp-orchestrator/actions)
[](CONTRIBUTING.md)
A central hub that connects to multiple downstream MCP servers, aggregates their tools, and provides unified access with powerful tool search capabilities.
> Built around **deferred tool loading** — search across all your servers without blowing Claude's context window.
## Features
- **Config-based Server Registration**: Add downstream MCP servers via JSON config file
- **Tool Namespacing**: Automatic `server_name__tool_name` format
- **Tool Search**: Unified BM25/regex search with deferred loading support
- **Flexible Authentication**: Static saved headers or token forwarding
- **Multiple Transports**: stdio or HTTP
- **Tool Definition Caching**: Cached definitions, raw result passthrough
- **Storage Backends**: In-memory (development) or Redis (production)
## Quick Start
### Installation
```bash
pip install mcp-orchestrator
```
### Running the MCP Server
```bash
# Run as stdio MCP server (for Claude Desktop, Cursor, etc.)
mcp-orchestrator
# Or run with Python directly
python -m mcp_orchestrator.main
```
**HTTP Transport:**
```bash
ORCHESTRATOR_TRANSPORT=http ORCHESTRATOR_PORT=8080 python -m mcp_orchestrator.main
```
This starts the server on `http://localhost:8080/mcp` with CORS enabled.
### Configuring Servers
Add downstream MCP servers in `server_config.json`:
```json
{
"servers": [
{
"name": "my-server",
"url": "http://localhost:8080/mcp",
"transport": "http",
"auth_type": "static",
"auth_headers": {
"Authorization": "Bearer my-token"
}
},
{
"name": "my-stdio-server",
"url": "server.py",
"transport": "stdio",
"command": "uv",
"args": ["run", "python", "server.py"]
}
]
}
```
### Searching for Tools
The orchestrator provides unified tool search (BM25 by default, regex optional):
```python
# BM25 search (default - natural language)
results = await mcp_client.call_tool("tool_search", {
"query": "get weather information",
"max_results": 3
})
# Regex search (set use_regex=true)
results = await mcp_client.call_tool("tool_search", {
"query": "weather|forecast",
"use_regex": true,
"max_results": 3
})
```
## Architecture
```
┌─────────────────────────────────────────────────────┐
│ MCP Orchestrator │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ FastMCP Server │ │
│ │ ┌─────────────┐ ┌──────────────────┐ │ │
│ │ │ tool_search │ │ call_remote_tool │ │ │
│ │ └─────────────┘ └──────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Server │ │ Tool │ │ Storage │ │
│ │ Registry │ │ Search │ │(Memory/Redis)│ │
│ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ MCP Svr │ │ MCP Svr │ │ MCP Svr │
│ #1 │ │ #2 │ │ #N │
└─────────┘ └─────────┘ └─────────┘
```
## Configuration
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `STORAGE_BACKEND` | `memory` | Storage backend (`memory` or `redis`) |
| `REDIS_URL` | `redis://localhost:6379/0` | Redis connection URL |
| `MCP_ORCHESTRATOR_TOOL_CACHE_TTL` | `300` | Tool schema cache TTL in seconds |
| `MCP_ORCHESTRATOR_DEFAULT_CONNECTION_MODE` | `stateless` | Default connection mode |
| `MCP_ORCHESTRATOR_CONNECTION_TIMEOUT` | `30.0` | Connection timeout in seconds |
| `MCP_ORCHESTRATOR_MAX_RETRIES` | `3` | Maximum retry attempts |
| `ORCHESTRATOR_TRANSPORT` | `stdio` | MCP transport (`stdio` or `http`) |
| `ORCHESTRATOR_PORT` | `8080` | Port for HTTP transport |
| `ORCHESTRATOR_HOST` | `0.0.0.0` | Host for HTTP transport |
| `ORCHESTRATOR_LOG_LEVEL` | `INFO` | Logging level |
| `SERVER_CONFIG_PATH` | `server_config.json` | Path to server configuration file |
### Claude Desktop Integration
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"mcp-orchestrator": {
"command": "mcp-orchestrator",
"env": {
"STORAGE_BACKEND": "memory",
"ORCHESTRATOR_LOG_LEVEL": "INFO"
}
}
}
}
```
## MCP Tools
### tool_search
Search for tools using BM25 relevance ranking or regex pattern matching.
```python
@mcp.tool()
async def tool_search(
query: str,
max_results: int = 3,
use_regex: bool = False,
) -> dict:
"""Search for tools using BM25 or regex.
By default uses BM25 natural language search. Set use_regex=True
to search using Python regex patterns instead.
"""
```
### discover_tools
Discover tools from a registered downstream server.
```python
@mcp.tool()
async def discover_tools(
server_name: str,
) -> dict:
"""Discover tools from a registered server and index them for search.
Returns the list of discovered tools with their schemas.
"""
```
### call_remote_tool
Call a tool directly on a downstream MCP server.
```python
@mcp.tool()
async def call_remote_tool(
tool_name: str,
arguments: Optional[dict] = None,
auth_header: Optional[str] = None,
) -> Any:
"""Call a tool on a downstream server.
Args:
tool_name: Namespaced tool name (server_name__tool_name)
arguments: Tool arguments
auth_header: Optional auth header to override server's configured auth
"""
```
## Tool Search Results
The search tools return results in the format expected by Claude's tool search system:
```json
{
"success": true,
"tool_references": [
{
"type": "tool_reference",
"tool_name": "server_name__tool_name"
}
],
"total_matches": 5,
"query": "weather"
}
```
## Testing
Run the test suite:
```bash
uv run pytest
```
Run with coverage:
```bash
uv run pytest --cov=mcp_orchestrator
```
## Project Structure
```
mcp-orchestrator/
├── src/mcp_orchestrator/
│ ├── __init__.py
│ ├── main.py # Entry point
│ ├── models.py # Pydantic models
│ ├── mcp_server.py # FastMCP server
│ ├── config_loader.py # Config file loader
│ ├── server/
│ │ └── registry.py # Server registry
│ ├── tools/
│ │ ├── router.py # Tool router
│ │ └── search.py # Tool search service
│ └── storage/
│ ├── base.py # Storage interface
│ ├── memory.py # In-memory backend
│ └── redis.py # Redis backend
├── tests/
│ ├── test_registry.py
│ ├── test_search.py
│ ├── test_storage.py
│ ├── test_models.py
│ └── test_integration.py
├── server_config.json # Pre-configured downstream servers
├── pyproject.toml
├── README.md
└── .env # Environment variables (not committed)
```
## License
MIT License
## Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.