{
  "markdown": "# MCP Orchestrator\n\n<!-- mcp-name: io.github.rupinder2/mcp-orchestrator -->\n\n[![PyPI Version](https://img.shields.io/pypi/v/mcp-orchestrator.svg)](https://pypi.org/project/mcp-orchestrator/)\n[![Python Version](https://img.shields.io/pypi/pyversions/mcp-orchestrator)](https://pypi.org/project/mcp-orchestrator/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Tests](https://github.com/rupinder2/mcp-orchestrator/actions/workflows/ci.yml/badge.svg)](https://github.com/rupinder2/mcp-orchestrator/actions)\n[![Contributions Welcome](https://img.shields.io/badge/Contributions-Welcome-blue.svg)](CONTRIBUTING.md)\n\nA central hub that connects to multiple downstream MCP servers, aggregates their tools, and provides unified access with powerful tool search capabilities.\n\n> Built around **deferred tool loading** — search across all your servers without blowing Claude's context window.\n\n## Features\n\n- **Config-based Server Registration**: Add downstream MCP servers via JSON config file\n- **Tool Namespacing**: Automatic `server_name__tool_name` format\n- **Tool Search**: Unified BM25/regex search with deferred loading support\n- **Flexible Authentication**: Static saved headers or token forwarding\n- **Multiple Transports**: stdio or HTTP\n- **Tool Definition Caching**: Cached definitions, raw result passthrough\n- **Storage Backends**: In-memory (development) or Redis (production)\n\n## Quick Start\n\n### Installation\n\n```bash\npip install mcp-orchestrator\n```\n\n### Running the MCP Server\n\n```bash\n# Run as stdio MCP server (for Claude Desktop, Cursor, etc.)\nmcp-orchestrator\n\n# Or run with Python directly\npython -m mcp_orchestrator.main\n```\n\n**HTTP Transport:**\n\n```bash\nORCHESTRATOR_TRANSPORT=http ORCHESTRATOR_PORT=8080 python -m mcp_orchestrator.main\n```\n\nThis starts the server on `http://localhost:8080/mcp` with CORS enabled.\n\n### Configuring Servers\n\nAdd downstream MCP servers in `server_config.json`:\n\n```json\n{\n  \"servers\": [\n    {\n      \"name\": \"my-server\",\n      \"url\": \"http://localhost:8080/mcp\",\n      \"transport\": \"http\",\n      \"auth_type\": \"static\",\n      \"auth_headers\": {\n        \"Authorization\": \"Bearer my-token\"\n      }\n    },\n    {\n      \"name\": \"my-stdio-server\",\n      \"url\": \"server.py\",\n      \"transport\": \"stdio\",\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"python\", \"server.py\"]\n    }\n  ]\n}\n```\n\n### Searching for Tools\n\nThe orchestrator provides unified tool search (BM25 by default, regex optional):\n\n```python\n# BM25 search (default - natural language)\nresults = await mcp_client.call_tool(\"tool_search\", {\n    \"query\": \"get weather information\",\n    \"max_results\": 3\n})\n\n# Regex search (set use_regex=true)\nresults = await mcp_client.call_tool(\"tool_search\", {\n    \"query\": \"weather|forecast\",\n    \"use_regex\": true,\n    \"max_results\": 3\n})\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────┐\n│                  MCP Orchestrator                    │\n│                                                      │\n│  ┌──────────────────────────────────────────────┐   │\n│  │              FastMCP Server                   │   │\n│  │  ┌─────────────┐  ┌──────────────────┐   │   │\n│  │  │ tool_search │  │ call_remote_tool  │   │   │\n│  │  └─────────────┘  └──────────────────┘   │   │\n│  └──────────────────────────────────────────────┘   │\n│                                                      │\n│  ┌──────────┐  ┌──────────┐  ┌──────────────┐      │\n│  │  Server  │  │   Tool   │  │   Storage    │      │\n│  │ Registry │  │  Search  │  │(Memory/Redis)│      │\n│  └──────────┘  └──────────┘  └──────────────┘      │\n└─────────────────────────────────────────────────────┘\n                           │\n        ┌───────────────────┼───────────────────┐\n        ▼                   ▼                   ▼\n   ┌─────────┐        ┌─────────┐        ┌─────────┐\n   │ MCP Svr │        │ MCP Svr │        │ MCP Svr │\n   │   #1    │        │   #2    │        │   #N    │\n   └─────────┘        └─────────┘        └─────────┘\n```\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STORAGE_BACKEND` | `memory` | Storage backend (`memory` or `redis`) |\n| `REDIS_URL` | `redis://localhost:6379/0` | Redis connection URL |\n| `MCP_ORCHESTRATOR_TOOL_CACHE_TTL` | `300` | Tool schema cache TTL in seconds |\n| `MCP_ORCHESTRATOR_DEFAULT_CONNECTION_MODE` | `stateless` | Default connection mode |\n| `MCP_ORCHESTRATOR_CONNECTION_TIMEOUT` | `30.0` | Connection timeout in seconds |\n| `MCP_ORCHESTRATOR_MAX_RETRIES` | `3` | Maximum retry attempts |\n| `ORCHESTRATOR_TRANSPORT` | `stdio` | MCP transport (`stdio` or `http`) |\n| `ORCHESTRATOR_PORT` | `8080` | Port for HTTP transport |\n| `ORCHESTRATOR_HOST` | `0.0.0.0` | Host for HTTP transport |\n| `ORCHESTRATOR_LOG_LEVEL` | `INFO` | Logging level |\n| `SERVER_CONFIG_PATH` | `server_config.json` | Path to server configuration file |\n\n### Claude Desktop Integration\n\nAdd to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"mcp-orchestrator\": {\n      \"command\": \"mcp-orchestrator\",\n      \"env\": {\n        \"STORAGE_BACKEND\": \"memory\",\n        \"ORCHESTRATOR_LOG_LEVEL\": \"INFO\"\n      }\n    }\n  }\n}\n```\n\n## MCP Tools\n\n### tool_search\n\nSearch for tools using BM25 relevance ranking or regex pattern matching.\n\n```python\n@mcp.tool()\nasync def tool_search(\n    query: str,\n    max_results: int = 3,\n    use_regex: bool = False,\n) -> dict:\n    \"\"\"Search for tools using BM25 or regex.\n\n    By default uses BM25 natural language search. Set use_regex=True\n    to search using Python regex patterns instead.\n    \"\"\"\n```\n\n### discover_tools\n\nDiscover tools from a registered downstream server.\n\n```python\n@mcp.tool()\nasync def discover_tools(\n    server_name: str,\n) -> dict:\n    \"\"\"Discover tools from a registered server and index them for search.\n\n    Returns the list of discovered tools with their schemas.\n    \"\"\"\n```\n\n### call_remote_tool\n\nCall a tool directly on a downstream MCP server.\n\n```python\n@mcp.tool()\nasync def call_remote_tool(\n    tool_name: str,\n    arguments: Optional[dict] = None,\n    auth_header: Optional[str] = None,\n) -> Any:\n    \"\"\"Call a tool on a downstream server.\n\n    Args:\n        tool_name: Namespaced tool name (server_name__tool_name)\n        arguments: Tool arguments\n        auth_header: Optional auth header to override server's configured auth\n    \"\"\"\n```\n\n## Tool Search Results\n\nThe search tools return results in the format expected by Claude's tool search system:\n\n```json\n{\n  \"success\": true,\n  \"tool_references\": [\n    {\n      \"type\": \"tool_reference\",\n      \"tool_name\": \"server_name__tool_name\"\n    }\n  ],\n  \"total_matches\": 5,\n  \"query\": \"weather\"\n}\n```\n\n## Testing\n\nRun the test suite:\n\n```bash\nuv run pytest\n```\n\nRun with coverage:\n\n```bash\nuv run pytest --cov=mcp_orchestrator\n```\n\n## Project Structure\n\n```\nmcp-orchestrator/\n├── src/mcp_orchestrator/\n│   ├── __init__.py\n│   ├── main.py              # Entry point\n│   ├── models.py            # Pydantic models\n│   ├── mcp_server.py        # FastMCP server\n│   ├── config_loader.py     # Config file loader\n│   ├── server/\n│   │   └── registry.py      # Server registry\n│   ├── tools/\n│   │   ├── router.py       # Tool router\n│   │   └── search.py       # Tool search service\n│   └── storage/\n│       ├── base.py          # Storage interface\n│       ├── memory.py        # In-memory backend\n│       └── redis.py         # Redis backend\n├── tests/\n│   ├── test_registry.py\n│   ├── test_search.py\n│   ├── test_storage.py\n│   ├── test_models.py\n│   └── test_integration.py\n├── server_config.json       # Pre-configured downstream servers\n├── pyproject.toml\n├── README.md\n└── .env                    # Environment variables (not committed)\n```\n\n## License\n\nMIT License\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n",
  "bytes": 7964,
  "sha": "8c1122baa6a569e3bb74b029dd6bf8dfd560c180b53978465199eafc395d57b7",
  "repo_slug": "rupinder2/mcp-orchestrator",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_rupinder2_mcp_orchestrator_7441d249/readme"
}