- Tool Gating MCP
Tool Gating MCP
Tool Gating MCP
An intelligent proxy/router for Model Context Protocol (MCP) that enables Claude Desktop and other MCP clients to dynamically discover and use tools from multiple MCP servers while maintaining a single connection point. This system prevents context bloat by intelligently selecting only the most relevant tools for each task.
🎯 The Problem
MCP clients like Claude Desktop must load all servers at startup and cannot dynamically add servers during conversations. When using multiple MCP servers:
- Exa server: 7 search tools (web, research papers, Twitter, companies, etc.)
- Puppeteer: Browser automation tools
- Context7: Documentation search tools
- Desktop Commander: 18+ desktop automation tools
Loading all servers directly leads to:
- 🚨 Context bloat: 100+ tools consuming most of the context window
- 🔒 Static configuration: Cannot add servers without restarting Claude
- 💸 Increased costs: More tokens consumed per request
- 🎯 Poor tool selection: AI struggles to choose from too many options
💡 The Solution
Tool Gating MCP acts as an intelligent proxy that:
- Single Connection: Claude Desktop connects only to Tool Gating
- Backend Management: Maintains connections to multiple MCP servers
- Smart Discovery: Finds relevant tools across all servers using semantic search
- Dynamic Provisioning: Loads only needed tools within token budgets
- Transparent Routing: Executes tools on appropriate backend servers
Example: Instead of configuring 10 MCP servers with 100+ tools, configure just Tool Gating. Then dynamically discover and use only the 2-3 tools you need.
🚀 Features
- Proxy Architecture: Single MCP server that routes to multiple backend servers
- Dynamic Tool Discovery: Find tools across all servers without manual configuration
- Semantic Search: Natural language queries to find the right tools
- Smart Provisioning: Load only relevant tools within token budgets
- Transparent Execution: Route tool calls to appropriate backend servers
- Native MCP Server: Direct integration with Claude Desktop via mcp-proxy
- Cross-Server Intelligence: Unified view of tools from Puppeteer, Exa, Context7, etc.
- Token Optimization: 90%+ reduction in context usage vs. loading all servers
- Zero Configuration: Claude Desktop needs only Tool Gating configuration
📋 Prerequisites
- Python 3.12+
- uv package manager
🔧 Installation
- Clone the repository:
git clone https://github.com/yourusername/tool-gating-mcp.git
cd tool-gating-mcp
- Create and activate virtual environment:
uv venv
source .venv/bin/activate # On Unix/macOS
# .venv\Scripts\activate # On Windows
- Install dependencies:
uv sync
- Install package in development mode:
uv pip install -e .
🏃 Running the Server
As HTTP API Server
# Start the server
tool-gating-mcp
# Or with uvicorn for development
uvicorn tool_gating_mcp.main:app --reload
The server will run on http://localhost:8000
API documentation available at:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc - MCP Endpoint:
http://localhost:8000/mcp(SSE transport)
As MCP Server (Recommended)
Tool Gating MCP is now a native MCP server that works directly with Claude Desktop:
-
Start the server:
tool-gating-mcp -
Install mcp-proxy (if not already installed):
uv tool install mcp-proxy -
Add to Claude Desktop:
Edit
~/Library/Application Support/Claude/claude_desktop_config.json:{ "mcpServers": { "tool-gating": { "command": "/Users/YOUR_USERNAME/.local/bin/mcp-proxy", "args": ["http://localhost:8000/mcp"] } } }Note: Replace
YOUR_USERNAMEwith your actual username. -
Restart Claude Desktop
You'll see Tool Gating's tools available in Claude, including:
discover_tools- Find relevant tools based on queriesprovision_tools- Select tools within token budgetsregister_tool- Add new tools to the registrylist_mcp_servers- View registered MCP servers- And more!
See MCP Native Usage Guide for detailed instructions.
🔍 API Endpoints
Tool Discovery
POST /api/tools/discover
Discover relevant tools based on semantic search.
Request:
{
"query": "I need to perform calculations",
"tags": ["math", "calculation"],
"limit": 5
}
Response:
{
"tools": [
{
"tool_id": "calculator",
"name": "Calculator",
"description": "Perform mathematical calculations",
"score": 0.95,
"matched_tags": ["math", "calculation"],
"estimated_tokens": 50
}
],
"query_id": "uuid",
"timestamp": "2024-01-01T00:00:00"
}
Tool Provisioning
POST /api/tools/provision
Select and format tools for LLM consumption with token budget enforcement.
Request:
{
"tool_ids": ["calculator", "web-search"],
"max_tools": 3
}
Response:
{
"tools": [
{
"name": "Calculator",
"description": "Perform mathematical calculations",
"parameters": { "type": "object", "properties": {...} },
"token_count": 50
}
],
"metadata": {
"total_tokens": 150,
"gating_applied": true
}
}
🔄 How It Works
-
Claude Desktop Configuration: Configure only Tool Gating MCP
{ "mcpServers": { "tool-gating": { "command": "mcp-proxy", "args": ["http://localhost:8000/mcp"] } } } -
Backend Server Connection: Tool Gating connects to multiple MCP servers
Tool Gating → puppeteer (browser tools) → exa (search tools) → context7 (documentation) → filesystem (file operations) -
Natural Language Discovery: "I need to search for research papers"
Claude → discover_tools → Semantic Search → Returns relevant tools -
Real-time Tool Execution: Tools are loaded on-demand
execute_tool("exa_research_paper_search", {...}) → Validates → Loads → ExecutesNo provisioning needed! Tools are dynamically loaded when you use them.
🎯 Usage Examples
Running the Demo
# Make sure the server is running first
tool-gating-mcp
# In another terminal, run the interactive demo
python demo.py
Manual Testing
# Test the server endpoints
python test_server.py
Example: Finding Math Tools
import httpx
import asyncio
async def find_math_tools():
async with httpx.AsyncClient() as client:
response = await client.post(
"http://localhost:8000/api/tools/discover",
json={
"query": "I need to solve equations",
"tags": ["math"],
"limit": 3
}
)
tools = response.json()["tools"]
print(f"Found {len(tools)} relevant tools")
for tool in tools:
print(f"- {tool['name']}: {tool['score']:.3f}")
asyncio.run(find_math_tools())
🧪 Testing
# Run all tests
pytest
# Run with coverage
pytest --cov=tool_gating_mcp
# Run specific test files
pytest tests/test_discovery_service.py -v
# Run integration tests
pytest tests/test_integration.py -v
📊 Architecture Details
- Tool Registration: Tools are registered with metadata, tags, and token estimates
- Semantic Search: User queries are embedded using sentence transformers
- Relevance Scoring: Tools are scored based on:
- Cosine similarity between query and tool embeddings
- Tag matches (adds 0.2 boost per matching tag)
- Real-time Loading: Tools are validated and loaded on-demand during execution
- MCP Formatting: Selected tools are formatted according to MCP protocol
🔧 Configuration
The system uses sensible defaults but can be configured:
- Max Tokens: Default 2000 tokens per request
- Max Tools: Default 10 tools per request
- Embedding Model:
all-MiniLM-L6-v2(384-dimensional embeddings)
📖 Documentation
- Tool Discovery System - How semantic search and tags work together
- Adding New MCP Servers - Step-by-step guide to integrate new servers
- AI Integration Guide - How AI assistants can automatically add MCP servers
- Architecture Overview - System design and component interactions
📁 Project Structure
tool-gating-mcp/
├── src/
│ └── tool_gating_mcp/
│ ├── __init__.py
│ ├── main.py # FastAPI application
│ ├── api/
│ │ ├── models.py # Pydantic models
│ │ ├── tools.py # Tool management endpoints
│ │ └── mcp.py # MCP server endpoints
│ ├── models/
│ │ └── tool.py # Domain models
│ └── services/
│ ├── discovery.py # Semantic search
│ ├── gating.py # Tool selection logic
│ └── repository.py # Tool storage
├── tests/
│ ├── test_*.py # Test files
│ └── test_integration.py # Integration tests
├── demo.py # Interactive demo
├── test_server.py # Manual testing script
└── pyproject.toml # Project configuration
🔌 Integration with MCP Servers
Registering Tools from MCP Servers
# 1. Clear existing demo tools
DELETE /api/tools/clear
# 2. Register tools from your MCP servers
POST /api/tools/register
{
"id": "exa_research_paper_search",
"name": "research_paper_search",
"description": "Search across 100M+ research papers with full text access",
"tags": ["search", "research", "academic"],
"estimated_tokens": 250,
"server": "exa",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"numResults": {"type": "number", "default": 5}
},
"required": ["query"]
}
}
Using with LLM Orchestration
- LLM receives user query: "Find recent papers on quantum computing"
- Orchestrator queries tool gating:
POST /api/tools/discover {"query": "find research papers", "limit": 3} - System returns relevant tools: Only research tools, not file editors
- Orchestrator provisions tools:
POST /api/tools/provision {"tool_ids": ["exa_research_paper_search"], "max_tokens": 500} - LLM executes directly with MCP server: Using the provisioned tool definition
AI-Assisted Server Registration
AI assistants can automatically add new MCP servers:
# User: "Add this Slack MCP server to tool gating"
# AI: Connects to server, discovers tools, and registers everything
POST /api/mcp/ai/register-server
{
"server_name": "slack",
"config": {
"command": "npx",
"args": ["@slack/mcp-server"],
"env": {"SLACK_TOKEN": "xoxb-..."}
},
"tools": [
// AI provides all discovered tools with metadata
]
}
# Result: Slack server + all tools registered and ready for use
🧑💻 Development
Code Quality
# Format code
black .
# Run linter
ruff check . --fix
# Type checking
mypy .
# Run all checks
black . && ruff check . --fix && mypy . && pytest
Adding New Tools
Tools can be added to the repository in services/repository.py:
Tool(
id="my-tool",
name="My Tool",
description="Description for semantic search",
tags=["category", "function"],
estimated_tokens=100,
parameters={
"type": "object",
"properties": {...},
"required": [...]
}
)
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests
- Run quality checks (
black,ruff,mypy,pytest) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with FastAPI
- Semantic search powered by Sentence Transformers
- MCP protocol integration via fastapi-mcp
- Demo UI using Rich