mcp-llm-router
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-llm-routerroute 'explain quantum entanglement' to deepseek-r1 and save to memory"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
╔════════════════════════════════════════════════════════════╗
║ ║
║ ███╗ ███╗ ██████╗██████╗ ██╗ ██╗ ███╗ ███╗║
║ ████╗ ████║██╔════╝██╔══██╗ ██║ ██║ ████╗ ████║║
║ ██╔████╔██║██║ ██████╔╝ ██║ ██║ ██╔████╔██║║
║ ██║╚██╔╝██║██║ ██╔═══╝ ██║ ██║ ██║╚██╔╝██║║
║ ██║ ╚═╝ ██║╚██████╗██║ ███████╗███████╗██║ ╚═╝ ██║║
║ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝║
║ ║
║ L L M R O U T E R ║
║ ║
╚════════════════════════════════════════════════════════════╝MCP LLM Router
A Model Context Protocol (MCP) server for routing LLM requests across multiple providers and connecting to other MCP servers. Designed with an "all-local except the brain" architecture for privacy and control.
Features (Unified Router + Judge)
One server, two roles:
mcp_llm_router.servernow ships Judge tools in-process—no separatemcp-as-a-judgeserver required.Multi-Provider LLM Routing: Route requests to OpenAI, OpenRouter, DeepInfra, and other OpenAI-compatible APIs.
Configurable "Brain" Model: Choose DeepSeek reasoning or any OpenAI-compatible model as the router brain.
Session Management: Track agent sessions with goals, constraints, and event logging.
Quality Gating (Judge): Plan → code → test → completion validation using the embedded Judge toolset.
MCP-Native Context: Embedded judge resources expose current task state, history, rubric, and workflow state snapshots.
Local-First Memory: Default: Local embeddings via Ollama with optional ChromaDB vector store for efficient semantic search. OpenAI-compatible endpoints supported as fallback.
Local Cross-Encoder Reranking: Optional privacy-focused reranking using Qwen3-Reranker-0.6B for improved search relevance without external API calls.
MCP Server Orchestration: Connect to and orchestrate multiple MCP servers.
Cross-Server Tool Calling: Call tools across different MCP servers.
Universal MCP Compatibility: Works with any MCP-compatible client (not tied to specific IDEs).
Related MCP server: MCP Server Copilot
Architecture: All-Local Except the Brain
This project follows an "all-local except the brain" design philosophy:
✅ Embeddings: Run locally via Ollama (default:
qwen3-embedding:0.6b)✅ Vector Storage: SQLite (default) or ChromaDB with HNSW indexing (optional RAG package)
✅ Document Chunking: Token-based chunking with overlap (optional RAG package)
✅ Semantic Search: Local cosine similarity with L2-normalized vectors
✅ Reranking: Optional local cross-encoder reranking with Qwen3-Reranker-0.6B
🌐 LLM "Brain": Configurable external API (DeepSeek, OpenAI, etc.) for reasoning and generation
Why? This architecture keeps your data and semantic search private and fast, while leveraging powerful external LLMs only for high-level reasoning tasks.
Installation
This project is tested on Python 3.12 and 3.13.
Quick Install (Recommended)
One-command automated installation:
./install.shThis script will:
✅ Create a Python virtual environment
✅ Install all dependencies from
pyproject.toml✅ Check for Ollama installation
✅ Verify the setup
✅ Display next steps with your specific paths
Manual Installation
If you prefer manual installation or need a Conda environment:
# Clone the repository
git clone https://github.com/groxaxo/mcp-llm-router.git
cd mcp-llm-router
# Option 1: Using venv (recommended)
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -U pip
pip install -e .
# Option 2: Using Conda
conda create -n mcp-router python=3.13 -y
conda activate mcp-router
pip install -U pip
pip install -e .Ollama Setup (Required for Local Embeddings)
Install Ollama for local, privacy-focused embeddings:
# Linux/macOS
curl -fsSL https://ollama.ai/install.sh | sh
# Or download from https://ollama.aiPull the embedding model:
ollama pull qwen3-embedding:0.6bVerify Ollama is running:
curl http://localhost:11434/api/versionAlternative Embedding Models:
nomic-embed-text- General-purpose embeddingsmxbai-embed-large- Larger model for better quality
Set via environment variable:
export EMBEDDINGS_MODEL="nomic-embed-text"Project Structure
mcp-llm-router/
├── install.sh # Automated installation script
├── README.md # This file
├── pyproject.toml # Python package configuration
│
├── mcp_llm_router/ # Main package
│ ├── server.py # MCP server entry point
│ ├── brain.py # LLM routing logic
│ ├── memory.py # Memory management (embeddings, search, rerank)
│ ├── codex.py # MCP server orchestration
│ └── judge/ # Embedded judge tools for quality gating
│
├── rag/ # Optional RAG package (ChromaDB, chunking)
│ ├── main.py # CLI for indexing and queries
│ ├── indexer.py # Document indexing
│ ├── retriever.py # Vector search
│ └── reranker.py # Local cross-encoder reranking
│
├── scripts/ # Utility scripts
│ ├── verify_server.py # Installation verification
│ ├── opencode # CLI tool for direct LLM requests
│ ├── mcp_client.py # MCP client for testing
│ └── mcp_manager.py # MCP server management
│
├── examples/ # Example configurations and demos
│ ├── demo_judge_gating.py # End-to-end judge workflow demo
│ ├── local_reranker_example.py # Local reranking example
│ ├── mcp-config.deepseek-ollama.json
│ └── mcp-config.local-reranker.json
│
└── tests/ # Test suite
├── test_server.py
├── test_mcp.py
└── test_local_reranker.pyConfiguration
MCP Server Configuration (mcp-config.json)
Canonical minimal config
{
"mcpServers": {
"llm-router": {
"command": "python",
"args": ["-m", "mcp_llm_router.server"],
"env": {
"DEEPSEEK_API_KEY": "your-deepseek-key",
"ROUTER_BRAIN_PROVIDER": "deepseek",
"ROUTER_BRAIN_MODEL": "deepseek-reasoner",
"ROUTER_BRAIN_API_KEY_ENV": "DEEPSEEK_API_KEY",
"EMBEDDINGS_PROVIDER": "ollama",
"EMBEDDINGS_BASE_URL": "http://localhost:11434",
"EMBEDDINGS_MODEL": "qwen3-embedding:0.6b"
}
}
}
}Provider override example
{
"mcpServers": {
"llm-router": {
"command": "python",
"args": ["-m", "mcp_llm_router.server"],
"env": {
"OPENROUTER_API_KEY": "sk-or-...",
"ROUTER_BRAIN_PROVIDER": "openrouter",
"ROUTER_BRAIN_MODEL": "anthropic/claude-3.7-sonnet",
"ROUTER_BRAIN_API_KEY_ENV": "OPENROUTER_API_KEY",
"ROUTER_BRAIN_BASE_URL": "https://openrouter.ai/api/v1",
"EMBEDDINGS_PROVIDER": "ollama",
"EMBEDDINGS_BASE_URL": "http://localhost:11434",
"EMBEDDINGS_MODEL": "qwen3-embedding:0.6b"
}
}
}
}Example Config + Demo
examples/mcp-config.deepseek-ollama.json- DeepSeek brain + Ollama embeddings + judge history persistence.examples/mcp-config.local-reranker.json- DeepSeek brain + Ollama embeddings + local cross-encoder reranking.examples/demo_judge_gating.py- End-to-end demo that indexes memory and walks a task through judge gating viarouter_chat.examples/local_reranker_example.py- Example of using local cross-encoder reranking to improve search relevance.
Run the demo:
python examples/demo_judge_gating.py --config examples/mcp-config.deepseek-ollama.jsonRun the local reranker example:
python examples/local_reranker_example.pyNote: the demo skips request_plan_approval because it requires user elicitation. Ensure DEEPSEEK_API_KEY (or LLM_API_KEY) is set and Ollama is running for embeddings.
Embedded judge resources + prompts
The embedded judge now exposes additive MCP resources and prompts alongside the existing tools:
Resources:
judge://current-taskjudge://task/{task_id}judge://task/{task_id}/historyjudge://policy/rubricjudge://workflow/states
Prompts:
start_judged_coding_tasksubmit_implementation_for_reviewprepare_testing_evidence
When an MCP client exposes roots, judge review/testing tools validate submitted paths against those roots. When roots are unavailable, the server preserves the existing stdio-first behavior.
Environment Variables
Set API keys in your environment or in the config:
export OPENAI_API_KEY="sk-proj-..."
export DEEPINFRA_API_KEY="..."
export OPENROUTER_API_KEY="sk-or-..."
export DEEPSEEK_API_KEY="..."Brain Configuration (Router LLM)
The canonical examples in this README use a DeepSeek brain + local Ollama embeddings baseline. Provider overrides only need to change the ROUTER_BRAIN_* variables and API key.
# Core brain settings
export ROUTER_BRAIN_MODEL="deepseek-reasoner"
export ROUTER_BRAIN_PROVIDER="deepseek"
export ROUTER_BRAIN_API_KEY_ENV="DEEPSEEK_API_KEY"
# Optional overrides
export ROUTER_BRAIN_BASE_URL="https://api.deepseek.com"
export ROUTER_BRAIN_MAX_TOKENS="4000"
export ROUTER_BRAIN_TEMPERATURE="0.2"You can also set the brain per session using the configure_brain tool.
Memory Configuration (Embeddings + Rerank)
Default: Local Ollama Embeddings (Recommended)
No API keys required! The default configuration uses local Ollama embeddings:
# Storage paths
export MCP_ROUTER_DATA_DIR="./.mcp-llm-router"
export MCP_ROUTER_MEMORY_DB="./.mcp-llm-router/memory.db"
# Local embeddings via Ollama (DEFAULT - no API key needed)
export EMBEDDINGS_PROVIDER="ollama"
export EMBEDDINGS_BASE_URL="http://localhost:11434"
export EMBEDDINGS_MODEL="qwen3-embedding:0.6b"
export EMBEDDINGS_PATH="/api/embed"
# No EMBEDDINGS_API_KEY_ENV needed for local Ollama!Alternative: OpenAI-Compatible Embeddings
If you prefer cloud-based embeddings:
# Embeddings via OpenAI
export EMBEDDINGS_PROVIDER="openai"
export EMBEDDINGS_BASE_URL="https://api.openai.com/v1"
export EMBEDDINGS_MODEL="text-embedding-3-small"
export EMBEDDINGS_API_KEY_ENV="OPENAI_API_KEY"
export EMBEDDINGS_PATH="/embeddings"Reranking (Optional)
Reranking is optional and defaults to "none". Three modes are available:
1. Local Cross-Encoder Reranking (Recommended for Privacy)
Uses the local Qwen3-Reranker-0.6B model for reranking without external API calls:
# Local cross-encoder reranking (requires transformers and torch)
export RERANK_PROVIDER="local"
export RERANK_MODE="local"
export RERANK_MODEL="tomaarsen/Qwen3-Reranker-0.6B-seq-cls" # Default modelRequirements:
Install PyTorch:
pip install torchInstall Transformers:
pip install transformersThe model will be automatically downloaded on first use (~1.2GB)
2. LLM-Based Reranking
Uses an external LLM API for reranking:
# Rerank using OpenAI-compatible LLM (optional)
export RERANK_PROVIDER="openai"
export RERANK_BASE_URL="https://api.openai.com/v1"
export RERANK_MODEL="gpt-4o-mini"
export RERANK_API_KEY_ENV="OPENAI_API_KEY"
export RERANK_PATH="/chat/completions"
export RERANK_MODE="llm"3. Disable Reranking
# Or disable reranking entirely (default)
export RERANK_PROVIDER="none"Judge Persistence (embedded Judge)
# Persist judge conversation history + task metadata
export MCP_JUDGE_DATABASE_URL="sqlite:///./.mcp-llm-router/judge_history.db"Advanced: ChromaDB + Token Chunking (RAG Package)
For enhanced semantic search with vector indexing and intelligent chunking, this repository includes an optional rag package that provides:
Token-based chunking with overlap for consistent semantic granularity
ChromaDB vector store with HNSW indexing for fast similarity search
L2-normalized embeddings for consistent cosine similarity
Batch embedding and efficient upserts
Using the RAG Package
Install additional dependencies (already included in
pyproject.toml):pip install -e . # chromadb, transformers are now includedIndex your codebase:
python -m rag.main --path . --exts .py,.md --interactiveThis will:
Scan the current directory for
.pyand.mdfilesChunk them into 400-token segments with 80-token overlap
Embed using Ollama (
qwen3-embedding:0.6b)Store in ChromaDB at
data/chroma/Enter interactive mode for testing queries
Use in your code:
from rag.retriever import retrieve from rag.indexer import index_path # Index documents stats = index_path("/path/to/docs", exts=[".py", ".md"]) print(f"Indexed {stats['files_indexed']} files") # Retrieve relevant chunks results = retrieve("How does authentication work?", top_k=5) for hit in results: print(f"Score: {hit['distance']:.4f}") print(f"File: {hit['meta']['path']}") print(f"Content: {hit['doc']}\n")
RAG Package Components:
rag/embedding_config.py- Configuration constantsrag/chunker.py- Token-based text chunkingrag/ollama_embedder.py- Ollama embedding with normalizationrag/chroma_store.py- ChromaDB initialization and managementrag/indexer.py- Document indexing pipelinerag/retriever.py- Vector search and retrievalrag/main.py- CLI for indexing and queries
Note: The RAG package is a self-contained enhancement. The core MCP server works with its built-in SQLite memory store without requiring ChromaDB.
Usage
Running MCP Servers
Using the Server Runner
# List configured servers
python scripts/mcp_server_runner.py list
# Run a specific server
python scripts/mcp_server_runner.py run llm-routerUsing the Server Manager
# Add a new server
python scripts/mcp_manager.py add my-server python -m my_mcp_server
# List servers
python scripts/mcp_manager.py list
# Test server connection
python scripts/mcp_manager.py test llm-router
# Remove a server
python scripts/mcp_manager.py remove my-serverConnecting to MCP Servers
Using the MCP Client
# List tools on a server
python scripts/mcp_client.py list-tools llm-router
# Call a tool on a server
python scripts/mcp_client.py call-tool llm-router start_session '{"goal": "Test session"}'Using the Server Manager for Cross-Server Operations
# Call a tool across all configured servers
python scripts/mcp_manager.py call start_session '{"goal": "Test all servers"}'MCP Tools Available
Session Management
start_session(goal, constraints, context, metadata)- Start a new agent sessionlog_event(session_id, kind, message, details)- Log events to a sessionget_session_context(session_id)- Retrieve full session data
LLM Routing
agent_llm_request(session_id, prompt, model, base_url, api_key_env, ...)- Route to LLM providersconfigure_brain(...)- Set the global or per-session brain model/settingsget_brain_config(session_id)- Read the active brain configurationrouter_chat(session_id, message, ...)- Main brain chat (memory + workflow guidance)
Memory (Embeddings + Rerank)
configure_memory(...)- Set embedding/rerank configuration globally or per-sessionmemory_index(namespace, texts, metadatas, doc_ids)- Index texts into memorymemory_search(namespace, query, top_k, rerank)- Retrieve relevant memory hitsmemory_delete(namespace, doc_id)- Delete one doc or a whole namespacememory_list_namespaces()- List namespacesmemory_stats()- Show memory counts
MCP Server Orchestration
connect_mcp_server(server_name, command, args, env)- Configure connection to another MCP serverlist_mcp_servers()- List configured MCP server connectionscall_mcp_tool(server_name, tool_name, arguments)- Call tools on other MCP serverslist_mcp_tools(server_name)- List tools available on another MCP server
Judge Tools (built-in)
set_coding_task(...)get_current_coding_task()request_plan_approval(...)judge_coding_plan(...)judge_code_change(...)judge_testing_implementation(...)judge_coding_task_completion(...)raise_obstacle(...)raise_missing_requirements(...)
Integration with MCP Clients
Any MCP-Compatible Client
The server works with any client that supports the MCP protocol:
{
"mcpServers": {
"llm-router": {
"command": "python",
"args": ["-m", "mcp_llm_router.server"],
"env": {
"OPENAI_API_KEY": "your-key"
}
}
}
}Example: Claude Desktop
Add to your Claude Desktop MCP configuration:
{
"mcpServers": {
"llm-router": {
"command": "python",
"args": ["-m", "mcp_llm_router.server"],
"env": {
"OPENAI_API_KEY": "sk-...",
"DEEPINFRA_API_KEY": "..."
}
}
}
}Example: Custom MCP Client
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
server_params = StdioServerParameters(
command="python",
args=["-m", "mcp_llm_router.server"],
env={"OPENAI_API_KEY": "your-key"}
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Start a session
result = await session.call_tool("start_session", {
"goal": "Test the MCP server"
})
print("Session started:", result)
if __name__ == "__main__":
asyncio.run(main())Provider Configuration
OpenAI
{
"base_url": null, # Uses default
"api_key_env": "OPENAI_API_KEY"
}OpenRouter
{
"base_url": "https://openrouter.ai/api/v1",
"api_key_env": "OPENROUTER_API_KEY"
}DeepInfra
{
"base_url": "https://api.deepinfra.com/v1/openai",
"api_key_env": "DEEPINFRA_API_KEY"
}CLI Tool
The opencode command provides direct CLI access:
# Basic usage
scripts/opencode run "What is Python"
# Use specific provider
scripts/opencode run "Explain Docker" --provider deepinfra --model meta-llama/Meta-Llama-3.1-70B-InstructDevelopment
Running the Server Directly
cd ~/mcp-llm-router
conda activate mcp-router
python -m mcp_llm_router.serverTesting
# Test server startup
timeout 5 python -m mcp_llm_router.server
# Test CLI
scripts/opencode run "Hello world"
# Test MCP client
python scripts/mcp_client.py list-tools llm-routerArchitecture
┌─────────────────┐ ┌──────────────────────────────────────┐
│ MCP Client │◄──►│ LLM Router MCP Server │
│ (Claude, etc.) │ │ ┌────────────────────────────────┐ │
└─────────────────┘ │ │ Session & Memory Management │ │
│ │ • SQLite/ChromaDB (local) │ │
│ │ • Ollama Embeddings (local) │ │
│ │ • L2-normalized vectors │ │
│ └────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ Brain (External LLM API) │ │
│ │ • DeepSeek / OpenAI / etc. │ │
│ │ • Reasoning & Generation │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────┘
│
▼
┌──────────────────┐
│ Other MCP Servers│
│ • File system │
│ • Database │
│ • APIs │
└──────────────────┘
All-Local Except the Brain:
✅ Embeddings: Ollama (local, no API key)
✅ Vector Store: SQLite or ChromaDB (local)
✅ Semantic Search: Local cosine similarity
🌐 LLM Brain: External API (configurable)License
MIT License - see LICENSE file for details.
# Basic usage with OpenAI (default)
scripts/opencode run "Explain quantum computing"
# Use a specific provider
scripts/opencode run "Write a Python function" --provider openrouter --model anthropic/claude-3-opus
# Use DeepInfra
scripts/opencode run "Summarize this text" --provider deepinfra --model meta-llama/Llama-3.1-70B-InstructAvailable providers:
openai(default) - Uses OPENAI_API_KEYopenrouter- Uses OPENROUTER_API_KEYdeepinfra- Uses DEEPINFRA_API_KEY
MCP Tools
When used as an MCP server in Antigravity, the following tools are available:
start_session
Start a new agent session with a goal and constraints.
{
"goal": "Implement user authentication",
"constraints": "Use JWT tokens, no external dependencies",
"context": "FastAPI application"
}log_event
Log events during an agent session (info, error, warning, success).
{
"session_id": "uuid-here",
"kind": "error",
"message": "Build failed",
"details": {"exit_code": 1}
}agent_llm_request
Make a request to an LLM provider within a session.
{
"session_id": "uuid-here",
"prompt": "How do I fix this error?",
"model": "gpt-4",
"base_url": "https://openrouter.ai/api/v1", # optional
"api_key_env": "OPENROUTER_API_KEY"
}get_session_context
Retrieve full session history and events.
{
"session_id": "uuid-here"
}Example Agent Workflow in Antigravity
Start session:
Call start_session with goal="Build a REST API for task management"Work on task:
Create files, run commands, etc.Log progress:
Call log_event with kind="info", message="Created database schema"When stuck:
Call agent_llm_request with prompt="How do I handle authentication?"Review context:
Call get_session_context to see full history
Development
Run the MCP server directly:
cd ~/mcp-llm-router
conda activate mcp-router
python -m mcp_llm_router.serverOr use the packaged CLI entrypoint after installation:
mcp-llm-routerInspector-style capability smoke check:
python scripts/inspector_smoke.pyArchitecture and contributor guides:
docs/architecture.mddocs/how-to-add-a-judge-tool.md
Environment Variables
Set these in your ~/.bashrc or Antigravity config:
export OPENAI_API_KEY="sk-..."
export OPENROUTER_API_KEY="sk-or-..."
export DEEPINFRA_API_KEY="..."Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceA local MCP server for RAG memory, semantic search, and context optimization using Ollama and SQLite. It serves as a central hub that manages document embeddings, text compression, and proxies calls to other sub-MCP servers.
- FlicenseAqualityDmaintenanceA meta MCP server that scales LLMs to 1000+ servers via automatic routing, without exposing all servers and tools directly.317
- AlicenseNot gradedqualityAmaintenanceA local-first LLM routing MCP server that keeps sensitive data on your own models, with fail-closed privacy and manager-worker delegation, exposing route and complete tools to any MCP client.MIT
- AlicenseNot gradedqualityBmaintenanceA self-hostable MCP server that routes prompts to multiple LLM providers using declarative policies, with multi-role orchestration for independence and verification.MIT
Related MCP Connectors
An MCP memory server. One memory your agents share — across models, devices and apps.
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
Cloud-hosted MCP server for durable AI memory
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/groxaxo/mcp-llm-router'
If you have feedback or need assistance with the MCP directory API, please join our Discord server